about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs2
-rw-r--r--Cargo.lock57
-rw-r--r--README.md2
-rw-r--r--compiler/rustc_abi/src/lib.rs8
-rw-r--r--compiler/rustc_ast_lowering/locales/en-US.ftl3
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs19
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs19
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs39
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs153
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs4
-rw-r--r--compiler/rustc_ast_passes/locales/en-US.ftl150
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs591
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs483
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs56
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs2
-rw-r--r--compiler/rustc_ast_passes/src/show_span.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs25
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs24
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs7
-rw-r--r--compiler/rustc_borrowck/src/lib.rs11
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs36
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs5
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs6
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs10
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs39
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs47
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs3
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs11
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs6
-rw-r--r--compiler/rustc_const_eval/src/lib.rs7
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs24
-rw-r--r--compiler/rustc_const_eval/src/util/might_permit_raw_init.rs6
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs5
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs13
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0476.md21
-rw-r--r--compiler/rustc_error_codes/src/lib.rs7
-rw-r--r--compiler/rustc_error_messages/src/lib.rs7
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs1
-rw-r--r--compiler/rustc_errors/src/json.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs20
-rw-r--r--compiler/rustc_errors/src/registry.rs12
-rw-r--r--compiler/rustc_errors/src/translation.rs17
-rw-r--r--compiler/rustc_expand/locales/en-US.ftl4
-rw-r--r--compiler/rustc_expand/src/errors.rs15
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs12
-rw-r--r--compiler/rustc_feature/src/accepted.rs4
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_hir/src/hir.rs14
-rw-r--r--compiler/rustc_hir/src/intravisit.rs4
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_hir_analysis/locales/en-US.ftl36
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs53
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs23
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs133
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs19
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs101
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs94
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs2
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs37
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs117
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs63
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs254
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs8
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs10
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs5
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs12
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs5
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs5
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs7
-rw-r--r--compiler/rustc_infer/src/lib.rs1
-rw-r--r--compiler/rustc_infer/src/traits/util.rs31
-rw-r--r--compiler/rustc_interface/locales/en-US.ftl4
-rw-r--r--compiler/rustc_interface/src/errors.rs4
-rw-r--r--compiler/rustc_interface/src/passes.rs34
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lint/locales/en-US.ftl7
-rw-r--r--compiler/rustc_lint/src/builtin.rs6
-rw-r--r--compiler/rustc_lint/src/context.rs17
-rw-r--r--compiler/rustc_lint/src/lib.rs6
-rw-r--r--compiler/rustc_lint/src/lints.rs16
-rw-r--r--compiler/rustc_lint/src/map_unit_fn.rs120
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs30
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs7
-rw-r--r--compiler/rustc_macros/src/serialize.rs47
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs9
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs2
-rw-r--r--compiler/rustc_middle/src/arena.rs1
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs5
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs14
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs4
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs7
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs6
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs2
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs2
-rw-r--r--compiler/rustc_middle/src/query/keys.rs24
-rw-r--r--compiler/rustc_middle/src/query/mod.rs21
-rw-r--r--compiler/rustc_middle/src/thir.rs27
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs20
-rw-r--r--compiler/rustc_middle/src/ty/_match.rs4
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs2
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs60
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs38
-rw-r--r--compiler/rustc_middle/src/ty/context.rs300
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs2
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs2
-rw-r--r--compiler/rustc_middle/src/ty/impls_ty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs2
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs25
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs13
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs4
-rw-r--r--compiler/rustc_middle/src/ty/query.rs6
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs17
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs11
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs18
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs20
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs2
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs2
-rw-r--r--compiler/rustc_middle/src/values.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs188
-rw-r--r--compiler/rustc_mir_build/src/lib.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs47
-rw-r--r--compiler/rustc_mir_build/src/thir/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs (renamed from compiler/rustc_middle/src/thir/print.rs)27
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs31
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs32
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs6
-rw-r--r--compiler/rustc_mir_transform/src/copy_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs25
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs4
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs57
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs19
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/instcombine.rs59
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs7
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs2
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs8
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs2
-rw-r--r--compiler/rustc_parse/locales/en-US.ftl2
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs4
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs236
-rw-r--r--compiler/rustc_parse/src/parser/item.rs4
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs6
-rw-r--r--compiler/rustc_parse/src/parser/path.rs2
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs10
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs4
-rw-r--r--compiler/rustc_passes/locales/en-US.ftl9
-rw-r--r--compiler/rustc_passes/src/check_attr.rs31
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs63
-rw-r--r--compiler/rustc_passes/src/errors.rs28
-rw-r--r--compiler/rustc_passes/src/liveness.rs6
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs5
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs4
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs61
-rw-r--r--compiler/rustc_query_system/src/query/caches.rs6
-rw-r--r--compiler/rustc_query_system/src/query/config.rs4
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs61
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs135
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs8
-rw-r--r--compiler/rustc_resolve/src/lib.rs9
-rw-r--r--compiler/rustc_serialize/src/serialize.rs12
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_span/src/lib.rs14
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs4
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs5
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs47
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs52
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs124
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs53
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs4
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs8
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs39
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs12
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs2
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs6
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs40
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs4
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs13
-rw-r--r--config.toml.example3
-rw-r--r--library/alloc/src/collections/binary_heap/mod.rs24
-rw-r--r--library/alloc/src/collections/binary_heap/tests.rs19
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs117
-rw-r--r--library/alloc/src/collections/vec_deque/tests.rs42
-rw-r--r--library/alloc/src/vec/mod.rs4
-rw-r--r--library/core/src/convert/mod.rs2
-rw-r--r--library/core/src/iter/mod.rs1
-rw-r--r--library/core/src/iter/traits/iterator.rs77
-rw-r--r--library/core/src/lib.rs8
-rw-r--r--library/core/src/net/display_buffer.rs (renamed from library/std/src/net/display_buffer.rs)0
-rw-r--r--library/core/src/net/ip_addr.rs2070
-rw-r--r--library/core/src/net/mod.rs24
-rw-r--r--library/core/src/net/parser.rs (renamed from library/std/src/net/parser.rs)4
-rw-r--r--library/core/src/net/socket_addr.rs664
-rw-r--r--library/core/src/num/int_macros.rs45
-rw-r--r--library/core/src/num/uint_macros.rs37
-rw-r--r--library/core/src/slice/sort.rs24
-rw-r--r--library/core/tests/lib.rs5
-rw-r--r--library/core/tests/net/ip_addr.rs1035
-rw-r--r--library/core/tests/net/mod.rs13
-rw-r--r--library/core/tests/net/parser.rs (renamed from library/std/src/net/parser/tests.rs)4
-rw-r--r--library/core/tests/net/socket_addr.rs233
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/fs/tests.rs16
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/net/ip_addr.rs2075
-rw-r--r--library/std/src/net/ip_addr/tests.rs1035
-rw-r--r--library/std/src/net/mod.rs6
-rw-r--r--library/std/src/net/socket_addr.rs689
-rw-r--r--library/std/src/os/fd/owned.rs9
-rw-r--r--library/std/src/os/fd/raw.rs10
-rw-r--r--library/std/src/os/hermit/io/mod.rs13
-rw-r--r--library/std/src/os/hermit/io/net.rs46
-rw-r--r--library/std/src/os/hermit/mod.rs5
-rw-r--r--library/std/src/os/mod.rs12
-rw-r--r--library/std/src/sys/hermit/args.rs2
-rw-r--r--library/std/src/sys/hermit/fd.rs77
-rw-r--r--library/std/src/sys/hermit/fs.rs57
-rw-r--r--library/std/src/sys/hermit/mod.rs87
-rw-r--r--library/std/src/sys/hermit/net.rs639
-rw-r--r--library/std/src/sys/hermit/os.rs2
-rw-r--r--library/std/src/sys/hermit/time.rs98
-rw-r--r--library/std/src/sys/windows/args.rs11
-rw-r--r--library/std/src/sys/windows/c.rs40
-rw-r--r--library/std/src/sys/windows/io.rs32
-rw-r--r--library/std/src/sys/windows/stdio.rs74
-rw-r--r--library/std/src/sys_common/mod.rs1
-rw-r--r--library/std/src/time.rs6
-rw-r--r--library/std/tests/common/mod.rs58
-rw-r--r--library/std/tests/create_dir_all_bare.rs39
-rw-r--r--library/std/tests/env.rs14
-rw-r--r--library/test/Cargo.toml2
-rw-r--r--src/bootstrap/Cargo.lock4
-rw-r--r--src/bootstrap/Cargo.toml5
-rw-r--r--src/bootstrap/builder.rs9
-rw-r--r--src/bootstrap/check.rs88
-rw-r--r--src/bootstrap/compile.rs2
-rw-r--r--src/bootstrap/config.rs4
-rwxr-xr-xsrc/bootstrap/configure.py26
-rw-r--r--src/bootstrap/flags.rs13
-rw-r--r--src/bootstrap/format.rs6
-rw-r--r--src/bootstrap/metadata.rs2
-rw-r--r--src/bootstrap/metrics.rs2
-rw-r--r--src/bootstrap/setup.rs120
-rw-r--r--src/bootstrap/toolstate.rs2
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rwxr-xr-xsrc/ci/docker/scripts/fuchsia-test-runner.py82
-rw-r--r--src/doc/index.md228
-rw-r--r--src/doc/rustc/src/platform-support/fuchsia.md94
-rw-r--r--src/librustdoc/clean/mod.rs6
-rw-r--r--src/librustdoc/html/markdown.rs5
-rw-r--r--src/librustdoc/html/static/js/search.js17
-rw-r--r--src/librustdoc/html/static/js/source-script.js3
-rw-r--r--src/librustdoc/visit_ast.rs20
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/CHANGELOG.md7
-rw-r--r--src/tools/clippy/README.md39
-rw-r--r--src/tools/clippy/book/src/development/infrastructure/backport.md1
-rw-r--r--src/tools/clippy/book/src/development/infrastructure/sync.md3
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md18
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs9
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs93
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs153
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_used.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/module_style.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark_used.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs110
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs399
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs107
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/numeric_literal.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs33
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs12
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs5
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.rs3
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr4
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr18
-rw-r--r--src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs12
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs59
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr52
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr1
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs6
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr10
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.rs27
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.stderr198
-rw-r--r--src/tools/clippy/tests/ui/box_default.fixed18
-rw-r--r--src/tools/clippy/tests/ui/box_default.rs18
-rw-r--r--src/tools/clippy/tests/ui/box_default.stderr14
-rw-r--r--src/tools/clippy/tests/ui/bytes_nth.fixed6
-rw-r--r--src/tools/clippy/tests/ui/bytes_nth.rs2
-rw-r--r--src/tools/clippy/tests/ui/bytes_nth.stderr10
-rw-r--r--src/tools/clippy/tests/ui/cast.stderr36
-rw-r--r--src/tools/clippy/tests/ui/cast_size.stderr18
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs9
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr15
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.rs4
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.stderr24
-rw-r--r--src/tools/clippy/tests/ui/entry.fixed14
-rw-r--r--src/tools/clippy/tests/ui/entry.rs14
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.fixed14
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.rs14
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_type_parameters.rs53
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr42
-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.stderr30
-rw-r--r--src/tools/clippy/tests/ui/impl_trait_in_params.rs17
-rw-r--r--src/tools/clippy/tests/ui/impl_trait_in_params.stderr25
-rw-r--r--src/tools/clippy/tests/ui/large_digit_groups.fixed4
-rw-r--r--src/tools/clippy/tests/ui/large_digit_groups.stderr20
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_untyped.rs54
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_untyped.stderr51
-rw-r--r--src/tools/clippy/tests/ui/literals.stderr10
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.rs11
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.rs29
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.stderr15
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.fixed1
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.rs1
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.stderr18
-rw-r--r--src/tools/clippy/tests/ui/methods.rs1
-rw-r--r--src/tools/clippy/tests/ui/methods.stderr4
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.fixed2
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.rs2
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.fixed10
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.rs10
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed10
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs10
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr18
-rw-r--r--src/tools/clippy/tests/ui/never_loop.rs45
-rw-r--r--src/tools/clippy/tests/ui/never_loop.stderr15
-rw-r--r--src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed48
-rw-r--r--src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs48
-rw-r--r--src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr45
-rw-r--r--src/tools/clippy/tests/ui/question_mark_used.rs15
-rw-r--r--src/tools/clippy/tests/ui/question_mark_used.stderr11
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.fixed84
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.rs80
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.stderr94
-rw-r--r--src/tools/clippy/tests/ui/suspicious_command_arg_space.rs10
-rw-r--r--src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr25
-rw-r--r--src/tools/clippy/tests/ui/swap.fixed24
-rw-r--r--src/tools/clippy/tests/ui/swap.rs29
-rw-r--r--src/tools/clippy/tests/ui/swap.stderr65
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs41
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr64
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args.fixed4
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args.rs4
-rw-r--r--src/tools/clippy/tests/ui/unreadable_literal.fixed2
-rw-r--r--src/tools/clippy/tests/ui/unreadable_literal.stderr10
-rw-r--r--src/tools/error_index_generator/Cargo.toml1
-rw-r--r--src/tools/error_index_generator/main.rs58
-rw-r--r--src/tools/jsondoclint/src/validator.rs28
-rw-r--r--src/tools/miri/CONTRIBUTING.md7
-rw-r--r--src/tools/miri/README.md6
-rw-r--r--src/tools/miri/cargo-miri/Cargo.lock4
-rw-r--r--src/tools/miri/cargo-miri/Cargo.toml2
-rw-r--r--src/tools/miri/cargo-miri/build.rs9
-rwxr-xr-xsrc/tools/miri/ci.sh2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs3
-rw-r--r--src/tools/miri/src/eval.rs2
-rw-r--r--src/tools/miri/src/lib.rs3
-rw-r--r--src/tools/miri/src/machine.rs19
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs13
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd.rs58
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd/event.rs35
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs6
-rw-r--r--src/tools/miri/test-cargo-miri/src/main.rs6
-rw-r--r--src/tools/miri/test-cargo-miri/subcrate/main.rs6
-rw-r--r--src/tools/miri/test-cargo-miri/subcrate/test.rs6
-rw-r--r--src/tools/miri/test_dependencies/Cargo.lock4
-rw-r--r--src/tools/miri/test_dependencies/Cargo.toml2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-fs.rs8
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-misc.rs8
-rw-r--r--src/tools/miri/tests/pass-dep/tokio/sleep.rs14
-rw-r--r--src/tools/miri/tests/pass-dep/tokio/tokio_mvp.rs (renamed from src/tools/miri/tests/pass-dep/tokio_mvp.rs)2
-rw-r--r--src/tools/miri/tests/pass/dyn-star.rs3
-rw-r--r--src/tools/miri/tests/pass/move-data-across-await-point.rs81
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs2
-rw-r--r--src/tools/tidy/src/error_codes.rs26
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.diff82
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.rs16
-rw-r--r--tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.diff6
-rw-r--r--tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff4
-rw-r--r--tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff4
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff2
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff2
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff2
-rw-r--r--tests/mir-opt/inline/inline_compatibility.rs1
-rw-r--r--tests/mir-opt/issue_41110.main.ElaborateDrops.after.mir70
-rw-r--r--tests/mir-opt/issue_41110.main.ElaborateDrops.diff75
-rw-r--r--tests/mir-opt/issue_41110.rs4
-rw-r--r--tests/mir-opt/issue_41110.test.ElaborateDrops.after.mir101
-rw-r--r--tests/mir-opt/issue_41110.test.ElaborateDrops.diff109
-rw-r--r--tests/mir-opt/issue_41888.main.ElaborateDrops.after.mir152
-rw-r--r--tests/mir-opt/issue_41888.main.ElaborateDrops.diff158
-rw-r--r--tests/mir-opt/issue_41888.rs2
-rw-r--r--tests/rustdoc-gui/help-page.goml3
-rw-r--r--tests/rustdoc-ui/auxiliary/panic-handler.rs9
-rw-r--r--tests/rustdoc-ui/issue-107918.rs12
-rw-r--r--tests/rustdoc-ui/proc_macro_bug.rs12
-rw-r--r--tests/rustdoc-ui/proc_macro_bug.stderr8
-rw-r--r--tests/rustdoc-ui/unable-fulfill-trait.stderr2
-rw-r--r--tests/rustdoc-ui/z-help.stdout1
-rw-r--r--tests/rustdoc/item-desc-list-at-start.item-table.html1
-rw-r--r--tests/rustdoc/item-desc-list-at-start.rs9
-rw-r--r--tests/rustdoc/reexports-of-same-name.rs26
-rw-r--r--tests/ui-fulldeps/create-dir-all-bare.rs11
-rw-r--r--tests/ui-fulldeps/rename-directory.rs30
-rw-r--r--tests/ui-fulldeps/std/issue-15149.rs (renamed from tests/ui-fulldeps/issue-15149.rs)0
-rw-r--r--tests/ui-fulldeps/std/issue-81357-unsound-file-methods.rs (renamed from tests/ui-fulldeps/issue-81357-unsound-file-methods.rs)0
-rw-r--r--tests/ui-fulldeps/std/stdio-from.rs (renamed from tests/ui-fulldeps/stdio-from.rs)0
-rw-r--r--tests/ui-fulldeps/std/switch-stdout.rs (renamed from tests/ui-fulldeps/switch-stdout.rs)0
-rw-r--r--tests/ui/argument-suggestions/issue-100154.stderr2
-rw-r--r--tests/ui/asm/x86_64/issue-89875.rs2
-rw-r--r--tests/ui/associated-consts/issue-105330.stderr2
-rw-r--r--tests/ui/associated-type-bounds/bad-universal-in-dyn-in-where-clause.rs14
-rw-r--r--tests/ui/associated-type-bounds/bad-universal-in-dyn-in-where-clause.stderr8
-rw-r--r--tests/ui/associated-type-bounds/bad-universal-in-impl-sig.rs13
-rw-r--r--tests/ui/associated-type-bounds/bad-universal-in-impl-sig.stderr8
-rw-r--r--tests/ui/associated-type-bounds/inside-adt.rs22
-rw-r--r--tests/ui/associated-type-bounds/inside-adt.stderr105
-rw-r--r--tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs71
-rw-r--r--tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr26
-rw-r--r--tests/ui/async-await/in-trait/fn-not-async-err2.rs2
-rw-r--r--tests/ui/async-await/in-trait/fn-not-async-err2.stderr2
-rw-r--r--tests/ui/async-await/issues/issue-65159.rs2
-rw-r--r--tests/ui/async-await/issues/issue-65159.stderr2
-rw-r--r--tests/ui/attributes/invalid_macro_export_argument.rs26
-rw-r--r--tests/ui/attributes/invalid_macro_export_argument.stderr16
-rw-r--r--tests/ui/auto-traits/auto-trait-validation.stderr6
-rw-r--r--tests/ui/auto-traits/issue-23080-2.stderr2
-rw-r--r--tests/ui/auto-traits/issue-23080.stderr2
-rw-r--r--tests/ui/auto-traits/issue-84075.stderr2
-rw-r--r--tests/ui/auto-traits/str-contains-slice-conceptually.rs13
-rw-r--r--tests/ui/auto-traits/str-contains-slice-conceptually.stderr16
-rw-r--r--tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr4
-rw-r--r--tests/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr2
-rw-r--r--tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs4
-rw-r--r--tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-102768.rs4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-102768.stderr4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-76595.stderr2
-rw-r--r--tests/ui/const-generics/incorrect-number-of-const-args.stderr4
-rw-r--r--tests/ui/const-generics/invalid-const-arg-for-type-param.rs4
-rw-r--r--tests/ui/const-generics/invalid-const-arg-for-type-param.stderr4
-rw-r--r--tests/ui/const-generics/invalid-constant-in-args.rs2
-rw-r--r--tests/ui/const-generics/invalid-constant-in-args.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-87493.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-87493.stderr2
-rw-r--r--tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs2
-rw-r--r--tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr2
-rw-r--r--tests/ui/const-generics/parser-error-recovery/issue-89013.rs2
-rw-r--r--tests/ui/const-generics/parser-error-recovery/issue-89013.stderr2
-rw-r--r--tests/ui/constructor-lifetime-args.rs8
-rw-r--r--tests/ui/constructor-lifetime-args.stderr8
-rw-r--r--tests/ui/consts/gate-do-not-const-check.rs5
-rw-r--r--tests/ui/consts/gate-do-not-const-check.stderr11
-rw-r--r--tests/ui/error-codes/E0107.rs20
-rw-r--r--tests/ui/error-codes/E0107.stderr20
-rw-r--r--tests/ui/error-codes/E0476.rs13
-rw-r--r--tests/ui/error-codes/E0476.stderr31
-rw-r--r--tests/ui/expr/malformed_closure/missing_braces_around_block.fixed9
-rw-r--r--tests/ui/expr/malformed_closure/missing_braces_around_block.rs9
-rw-r--r--tests/ui/expr/malformed_closure/missing_braces_around_block.stderr33
-rw-r--r--tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr6
-rw-r--r--tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr6
-rw-r--r--tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs6
-rw-r--r--tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr6
-rw-r--r--tests/ui/generic-associated-types/missing_lifetime_args.rs4
-rw-r--r--tests/ui/generic-associated-types/missing_lifetime_args.stderr4
-rw-r--r--tests/ui/generic-associated-types/missing_lifetime_const.rs2
-rw-r--r--tests/ui/generic-associated-types/missing_lifetime_const.stderr2
-rw-r--r--tests/ui/generic-associated-types/parameter_number_and_kind.rs6
-rw-r--r--tests/ui/generic-associated-types/parameter_number_and_kind.stderr6
-rw-r--r--tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs4
-rw-r--r--tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr4
-rw-r--r--tests/ui/generics/bad-mid-path-type-params.rs10
-rw-r--r--tests/ui/generics/bad-mid-path-type-params.stderr10
-rw-r--r--tests/ui/generics/generic-arg-mismatch-recover.rs6
-rw-r--r--tests/ui/generics/generic-arg-mismatch-recover.stderr6
-rw-r--r--tests/ui/generics/generic-impl-less-params-with-defaults.rs2
-rw-r--r--tests/ui/generics/generic-impl-less-params-with-defaults.stderr2
-rw-r--r--tests/ui/generics/generic-impl-more-params-with-defaults.rs2
-rw-r--r--tests/ui/generics/generic-impl-more-params-with-defaults.stderr2
-rw-r--r--tests/ui/generics/generic-type-more-params-with-defaults.rs2
-rw-r--r--tests/ui/generics/generic-type-more-params-with-defaults.stderr2
-rw-r--r--tests/ui/generics/wrong-number-of-args.rs106
-rw-r--r--tests/ui/generics/wrong-number-of-args.stderr106
-rw-r--r--tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr2
-rw-r--r--tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr2
-rw-r--r--tests/ui/impl-trait/issues/issue-54600.stderr2
-rw-r--r--tests/ui/impl-trait/issues/issue-54840.stderr2
-rw-r--r--tests/ui/impl-trait/issues/issue-58504.stderr2
-rw-r--r--tests/ui/impl-trait/issues/issue-58956.stderr4
-rw-r--r--tests/ui/impl-trait/issues/issue-70971.stderr2
-rw-r--r--tests/ui/impl-trait/issues/issue-79099.stderr2
-rw-r--r--tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr4
-rw-r--r--tests/ui/impl-trait/issues/issue-84919.stderr2
-rw-r--r--tests/ui/impl-trait/issues/issue-86642.stderr2
-rw-r--r--tests/ui/impl-trait/issues/issue-87295.stderr2
-rw-r--r--tests/ui/impl-trait/nested_impl_trait.stderr2
-rw-r--r--tests/ui/impl-trait/where-allowed.stderr78
-rw-r--r--tests/ui/issues/issue-106755.rs19
-rw-r--r--tests/ui/issues/issue-106755.stderr22
-rw-r--r--tests/ui/issues/issue-18423.rs2
-rw-r--r--tests/ui/issues/issue-18423.stderr2
-rw-r--r--tests/ui/issues/issue-3214.rs2
-rw-r--r--tests/ui/issues/issue-3214.stderr2
-rw-r--r--tests/ui/issues/issue-47715.stderr8
-rw-r--r--tests/ui/issues/issue-53251.rs4
-rw-r--r--tests/ui/issues/issue-53251.stderr4
-rw-r--r--tests/ui/issues/issue-60622.rs2
-rw-r--r--tests/ui/issues/issue-60622.stderr2
-rw-r--r--tests/ui/issues/issue-70093/issue-70093-link-directives.rs10
-rw-r--r--tests/ui/issues/issue-70093/issue-70093.rs (renamed from tests/ui/issues/issue-70093.rs)0
-rw-r--r--tests/ui/late-bound-lifetimes/mismatched_arg_count.rs2
-rw-r--r--tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr2
-rw-r--r--tests/ui/lifetimes/issue-107988.rs13
-rw-r--r--tests/ui/lifetimes/issue-107988.stderr27
-rw-r--r--tests/ui/lint/issue-106991.rs13
-rw-r--r--tests/ui/lint/issue-106991.stderr11
-rw-r--r--tests/ui/lint/lint_map_unit_fn.rs20
-rw-r--r--tests/ui/lint/lint_map_unit_fn.stderr66
-rw-r--r--tests/ui/methods/issues/issue-105732.stderr2
-rw-r--r--tests/ui/methods/method-call-lifetime-args-fail.rs8
-rw-r--r--tests/ui/methods/method-call-lifetime-args-fail.stderr8
-rw-r--r--tests/ui/mir/validate/storage-live.rs30
-rw-r--r--tests/ui/mir/validate/storage-live.stderr13
-rw-r--r--tests/ui/parser/match-arm-without-braces.stderr10
-rw-r--r--tests/ui/resolve/issue-108529.rs8
-rw-r--r--tests/ui/resolve/issue-108529.stderr9
-rw-r--r--tests/ui/rfc-2091-track-caller/error-with-main.stderr2
-rw-r--r--tests/ui/rfc-2457/mod_file_nonascii_forbidden.stderr2
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/do-not-const-check-override.rs19
-rw-r--r--tests/ui/rfc-2632-const-trait-impl/do-not-const-check.rs18
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs2
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs2
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs6
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr14
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs2
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs2
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr24
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs2
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr20
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs2
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr20
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs2
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr2
-rw-r--r--tests/ui/rust-2018/remove-extern-crate.fixed10
-rw-r--r--tests/ui/rust-2018/remove-extern-crate.rs10
-rw-r--r--tests/ui/rust-2018/remove-extern-crate.stderr22
-rw-r--r--tests/ui/seq-args.rs4
-rw-r--r--tests/ui/seq-args.stderr4
-rw-r--r--tests/ui/stability-attribute/unresolved_stability_lint.rs8
-rw-r--r--tests/ui/stability-attribute/unresolved_stability_lint.stderr9
-rw-r--r--tests/ui/structs/struct-path-associated-type.rs4
-rw-r--r--tests/ui/structs/struct-path-associated-type.stderr4
-rw-r--r--tests/ui/structs/structure-constructor-type-mismatch.rs4
-rw-r--r--tests/ui/structs/structure-constructor-type-mismatch.stderr4
-rw-r--r--tests/ui/suggestions/issue-101421.rs2
-rw-r--r--tests/ui/suggestions/issue-101421.stderr2
-rw-r--r--tests/ui/suggestions/issue-104287.rs2
-rw-r--r--tests/ui/suggestions/issue-104287.stderr2
-rw-r--r--tests/ui/suggestions/issue-85347.rs2
-rw-r--r--tests/ui/suggestions/issue-85347.stderr2
-rw-r--r--tests/ui/suggestions/issue-89064.stderr8
-rw-r--r--tests/ui/suggestions/missing-lifetime-specifier.rs20
-rw-r--r--tests/ui/suggestions/missing-lifetime-specifier.stderr20
-rw-r--r--tests/ui/suggestions/missing-type-param-used-in-param.stderr2
-rw-r--r--tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs2
-rw-r--r--tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr2
-rw-r--r--tests/ui/suggestions/type-ascription-instead-of-path-in-type.stderr2
-rw-r--r--tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs2
-rw-r--r--tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr2
-rw-r--r--tests/ui/target-feature/invalid-attribute.rs13
-rw-r--r--tests/ui/target-feature/invalid-attribute.stderr43
-rw-r--r--tests/ui/thir-print/thir-flat.stdout3
-rw-r--r--tests/ui/tool-attributes/auxiliary/p1.rs3
-rw-r--r--tests/ui/tool-attributes/auxiliary/p2.rs3
-rw-r--r--tests/ui/tool-attributes/duplicate-diagnostic.rs13
-rw-r--r--tests/ui/tool-attributes/duplicate-diagnostic.stderr14
-rw-r--r--tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr2
-rw-r--r--tests/ui/traits/issue-77982.stderr2
-rw-r--r--tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs17
-rw-r--r--tests/ui/traits/new-solver/more-object-bound.rs27
-rw-r--r--tests/ui/traits/new-solver/more-object-bound.stderr19
-rw-r--r--tests/ui/traits/new-solver/object-unsafety.rs20
-rw-r--r--tests/ui/traits/new-solver/object-unsafety.stderr19
-rw-r--r--tests/ui/traits/new-solver/try-example.rs28
-rw-r--r--tests/ui/traits/object/vs-lifetime.rs4
-rw-r--r--tests/ui/traits/object/vs-lifetime.stderr4
-rw-r--r--tests/ui/traits/test-2.rs4
-rw-r--r--tests/ui/traits/test-2.stderr4
-rw-r--r--tests/ui/transmutability/issue-101739-2.rs2
-rw-r--r--tests/ui/transmutability/issue-101739-2.stderr2
-rw-r--r--tests/ui/type-alias-enum-variants/enum-variant-generic-args.rs12
-rw-r--r--tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr12
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr2
-rw-r--r--tests/ui/typeck/issue-104513-ice.stderr2
-rw-r--r--tests/ui/typeck/issue-75883.rs4
-rw-r--r--tests/ui/typeck/issue-75883.stderr4
-rw-r--r--tests/ui/typeck/lazy-norm/cast-checks-handling-projections.rs6
-rw-r--r--tests/ui/typeck/lazy-norm/cast-checks-handling-projections.stderr9
-rw-r--r--tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs24
-rw-r--r--tests/ui/typeck/lazy-norm/equating-projection-cyclically.stderr14
-rw-r--r--tests/ui/typeck/typeck-builtin-bound-type-parameters.rs12
-rw-r--r--tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr12
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_item.rs4
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_item.stderr34
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_lifetime_1.rs2
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr2
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_lifetime_2.rs2
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr2
-rw-r--r--tests/ui/ufcs/ufcs-qpath-missing-params.rs2
-rw-r--r--tests/ui/ufcs/ufcs-qpath-missing-params.stderr2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs10
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr10
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.rs2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr2
-rw-r--r--triagebot.toml2
750 files changed, 14542 insertions, 8952 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index d20f19e60e8..353bfcb6ac1 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -1,3 +1,5 @@
+# Use `git config blame.ignorerevsfile .git-blame-ignore-revs` to make `git blame` ignore the following commits.
+
 # format the world
 a06baa56b95674fc626b3c3fd680d6a65357fe60
 # format libcore
diff --git a/Cargo.lock b/Cargo.lock
index 8d6db8cf17d..c4704fb0dd5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -90,15 +90,6 @@ dependencies = [
 
 [[package]]
 name = "ansi_term"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "ansi_term"
 version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
@@ -390,7 +381,6 @@ dependencies = [
  "os_info",
  "pasetors",
  "pathdiff",
- "percent-encoding",
  "pretty_env_logger",
  "rustc-workspace-hack",
  "rustfix",
@@ -454,7 +444,7 @@ dependencies = [
  "directories",
  "rustc-build-sysroot",
  "rustc-workspace-hack",
- "rustc_tools_util 0.2.1",
+ "rustc_tools_util",
  "rustc_version",
  "serde",
  "serde_json",
@@ -748,7 +738,7 @@ dependencies = [
  "regex",
  "rustc-semver",
  "rustc-workspace-hack",
- "rustc_tools_util 0.3.0",
+ "rustc_tools_util",
  "semver",
  "serde",
  "syn",
@@ -1217,12 +1207,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
 
 [[package]]
-name = "difference"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
-
-[[package]]
 name = "digest"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1389,9 +1373,9 @@ dependencies = [
 
 [[package]]
 name = "ena"
-version = "0.14.0"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
+checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d"
 dependencies = [
  "log",
 ]
@@ -1461,6 +1445,7 @@ name = "error_index_generator"
 version = "0.0.0"
 dependencies = [
  "mdbook",
+ "rustc_error_codes",
 ]
 
 [[package]]
@@ -1943,8 +1928,16 @@ version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
 dependencies = [
- "compiler_builtins",
  "libc",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01"
+dependencies = [
+ "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
@@ -3193,14 +3186,14 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
 [[package]]
 name = "pretty_assertions"
-version = "0.6.1"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
+checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
 dependencies = [
- "ansi_term 0.11.0",
  "ctor",
- "difference",
+ "diff",
  "output_vt100",
+ "yansi",
 ]
 
 [[package]]
@@ -4734,12 +4727,6 @@ dependencies = [
 
 [[package]]
 name = "rustc_tools_util"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "598f48ce2a421542b3e64828aa742b687cc1b91d2f96591cfdb7ac5988cd6366"
-
-[[package]]
-name = "rustc_tools_util"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
@@ -5310,7 +5297,7 @@ dependencies = [
  "dlmalloc",
  "fortanix-sgx-abi",
  "hashbrown 0.12.3",
- "hermit-abi 0.2.6",
+ "hermit-abi 0.3.0",
  "libc",
  "miniz_oxide",
  "object 0.29.0",
@@ -5505,10 +5492,8 @@ dependencies = [
 name = "test"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
  "core",
  "getopts",
- "libc",
  "panic_abort",
  "panic_unwind",
  "proc_macro",
@@ -5783,7 +5768,7 @@ version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "245da694cc7fc4729f3f418b304cb57789f1bed2a78c575407ab8a23f53cb4d3"
 dependencies = [
- "ansi_term 0.12.1",
+ "ansi_term",
  "lazy_static",
  "matchers",
  "parking_lot 0.11.2",
@@ -5802,7 +5787,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3ce989c9962c7f61fe084dd4a230eec784649dfc2392467c790007c3a6e134e7"
 dependencies = [
- "ansi_term 0.12.1",
+ "ansi_term",
  "atty",
  "tracing-core",
  "tracing-log",
diff --git a/README.md b/README.md
index 0eb7c4b266a..c424bd12ffd 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
 # The Rust Programming Language
 
+[![Rust Community](https://img.shields.io/badge/Rust_Community%20-Join_us-brightgreen?style=plastic&logo=rust)](https://www.rust-lang.org/community)
+
 This is the main source code repository for [Rust]. It contains the compiler,
 standard library, and documentation.
 
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index aa3a666b0b2..39574ca558f 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1505,14 +1505,6 @@ pub struct PointeeInfo {
     pub safe: Option<PointerKind>,
 }
 
-/// Used in `might_permit_raw_init` to indicate the kind of initialisation
-/// that is checked to be valid
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum InitKind {
-    Zero,
-    UninitMitigated0x01Fill,
-}
-
 impl LayoutS {
     /// Returns `true` if the layout corresponds to an unsized type.
     pub fn is_unsized(&self) -> bool {
diff --git a/compiler/rustc_ast_lowering/locales/en-US.ftl b/compiler/rustc_ast_lowering/locales/en-US.ftl
index 03c88c6c0eb..a2837deafde 100644
--- a/compiler/rustc_ast_lowering/locales/en-US.ftl
+++ b/compiler/rustc_ast_lowering/locales/en-US.ftl
@@ -19,6 +19,9 @@ ast_lowering_remove_parentheses = remove these parentheses
 ast_lowering_misplaced_impl_trait =
     `impl Trait` only allowed in function and inherent method return types, not in {$position}
 
+ast_lowering_misplaced_assoc_ty_binding =
+    associated type bounds are only allowed in where clauses and function signatures, not in {$position}
+
 ast_lowering_rustc_box_attribute_error =
     #[rustc_box] requires precisely one argument and no other attributes are allowed
 
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 8b302ac2142..def74c2adee 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -79,6 +79,14 @@ pub struct MisplacedImplTrait<'a> {
     pub position: DiagnosticArgFromDisplay<'a>,
 }
 
+#[derive(Diagnostic)]
+#[diag(ast_lowering_misplaced_assoc_ty_binding)]
+pub struct MisplacedAssocTyBinding<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub position: DiagnosticArgFromDisplay<'a>,
+}
+
 #[derive(Diagnostic, Clone, Copy)]
 #[diag(ast_lowering_rustc_box_attribute_error)]
 pub struct RustcBoxAttributeError {
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index dfe790b4851..d4fafe38638 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -88,8 +88,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             let kind = hir::ExprKind::Box(self.lower_expr(&inner));
                             return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
                         } else {
-                            self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span });
-                            hir::ExprKind::Err
+                            let guar = self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span });
+                            hir::ExprKind::Err(guar)
                         }
                     } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
                         self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
@@ -266,8 +266,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
                 }
                 ExprKind::Underscore => {
-                    self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span });
-                    hir::ExprKind::Err
+                    let guar = self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span });
+                    hir::ExprKind::Err(guar)
                 }
                 ExprKind::Path(qself, path) => {
                     let qpath = self.lower_qpath(
@@ -299,8 +299,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let rest = match &se.rest {
                         StructRest::Base(e) => Some(self.lower_expr(e)),
                         StructRest::Rest(sp) => {
-                            self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp });
-                            Some(&*self.arena.alloc(self.expr_err(*sp)))
+                            let guar =
+                                self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp });
+                            Some(&*self.arena.alloc(self.expr_err(*sp, guar)))
                         }
                         StructRest::None => None,
                     };
@@ -318,7 +319,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     )
                 }
                 ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
-                ExprKind::Err => hir::ExprKind::Err,
+                ExprKind::Err => hir::ExprKind::Err(
+                    self.tcx.sess.delay_span_bug(e.span, "lowered ExprKind::Err"),
+                ),
                 ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
 
                 ExprKind::Paren(_) | ExprKind::ForLoop(..) => unreachable!("already handled"),
@@ -761,7 +764,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 self.expr_ident_mut(span, task_context_ident, task_context_hid)
             } else {
                 // Use of `await` outside of an async context, we cannot use `task_context` here.
-                self.expr_err(span)
+                self.expr_err(span, self.tcx.sess.delay_span_bug(span, "no task_context hir id"))
             };
             let new_unchecked = self.expr_call_lang_item_fn_mut(
                 span,
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index e7dd0b18a03..4095e225a80 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -102,7 +102,12 @@ fn make_count<'hir>(
                 let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, i)]);
                 ctx.expr_call_mut(sp, count_param, value)
             } else {
-                ctx.expr(sp, hir::ExprKind::Err)
+                ctx.expr(
+                    sp,
+                    hir::ExprKind::Err(
+                        ctx.tcx.sess.delay_span_bug(sp, "lowered bad format_args count"),
+                    ),
+                )
             }
         }
         None => ctx.expr_lang_item_type_relative(sp, hir::LangItem::FormatCount, sym::Implied),
@@ -135,7 +140,10 @@ fn make_format_spec<'hir>(
                 argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
             ctx.expr_usize(sp, i)
         }
-        Err(_) => ctx.expr(sp, hir::ExprKind::Err),
+        Err(_) => ctx.expr(
+            sp,
+            hir::ExprKind::Err(ctx.tcx.sess.delay_span_bug(sp, "lowered bad format_args count")),
+        ),
     };
     let &FormatOptions {
         ref width,
@@ -294,7 +302,12 @@ fn expand_format_args<'hir>(
                 ));
                 make_argument(ctx, sp, arg, ty)
             } else {
-                ctx.expr(macsp, hir::ExprKind::Err)
+                ctx.expr(
+                    macsp,
+                    hir::ExprKind::Err(
+                        ctx.tcx.sess.delay_span_bug(macsp, format!("no arg at {arg_index}")),
+                    ),
+                )
             }
         }));
         let elements: Vec<_> = arguments
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 4a0e005b8b9..7325bce6055 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -7,6 +7,7 @@ use rustc_ast::ptr::P;
 use rustc_ast::visit::AssocCtxt;
 use rustc_ast::*;
 use rustc_data_structures::sorted_map::SortedMap;
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -284,7 +285,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
             },
             ItemKind::GlobalAsm(asm) => hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)),
-            ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty: Some(ty), .. }) => {
+            ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
                 // We lower
                 //
                 // type Foo = impl Trait
@@ -299,18 +300,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     &generics,
                     id,
                     &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    |this| this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy),
-                );
-                hir::ItemKind::TyAlias(ty, generics)
-            }
-            ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty: None, .. }) => {
-                let mut generics = generics.clone();
-                add_ty_alias_where_clause(&mut generics, *where_clauses, true);
-                let (generics, ty) = self.lower_generics(
-                    &generics,
-                    id,
-                    &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    |this| this.arena.alloc(this.ty(span, hir::TyKind::Err)),
+                    |this| match ty {
+                        None => {
+                            let guar = this.tcx.sess.delay_span_bug(
+                                span,
+                                "expected to lower type alias type, but it was missing",
+                            );
+                            this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
+                        }
+                        Some(ty) => this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy),
+                    },
                 );
                 hir::ItemKind::TyAlias(ty, generics)
             }
@@ -798,8 +797,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     /// Construct `ExprKind::Err` for the given `span`.
-    pub(crate) fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> {
-        self.expr(span, hir::ExprKind::Err)
+    pub(crate) fn expr_err(&mut self, span: Span, guar: ErrorGuaranteed) -> hir::Expr<'hir> {
+        self.expr(span, hir::ExprKind::Err(guar))
     }
 
     fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
@@ -847,7 +846,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| match ty {
                         None => {
-                            let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
+                            let guar = this.tcx.sess.delay_span_bug(
+                                i.span,
+                                "expected to lower associated type, but it was missing",
+                            );
+                            let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err(guar)));
                             hir::ImplItemKind::Type(ty)
                         }
                         Some(ty) => {
@@ -973,7 +976,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> {
         match block {
             Some(block) => self.lower_block_expr(block),
-            None => self.expr_err(span),
+            None => self.expr_err(span, self.tcx.sess.delay_span_bug(span, "no block")),
         }
     }
 
@@ -983,7 +986,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 &[],
                 match expr {
                     Some(expr) => this.lower_expr_mut(expr),
-                    None => this.expr_err(span),
+                    None => this.expr_err(span, this.tcx.sess.delay_span_bug(span, "no block")),
                 },
             )
         })
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index a726fbb72e9..5d78d914b6d 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -288,31 +288,31 @@ enum ImplTraitPosition {
 impl std::fmt::Display for ImplTraitPosition {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         let name = match self {
-            ImplTraitPosition::Path => "path",
-            ImplTraitPosition::Variable => "variable binding",
-            ImplTraitPosition::Trait => "trait",
-            ImplTraitPosition::AsyncBlock => "async block",
-            ImplTraitPosition::Bound => "bound",
-            ImplTraitPosition::Generic => "generic",
-            ImplTraitPosition::ExternFnParam => "`extern fn` param",
-            ImplTraitPosition::ClosureParam => "closure param",
-            ImplTraitPosition::PointerParam => "`fn` pointer param",
-            ImplTraitPosition::FnTraitParam => "`Fn` trait param",
-            ImplTraitPosition::TraitParam => "trait method param",
-            ImplTraitPosition::ImplParam => "`impl` method param",
-            ImplTraitPosition::ExternFnReturn => "`extern fn` return",
-            ImplTraitPosition::ClosureReturn => "closure return",
-            ImplTraitPosition::PointerReturn => "`fn` pointer return",
-            ImplTraitPosition::FnTraitReturn => "`Fn` trait return",
-            ImplTraitPosition::TraitReturn => "trait method return",
-            ImplTraitPosition::ImplReturn => "`impl` method return",
-            ImplTraitPosition::GenericDefault => "generic parameter default",
-            ImplTraitPosition::ConstTy => "const type",
-            ImplTraitPosition::StaticTy => "static type",
-            ImplTraitPosition::AssocTy => "associated type",
-            ImplTraitPosition::FieldTy => "field type",
-            ImplTraitPosition::Cast => "cast type",
-            ImplTraitPosition::ImplSelf => "impl header",
+            ImplTraitPosition::Path => "paths",
+            ImplTraitPosition::Variable => "variable bindings",
+            ImplTraitPosition::Trait => "traits",
+            ImplTraitPosition::AsyncBlock => "async blocks",
+            ImplTraitPosition::Bound => "bounds",
+            ImplTraitPosition::Generic => "generics",
+            ImplTraitPosition::ExternFnParam => "`extern fn` params",
+            ImplTraitPosition::ClosureParam => "closure params",
+            ImplTraitPosition::PointerParam => "`fn` pointer params",
+            ImplTraitPosition::FnTraitParam => "`Fn` trait params",
+            ImplTraitPosition::TraitParam => "trait method params",
+            ImplTraitPosition::ImplParam => "`impl` method params",
+            ImplTraitPosition::ExternFnReturn => "`extern fn` return types",
+            ImplTraitPosition::ClosureReturn => "closure return types",
+            ImplTraitPosition::PointerReturn => "`fn` pointer return types",
+            ImplTraitPosition::FnTraitReturn => "`Fn` trait return types",
+            ImplTraitPosition::TraitReturn => "trait method return types",
+            ImplTraitPosition::ImplReturn => "`impl` method return types",
+            ImplTraitPosition::GenericDefault => "generic parameter defaults",
+            ImplTraitPosition::ConstTy => "const types",
+            ImplTraitPosition::StaticTy => "static types",
+            ImplTraitPosition::AssocTy => "associated types",
+            ImplTraitPosition::FieldTy => "field types",
+            ImplTraitPosition::Cast => "cast types",
+            ImplTraitPosition::ImplSelf => "impl headers",
         };
 
         write!(f, "{name}")
@@ -1002,8 +1002,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         } else {
             self.arena.alloc(hir::GenericArgs::none())
         };
-        let itctx_tait = &ImplTraitContext::TypeAliasesOpaqueTy;
-
         let kind = match &constraint.kind {
             AssocConstraintKind::Equality { term } => {
                 let term = match term {
@@ -1013,8 +1011,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 hir::TypeBindingKind::Equality { term }
             }
             AssocConstraintKind::Bound { bounds } => {
+                enum DesugarKind<'a> {
+                    ImplTrait,
+                    Error(&'a ImplTraitPosition),
+                    Bound,
+                }
+
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
-                let (desugar_to_impl_trait, itctx) = match itctx {
+                let desugar_kind = match itctx {
                     // We are in the return position:
                     //
                     //     fn foo() -> impl Iterator<Item: Debug>
@@ -1023,7 +1027,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     //
                     //     fn foo() -> impl Iterator<Item = impl Debug>
                     ImplTraitContext::ReturnPositionOpaqueTy { .. }
-                    | ImplTraitContext::TypeAliasesOpaqueTy { .. } => (true, itctx),
+                    | ImplTraitContext::TypeAliasesOpaqueTy { .. } => DesugarKind::ImplTrait,
 
                     // We are in the argument position, but within a dyn type:
                     //
@@ -1032,15 +1036,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // so desugar to
                     //
                     //     fn foo(x: dyn Iterator<Item = impl Debug>)
-                    ImplTraitContext::Universal if self.is_in_dyn_type => (true, itctx),
+                    ImplTraitContext::Universal if self.is_in_dyn_type => DesugarKind::ImplTrait,
 
-                    // In `type Foo = dyn Iterator<Item: Debug>` we desugar to
-                    // `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
-                    // "impl trait context" to permit `impl Debug` in this position (it desugars
-                    // then to an opaque type).
-                    //
-                    // FIXME: this is only needed until `impl Trait` is allowed in type aliases.
-                    ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => (true, itctx_tait),
+                    ImplTraitContext::Disallowed(position) if self.is_in_dyn_type => {
+                        DesugarKind::Error(position)
+                    }
 
                     // We are in the parameter position, but not within a dyn type:
                     //
@@ -1049,35 +1049,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // so we leave it as is and this gets expanded in astconv to a bound like
                     // `<T as Iterator>::Item: Debug` where `T` is the type parameter for the
                     // `impl Iterator`.
-                    _ => (false, itctx),
+                    _ => DesugarKind::Bound,
                 };
 
-                if desugar_to_impl_trait {
-                    // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
-                    // constructing the HIR for `impl bounds...` and then lowering that.
-
-                    let impl_trait_node_id = self.next_node_id();
-
-                    self.with_dyn_type_scope(false, |this| {
-                        let node_id = this.next_node_id();
-                        let ty = this.lower_ty(
-                            &Ty {
-                                id: node_id,
-                                kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
-                                span: this.lower_span(constraint.span),
-                                tokens: None,
-                            },
-                            itctx,
-                        );
+                match desugar_kind {
+                    DesugarKind::ImplTrait => {
+                        // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
+                        // constructing the HIR for `impl bounds...` and then lowering that.
 
-                        hir::TypeBindingKind::Equality { term: ty.into() }
-                    })
-                } else {
-                    // Desugar `AssocTy: Bounds` into a type binding where the
-                    // later desugars into a trait predicate.
-                    let bounds = self.lower_param_bounds(bounds, itctx);
+                        let impl_trait_node_id = self.next_node_id();
 
-                    hir::TypeBindingKind::Constraint { bounds }
+                        self.with_dyn_type_scope(false, |this| {
+                            let node_id = this.next_node_id();
+                            let ty = this.lower_ty(
+                                &Ty {
+                                    id: node_id,
+                                    kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
+                                    span: this.lower_span(constraint.span),
+                                    tokens: None,
+                                },
+                                itctx,
+                            );
+
+                            hir::TypeBindingKind::Equality { term: ty.into() }
+                        })
+                    }
+                    DesugarKind::Bound => {
+                        // Desugar `AssocTy: Bounds` into a type binding where the
+                        // later desugars into a trait predicate.
+                        let bounds = self.lower_param_bounds(bounds, itctx);
+
+                        hir::TypeBindingKind::Constraint { bounds }
+                    }
+                    DesugarKind::Error(position) => {
+                        let guar = self.tcx.sess.emit_err(errors::MisplacedAssocTyBinding {
+                            span: constraint.span,
+                            position: DiagnosticArgFromDisplay(position),
+                        });
+                        let err_ty =
+                            &*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
+                        hir::TypeBindingKind::Equality { term: err_ty.into() }
+                    }
                 }
             }
         };
@@ -1244,7 +1256,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir> {
         let kind = match &t.kind {
             TyKind::Infer => hir::TyKind::Infer,
-            TyKind::Err => hir::TyKind::Err,
+            TyKind::Err => {
+                hir::TyKind::Err(self.tcx.sess.delay_span_bug(t.span, "TyKind::Err lowered"))
+            }
             TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
             TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
             TyKind::Ref(region, mt) => {
@@ -1370,7 +1384,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         path
                     }
                     ImplTraitContext::FeatureGated(position, feature) => {
-                        self.tcx
+                        let guar = self
+                            .tcx
                             .sess
                             .create_feature_err(
                                 MisplacedImplTrait {
@@ -1380,24 +1395,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 *feature,
                             )
                             .emit();
-                        hir::TyKind::Err
+                        hir::TyKind::Err(guar)
                     }
                     ImplTraitContext::Disallowed(position) => {
-                        self.tcx.sess.emit_err(MisplacedImplTrait {
+                        let guar = self.tcx.sess.emit_err(MisplacedImplTrait {
                             span: t.span,
                             position: DiagnosticArgFromDisplay(position),
                         });
-                        hir::TyKind::Err
+                        hir::TyKind::Err(guar)
                     }
                 }
             }
             TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
             TyKind::CVarArgs => {
-                self.tcx.sess.delay_span_bug(
+                let guar = self.tcx.sess.delay_span_bug(
                     t.span,
                     "`TyKind::CVarArgs` should have been handled elsewhere",
                 );
-                hir::TyKind::Err
+                hir::TyKind::Err(guar)
             }
         };
 
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 06d885a45fb..2509b705639 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -330,8 +330,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             ExprKind::Path(..) if allow_paths => {}
             ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
             _ => {
-                self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span });
-                return self.arena.alloc(self.expr_err(expr.span));
+                let guar = self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span });
+                return self.arena.alloc(self.expr_err(expr.span, guar));
             }
         }
         self.lower_expr(expr)
diff --git a/compiler/rustc_ast_passes/locales/en-US.ftl b/compiler/rustc_ast_passes/locales/en-US.ftl
index 5f28839f136..747bd52b22c 100644
--- a/compiler/rustc_ast_passes/locales/en-US.ftl
+++ b/compiler/rustc_ast_passes/locales/en-US.ftl
@@ -11,9 +11,6 @@ ast_passes_forbidden_let_stable =
 ast_passes_deprecated_where_clause_location =
     where clause not allowed here
 
-ast_passes_forbidden_assoc_constraint =
-    associated type bounds are not allowed within structs, enums, or unions
-
 ast_passes_keyword_lifetime =
     lifetimes cannot use keyword names
 
@@ -90,3 +87,150 @@ ast_passes_fn_without_body =
     .suggestion = provide a definition for the function
 
 ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
+
+ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
+
+ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$descr}
+    .suggestion = remove the {$remove_descr}
+    .label = `extern` block begins here
+
+ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
+    .cannot_have = cannot have a body
+    .invalid = the invalid body
+    .existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body
+
+ast_passes_fn_body_extern = incorrect function inside `extern` block
+    .cannot_have = cannot have a body
+    .suggestion = remove the invalid body
+    .help = you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
+    .label = `extern` blocks define existing foreign functions and functions inside of them cannot have a body
+
+ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
+    .label = in this `extern` block
+    .suggestion = remove the qualifiers
+
+ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
+    .label = in this `extern` block
+    .note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information
+
+ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic
+
+ast_passes_item_underscore = `{$kind}` items in this context need a name
+    .label = `_` is not a valid name for this `{$kind}` item
+
+ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
+
+ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
+    .help = consider using the `#[path]` attribute to specify filesystem path
+
+ast_passes_auto_generic = auto traits cannot have generic parameters
+    .label = auto trait cannot have generic parameters
+    .suggestion = remove the parameters
+
+ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds
+    .label = {ast_passes_auto_super_lifetime}
+    .suggestion = remove the super traits or lifetime bounds
+
+ast_passes_auto_items = auto traits cannot have associated items
+    .label = {ast_passes_auto_items}
+    .suggestion = remove these associated items
+
+ast_passes_generic_before_constraints = generic arguments must come before the first constraint
+    .constraints = {$constraint_len ->
+    [one] constraint
+    *[other] constraints
+    }
+    .args = generic {$args_len ->
+    [one] argument
+    *[other] arguments
+    }
+    .empty_string = {""},
+    .suggestion = move the {$constraint_len ->
+    [one] constraint
+    *[other] constraints
+    } after the generic {$args_len ->
+    [one] argument
+    *[other] arguments
+    }
+
+ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types
+
+ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
+
+ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
+
+ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
+    .outer = outer `impl Trait`
+    .inner = nested `impl Trait` here
+
+ast_passes_at_least_one_trait = at least one trait must be specified
+
+ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated
+
+ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
+    .suggestion = reorder the parameters: lifetimes, then consts and types
+
+ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
+    .help = use `auto trait Trait {"{}"}` instead
+
+ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
+    .negative = negative because of this
+    .unsafe = unsafe because of this
+
+ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
+    .because = {$annotation} because of this
+    .type = inherent impl for this type
+    .only_trait = only trait implementations may be annotated with {$annotation}
+
+ast_passes_unsafe_item = {$kind} cannot be declared unsafe
+
+ast_passes_fieldless_union = unions cannot have zero fields
+
+ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases
+    .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+
+ast_passes_generic_default_trailing = generic parameters with a default must be trailing
+
+ast_passes_nested_lifetimes = nested quantification of lifetimes
+
+ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits
+    .note = traits are `?{$path_str}` by default
+
+ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
+
+ast_passes_tilde_const_disallowed = `~const` is not allowed here
+    .trait = trait objects cannot have `~const` trait bounds
+    .closure = closures cannot have `~const` trait bounds
+    .function = this function is not `const`, so it cannot have `~const` trait bounds
+
+ast_passes_optional_const_exclusive = `~const` and `?` are mutually exclusive
+
+ast_passes_const_and_async = functions cannot be both `const` and `async`
+    .const = `const` because of this
+    .async = `async` because of this
+    .label = {""}
+
+ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
+    .label = pattern not allowed in foreign function
+
+ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies
+    .label = pattern not allowed in function without body
+
+ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
+    .label = not supported
+    .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
+    .suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax
+    .note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+
+ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library
+
+ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
+    .suggestion = remove the attribute
+    .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
+
+ast_passes_incompatbile_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
+    .help = remove one of these features
+
+ast_passes_show_span = {$msg}
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 56977e45a1a..1c561375626 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -13,7 +13,6 @@ use rustc_ast::walk_list;
 use rustc_ast::*;
 use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
 use rustc_macros::Subdiagnostic;
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
@@ -29,12 +28,9 @@ use std::mem;
 use std::ops::{Deref, DerefMut};
 use thin_vec::thin_vec;
 
-use crate::errors::*;
+use crate::errors;
 use crate::fluent_generated as fluent;
 
-const MORE_EXTERN: &str =
-    "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
-
 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
 enum SelfSemantic {
     Yes,
@@ -71,10 +67,6 @@ struct AstValidator<'a> {
     /// or `Foo::Bar<impl Trait>`
     is_impl_trait_banned: bool,
 
-    /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
-    /// certain positions.
-    is_assoc_ty_bound_banned: bool,
-
     /// See [ForbiddenLetReason]
     forbidden_let_reason: Option<ForbiddenLetReason>,
 
@@ -138,9 +130,9 @@ impl<'a> AstValidator<'a> {
     fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
         let sess = &self.session;
         if sess.opts.unstable_features.is_nightly_build() {
-            sess.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
+            sess.emit_err(errors::ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
         } else {
-            sess.emit_err(ForbiddenLetStable { span: expr.span });
+            sess.emit_err(errors::ForbiddenLetStable { span: expr.span });
         }
     }
 
@@ -180,30 +172,12 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
-        f(self);
-        self.is_assoc_ty_bound_banned = old;
-    }
-
     fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
         let old = mem::replace(&mut self.outer_impl_trait, outer);
         f(self);
         self.outer_impl_trait = old;
     }
 
-    fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
-        match constraint.kind {
-            AssocConstraintKind::Equality { .. } => {}
-            AssocConstraintKind::Bound { .. } => {
-                if self.is_assoc_ty_bound_banned {
-                    self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span });
-                }
-            }
-        }
-        self.visit_assoc_constraint(constraint);
-    }
-
     // Mirrors `visit::walk_ty`, but tracks relevant state.
     fn walk_ty(&mut self, t: &'a Ty) {
         match &t.kind {
@@ -256,22 +230,22 @@ impl<'a> AstValidator<'a> {
     fn check_lifetime(&self, ident: Ident) {
         let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
         if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
-            self.session.emit_err(KeywordLifetime { span: ident.span });
+            self.session.emit_err(errors::KeywordLifetime { span: ident.span });
         }
     }
 
     fn check_label(&self, ident: Ident) {
         if ident.without_first_quote().is_reserved() {
-            self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
+            self.session.emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
         }
     }
 
-    fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
+    fn invalid_visibility(&self, vis: &Visibility, note: Option<errors::InvalidVisibilityNote>) {
         if let VisibilityKind::Inherited = vis.kind {
             return;
         }
 
-        self.session.emit_err(InvalidVisibility {
+        self.session.emit_err(errors::InvalidVisibility {
             span: vis.span,
             implied: vis.kind.is_pub().then_some(vis.span),
             note,
@@ -292,7 +266,7 @@ impl<'a> AstValidator<'a> {
 
     fn check_trait_fn_not_const(&self, constness: Const) {
         if let Const::Yes(span) = constness {
-            self.session.emit_err(TraitFnConst { span });
+            self.session.emit_err(errors::TraitFnConst { span });
         }
     }
 
@@ -309,7 +283,7 @@ impl<'a> AstValidator<'a> {
         let max_num_args: usize = u16::MAX.into();
         if fn_decl.inputs.len() > max_num_args {
             let Param { span, .. } = fn_decl.inputs[0];
-            self.session.emit_fatal(FnParamTooMany { span, max_num_args });
+            self.session.emit_fatal(errors::FnParamTooMany { span, max_num_args });
         }
     }
 
@@ -317,13 +291,13 @@ impl<'a> AstValidator<'a> {
         match &*fn_decl.inputs {
             [Param { ty, span, .. }] => {
                 if let TyKind::CVarArgs = ty.kind {
-                    self.session.emit_err(FnParamCVarArgsOnly { span: *span });
+                    self.session.emit_err(errors::FnParamCVarArgsOnly { span: *span });
                 }
             }
             [ps @ .., _] => {
                 for Param { ty, span, .. } in ps {
                     if let TyKind::CVarArgs = ty.kind {
-                        self.session.emit_err(FnParamCVarArgsNotLast { span: *span });
+                        self.session.emit_err(errors::FnParamCVarArgsNotLast { span: *span });
                     }
                 }
             }
@@ -350,9 +324,9 @@ impl<'a> AstValidator<'a> {
             })
             .for_each(|attr| {
                 if attr.is_doc_comment() {
-                    self.session.emit_err(FnParamDocComment { span: attr.span });
+                    self.session.emit_err(errors::FnParamDocComment { span: attr.span });
                 } else {
-                    self.session.emit_err(FnParamForbiddenAttr { span: attr.span });
+                    self.session.emit_err(errors::FnParamForbiddenAttr { span: attr.span });
                 }
             });
     }
@@ -360,7 +334,7 @@ impl<'a> AstValidator<'a> {
     fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
         if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
             if param.is_self() {
-                self.session.emit_err(FnParamForbiddenSelf { span: param.span });
+                self.session.emit_err(errors::FnParamForbiddenSelf { span: param.span });
             }
         }
     }
@@ -368,7 +342,7 @@ impl<'a> AstValidator<'a> {
     fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
         if let Defaultness::Default(def_span) = defaultness {
             let span = self.session.source_map().guess_head_span(span);
-            self.session.emit_err(ForbiddenDefault { span, def_span });
+            self.session.emit_err(errors::ForbiddenDefault { span, def_span });
         }
     }
 
@@ -391,27 +365,17 @@ impl<'a> AstValidator<'a> {
             [b0] => b0.span(),
             [b0, .., bl] => b0.span().to(bl.span()),
         };
-        self.err_handler()
-            .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
-            .emit();
+        self.err_handler().emit_err(errors::BoundInContext { span, ctx });
     }
 
     fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
         let cannot_have = |span, descr, remove_descr| {
-            self.err_handler()
-                .struct_span_err(
-                    span,
-                    &format!("`type`s inside `extern` blocks cannot have {}", descr),
-                )
-                .span_suggestion(
-                    span,
-                    &format!("remove the {}", remove_descr),
-                    "",
-                    Applicability::MaybeIncorrect,
-                )
-                .span_label(self.current_extern_span(), "`extern` block begins here")
-                .note(MORE_EXTERN)
-                .emit();
+            self.err_handler().emit_err(errors::ExternTypesCannotHave {
+                span,
+                descr,
+                remove_descr,
+                block_span: self.current_extern_span(),
+            });
         };
 
         if !generics.params.is_empty() {
@@ -427,20 +391,12 @@ impl<'a> AstValidator<'a> {
         let Some(body) = body else {
             return;
         };
-        self.err_handler()
-            .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
-            .span_label(ident.span, "cannot have a body")
-            .span_label(body, "the invalid body")
-            .span_label(
-                self.current_extern_span(),
-                format!(
-                    "`extern` blocks define existing foreign {0}s and {0}s \
-                    inside of them cannot have a body",
-                    kind
-                ),
-            )
-            .note(MORE_EXTERN)
-            .emit();
+        self.err_handler().emit_err(errors::BodyInExtern {
+            span: ident.span,
+            body,
+            block: self.current_extern_span(),
+            kind,
+        });
     }
 
     /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
@@ -448,26 +404,11 @@ impl<'a> AstValidator<'a> {
         let Some(body) = body else {
             return;
         };
-        self.err_handler()
-            .struct_span_err(ident.span, "incorrect function inside `extern` block")
-            .span_label(ident.span, "cannot have a body")
-            .span_suggestion(
-                body.span,
-                "remove the invalid body",
-                ";",
-                Applicability::MaybeIncorrect,
-            )
-            .help(
-                "you might have meant to write a function accessible through FFI, \
-                which can be done by writing `extern fn` outside of the `extern` block",
-            )
-            .span_label(
-                self.current_extern_span(),
-                "`extern` blocks define existing foreign functions and functions \
-                inside of them cannot have a body",
-            )
-            .note(MORE_EXTERN)
-            .emit();
+        self.err_handler().emit_err(errors::FnBodyInExtern {
+            span: ident.span,
+            body: body.span,
+            block: self.current_extern_span(),
+        });
     }
 
     fn current_extern_span(&self) -> Span {
@@ -477,34 +418,21 @@ impl<'a> AstValidator<'a> {
     /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
     fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
         if header.has_qualifiers() {
-            self.err_handler()
-                .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
-                .span_label(self.current_extern_span(), "in this `extern` block")
-                .span_suggestion_verbose(
-                    span.until(ident.span.shrink_to_lo()),
-                    "remove the qualifiers",
-                    "fn ",
-                    Applicability::MaybeIncorrect,
-                )
-                .emit();
+            self.err_handler().emit_err(errors::FnQualifierInExtern {
+                span: ident.span,
+                block: self.current_extern_span(),
+                sugg_span: span.until(ident.span.shrink_to_lo()),
+            });
         }
     }
 
     /// An item in `extern { ... }` cannot use non-ascii identifier.
     fn check_foreign_item_ascii_only(&self, ident: Ident) {
         if !ident.as_str().is_ascii() {
-            let n = 83942;
-            self.err_handler()
-                .struct_span_err(
-                    ident.span,
-                    "items in `extern` blocks cannot use non-ascii identifiers",
-                )
-                .span_label(self.current_extern_span(), "in this `extern` block")
-                .note(&format!(
-                    "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
-                    n, n,
-                ))
-                .emit();
+            self.err_handler().emit_err(errors::ExternItemAscii {
+                span: ident.span,
+                block: self.current_extern_span(),
+            });
         }
     }
 
@@ -527,12 +455,7 @@ impl<'a> AstValidator<'a> {
 
         for Param { ty, span, .. } in &fk.decl().inputs {
             if let TyKind::CVarArgs = ty.kind {
-                self.err_handler()
-                    .struct_span_err(
-                        *span,
-                        "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
-                    )
-                    .emit();
+                self.err_handler().emit_err(errors::BadCVariadic { span: *span });
             }
         }
     }
@@ -541,75 +464,32 @@ impl<'a> AstValidator<'a> {
         if ident.name != kw::Underscore {
             return;
         }
-        self.err_handler()
-            .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
-            .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
-            .emit();
+        self.err_handler().emit_err(errors::ItemUnderscore { span: ident.span, kind });
     }
 
     fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
         if ident.name.as_str().is_ascii() {
             return;
         }
-        let head_span = self.session.source_map().guess_head_span(item_span);
-        struct_span_err!(
-            self.session,
-            head_span,
-            E0754,
-            "`#[no_mangle]` requires ASCII identifier"
-        )
-        .emit();
+        let span = self.session.source_map().guess_head_span(item_span);
+        self.session.emit_err(errors::NoMangleAscii { span });
     }
 
     fn check_mod_file_item_asciionly(&self, ident: Ident) {
         if ident.name.as_str().is_ascii() {
             return;
         }
-        struct_span_err!(
-            self.session,
-            ident.span,
-            E0754,
-            "trying to load file for module `{}` with non-ascii identifier name",
-            ident.name
-        )
-        .help("consider using `#[path]` attribute to specify filesystem path")
-        .emit();
+        self.session.emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
     }
 
-    fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
+    fn deny_generic_params(&self, generics: &Generics, ident: Span) {
         if !generics.params.is_empty() {
-            struct_span_err!(
-                self.session,
-                generics.span,
-                E0567,
-                "auto traits cannot have generic parameters"
-            )
-            .span_label(ident_span, "auto trait cannot have generic parameters")
-            .span_suggestion(
-                generics.span,
-                "remove the parameters",
-                "",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+            self.session.emit_err(errors::AutoTraitGeneric { span: generics.span, ident });
         }
     }
 
-    fn emit_e0568(&self, span: Span, ident_span: Span) {
-        struct_span_err!(
-            self.session,
-            span,
-            E0568,
-            "auto traits cannot have super traits or lifetime bounds"
-        )
-        .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
-        .span_suggestion(
-            span,
-            "remove the super traits or lifetime bounds",
-            "",
-            Applicability::MachineApplicable,
-        )
-        .emit();
+    fn emit_e0568(&self, span: Span, ident: Span) {
+        self.session.emit_err(errors::AutoTraitBounds { span, ident });
     }
 
     fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
@@ -625,24 +505,11 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
+    fn deny_items(&self, trait_items: &[P<AssocItem>], ident: Span) {
         if !trait_items.is_empty() {
             let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
-            let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
-            struct_span_err!(
-                self.session,
-                spans,
-                E0380,
-                "auto traits cannot have associated items"
-            )
-            .span_suggestion(
-                total_span,
-                "remove these associated items",
-                "",
-                Applicability::MachineApplicable,
-            )
-            .span_label(ident_span, "auto trait cannot have associated items")
-            .emit();
+            let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
+            self.session.emit_err(errors::AutoTraitItems { spans, total, ident });
         }
     }
 
@@ -688,29 +555,17 @@ impl<'a> AstValidator<'a> {
         let args_len = arg_spans.len();
         let constraint_len = constraint_spans.len();
         // ...and then error:
-        self.err_handler()
-            .struct_span_err(
-                arg_spans.clone(),
-                "generic arguments must come before the first constraint",
-            )
-            .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
-            .span_label(
-                *arg_spans.iter().last().unwrap(),
-                &format!("generic argument{}", pluralize!(args_len)),
-            )
-            .span_labels(constraint_spans, "")
-            .span_labels(arg_spans, "")
-            .span_suggestion_verbose(
-                data.span,
-                &format!(
-                    "move the constraint{} after the generic argument{}",
-                    pluralize!(constraint_len),
-                    pluralize!(args_len)
-                ),
-                self.correct_generic_order_suggestion(&data),
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.err_handler().emit_err(errors::ArgsBeforeConstraint {
+            arg_spans: arg_spans.clone(),
+            constraints: constraint_spans[0],
+            args: *arg_spans.iter().last().unwrap(),
+            data: data.span,
+            constraint_spans: errors::EmptyLabelManySpans(constraint_spans),
+            arg_spans2: errors::EmptyLabelManySpans(arg_spans),
+            suggestion: self.correct_generic_order_suggestion(&data),
+            constraint_len,
+            args_len,
+        });
     }
 
     fn visit_ty_common(&mut self, ty: &'a Ty) {
@@ -718,13 +573,7 @@ impl<'a> AstValidator<'a> {
             TyKind::BareFn(bfty) => {
                 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
                 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
-                    struct_span_err!(
-                        self.session,
-                        span,
-                        E0561,
-                        "patterns aren't allowed in function pointer types"
-                    )
-                    .emit();
+                    self.session.emit_err(errors::PatternFnPointer { span });
                 });
                 if let Extern::Implicit(_) = bfty.ext {
                     let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
@@ -736,13 +585,8 @@ impl<'a> AstValidator<'a> {
                 for bound in bounds {
                     if let GenericBound::Outlives(lifetime) = bound {
                         if any_lifetime_bounds {
-                            struct_span_err!(
-                                self.session,
-                                lifetime.ident.span,
-                                E0226,
-                                "only a single explicit lifetime bound is permitted"
-                            )
-                            .emit();
+                            self.session
+                                .emit_err(errors::TraitObjectBound { span: lifetime.ident.span });
                             break;
                         }
                         any_lifetime_bounds = true;
@@ -751,29 +595,19 @@ impl<'a> AstValidator<'a> {
             }
             TyKind::ImplTrait(_, bounds) => {
                 if self.is_impl_trait_banned {
-                    struct_span_err!(
-                        self.session,
-                        ty.span,
-                        E0667,
-                        "`impl Trait` is not allowed in path parameters"
-                    )
-                    .emit();
+                    self.session.emit_err(errors::ImplTraitPath { span: ty.span });
                 }
 
                 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
-                    struct_span_err!(
-                        self.session,
-                        ty.span,
-                        E0666,
-                        "nested `impl Trait` is not allowed"
-                    )
-                    .span_label(outer_impl_trait_sp, "outer `impl Trait`")
-                    .span_label(ty.span, "nested `impl Trait` here")
-                    .emit();
+                    self.session.emit_err(errors::NestedImplTrait {
+                        span: ty.span,
+                        outer: outer_impl_trait_sp,
+                        inner: ty.span,
+                    });
                 }
 
                 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
-                    self.err_handler().span_err(ty.span, "at least one trait must be specified");
+                    self.err_handler().emit_err(errors::AtLeastOneTrait { span: ty.span });
                 }
             }
             _ => {}
@@ -794,7 +628,7 @@ impl<'a> AstValidator<'a> {
                 MISSING_ABI,
                 id,
                 span,
-                "extern declarations without an explicit ABI are deprecated",
+                fluent::ast_passes_extern_without_abi,
                 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
             )
         }
@@ -867,20 +701,13 @@ fn validate_generic_param_order(
         ordered_params += ">";
 
         for (param_ord, (max_param, spans)) in &out_of_order {
-            let mut err = handler.struct_span_err(
-                spans.clone(),
-                &format!(
-                    "{} parameters must be declared prior to {} parameters",
-                    param_ord, max_param,
-                ),
-            );
-            err.span_suggestion(
-                span,
-                "reorder the parameters: lifetimes, then consts and types",
-                &ordered_params,
-                Applicability::MachineApplicable,
-            );
-            err.emit();
+            handler.emit_err(errors::OutOfOrderParams {
+                spans: spans.clone(),
+                sugg_span: span,
+                param_ord,
+                max_param,
+                ordered_params: &ordered_params,
+            });
         }
     }
 }
@@ -994,25 +821,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.with_in_trait_impl(true, Some(*constness), |this| {
                     this.invalid_visibility(&item.vis, None);
                     if let TyKind::Err = self_ty.kind {
-                        this.err_handler()
-                            .struct_span_err(
-                                item.span,
-                                "`impl Trait for .. {}` is an obsolete syntax",
-                            )
-                            .help("use `auto trait Trait {}` instead")
-                            .emit();
+                        this.err_handler().emit_err(errors::ObsoleteAuto { span: item.span });
                     }
                     if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)
                     {
-                        struct_span_err!(
-                            this.session,
-                            sp.to(t.path.span),
-                            E0198,
-                            "negative impls cannot be unsafe"
-                        )
-                        .span_label(sp, "negative because of this")
-                        .span_label(span, "unsafe because of this")
-                        .emit();
+                        this.session.emit_err(errors::UnsafeNegativeImpl {
+                            span: sp.to(t.path.span),
+                            negative: sp,
+                            r#unsafe: span,
+                        });
                     }
 
                     this.visit_vis(&item.vis);
@@ -1040,52 +857,54 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self_ty,
                 items: _,
             }) => {
-                let error = |annotation_span, annotation| {
-                    let mut err = self.err_handler().struct_span_err(
-                        self_ty.span,
-                        &format!("inherent impls cannot be {}", annotation),
-                    );
-                    err.span_label(annotation_span, &format!("{} because of this", annotation));
-                    err.span_label(self_ty.span, "inherent impl for this type");
-                    err
-                };
+                let error =
+                    |annotation_span, annotation, only_trait: bool| errors::InherentImplCannot {
+                        span: self_ty.span,
+                        annotation_span,
+                        annotation,
+                        self_ty: self_ty.span,
+                        only_trait: only_trait.then_some(()),
+                    };
 
                 self.invalid_visibility(
                     &item.vis,
-                    Some(InvalidVisibilityNote::IndividualImplItems),
+                    Some(errors::InvalidVisibilityNote::IndividualImplItems),
                 );
                 if let &Unsafe::Yes(span) = unsafety {
-                    error(span, "unsafe").code(error_code!(E0197)).emit();
+                    self.err_handler().emit_err(errors::InherentImplCannotUnsafe {
+                        span: self_ty.span,
+                        annotation_span: span,
+                        annotation: "unsafe",
+                        self_ty: self_ty.span,
+                    });
                 }
                 if let &ImplPolarity::Negative(span) = polarity {
-                    error(span, "negative").emit();
+                    self.err_handler().emit_err(error(span, "negative", false));
                 }
                 if let &Defaultness::Default(def_span) = defaultness {
-                    error(def_span, "`default`")
-                        .note("only trait implementations may be annotated with `default`")
-                        .emit();
+                    self.err_handler().emit_err(error(def_span, "`default`", true));
                 }
                 if let &Const::Yes(span) = constness {
-                    error(span, "`const`")
-                        .note("only trait implementations may be annotated with `const`")
-                        .emit();
+                    self.err_handler().emit_err(error(span, "`const`", true));
                 }
             }
             ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => {
                 self.check_defaultness(item.span, *defaultness);
 
                 if body.is_none() {
-                    self.session.emit_err(FnWithoutBody {
+                    self.session.emit_err(errors::FnWithoutBody {
                         span: item.span,
                         replace_span: self.ending_semi_or_hi(item.span),
                         extern_block_suggestion: match sig.header.ext {
                             Extern::None => None,
-                            Extern::Implicit(start_span) => Some(ExternBlockSuggestion::Implicit {
-                                start_span,
-                                end_span: item.span.shrink_to_hi(),
-                            }),
+                            Extern::Implicit(start_span) => {
+                                Some(errors::ExternBlockSuggestion::Implicit {
+                                    start_span,
+                                    end_span: item.span.shrink_to_hi(),
+                                })
+                            }
                             Extern::Explicit(abi, start_span) => {
-                                Some(ExternBlockSuggestion::Explicit {
+                                Some(errors::ExternBlockSuggestion::Explicit {
                                     start_span,
                                     end_span: item.span.shrink_to_hi(),
                                     abi: abi.symbol_unescaped,
@@ -1107,10 +926,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 let old_item = mem::replace(&mut self.extern_mod, Some(item));
                 self.invalid_visibility(
                     &item.vis,
-                    Some(InvalidVisibilityNote::IndividualForeignItems),
+                    Some(errors::InvalidVisibilityNote::IndividualForeignItems),
                 );
                 if let &Unsafe::Yes(span) = unsafety {
-                    self.err_handler().span_err(span, "extern block cannot be declared unsafe");
+                    self.err_handler().emit_err(errors::UnsafeItem { span, kind: "extern block" });
                 }
                 if abi.is_none() {
                     self.maybe_lint_missing_abi(item.span, item.id);
@@ -1150,7 +969,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::Mod(unsafety, mod_kind) => {
                 if let &Unsafe::Yes(span) = unsafety {
-                    self.err_handler().span_err(span, "module cannot be declared unsafe");
+                    self.err_handler().emit_err(errors::UnsafeItem { span, kind: "module" });
                 }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
                 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
@@ -1161,18 +980,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::Union(vdata, ..) => {
                 if vdata.fields().is_empty() {
-                    self.err_handler().span_err(item.span, "unions cannot have zero fields");
+                    self.err_handler().emit_err(errors::FieldlessUnion { span: item.span });
                 }
             }
             ItemKind::Const(def, .., None) => {
                 self.check_defaultness(item.span, *def);
-                self.session.emit_err(ConstWithoutBody {
+                self.session.emit_err(errors::ConstWithoutBody {
                     span: item.span,
                     replace_span: self.ending_semi_or_hi(item.span),
                 });
             }
             ItemKind::Static(.., None) => {
-                self.session.emit_err(StaticWithoutBody {
+                self.session.emit_err(errors::StaticWithoutBody {
                     span: item.span,
                     replace_span: self.ending_semi_or_hi(item.span),
                 });
@@ -1180,21 +999,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             ItemKind::TyAlias(box TyAlias { defaultness, where_clauses, bounds, ty, .. }) => {
                 self.check_defaultness(item.span, *defaultness);
                 if ty.is_none() {
-                    self.session.emit_err(TyAliasWithoutBody {
+                    self.session.emit_err(errors::TyAliasWithoutBody {
                         span: item.span,
                         replace_span: self.ending_semi_or_hi(item.span),
                     });
                 }
                 self.check_type_no_bounds(bounds, "this context");
                 if where_clauses.1.0 {
-                    let mut err = self.err_handler().struct_span_err(
-                        where_clauses.1.1,
-                        "where clauses are not allowed after the type for type aliases",
-                    );
-                    err.note(
-                        "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
-                    );
-                    err.emit();
+                    self.err_handler()
+                        .emit_err(errors::WhereAfterTypeAlias { span: where_clauses.1.1 });
                 }
             }
             _ => {}
@@ -1248,7 +1061,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_constraint_from_generic_args(constraint);
+                                this.visit_assoc_constraint(constraint);
                             });
                         }
                     }
@@ -1276,11 +1089,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
                     if let Some(span) = prev_param_default {
-                        let mut err = self.err_handler().struct_span_err(
-                            span,
-                            "generic parameters with a default must be trailing",
-                        );
-                        err.emit();
+                        self.err_handler().emit_err(errors::GenericDefaultTrailing { span });
                         break;
                     }
                 }
@@ -1308,13 +1117,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                             match bound {
                                 GenericBound::Trait(t, _) => {
                                     if !t.bound_generic_params.is_empty() {
-                                        struct_span_err!(
-                                            self.err_handler(),
-                                            t.span,
-                                            E0316,
-                                            "nested quantification of lifetimes"
-                                        )
-                                        .emit();
+                                        self.err_handler()
+                                            .emit_err(errors::NestedLifetimes { span: t.span });
                                     }
                                 }
                                 GenericBound::Outlives(_) => {}
@@ -1339,32 +1143,27 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         if let GenericBound::Trait(poly, modify) = bound {
             match (ctxt, modify) {
                 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
-                    let mut err = self
-                        .err_handler()
-                        .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
-                    let path_str = pprust::path_to_string(&poly.trait_ref.path);
-                    err.note(&format!("traits are `?{}` by default", path_str));
-                    err.emit();
+                    self.err_handler().emit_err(errors::OptionalTraitSupertrait {
+                        span: poly.span,
+                        path_str: pprust::path_to_string(&poly.trait_ref.path)
+                    });
                 }
                 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
-                    let mut err = self.err_handler().struct_span_err(
-                        poly.span,
-                        "`?Trait` is not permitted in trait object types",
-                    );
-                    err.emit();
+                    self.err_handler().emit_err(errors::OptionalTraitObject {span: poly.span});
                 }
                 (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
-                    let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
-                    match reason {
-                        DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
-                        DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
-                        DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
+                    let reason = match reason {
+                        DisallowTildeConstContext::TraitObject => errors::TildeConstReason::TraitObject,
+                        DisallowTildeConstContext::Fn(FnKind::Closure(..)) => errors::TildeConstReason::Closure,
+                        DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => errors::TildeConstReason::Function { ident: ident.span },
                     };
-                    err.emit();
+                    self.err_handler().emit_err(errors::TildeConstDisallowed {
+                        span: bound.span(),
+                        reason
+                    });
                 }
                 (_, TraitBoundModifier::MaybeConstMaybe) => {
-                    self.err_handler()
-                        .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
+                    self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span()});
                 }
                 _ => {}
             }
@@ -1373,14 +1172,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         visit::walk_param_bound(self, bound)
     }
 
-    fn visit_variant_data(&mut self, s: &'a VariantData) {
-        self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
-    }
-
-    fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
-        self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
-    }
-
     fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
         // Only associated `fn`s can have `self` parameters.
         let self_semantic = match fk.ctxt() {
@@ -1392,21 +1183,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         self.check_c_variadic_type(fk);
 
         // Functions cannot both be `const async`
-        if let Some(FnHeader {
+        if let Some(&FnHeader {
             constness: Const::Yes(cspan),
             asyncness: Async::Yes { span: aspan, .. },
             ..
         }) = fk.header()
         {
-            self.err_handler()
-                .struct_span_err(
-                    vec![*cspan, *aspan],
-                    "functions cannot be both `const` and `async`",
-                )
-                .span_label(*cspan, "`const` because of this")
-                .span_label(*aspan, "`async` because of this")
-                .span_label(span, "") // Point at the fn header.
-                .emit();
+            self.err_handler().emit_err(errors::ConstAndAsync {
+                spans: vec![cspan, aspan],
+                cspan,
+                aspan,
+                span,
+            });
         }
 
         if let FnKind::Fn(
@@ -1424,20 +1212,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         // Functions without bodies cannot have patterns.
         if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
             Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
-                let (code, msg, label) = match ctxt {
-                    FnCtxt::Foreign => (
-                        error_code!(E0130),
-                        "patterns aren't allowed in foreign function declarations",
-                        "pattern not allowed in foreign function",
-                    ),
-                    _ => (
-                        error_code!(E0642),
-                        "patterns aren't allowed in functions without bodies",
-                        "pattern not allowed in function without body",
-                    ),
-                };
                 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
                     if let Some(ident) = ident {
+                        let msg = match ctxt {
+                            FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign,
+                            _ => fluent::ast_passes_pattern_in_bodiless,
+                        };
                         let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
                         self.lint_buffer.buffer_lint_with_diagnostic(
                             PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -1448,11 +1228,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         )
                     }
                 } else {
-                    self.err_handler()
-                        .struct_span_err(span, msg)
-                        .span_label(span, label)
-                        .code(code)
-                        .emit();
+                    match ctxt {
+                        FnCtxt::Foreign => {
+                            self.err_handler().emit_err(errors::PatternInForeign { span })
+                        }
+                        _ => self.err_handler().emit_err(errors::PatternInBodiless { span }),
+                    };
                 }
             });
         }
@@ -1479,7 +1260,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             match &item.kind {
                 AssocItemKind::Const(_, _, body) => {
                     if body.is_none() {
-                        self.session.emit_err(AssocConstWithoutBody {
+                        self.session.emit_err(errors::AssocConstWithoutBody {
                             span: item.span,
                             replace_span: self.ending_semi_or_hi(item.span),
                         });
@@ -1487,7 +1268,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 AssocItemKind::Fn(box Fn { body, .. }) => {
                     if body.is_none() {
-                        self.session.emit_err(AssocFnWithoutBody {
+                        self.session.emit_err(errors::AssocFnWithoutBody {
                             span: item.span,
                             replace_span: self.ending_semi_or_hi(item.span),
                         });
@@ -1502,7 +1283,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     ..
                 }) => {
                     if ty.is_none() {
-                        self.session.emit_err(AssocTypeWithoutBody {
+                        self.session.emit_err(errors::AssocTypeWithoutBody {
                             span: item.span,
                             replace_span: self.ending_semi_or_hi(item.span),
                         });
@@ -1574,11 +1355,7 @@ fn deny_equality_constraints(
     predicate: &WhereEqPredicate,
     generics: &Generics,
 ) {
-    let mut err = this.err_handler().struct_span_err(
-        predicate.span,
-        "equality constraints are not yet supported in `where` clauses",
-    );
-    err.span_label(predicate.span, "not supported");
+    let mut err = errors::EqualityInWhere { span: predicate.span, assoc: None, assoc2: None };
 
     // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
     if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
@@ -1622,20 +1399,12 @@ fn deny_equality_constraints(
                                             .into();
                                         }
                                     }
-                                    err.span_suggestion_verbose(
-                                        predicate.span,
-                                        &format!(
-                                            "if `{}` is an associated type you're trying to set, \
-                                            use the associated type binding syntax",
-                                            ident
-                                        ),
-                                        format!(
-                                            "{}: {}",
-                                            param,
-                                            pprust::path_to_string(&assoc_path)
-                                        ),
-                                        Applicability::MaybeIncorrect,
-                                    );
+                                    err.assoc = Some(errors::AssociatedSuggestion {
+                                        span: predicate.span,
+                                        ident: *ident,
+                                        param: *param,
+                                        path: pprust::path_to_string(&assoc_path),
+                                    })
                                 }
                                 _ => {}
                             };
@@ -1677,15 +1446,13 @@ fn deny_equality_constraints(
                                         trait_segment.span().shrink_to_hi(),
                                     ),
                                 };
-                                err.multipart_suggestion(
-                                    &format!(
-                                        "if `{}::{}` is an associated type you're trying to set, \
-                                        use the associated type binding syntax",
-                                        trait_segment.ident, potential_assoc.ident,
-                                    ),
-                                    vec![(span, args), (predicate.span, String::new())],
-                                    Applicability::MaybeIncorrect,
-                                );
+                                err.assoc2 = Some(errors::AssociatedSuggestion2 {
+                                    span,
+                                    args,
+                                    predicate: predicate.span,
+                                    trait_segment: trait_segment.ident,
+                                    potential_assoc: potential_assoc.ident,
+                                });
                             }
                         }
                     }
@@ -1693,10 +1460,7 @@ fn deny_equality_constraints(
             }
         }
     }
-    err.note(
-        "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
-    );
-    err.emit();
+    this.err_handler().emit_err(err);
 }
 
 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
@@ -1709,7 +1473,6 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
         outer_impl_trait: None,
         disallow_tilde_const: None,
         is_impl_trait_banned: false,
-        is_assoc_ty_bound_banned: false,
         forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
         lint_buffer: lints,
     };
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 69ce8daa455..d007097d918 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -1,9 +1,12 @@
 //! Errors emitted by ast_passes.
 
+use rustc_ast::ParamKindOrd;
+use rustc_errors::AddToDiagnostic;
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_span::{Span, Symbol};
+use rustc_span::{symbol::Ident, Span, Symbol};
 
 use crate::ast_validation::ForbiddenLetReason;
+use crate::fluent_generated as fluent;
 
 #[derive(Diagnostic)]
 #[diag(ast_passes_forbidden_let)]
@@ -24,13 +27,6 @@ pub struct ForbiddenLetStable {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_forbidden_assoc_constraint)]
-pub struct ForbiddenAssocConstraint {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(ast_passes_keyword_lifetime)]
 pub struct KeywordLifetime {
     #[primary_span]
@@ -224,3 +220,474 @@ pub enum ExternBlockSuggestion {
         abi: Symbol,
     },
 }
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_bound_in_context)]
+pub struct BoundInContext<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub ctx: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_extern_types_cannot)]
+#[note(ast_passes_extern_keyword_link)]
+pub struct ExternTypesCannotHave<'a> {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    pub span: Span,
+    pub descr: &'a str,
+    pub remove_descr: &'a str,
+    #[label]
+    pub block_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_body_in_extern)]
+#[note(ast_passes_extern_keyword_link)]
+pub struct BodyInExtern<'a> {
+    #[primary_span]
+    #[label(ast_passes_cannot_have)]
+    pub span: Span,
+    #[label(ast_passes_invalid)]
+    pub body: Span,
+    #[label(ast_passes_existing)]
+    pub block: Span,
+    pub kind: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_body_extern)]
+#[help]
+#[note(ast_passes_extern_keyword_link)]
+pub struct FnBodyInExtern {
+    #[primary_span]
+    #[label(ast_passes_cannot_have)]
+    pub span: Span,
+    #[suggestion(code = ";", applicability = "maybe-incorrect")]
+    pub body: Span,
+    #[label]
+    pub block: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_extern_fn_qualifiers)]
+pub struct FnQualifierInExtern {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub block: Span,
+    #[suggestion(code = "fn ", applicability = "maybe-incorrect", style = "verbose")]
+    pub sugg_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_extern_item_ascii)]
+#[note]
+pub struct ExternItemAscii {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub block: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_bad_c_variadic)]
+pub struct BadCVariadic {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_item_underscore)]
+pub struct ItemUnderscore<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub kind: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_nomangle_ascii, code = "E0754")]
+pub struct NoMangleAscii {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_module_nonascii, code = "E0754")]
+#[help]
+pub struct ModuleNonAscii {
+    #[primary_span]
+    pub span: Span,
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_auto_generic, code = "E0567")]
+pub struct AutoTraitGeneric {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub span: Span,
+    #[label]
+    pub ident: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_auto_super_lifetime, code = "E0568")]
+pub struct AutoTraitBounds {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub span: Span,
+    #[label]
+    pub ident: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_auto_items, code = "E0380")]
+pub struct AutoTraitItems {
+    #[primary_span]
+    pub spans: Vec<Span>,
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub total: Span,
+    #[label]
+    pub ident: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_generic_before_constraints)]
+pub struct ArgsBeforeConstraint {
+    #[primary_span]
+    pub arg_spans: Vec<Span>,
+    #[label(ast_passes_constraints)]
+    pub constraints: Span,
+    #[label(ast_passes_args)]
+    pub args: Span,
+    #[suggestion(code = "{suggestion}", applicability = "machine-applicable", style = "verbose")]
+    pub data: Span,
+    pub suggestion: String,
+    pub constraint_len: usize,
+    pub args_len: usize,
+    #[subdiagnostic]
+    pub constraint_spans: EmptyLabelManySpans,
+    #[subdiagnostic]
+    pub arg_spans2: EmptyLabelManySpans,
+}
+
+pub struct EmptyLabelManySpans(pub Vec<Span>);
+
+// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each
+impl AddToDiagnostic for EmptyLabelManySpans {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        diag.span_labels(self.0, "");
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_pattern_in_fn_pointer, code = "E0561")]
+pub struct PatternFnPointer {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_trait_object_single_bound, code = "E0226")]
+pub struct TraitObjectBound {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_impl_trait_path, code = "E0667")]
+pub struct ImplTraitPath {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_nested_impl_trait, code = "E0666")]
+pub struct NestedImplTrait {
+    #[primary_span]
+    pub span: Span,
+    #[label(ast_passes_outer)]
+    pub outer: Span,
+    #[label(ast_passes_inner)]
+    pub inner: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_at_least_one_trait)]
+pub struct AtLeastOneTrait {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_out_of_order_params)]
+pub struct OutOfOrderParams<'a> {
+    #[primary_span]
+    pub spans: Vec<Span>,
+    #[suggestion(code = "{ordered_params}", applicability = "machine-applicable")]
+    pub sugg_span: Span,
+    pub param_ord: &'a ParamKindOrd,
+    pub max_param: &'a ParamKindOrd,
+    pub ordered_params: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_obsolete_auto)]
+#[help]
+pub struct ObsoleteAuto {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_unsafe_negative_impl, code = "E0198")]
+pub struct UnsafeNegativeImpl {
+    #[primary_span]
+    pub span: Span,
+    #[label(ast_passes_negative)]
+    pub negative: Span,
+    #[label(ast_passes_unsafe)]
+    pub r#unsafe: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_inherent_cannot_be)]
+pub struct InherentImplCannot<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[label(ast_passes_because)]
+    pub annotation_span: Span,
+    pub annotation: &'a str,
+    #[label(ast_passes_type)]
+    pub self_ty: Span,
+    #[note(ast_passes_only_trait)]
+    pub only_trait: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_inherent_cannot_be, code = "E0197")]
+pub struct InherentImplCannotUnsafe<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[label(ast_passes_because)]
+    pub annotation_span: Span,
+    pub annotation: &'a str,
+    #[label(ast_passes_type)]
+    pub self_ty: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_unsafe_item)]
+pub struct UnsafeItem {
+    #[primary_span]
+    pub span: Span,
+    pub kind: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_fieldless_union)]
+pub struct FieldlessUnion {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_where_after_type_alias)]
+#[note]
+pub struct WhereAfterTypeAlias {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_generic_default_trailing)]
+pub struct GenericDefaultTrailing {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_nested_lifetimes, code = "E0316")]
+pub struct NestedLifetimes {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_optional_trait_supertrait)]
+#[note]
+pub struct OptionalTraitSupertrait {
+    #[primary_span]
+    pub span: Span,
+    pub path_str: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_optional_trait_object)]
+pub struct OptionalTraitObject {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_tilde_const_disallowed)]
+pub struct TildeConstDisallowed {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub reason: TildeConstReason,
+}
+
+#[derive(Subdiagnostic)]
+pub enum TildeConstReason {
+    #[note(ast_passes_trait)]
+    TraitObject,
+    #[note(ast_passes_closure)]
+    Closure,
+    #[note(ast_passes_function)]
+    Function {
+        #[primary_span]
+        ident: Span,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_optional_const_exclusive)]
+pub struct OptionalConstExclusive {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_const_and_async)]
+pub struct ConstAndAsync {
+    #[primary_span]
+    pub spans: Vec<Span>,
+    #[label(ast_passes_const)]
+    pub cspan: Span,
+    #[label(ast_passes_async)]
+    pub aspan: Span,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_pattern_in_foreign, code = "E0130")]
+pub struct PatternInForeign {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_pattern_in_bodiless, code = "E0642")]
+pub struct PatternInBodiless {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_equality_in_where)]
+#[note]
+pub struct EqualityInWhere {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub assoc: Option<AssociatedSuggestion>,
+    #[subdiagnostic]
+    pub assoc2: Option<AssociatedSuggestion2>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    ast_passes_suggestion,
+    code = "{param}: {path}",
+    style = "verbose",
+    applicability = "maybe-incorrect"
+)]
+pub struct AssociatedSuggestion {
+    #[primary_span]
+    pub span: Span,
+    pub ident: Ident,
+    pub param: Ident,
+    pub path: String,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(ast_passes_suggestion_path, applicability = "maybe-incorrect")]
+pub struct AssociatedSuggestion2 {
+    #[suggestion_part(code = "{args}")]
+    pub span: Span,
+    pub args: String,
+    #[suggestion_part(code = "")]
+    pub predicate: Span,
+    pub trait_segment: Ident,
+    pub potential_assoc: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_stability_outside_std, code = "E0734")]
+pub struct StabilityOutsideStd {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_feature_on_non_nightly, code = "E0554")]
+pub struct FeatureOnNonNightly {
+    #[primary_span]
+    pub span: Span,
+    pub channel: &'static str,
+    #[subdiagnostic]
+    pub stable_features: Vec<StableFeature>,
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub sugg: Option<Span>,
+}
+
+pub struct StableFeature {
+    pub name: Symbol,
+    pub since: Symbol,
+}
+
+impl AddToDiagnostic for StableFeature {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        diag.set_arg("name", self.name);
+        diag.set_arg("since", self.since);
+        diag.help(fluent::ast_passes_stable_since);
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_incompatbile_features)]
+#[help]
+pub struct IncompatibleFeatures {
+    #[primary_span]
+    pub spans: Vec<Span>,
+    pub f1: Symbol,
+    pub f2: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_show_span)]
+pub struct ShowSpan {
+    #[primary_span]
+    pub span: Span,
+    pub msg: &'static str,
+}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index d69c84bf4d1..96042ea3078 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -2,7 +2,7 @@ use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
 use rustc_ast::{PatKind, RangeEnd};
-use rustc_errors::{struct_span_err, Applicability, StashKey};
+use rustc_errors::{Applicability, StashKey};
 use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
 use rustc_session::Session;
@@ -13,7 +13,7 @@ use rustc_target::spec::abi;
 use thin_vec::ThinVec;
 use tracing::debug;
 
-use crate::errors::ForbiddenLifetimeBound;
+use crate::errors;
 
 macro_rules! gate_feature_fn {
     ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
@@ -164,7 +164,7 @@ impl<'a> PostExpansionVisitor<'a> {
         for param in params {
             if !param.bounds.is_empty() {
                 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
-                self.sess.emit_err(ForbiddenLifetimeBound { spans });
+                self.sess.emit_err(errors::ForbiddenLifetimeBound { spans });
             }
         }
     }
@@ -218,13 +218,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 || attr.has_name(sym::rustc_const_stable)
                 || attr.has_name(sym::rustc_default_body_unstable)
             {
-                struct_span_err!(
-                    self.sess,
-                    attr.span,
-                    E0734,
-                    "stability attributes may not be used outside of the standard library",
-                )
-                .emit();
+                self.sess.emit_err(errors::StabilityOutsideStd { span: attr.span });
             }
         }
     }
@@ -392,7 +386,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             ).span_suggestion_verbose(
                 lhs.span.shrink_to_lo(),
                 "you might have meant to introduce a new binding",
-                "let ".to_string(),
+                "let ",
                 Applicability::MachineApplicable,
             ).emit();
         }
@@ -635,13 +629,13 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
             return;
         }
         for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
-            let mut err = struct_span_err!(
-                sess.parse_sess.span_diagnostic,
-                attr.span,
-                E0554,
-                "`#![feature]` may not be used on the {} release channel",
-                option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)")
-            );
+            let mut err = errors::FeatureOnNonNightly {
+                span: attr.span,
+                channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
+                stable_features: vec![],
+                sugg: None,
+            };
+
             let mut all_stable = true;
             for ident in
                 attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
@@ -652,24 +646,15 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
                     .flat_map(|&(feature, _, since)| if feature == name { since } else { None })
                     .next();
                 if let Some(since) = stable_since {
-                    err.help(&format!(
-                        "the feature `{}` has been stable since {} and no longer requires \
-                                  an attribute to enable",
-                        name, since
-                    ));
+                    err.stable_features.push(errors::StableFeature { name, since });
                 } else {
                     all_stable = false;
                 }
             }
             if all_stable {
-                err.span_suggestion(
-                    attr.span,
-                    "remove the attribute",
-                    "",
-                    Applicability::MachineApplicable,
-                );
+                err.sugg = Some(attr.span);
             }
-            err.emit();
+            sess.parse_sess.span_diagnostic.emit_err(err);
         }
     }
 }
@@ -692,16 +677,7 @@ fn check_incompatible_features(sess: &Session) {
             if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
             {
                 let spans = vec![f1_span, f2_span];
-                sess.struct_span_err(
-                    spans,
-                    &format!(
-                        "features `{}` and `{}` are incompatible, using them at the same time \
-                        is not allowed",
-                        f1_name, f2_name
-                    ),
-                )
-                .help("remove one of these features")
-                .emit();
+                sess.emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name });
             }
         }
     }
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 1be959b0de6..b9dcaee2373 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -10,6 +10,8 @@
 #![feature(iter_is_partitioned)]
 #![feature(let_chains)]
 #![recursion_limit = "256"]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_macros::fluent_messages;
diff --git a/compiler/rustc_ast_passes/src/show_span.rs b/compiler/rustc_ast_passes/src/show_span.rs
index 27637e311f4..280cf3284c3 100644
--- a/compiler/rustc_ast_passes/src/show_span.rs
+++ b/compiler/rustc_ast_passes/src/show_span.rs
@@ -9,6 +9,8 @@ use rustc_ast as ast;
 use rustc_ast::visit;
 use rustc_ast::visit::Visitor;
 
+use crate::errors;
+
 enum Mode {
     Expression,
     Pattern,
@@ -36,21 +38,21 @@ struct ShowSpanVisitor<'a> {
 impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
     fn visit_expr(&mut self, e: &'a ast::Expr) {
         if let Mode::Expression = self.mode {
-            self.span_diagnostic.span_warn(e.span, "expression");
+            self.span_diagnostic.emit_warning(errors::ShowSpan { span: e.span, msg: "expression" });
         }
         visit::walk_expr(self, e);
     }
 
     fn visit_pat(&mut self, p: &'a ast::Pat) {
         if let Mode::Pattern = self.mode {
-            self.span_diagnostic.span_warn(p.span, "pattern");
+            self.span_diagnostic.emit_warning(errors::ShowSpan { span: p.span, msg: "pattern" });
         }
         visit::walk_pat(self, p);
     }
 
     fn visit_ty(&mut self, t: &'a ast::Ty) {
         if let Mode::Type = self.mode {
-            self.span_diagnostic.span_warn(t.span, "type");
+            self.span_diagnostic.emit_warning(errors::ShowSpan { span: t.span, msg: "type" });
         }
         visit::walk_ty(self, t);
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 262e093b0fa..cb97699d7d2 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -6,7 +6,7 @@ use rustc_errors::{
     struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
-use rustc_hir::def::Res;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
 use rustc_infer::infer::TyCtxtInferExt;
@@ -236,10 +236,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             let ty = used_place.ty(self.body, self.infcx.tcx).ty;
             let needs_note = match ty.kind() {
                 ty::Closure(id, _) => {
-                    let tables = self.infcx.tcx.typeck(id.expect_local());
-                    let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local());
-
-                    tables.closure_kind_origins().get(hir_id).is_none()
+                    self.infcx.tcx.closure_kind_origin(id.expect_local()).is_none()
                 }
                 _ => true,
             };
@@ -1494,7 +1491,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         assert!(root_place.projection.is_empty());
         let proper_span = self.body.local_decls[root_place.local].source_info.span;
 
-        let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
+        let root_place_projection = self.infcx.tcx.mk_place_elems(root_place.projection);
 
         if self.access_place_error_reported.contains(&(
             Place { local: root_place.local, projection: root_place_projection },
@@ -1670,7 +1667,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 format!("`{}` would have to be valid for `{}`...", name, region_name),
             );
 
-            let fn_hir_id = self.mir_hir_id();
             err.span_label(
                 drop_span,
                 format!(
@@ -1678,19 +1674,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     name,
                     self.infcx
                         .tcx
-                        .hir()
-                        .opt_name(fn_hir_id)
+                        .opt_item_name(self.mir_def_id().to_def_id())
                         .map(|name| format!("function `{}`", name))
                         .unwrap_or_else(|| {
-                            match &self
-                                .infcx
-                                .tcx
-                                .typeck(self.mir_def_id())
-                                .node_type(fn_hir_id)
-                                .kind()
-                            {
-                                ty::Closure(..) => "enclosing closure",
-                                ty::Generator(..) => "enclosing generator",
+                            match &self.infcx.tcx.def_kind(self.mir_def_id()) {
+                                DefKind::Closure => "enclosing closure",
+                                DefKind::Generator => "enclosing generator",
                                 kind => bug!("expected closure or generator, found {:?}", kind),
                             }
                             .to_string()
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index f5bd99f15ab..a99fd594a07 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -115,11 +115,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
                     if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
                         let did = did.expect_local();
-                        let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
-
-                        if let Some((span, hir_place)) =
-                            self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
-                        {
+                        if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
                             diag.span_note(
                                 *span,
                                 &format!(
@@ -139,11 +135,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         if let Some(target) = target {
             if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
                 let did = did.expect_local();
-                let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
-
-                if let Some((span, hir_place)) =
-                    self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
-                {
+                if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
                     diag.span_note(
                         *span,
                         &format!(
@@ -373,14 +365,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     //
                     // We know the field exists so it's safe to call operator[] and `unwrap` here.
                     let def_id = def_id.expect_local();
-                    let var_id = self
-                        .infcx
-                        .tcx
-                        .typeck(def_id)
-                        .closure_min_captures_flattened(def_id)
-                        .nth(field.index())
-                        .unwrap()
-                        .get_root_variable();
+                    let var_id =
+                        self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();
 
                     Some(self.infcx.tcx.hir().name(var_id).to_string())
                 }
@@ -987,7 +973,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
         if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
             for (captured_place, place) in
-                self.infcx.tcx.typeck(def_id).closure_min_captures_flattened(def_id).zip(places)
+                self.infcx.tcx.closure_captures(def_id).iter().zip(places)
             {
                 match place {
                     Operand::Copy(place) | Operand::Move(place)
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index ea58ad5ae3e..5e4c7292e59 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -467,7 +467,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 err.span_suggestion_verbose(
                     span.shrink_to_lo(),
                     "consider borrowing here",
-                    "&".to_string(),
+                    '&',
                     Applicability::MaybeIncorrect,
                 );
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 9f37b915b77..328ac880dd4 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -385,7 +385,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     err.span_suggestion_verbose(
                         local_decl.source_info.span.shrink_to_lo(),
                         "consider changing this to be mutable",
-                        "mut ".to_string(),
+                        "mut ",
                         Applicability::MachineApplicable,
                     );
                     let tcx = self.infcx.tcx;
@@ -901,10 +901,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         err: &mut Diagnostic,
     ) {
         let tables = tcx.typeck(closure_local_def_id);
-        let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_local_def_id);
-        if let Some((span, closure_kind_origin)) =
-            &tables.closure_kind_origins().get(closure_hir_id)
-        {
+        if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) {
             let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
                 let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
                 let root_hir_id = upvar_id.var_path.hir_id;
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 42949143431..0f591460e9d 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1,6 +1,7 @@
 //! This query borrow-checks the MIR to (further) ensure it is not broken.
 
 #![allow(rustc::potential_query_instability)]
+#![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(let_chains)]
 #![feature(min_specialization)]
@@ -201,14 +202,14 @@ fn do_mir_borrowck<'tcx>(
     let mut errors = error::BorrowckErrors::new(infcx.tcx);
 
     // Gather the upvars of a closure, if any.
-    let tables = tcx.typeck_opt_const_arg(def);
-    if let Some(e) = tables.tainted_by_errors {
+    if let Some(e) = input_body.tainted_by_errors {
         infcx.set_tainted_by_errors(e);
         errors.set_tainted_by_errors(e);
     }
-    let upvars: Vec<_> = tables
-        .closure_min_captures_flattened(def.did)
-        .map(|captured_place| {
+    let upvars: Vec<_> = tcx
+        .closure_captures(def.did)
+        .iter()
+        .map(|&captured_place| {
             let capture = captured_place.info.capture_kind;
             let by_ref = match capture {
                 ty::UpvarCapture::ByValue => false,
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index ae1d89de80e..c550e37c63e 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::vec_map::VecMap;
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::OpaqueTyOrigin;
 use rustc_infer::infer::TyCtxtInferExt as _;
@@ -149,13 +150,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // once we convert the generic parameters to those of the opaque type.
             if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
                 if prev.ty != ty {
-                    if !ty.references_error() {
+                    let guar = ty.error_reported().err().unwrap_or_else(|| {
                         prev.report_mismatch(
                             &OpaqueHiddenType { ty, span: concrete_type.span },
                             infcx.tcx,
-                        );
-                    }
-                    prev.ty = infcx.tcx.ty_error();
+                        )
+                    });
+                    prev.ty = infcx.tcx.ty_error(guar);
                 }
                 // Pick a better span if there is one.
                 // FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
@@ -247,20 +248,20 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         origin: OpaqueTyOrigin,
     ) -> Ty<'tcx> {
         if let Some(e) = self.tainted_by_errors() {
-            return self.tcx.ty_error_with_guaranteed(e);
+            return self.tcx.ty_error(e);
         }
 
         let definition_ty = instantiated_ty
             .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
             .ty;
 
-        if !check_opaque_type_parameter_valid(
+        if let Err(guar) = check_opaque_type_parameter_valid(
             self.tcx,
             opaque_type_key,
             origin,
             instantiated_ty.span,
         ) {
-            return self.tcx.ty_error();
+            return self.tcx.ty_error(guar);
         }
 
         // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
@@ -325,7 +326,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
             definition_ty
         } else {
             let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
-            self.tcx.ty_error_with_guaranteed(reported)
+            self.tcx.ty_error(reported)
         }
     }
 }
@@ -335,7 +336,7 @@ fn check_opaque_type_parameter_valid(
     opaque_type_key: OpaqueTypeKey<'_>,
     origin: OpaqueTyOrigin,
     span: Span,
-) -> bool {
+) -> Result<(), ErrorGuaranteed> {
     match origin {
         // No need to check return position impl trait (RPIT)
         // because for type and const parameters they are correct
@@ -358,7 +359,7 @@ fn check_opaque_type_parameter_valid(
         // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
         //
         // which would error here on all of the `'static` args.
-        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
+        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()),
         // Check these
         OpaqueTyOrigin::TyAlias => {}
     }
@@ -379,13 +380,13 @@ fn check_opaque_type_parameter_valid(
             // Prevent `fn foo() -> Foo<u32>` from being defining.
             let opaque_param = opaque_generics.param_at(i, tcx);
             let kind = opaque_param.kind.descr();
-            tcx.sess.emit_err(NonGenericOpaqueTypeParam {
+
+            return Err(tcx.sess.emit_err(NonGenericOpaqueTypeParam {
                 ty: arg,
                 kind,
                 span,
                 param_span: tcx.def_span(opaque_param.def_id),
-            });
-            return false;
+            }));
         }
     }
 
@@ -396,12 +397,13 @@ fn check_opaque_type_parameter_valid(
                 .into_iter()
                 .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
                 .collect();
-            tcx.sess
+            return Err(tcx
+                .sess
                 .struct_span_err(span, "non-defining opaque type use in defining scope")
                 .span_note(spans, &format!("{} used multiple times", descr))
-                .emit();
-            return false;
+                .emit());
         }
     }
-    true
+
+    Ok(())
 }
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 1be20f18707..b27d5d20532 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -117,7 +117,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
     pub(super) fn prove_predicates(
         &mut self,
-        predicates: impl IntoIterator<Item = impl ToPredicate<'tcx> + std::fmt::Debug>,
+        predicates: impl IntoIterator<Item: ToPredicate<'tcx> + std::fmt::Debug>,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
     ) {
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 2dd24fe0340..e2f897a89e8 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -270,12 +270,13 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                 .and(type_op::normalize::Normalize::new(ty))
                 .fully_perform(self.infcx)
                 .unwrap_or_else(|_| {
-                    self.infcx
+                    let guar = self
+                        .infcx
                         .tcx
                         .sess
                         .delay_span_bug(span, &format!("failed to normalize {:?}", ty));
                     TypeOpOutput {
-                        output: self.infcx.tcx.ty_error(),
+                        output: self.infcx.tcx.ty_error(guar),
                         constraints: None,
                         error_info: None,
                     }
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index c6b78df9a5f..717020ea5b8 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -26,11 +26,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         if !self.tcx().is_closure(mir_def_id.to_def_id()) {
             return;
         }
-        let Some(user_provided_poly_sig) =
-            self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id)
-        else {
-            return;
-        };
+        let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id);
 
         // Instantiate the canonicalized variables from user-provided signature
         // (e.g., the `_` in the code above) with fresh variables.
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index eb0fa1b6859..a49da3da6c0 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -239,7 +239,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
                     decl.hidden_type.span,
                     &format!("could not resolve {:#?}", hidden_type.ty.kind()),
                 );
-                hidden_type.ty = infcx.tcx.ty_error_with_guaranteed(reported);
+                hidden_type.ty = infcx.tcx.ty_error(reported);
             }
 
             (opaque_type_key, (hidden_type, decl.origin))
@@ -529,9 +529,9 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
 
         for elem in place.projection.iter() {
             if place_ty.variant_index.is_none() {
-                if place_ty.ty.references_error() {
+                if let Err(guar) = place_ty.ty.error_reported() {
                     assert!(self.errors_reported);
-                    return PlaceTy::from_ty(self.tcx().ty_error());
+                    return PlaceTy::from_ty(self.tcx().ty_error(guar));
                 }
             }
             place_ty = self.sanitize_projection(place_ty, elem, place, location, context);
@@ -763,7 +763,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
 
     fn error(&mut self) -> Ty<'tcx> {
         self.errors_reported = true;
-        self.tcx().ty_error()
+        self.tcx().ty_error_misc()
     }
 
     fn get_ambient_variance(&self, context: PlaceContext) -> ty::Variance {
@@ -2633,7 +2633,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             DefKind::InlineConst => substs.as_inline_const().parent_substs(),
             other => bug!("unexpected item {:?}", other),
         };
-        let parent_substs = tcx.intern_substs(parent_substs);
+        let parent_substs = tcx.mk_substs(parent_substs);
 
         assert_eq!(typeck_root_substs.len(), parent_substs.len());
         if let Err(_) = self.eq_substs(
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 3e8731755fc..15d7613a812 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -18,7 +18,7 @@ use rustc_errors::Diagnostic;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{BodyOwnerKind, HirId};
+use rustc_hir::BodyOwnerKind;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::ty::fold::TypeFoldable;
@@ -231,9 +231,7 @@ impl<'tcx> UniversalRegions<'tcx> {
         mir_def: ty::WithOptConstParam<LocalDefId>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Self {
-        let tcx = infcx.tcx;
-        let mir_hir_id = tcx.hir().local_def_id_to_hir_id(mir_def.did);
-        UniversalRegionsBuilder { infcx, mir_def, mir_hir_id, param_env }.build()
+        UniversalRegionsBuilder { infcx, mir_def, param_env }.build()
     }
 
     /// Given a reference to a closure type, extracts all the values
@@ -390,7 +388,6 @@ impl<'tcx> UniversalRegions<'tcx> {
 struct UniversalRegionsBuilder<'cx, 'tcx> {
     infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
     mir_def: ty::WithOptConstParam<LocalDefId>,
-    mir_hir_id: HirId,
     param_env: ty::ParamEnv<'tcx>,
 }
 
@@ -516,7 +513,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 let va_list_ty =
                     self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]);
 
-                unnormalized_input_tys = self.infcx.tcx.mk_type_list(
+                unnormalized_input_tys = self.infcx.tcx.mk_type_list_from_iter(
                     unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)),
                 );
             }
@@ -560,12 +557,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
 
         match tcx.hir().body_owner_kind(self.mir_def.did) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
-                let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
-                    tcx.type_of(typeck_root_def_id).subst_identity()
-                } else {
-                    let tables = tcx.typeck(self.mir_def.did);
-                    tables.node_type(self.mir_hir_id)
-                };
+                let defining_ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity();
 
                 debug!("defining_ty (pre-replacement): {:?}", defining_ty);
 
@@ -594,7 +586,18 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                         self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
                     DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
                 } else {
-                    let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
+                    // FIXME this line creates a dependency between borrowck and typeck.
+                    //
+                    // This is required for `AscribeUserType` canonical query, which will call
+                    // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes
+                    // into borrowck, which is ICE #78174.
+                    //
+                    // As a workaround, inline consts have an additional generic param (`ty`
+                    // below), so that `type_of(inline_const_def_id).substs(substs)` uses the
+                    // proper type with NLL infer vars.
+                    let ty = tcx
+                        .typeck(self.mir_def.did)
+                        .node_type(tcx.local_def_id_to_hir_id(self.mir_def.did));
                     let substs = InlineConstSubsts::new(
                         tcx,
                         InlineConstSubstsParts { parent_substs: identity_substs, ty },
@@ -656,7 +659,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 assert_eq!(self.mir_def.did.to_def_id(), def_id);
                 let closure_sig = substs.as_closure().sig();
                 let inputs_and_output = closure_sig.inputs_and_output();
-                let bound_vars = tcx.mk_bound_variable_kinds(
+                let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
                     inputs_and_output
                         .bound_vars()
                         .iter()
@@ -680,7 +683,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 };
 
                 ty::Binder::bind_with_vars(
-                    tcx.mk_type_list(
+                    tcx.mk_type_list_from_iter(
                         iter::once(closure_ty).chain(inputs).chain(iter::once(output)),
                     ),
                     bound_vars,
@@ -693,7 +696,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 let output = substs.as_generator().return_ty();
                 let generator_ty = tcx.mk_generator(def_id, substs, movability);
                 let inputs_and_output =
-                    self.infcx.tcx.intern_type_list(&[generator_ty, resume_ty, output]);
+                    self.infcx.tcx.mk_type_list(&[generator_ty, resume_ty, output]);
                 ty::Binder::dummy(inputs_and_output)
             }
 
@@ -709,13 +712,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 assert_eq!(self.mir_def.did.to_def_id(), def_id);
                 let ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity();
                 let ty = indices.fold_to_region_vids(tcx, ty);
-                ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+                ty::Binder::dummy(tcx.mk_type_list(&[ty]))
             }
 
             DefiningTy::InlineConst(def_id, substs) => {
                 assert_eq!(self.mir_def.did.to_def_id(), def_id);
                 let ty = substs.as_inline_const().ty();
-                ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+                ty::Binder::dummy(tcx.mk_type_list(&[ty]))
             }
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 925392b500a..3fdbc971527 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -152,7 +152,7 @@ pub fn parse_asm_args<'a>(
                 ast::InlineAsmOperand::InOut { reg, expr, late: true }
             }
         } else if p.eat_keyword(kw::Const) {
-            let anon_const = p.parse_anon_const_expr()?;
+            let anon_const = p.parse_expr_anon_const()?;
             ast::InlineAsmOperand::Const { anon_const }
         } else if p.eat_keyword(sym::sym) {
             let expr = p.parse_expr()?;
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 3c34585d419..74396a66f54 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -405,9 +405,9 @@ pub(crate) fn codegen_terminator_call<'tcx>(
     };
 
     let extra_args = &args[fn_sig.inputs().skip_binder().len()..];
-    let extra_args = fx
-        .tcx
-        .mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
+    let extra_args = fx.tcx.mk_type_list_from_iter(
+        extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))),
+    );
     let fn_abi = if let Some(instance) = instance {
         RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
     } else {
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index b4a2537b5ea..40bfe70771c 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -56,7 +56,7 @@ pub(crate) fn maybe_codegen<'tcx>(
                     Some(fx.easy_call("__multi3", &[lhs, rhs], val_ty))
                 }
             } else {
-                let out_ty = fx.tcx.intern_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
+                let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
                 let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
                 let lhs = lhs.load_scalar(fx);
                 let rhs = rhs.load_scalar(fx);
@@ -78,7 +78,7 @@ pub(crate) fn maybe_codegen<'tcx>(
         }
         BinOp::Add | BinOp::Sub | BinOp::Mul => {
             assert!(checked);
-            let out_ty = fx.tcx.intern_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
+            let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
             let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
             let (param_types, args) = if fx.tcx.sess.target.is_like_windows {
                 let (lhs_ptr, lhs_extra) = lhs.force_stack(fx);
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index cbac2e66765..e5c4b244a1a 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -191,7 +191,7 @@ fn llvm_add_sub<'tcx>(
     // carry0 | carry1 -> carry or borrow respectively
     let cb_out = fx.bcx.ins().bor(cb0, cb1);
 
-    let layout = fx.layout_of(fx.tcx.intern_tup(&[fx.tcx.types.u8, fx.tcx.types.u64]));
+    let layout = fx.layout_of(fx.tcx.mk_tup(&[fx.tcx.types.u8, fx.tcx.types.u64]));
     let val = CValue::by_val_pair(cb_out, c, layout);
     ret.write_cvalue(fx, val);
 }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 6feb3a7732e..f00e9321070 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -21,7 +21,8 @@ mod simd;
 pub(crate) use cpuid::codegen_cpuid_call;
 pub(crate) use llvm::codegen_llvm_intrinsic_call;
 
-use rustc_middle::ty::layout::HasParamEnv;
+use rustc_middle::ty;
+use rustc_middle::ty::layout::{HasParamEnv, InitKind};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -642,7 +643,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
             if intrinsic == sym::assert_zero_valid
                 && !fx
                     .tcx
-                    .permits_zero_init(fx.param_env().and(ty))
+                    .check_validity_of_init((InitKind::Zero, fx.param_env().and(ty)))
                     .expect("expected to have layout during codegen")
             {
                 with_no_trimmed_paths!({
@@ -661,7 +662,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
             if intrinsic == sym::assert_mem_uninitialized_valid
                 && !fx
                     .tcx
-                    .permits_uninit_init(fx.param_env().and(ty))
+                    .check_validity_of_init((
+                        InitKind::UninitMitigated0x01Fill,
+                        fx.param_env().and(ty),
+                    ))
                     .expect("expected to have layout during codegen")
             {
                 with_no_trimmed_paths!({
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index 26327107df4..be908df83e8 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -119,7 +119,7 @@ pub(crate) fn maybe_create_entry_wrapper(
                     tcx,
                     ParamEnv::reveal_all(),
                     report.def_id,
-                    tcx.intern_substs(&[GenericArg::from(main_ret_ty)]),
+                    tcx.mk_substs(&[GenericArg::from(main_ret_ty)]),
                 )
                 .unwrap()
                 .unwrap()
@@ -146,7 +146,7 @@ pub(crate) fn maybe_create_entry_wrapper(
                     tcx,
                     ParamEnv::reveal_all(),
                     start_def_id,
-                    tcx.intern_substs(&[main_ret_ty.into()]),
+                    tcx.mk_substs(&[main_ret_ty.into()]),
                 )
                 .unwrap()
                 .unwrap()
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 05905a7bcdf..c058ece96d8 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -289,7 +289,7 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
         _ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, in_lhs, in_rhs),
     };
 
-    let out_layout = fx.layout_of(fx.tcx.intern_tup(&[in_lhs.layout().ty, fx.tcx.types.bool]));
+    let out_layout = fx.layout_of(fx.tcx.mk_tup(&[in_lhs.layout().ty, fx.tcx.types.bool]));
     CValue::by_val_pair(res, has_overflow, out_layout)
 }
 
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 4424b31c054..457006319af 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -383,7 +383,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                     tcx,
                     ty::ParamEnv::reveal_all(),
                     def_id,
-                    tcx.intern_substs(&[]),
+                    ty::List::empty(),
                 )
                 .unwrap().unwrap(),
             ),
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 37ee0e14020..3d29968d5d6 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -520,14 +520,9 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         let tcx = self.tcx;
         let llfn = match tcx.lang_items().eh_personality() {
             Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr(
-                ty::Instance::resolve(
-                    tcx,
-                    ty::ParamEnv::reveal_all(),
-                    def_id,
-                    tcx.intern_substs(&[]),
-                )
-                .unwrap()
-                .unwrap(),
+                ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, ty::List::empty())
+                    .unwrap()
+                    .unwrap(),
             ),
             _ => {
                 let name = if wants_msvc_seh(self.sess()) {
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 11bd47a8f0c..067a3e167fe 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -373,7 +373,7 @@ fn upstream_monomorphizations_provider(
                 ExportedSymbol::Generic(def_id, substs) => (def_id, substs),
                 ExportedSymbol::DropGlue(ty) => {
                     if let Some(drop_in_place_fn_def_id) = drop_in_place_fn_def_id {
-                        (drop_in_place_fn_def_id, tcx.intern_substs(&[ty.into()]))
+                        (drop_in_place_fn_def_id, tcx.mk_substs(&[ty.into()]))
                     } else {
                         // `drop_in_place` in place does not exist, don't try
                         // to use it.
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 4e13d4dbcb7..73179249bc4 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -476,7 +476,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                     cx.tcx(),
                     ty::ParamEnv::reveal_all(),
                     start_def_id,
-                    cx.tcx().intern_substs(&[main_ret_ty.into()]),
+                    cx.tcx().mk_substs(&[main_ret_ty.into()]),
                 )
                 .unwrap()
                 .unwrap(),
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 7d5c0048626..3619cb48d64 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -224,34 +224,23 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
             if !tcx.is_closure(did.to_def_id())
                 && tcx.fn_sig(did).skip_binder().unsafety() == hir::Unsafety::Normal
             {
-                if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
-                    // The `#[target_feature]` attribute is allowed on
-                    // WebAssembly targets on all functions, including safe
-                    // ones. Other targets require that `#[target_feature]` is
-                    // only applied to unsafe functions (pending the
-                    // `target_feature_11` feature) because on most targets
-                    // execution of instructions that are not supported is
-                    // considered undefined behavior. For WebAssembly which is a
-                    // 100% safe target at execution time it's not possible to
-                    // execute undefined instructions, and even if a future
-                    // feature was added in some form for this it would be a
-                    // deterministic trap. There is no undefined behavior when
-                    // executing WebAssembly so `#[target_feature]` is allowed
-                    // on safe functions (but again, only for WebAssembly)
-                    //
-                    // Note that this is also allowed if `actually_rustdoc` so
-                    // if a target is documenting some wasm-specific code then
-                    // it's not spuriously denied.
-                } else if !tcx.features().target_feature_11 {
-                    let mut err = feature_err(
-                        &tcx.sess.parse_sess,
-                        sym::target_feature_11,
-                        attr.span,
-                        "`#[target_feature(..)]` can only be applied to `unsafe` functions",
-                    );
-                    err.span_label(tcx.def_span(did), "not an `unsafe` function");
-                    err.emit();
-                } else {
+                // The `#[target_feature]` attribute is allowed on
+                // WebAssembly targets on all functions, including safe
+                // ones. Other targets have conditions on the usage of
+                // `#[target_feature]` because on most targets
+                // execution of instructions that are not supported is
+                // considered undefined behavior. For WebAssembly which is a
+                // 100% safe target at execution time it's not possible to
+                // execute undefined instructions, and even if a future
+                // feature was added in some form for this it would be a
+                // deterministic trap. There is no undefined behavior when
+                // executing WebAssembly so `#[target_feature]` is allowed
+                // on safe functions (but again, only for WebAssembly)
+                //
+                // Note that this is also allowed if `actually_rustdoc` so
+                // if a target is documenting some wasm-specific code then
+                // it's not spuriously denied.
+                if !(tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc) {
                     check_target_feature_trait_unsafe(tcx, did, attr.span);
                 }
             }
@@ -478,7 +467,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
     });
 
     // #73631: closures inherit `#[target_feature]` annotations
-    if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
+    if tcx.is_closure(did.to_def_id()) {
         let owner_id = tcx.parent(did.to_def_id());
         if tcx.def_kind(owner_id).has_codegen_attrs() {
             codegen_fn_attrs
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index cdc3e1dc237..b1abbd673a5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -14,7 +14,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::Idx;
 use rustc_middle::mir::{self, AssertKind, SwitchTargets};
-use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
+use rustc_middle::ty::layout::{HasTyCtxt, InitKind, LayoutOf};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt};
 use rustc_session::config::OptLevel;
@@ -676,11 +676,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 Inhabited => layout.abi.is_uninhabited(),
                 ZeroValid => !bx
                     .tcx()
-                    .permits_zero_init(bx.param_env().and(ty))
+                    .check_validity_of_init((InitKind::Zero, bx.param_env().and(ty)))
                     .expect("expected to have layout during codegen"),
                 MemUninitializedValid => !bx
                     .tcx()
-                    .permits_uninit_init(bx.param_env().and(ty))
+                    .check_validity_of_init((
+                        InitKind::UninitMitigated0x01Fill,
+                        bx.param_env().and(ty),
+                    ))
                     .expect("expected to have layout during codegen"),
             };
             Some(if do_panic {
@@ -783,7 +786,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         };
 
         let extra_args = &args[sig.inputs().skip_binder().len()..];
-        let extra_args = bx.tcx().mk_type_list(extra_args.iter().map(|op_arg| {
+        let extra_args = bx.tcx().mk_type_list_from_iter(extra_args.iter().map(|op_arg| {
             let op_ty = op_arg.ty(self.mir, bx.tcx());
             self.monomorphize(op_ty)
         }));
@@ -1547,7 +1550,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             slot
         } else {
             let layout = cx.layout_of(
-                cx.tcx().intern_tup(&[cx.tcx().mk_mut_ptr(cx.tcx().types.u8), cx.tcx().types.i32]),
+                cx.tcx().mk_tup(&[cx.tcx().mk_mut_ptr(cx.tcx().types.u8), cx.tcx().types.i32]),
             );
             let slot = PlaceRef::alloca(bx, layout);
             self.personality_slot = Some(slot);
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 41cd1c09a4e..3d856986fb4 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -413,7 +413,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     lhs.layout.ty,
                 );
                 let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
-                let operand_ty = bx.tcx().intern_tup(&[val_ty, bx.tcx().types.bool]);
+                let operand_ty = bx.tcx().mk_tup(&[val_ty, bx.tcx().types.bool]);
                 OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) }
             }
 
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 0432a9c5a12..e59fad99ad7 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -185,7 +185,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
     ("bmi1", None),
     ("bmi2", None),
-    ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
+    ("cmpxchg16b", None),
     ("ermsb", Some(sym::ermsb_target_feature)),
     ("f16c", None),
     ("fma", None),
@@ -394,7 +394,6 @@ pub fn from_target_feature(
                 Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
                 Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
                 Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
-                Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
                 Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
                 Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
                 Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 45f7c756055..7564ba17b40 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -180,7 +180,7 @@ pub(super) fn op_to_const<'tcx>(
                         (ecx.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes())
                     }
                     (None, _offset) => (
-                        ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable(
+                        ecx.tcx.mk_const_alloc(Allocation::from_bytes_byte_aligned_immutable(
                             b"" as &[u8],
                         )),
                         0,
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 21ef1836188..b220d21f68b 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -135,7 +135,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
     };
     // link the alloc id to the actual allocation
     leftover_allocations.extend(alloc.provenance().ptrs().iter().map(|&(_, alloc_id)| alloc_id));
-    let alloc = tcx.intern_const_alloc(alloc);
+    let alloc = tcx.mk_const_alloc(alloc);
     tcx.set_alloc_id_memory(alloc_id, alloc);
     None
 }
@@ -437,7 +437,7 @@ pub fn intern_const_alloc_recursive<
                     alloc.mutability = Mutability::Not;
                 }
             }
-            let alloc = tcx.intern_const_alloc(alloc);
+            let alloc = tcx.mk_const_alloc(alloc);
             tcx.set_alloc_id_memory(alloc_id, alloc);
             for &(_, alloc_id) in alloc.inner().provenance().ptrs().iter() {
                 if leftover_allocations.insert(alloc_id) {
@@ -479,6 +479,6 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
         f(self, &dest.into())?;
         let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1;
         alloc.mutability = Mutability::Not;
-        Ok(self.tcx.intern_const_alloc(alloc))
+        Ok(self.tcx.mk_const_alloc(alloc))
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index c5d558aeb6c..26c84b4ce61 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -11,7 +11,7 @@ use rustc_middle::mir::{
     BinOp, NonDivergingIntrinsic,
 };
 use rustc_middle::ty;
-use rustc_middle::ty::layout::LayoutOf as _;
+use rustc_middle::ty::layout::{InitKind, LayoutOf as _};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
@@ -45,7 +45,7 @@ fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<
 pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
     let path = crate::util::type_name(tcx, ty);
     let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
-    tcx.intern_const_alloc(alloc)
+    tcx.mk_const_alloc(alloc)
 }
 
 /// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
@@ -437,7 +437,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 if intrinsic_name == sym::assert_zero_valid {
                     let should_panic = !self
                         .tcx
-                        .permits_zero_init(self.param_env.and(ty))
+                        .check_validity_of_init((InitKind::Zero, self.param_env.and(ty)))
                         .map_err(|_| err_inval!(TooGeneric))?;
 
                     if should_panic {
@@ -454,7 +454,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 if intrinsic_name == sym::assert_mem_uninitialized_valid {
                     let should_panic = !self
                         .tcx
-                        .permits_uninit_init(self.param_env.and(ty))
+                        .check_validity_of_init((
+                            InitKind::UninitMitigated0x01Fill,
+                            self.param_env.and(ty),
+                        ))
                         .map_err(|_| err_inval!(TooGeneric))?;
 
                     if should_panic {
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
index f6a3937870e..cf52299b7ba 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -96,7 +96,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let loc_ty = self
             .tcx
             .type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
-            .subst(*self.tcx, self.tcx.intern_substs(&[self.tcx.lifetimes.re_erased.into()]));
+            .subst(*self.tcx, self.tcx.mk_substs(&[self.tcx.lifetimes.re_erased.into()]));
         let loc_layout = self.layout_of(loc_ty).unwrap();
         let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
 
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 422120084d3..4decfe863e6 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -19,7 +19,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ) -> InterpResult<'tcx> {
         let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?;
         debug_assert_eq!(
-            self.tcx.intern_tup(&[ty, self.tcx.types.bool]),
+            self.tcx.mk_tup(&[ty, self.tcx.types.bool]),
             dest.layout.ty,
             "type mismatch for result of {:?}",
             op,
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index d934cfbbb84..2aea7c79b6d 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -73,7 +73,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let fn_sig =
                     self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
                 let extra_args = &args[fn_sig.inputs().len()..];
-                let extra_args = self.tcx.mk_type_list(extra_args.iter().map(|arg| arg.layout.ty));
+                let extra_args =
+                    self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout.ty));
 
                 let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() {
                     ty::FnPtr(_sig) => {
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index e76d4c1728e..f7881c50960 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -240,10 +240,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 // FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar
                 // https://github.com/rust-lang/project-rfc-2229/issues/46
                 if let Some(local_def_id) = def_id.as_local() {
-                    let tables = self.ecx.tcx.typeck(local_def_id);
-                    if let Some(captured_place) =
-                        tables.closure_min_captures_flattened(local_def_id).nth(field)
-                    {
+                    let captures = self.ecx.tcx.closure_captures(local_def_id);
+                    if let Some(captured_place) = captures.get(field) {
                         // Sometimes the index is beyond the number of upvars (seen
                         // for a generator).
                         let var_hir_id = captured_place.get_root_variable();
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index fc6d61c79c2..092a7dc3d3b 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -38,7 +38,6 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_macros::fluent_messages;
 use rustc_middle::ty;
 use rustc_middle::ty::query::Providers;
-use rustc_target::abi::InitKind;
 
 fluent_messages! { "../locales/en-US.ftl" }
 
@@ -62,9 +61,7 @@ pub fn provide(providers: &mut Providers) {
         let (param_env, value) = param_env_and_value.into_parts();
         const_eval::deref_mir_constant(tcx, param_env, value)
     };
-    providers.permits_uninit_init = |tcx, param_env_and_ty| {
-        util::might_permit_raw_init(tcx, param_env_and_ty, InitKind::UninitMitigated0x01Fill)
+    providers.check_validity_of_init = |tcx, (init_kind, param_env_and_ty)| {
+        util::might_permit_raw_init(tcx, init_kind, param_env_and_ty)
     };
-    providers.permits_zero_init =
-        |tcx, param_env_and_ty| util::might_permit_raw_init(tcx, param_env_and_ty, InitKind::Zero);
 }
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index ba08f5d30d9..3f3b66b0645 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -866,7 +866,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
 
             let mut projection = vec![PlaceElem::Deref];
             projection.extend(place.projection);
-            place.projection = tcx.intern_place_elems(&projection);
+            place.projection = tcx.mk_place_elems(&projection);
 
             // Create a temp to hold the promoted reference.
             // This is because `*r` requires `r` to be a local,
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 3af2d0c4e66..fb37eb79a33 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -315,7 +315,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 }
             }
             ProjectionElem::Field(f, ty) => {
-                let parent = Place { local, projection: self.tcx.intern_place_elems(proj_base) };
+                let parent = Place { local, projection: self.tcx.mk_place_elems(proj_base) };
                 let parent_ty = parent.ty(&self.body.local_decls, self.tcx);
                 let fail_out_of_bounds = |this: &Self, location| {
                     this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty));
@@ -755,8 +755,26 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     self.fail(location, format!("explicit `{:?}` is forbidden", kind));
                 }
             }
-            StatementKind::StorageLive(..)
-            | StatementKind::StorageDead(..)
+            StatementKind::StorageLive(local) => {
+                // We check that the local is not live when entering a `StorageLive` for it.
+                // Technically, violating this restriction is only UB and not actually indicative
+                // of not well-formed MIR. This means that an optimization which turns MIR that
+                // already has UB into MIR that fails this check is not necessarily wrong. However,
+                // we have no such optimizations at the moment, and so we include this check anyway
+                // to help us catch bugs. If you happen to write an optimization that might cause
+                // this to incorrectly fire, feel free to remove this check.
+                if self.reachable_blocks.contains(location.block) {
+                    self.storage_liveness.seek_before_primary_effect(location);
+                    let locals_with_storage = self.storage_liveness.get();
+                    if locals_with_storage.contains(*local) {
+                        self.fail(
+                            location,
+                            format!("StorageLive({local:?}) which already has storage here"),
+                        );
+                    }
+                }
+            }
+            StatementKind::StorageDead(_)
             | StatementKind::Coverage(_)
             | StatementKind::ConstEvalCounter
             | StatementKind::Nop => {}
diff --git a/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
index 2eba1e11466..a78bf927ca1 100644
--- a/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
+++ b/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
@@ -1,7 +1,7 @@
-use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{InitKind, LayoutCx, LayoutError, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
 use rustc_session::Limit;
-use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
+use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
 
 use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
 use crate::interpret::{InterpCx, MemoryKind, OpTy};
@@ -20,8 +20,8 @@ use crate::interpret::{InterpCx, MemoryKind, OpTy};
 /// to the full uninit check).
 pub fn might_permit_raw_init<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
     kind: InitKind,
+    param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
 ) -> Result<bool, LayoutError<'tcx>> {
     if tcx.sess.opts.unstable_opts.strict_init_checks {
         might_permit_raw_init_strict(tcx.layout_of(param_env_and_ty)?, tcx, kind)
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index decbb6519ba..29cb2c0a33e 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@ edition = "2021"
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "1.2.1"
 cfg-if = "1.0"
-ena = "0.14"
+ena = "0.14.1"
 indexmap = { version = "1.9.1" }
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
 libc = "0.2"
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 54bcb154da2..464ddae476a 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -485,7 +485,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
     let normalised =
         if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") };
     match registry.try_find_description(&normalised) {
-        Ok(Some(description)) => {
+        Ok(description) => {
             let mut is_in_code_block = false;
             let mut text = String::new();
             // Slice off the leading newline and print.
@@ -509,9 +509,6 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
                 print!("{text}");
             }
         }
-        Ok(None) => {
-            early_error(output, &format!("no extended information for {code}"));
-        }
         Err(InvalidErrorCode) => {
             early_error(output, &format!("{code} is not a valid error code"));
         }
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 800f3c52177..df857be85ad 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -253,6 +253,7 @@ E0466: include_str!("./error_codes/E0466.md"),
 E0468: include_str!("./error_codes/E0468.md"),
 E0469: include_str!("./error_codes/E0469.md"),
 E0472: include_str!("./error_codes/E0472.md"),
+E0476: include_str!("./error_codes/E0476.md"),
 E0477: include_str!("./error_codes/E0477.md"),
 E0478: include_str!("./error_codes/E0478.md"),
 E0482: include_str!("./error_codes/E0482.md"),
@@ -512,7 +513,9 @@ E0790: include_str!("./error_codes/E0790.md"),
 E0791: include_str!("./error_codes/E0791.md"),
 E0792: include_str!("./error_codes/E0792.md"),
 E0793: include_str!("./error_codes/E0793.md"),
-;
+}
+
+// Undocumented removed error codes. Note that many removed error codes are documented.
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
 //  E0019, // merged into E0015
@@ -569,7 +572,7 @@ E0793: include_str!("./error_codes/E0793.md"),
 //  E0246, // invalid recursive type
 //  E0247,
 //  E0248, // value used as a type, now reported earlier during resolution
-           // as E0412
+//         // as E0412
 //  E0249,
 //  E0257,
 //  E0258,
@@ -611,7 +614,6 @@ E0793: include_str!("./error_codes/E0793.md"),
 //  E0473, // dereference of reference outside its lifetime
 //  E0474, // captured variable `..` does not outlive the enclosing closure
 //  E0475, // index of slice outside its lifetime
-    E0476, // lifetime of the source pointer does not outlive lifetime bound...
 //  E0479, // the type `..` (provided as the value of a type parameter) is...
 //  E0480, // lifetime of method receiver does not outlive the method call
 //  E0481, // lifetime of function argument does not outlive the function call
@@ -631,14 +633,14 @@ E0793: include_str!("./error_codes/E0793.md"),
 //  E0558, // replaced with a generic attribute input check
 //  E0563, // cannot determine a type for this `impl Trait` removed in 6383de15
 //  E0564, // only named lifetimes are allowed in `impl Trait`,
-           // but `{}` was found in the type `{}`
+//         // but `{}` was found in the type `{}`
 //  E0598, // lifetime of {} is too short to guarantee its contents can be...
 //  E0611, // merged into E0616
 //  E0612, // merged into E0609
 //  E0613, // Removed (merged with E0609)
 //  E0629, // missing 'feature' (rustc_const_unstable)
 //  E0630, // rustc_const_unstable attribute must be paired with stable/unstable
-           // attribute
+//         // attribute
 //  E0645, // trait aliases not finished
 //  E0694, // an unknown tool name found in scoped attributes
 //  E0702, // replaced with a generic attribute input check
@@ -647,4 +649,3 @@ E0793: include_str!("./error_codes/E0793.md"),
 //  E0721, // `await` keyword
 //  E0723, // unstable feature in `const` context
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
-}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0476.md b/compiler/rustc_error_codes/src/error_codes/E0476.md
new file mode 100644
index 00000000000..fc141ba77f5
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0476.md
@@ -0,0 +1,21 @@
+The coerced type does not outlive the value being coerced to.
+
+Example of erroneous code:
+
+```compile_fail,E0476
+#![feature(coerce_unsized)]
+#![feature(unsize)]
+
+use std::marker::Unsize;
+use std::ops::CoerceUnsized;
+
+// error: lifetime of the source pointer does not outlive lifetime bound of the
+//        object type
+impl<'a, 'b, T, S> CoerceUnsized<&'a T> for &'b S where S: Unsize<T> {}
+```
+
+During a coercion, the "source pointer" (the coerced type) did not outlive the
+"object type" (value being coerced to). In the above example, `'b` is not a
+subtype of `'a`. This error can currently only be encountered with the unstable
+`CoerceUnsized` trait which allows custom coercions of unsized types behind a
+smart pointer to be implemented.
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index bd424dd9d06..d6b120e4dfc 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -5,10 +5,9 @@
 //! the goal being to make their maintenance easier.
 
 macro_rules! register_diagnostics {
-    ($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => (
-        pub static DIAGNOSTICS: &[(&str, Option<&str>)] = &[
-            $( (stringify!($ecode), Some($message)), )*
-            $( (stringify!($code), None), )*
+    ($($ecode:ident: $message:expr,)*) => (
+        pub static DIAGNOSTICS: &[(&str, &str)] = &[
+            $( (stringify!($ecode), $message), )*
         ];
     )
 }
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 40ed10e7165..010e5f060bf 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -135,7 +135,10 @@ pub fn fluent_bundle(
 
     let fallback_locale = langid!("en-US");
     let requested_fallback_locale = requested_locale.as_ref() == Some(&fallback_locale);
-
+    trace!(?requested_fallback_locale);
+    if requested_fallback_locale && additional_ftl_path.is_none() {
+        return Ok(None);
+    }
     // If there is only `-Z additional-ftl-path`, assume locale is "en-US", otherwise use user
     // provided locale.
     let locale = requested_locale.clone().unwrap_or(fallback_locale);
@@ -153,7 +156,7 @@ pub fn fluent_bundle(
     bundle.set_use_isolating(with_directionality_markers);
 
     // If the user requests the default locale then don't try to load anything.
-    if !requested_fallback_locale && let Some(requested_locale) = requested_locale {
+    if let Some(requested_locale) = requested_locale {
         let mut found_resources = false;
         for sysroot in user_provided_sysroot.iter_mut().chain(sysroot_candidates.iter_mut()) {
             sysroot.push("share");
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index d4ddd0c53bf..e82bad67b21 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -54,6 +54,7 @@ macro_rules! into_diagnostic_arg_using_display {
 }
 
 into_diagnostic_arg_using_display!(
+    ast::ParamKindOrd,
     i8,
     u8,
     i16,
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index e475fc725c3..f32d6b96b9b 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -580,7 +580,7 @@ impl DiagnosticCode {
             let je_result =
                 je.registry.as_ref().map(|registry| registry.try_find_description(&s)).unwrap();
 
-            DiagnosticCode { code: s, explanation: je_result.unwrap_or(None) }
+            DiagnosticCode { code: s, explanation: je_result.ok() }
         })
     }
 }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index edec8cce92f..cbf595089cc 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -42,7 +42,7 @@ pub use rustc_error_messages::{
 pub use rustc_lint_defs::{pluralize, Applicability};
 use rustc_macros::fluent_messages;
 use rustc_span::source_map::SourceMap;
-use rustc_span::HashStableContext;
+pub use rustc_span::ErrorGuaranteed;
 use rustc_span::{Loc, Span};
 
 use std::borrow::Cow;
@@ -1477,9 +1477,7 @@ impl HandlerInner {
                 .emitted_diagnostic_codes
                 .iter()
                 .filter_map(|x| match &x {
-                    DiagnosticId::Error(s)
-                        if registry.try_find_description(s).map_or(false, |o| o.is_some()) =>
-                    {
+                    DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => {
                         Some(s.clone())
                     }
                     _ => None,
@@ -1846,17 +1844,3 @@ pub enum TerminalUrl {
     Yes,
     Auto,
 }
-
-/// Useful type to use with `Result<>` indicate that an error has already
-/// been reported to the user, so no need to continue checking.
-#[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)]
-#[derive(HashStable_Generic)]
-pub struct ErrorGuaranteed(());
-
-impl ErrorGuaranteed {
-    /// To be used only if you really know what you are doing... ideally, we would find a way to
-    /// eliminate all calls to this method.
-    pub fn unchecked_claim_error_was_emitted() -> Self {
-        ErrorGuaranteed(())
-    }
-}
diff --git a/compiler/rustc_errors/src/registry.rs b/compiler/rustc_errors/src/registry.rs
index da764d993bb..f26d8e7ebdc 100644
--- a/compiler/rustc_errors/src/registry.rs
+++ b/compiler/rustc_errors/src/registry.rs
@@ -5,21 +5,17 @@ pub struct InvalidErrorCode;
 
 #[derive(Clone)]
 pub struct Registry {
-    long_descriptions: FxHashMap<&'static str, Option<&'static str>>,
+    long_descriptions: FxHashMap<&'static str, &'static str>,
 }
 
 impl Registry {
-    pub fn new(long_descriptions: &[(&'static str, Option<&'static str>)]) -> Registry {
+    pub fn new(long_descriptions: &[(&'static str, &'static str)]) -> Registry {
         Registry { long_descriptions: long_descriptions.iter().copied().collect() }
     }
 
     /// Returns `InvalidErrorCode` if the code requested does not exist in the
-    /// registry. Otherwise, returns an `Option` where `None` means the error
-    /// code is valid but has no extended information.
-    pub fn try_find_description(
-        &self,
-        code: &str,
-    ) -> Result<Option<&'static str>, InvalidErrorCode> {
+    /// registry.
+    pub fn try_find_description(&self, code: &str) -> Result<&'static str, InvalidErrorCode> {
         self.long_descriptions.get(code).copied().ok_or(InvalidErrorCode)
     }
 }
diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs
index 1ac9b8e03c7..ed35eb1b6c4 100644
--- a/compiler/rustc_errors/src/translation.rs
+++ b/compiler/rustc_errors/src/translation.rs
@@ -1,4 +1,4 @@
-use crate::error::TranslateError;
+use crate::error::{TranslateError, TranslateErrorKind};
 use crate::snippet::Style;
 use crate::{DiagnosticArg, DiagnosticMessage, FluentBundle};
 use rustc_data_structures::sync::Lrc;
@@ -95,6 +95,16 @@ pub trait Translate {
                 // The primary bundle was present and translation succeeded
                 Some(Ok(t)) => t,
 
+                // If `translate_with_bundle` returns `Err` with the primary bundle, this is likely
+                // just that the primary bundle doesn't contain the message being translated, so
+                // proceed to the fallback bundle.
+                Some(Err(
+                    primary @ TranslateError::One {
+                        kind: TranslateErrorKind::MessageMissing, ..
+                    },
+                )) => translate_with_bundle(self.fallback_fluent_bundle())
+                    .map_err(|fallback| primary.and(fallback))?,
+
                 // Always yeet out for errors on debug (unless
                 // `RUSTC_TRANSLATION_NO_DEBUG_ASSERT` is set in the environment - this allows
                 // local runs of the test suites, of builds with debug assertions, to test the
@@ -106,9 +116,8 @@ pub trait Translate {
                     do yeet primary
                 }
 
-                // If `translate_with_bundle` returns `Err` with the primary bundle, this is likely
-                // just that the primary bundle doesn't contain the message being translated or
-                // something else went wrong) so proceed to the fallback bundle.
+                // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so
+                // just hide it and try with the fallback bundle.
                 Some(Err(primary)) => translate_with_bundle(self.fallback_fluent_bundle())
                     .map_err(|fallback| primary.and(fallback))?,
 
diff --git a/compiler/rustc_expand/locales/en-US.ftl b/compiler/rustc_expand/locales/en-US.ftl
index dbd80954382..b475d285f6b 100644
--- a/compiler/rustc_expand/locales/en-US.ftl
+++ b/compiler/rustc_expand/locales/en-US.ftl
@@ -129,3 +129,7 @@ expand_module_multiple_candidates =
     .help = delete or rename one of them to remove the ambiguity
 
 expand_trace_macro = trace_macro
+
+expand_proc_macro_panicked =
+    proc macro panicked
+    .help = message: {$message}
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index d9b2b5f4802..70ab222b484 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -375,3 +375,18 @@ pub struct TraceMacro {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(expand_proc_macro_panicked)]
+pub(crate) struct ProcMacroPanicked {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub message: Option<ProcMacroPanickedHelp>,
+}
+
+#[derive(Subdiagnostic)]
+#[help(expand_help)]
+pub(crate) struct ProcMacroPanickedHelp {
+    pub message: String,
+}
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index e9a69192068..cef64a10479 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -1,4 +1,5 @@
 use crate::base::{self, *};
+use crate::errors;
 use crate::proc_macro_server;
 
 use rustc_ast as ast;
@@ -60,11 +61,12 @@ impl base::BangProcMacro for BangProcMacro {
         let strategy = exec_strategy(ecx);
         let server = proc_macro_server::Rustc::new(ecx);
         self.client.run(&strategy, server, input, proc_macro_backtrace).map_err(|e| {
-            let mut err = ecx.struct_span_err(span, "proc macro panicked");
-            if let Some(s) = e.as_str() {
-                err.help(&format!("message: {}", s));
-            }
-            err.emit()
+            ecx.sess.emit_err(errors::ProcMacroPanicked {
+                span,
+                message: e
+                    .as_str()
+                    .map(|message| errors::ProcMacroPanickedHelp { message: message.into() }),
+            })
         })
     }
 }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index e064e87a59a..761f1ebdbac 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -90,6 +90,8 @@ declare_features! (
     (accepted, clone_closures, "1.26.0", Some(44490), None),
     /// Allows coercing non capturing closures to function pointers.
     (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None),
+    /// Allows using `cmpxchg16b` from `core::arch::x86_64`.
+    (accepted, cmpxchg16b_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None),
     /// Allows usage of the `compile_error!` macro.
     (accepted, compile_error, "1.20.0", Some(40872), None),
     /// Allows `impl Trait` in function return types.
@@ -312,6 +314,8 @@ declare_features! (
     (accepted, struct_variant, "1.0.0", None, None),
     /// Allows `#[target_feature(...)]`.
     (accepted, target_feature, "1.27.0", None, None),
+    /// Allows the use of `#[target_feature]` on safe functions.
+    (accepted, target_feature_11, "CURRENT_RUSTC_VERSION", Some(69098), None),
     /// Allows `fn main()` with return types which implements `Termination` (RFC 1937).
     (accepted, termination_trait, "1.26.0", Some(43301), None),
     /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937).
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 6d8f7e4a0f6..300348d78ed 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -256,7 +256,6 @@ declare_features! (
     (active, arm_target_feature, "1.27.0", Some(44839), None),
     (active, avx512_target_feature, "1.27.0", Some(44839), None),
     (active, bpf_target_feature, "1.54.0", Some(44839), None),
-    (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None),
     (active, ermsb_target_feature, "1.49.0", Some(44839), None),
     (active, hexagon_target_feature, "1.27.0", Some(44839), None),
     (active, mips_target_feature, "1.27.0", Some(44839), None),
@@ -513,8 +512,6 @@ declare_features! (
     (active, strict_provenance, "1.61.0", Some(95228), None),
     /// Allows string patterns to dereference values to match them.
     (active, string_deref_patterns, "1.67.0", Some(87121), None),
-    /// Allows the use of `#[target_feature]` on safe functions.
-    (active, target_feature_11, "1.45.0", Some(69098), None),
     /// Allows using `#[thread_local]` on `static` items.
     (active, thread_local, "1.0.0", Some(29594), None),
     /// Allows defining `trait X = A + B;` alias items.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 3f52f174cdf..72e9f7c1343 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -369,10 +369,10 @@ impl<'hir> GenericArgs<'hir> {
 
     pub fn has_err(&self) -> bool {
         self.args.iter().any(|arg| match arg {
-            GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err),
+            GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err(_)),
             _ => false,
         }) || self.bindings.iter().any(|arg| match arg.kind {
-            TypeBindingKind::Equality { term: Term::Ty(ty) } => matches!(ty.kind, TyKind::Err),
+            TypeBindingKind::Equality { term: Term::Ty(ty) } => matches!(ty.kind, TyKind::Err(_)),
             _ => false,
         })
     }
@@ -1688,7 +1688,7 @@ impl Expr<'_> {
             ExprKind::Struct(..) => ExprPrecedence::Struct,
             ExprKind::Repeat(..) => ExprPrecedence::Repeat,
             ExprKind::Yield(..) => ExprPrecedence::Yield,
-            ExprKind::Err => ExprPrecedence::Err,
+            ExprKind::Err(_) => ExprPrecedence::Err,
         }
     }
 
@@ -1754,7 +1754,7 @@ impl Expr<'_> {
             | ExprKind::Yield(..)
             | ExprKind::Cast(..)
             | ExprKind::DropTemps(..)
-            | ExprKind::Err => false,
+            | ExprKind::Err(_) => false,
         }
     }
 
@@ -1840,7 +1840,7 @@ impl Expr<'_> {
             | ExprKind::Binary(..)
             | ExprKind::Yield(..)
             | ExprKind::DropTemps(..)
-            | ExprKind::Err => true,
+            | ExprKind::Err(_) => true,
         }
     }
 
@@ -2013,7 +2013,7 @@ pub enum ExprKind<'hir> {
     Yield(&'hir Expr<'hir>, YieldSource),
 
     /// A placeholder for an expression that wasn't syntactically well formed in some way.
-    Err,
+    Err(rustc_span::ErrorGuaranteed),
 }
 
 /// Represents an optionally `Self`-qualified value/type path or associated extension.
@@ -2676,7 +2676,7 @@ pub enum TyKind<'hir> {
     /// specified. This can appear anywhere in a type.
     Infer,
     /// Placeholder for a type that has failed to be defined.
-    Err,
+    Err(rustc_span::ErrorGuaranteed),
 }
 
 #[derive(Debug, HashStable_Generic)]
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index f632babab0b..cc0f64017e4 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -790,7 +790,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         ExprKind::Yield(ref subexpression, _) => {
             visitor.visit_expr(subexpression);
         }
-        ExprKind::Lit(_) | ExprKind::Err => {}
+        ExprKind::Lit(_) | ExprKind::Err(_) => {}
     }
 }
 
@@ -844,7 +844,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
             visitor.visit_lifetime(lifetime);
         }
         TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
-        TyKind::Infer | TyKind::Err => {}
+        TyKind::Infer | TyKind::Err(_) => {}
     }
 }
 
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 04546330915..60fa5a99e10 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -302,8 +302,6 @@ language_item_table! {
     Context,                 sym::Context,             context,                    Target::Struct,         GenericRequirement::None;
     FuturePoll,              sym::poll,                future_poll_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
 
-    FromFrom,                sym::from,                from_fn,                    Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
-
     OptionSome,              sym::Some,                option_some_variant,        Target::Variant,        GenericRequirement::None;
     OptionNone,              sym::None,                option_none_variant,        Target::Variant,        GenericRequirement::None;
 
diff --git a/compiler/rustc_hir_analysis/locales/en-US.ftl b/compiler/rustc_hir_analysis/locales/en-US.ftl
index aa56e60ec75..40b5bc2a32e 100644
--- a/compiler/rustc_hir_analysis/locales/en-US.ftl
+++ b/compiler/rustc_hir_analysis/locales/en-US.ftl
@@ -62,14 +62,6 @@ hir_analysis_manual_implementation =
 
 hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
 
-hir_analysis_unused_extern_crate =
-    unused extern crate
-    .suggestion = remove it
-
-hir_analysis_extern_crate_not_idiomatic =
-    `extern crate` is not idiomatic in the new edition
-    .suggestion = convert it to a `{$msg_code}`
-
 hir_analysis_trait_object_declared_with_no_traits =
     at least one trait is required for an object type
     .alias_span = this alias does not contain a trait
@@ -127,5 +119,31 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh
     .label = deref recursion limit reached
     .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
 
+hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause
+    .label = `main` cannot have a `where` clause
+
 hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]`
-    .label = `main` function is not allowed to be `#[track_caller]`
+    .suggestion = remove this annotation
+
+hir_analysis_start_not_track_caller = `start` is not allowed to be `#[track_caller]`
+    .label = `start` is not allowed to be `#[track_caller]`
+
+hir_analysis_start_not_async = `start` is not allowed to be `async`
+    .label = `start` is not allowed to be `async`
+
+hir_analysis_start_function_where = start function is not allowed to have a `where` clause
+    .label = start function cannot have a `where` clause
+
+hir_analysis_start_function_parameters = start function is not allowed to have type parameters
+    .label = start function cannot have type parameters
+
+hir_analysis_main_function_return_type_generic = `main` function return type is not allowed to have generic parameters
+
+hir_analysis_main_function_async = `main` function is not allowed to be `async`
+    .label = `main` function is not allowed to be `async`
+
+hir_analysis_main_function_generic_parameters = `main` function is not allowed to have generic parameters
+    .label = `main` cannot have generic parameters
+
+hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions}
+    .label = C-variadic function must have a compatible calling convention
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index 499b51eef72..c49e4d9d581 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -377,7 +377,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     // `<Foo as Iterator>::Item = String`.
                     let projection_ty = pred.skip_binder().projection_ty;
 
-                    let substs_with_infer_self = tcx.mk_substs(
+                    let substs_with_infer_self = tcx.mk_substs_from_iter(
                         std::iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
                             .chain(projection_ty.substs.iter().skip(1)),
                     );
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index 630becc09d2..7f6518ffd71 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -370,7 +370,7 @@ pub fn create_substs_for_generic_args<'tcx, 'a>(
         }
     }
 
-    tcx.intern_substs(&substs)
+    tcx.mk_substs(&substs)
 }
 
 /// Checks that the correct number of generic arguments have been provided.
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 274b264ee10..a15cf454df7 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -381,7 +381,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // here and so associated type bindings will be handled regardless of whether there are any
         // non-`Self` generic parameters.
         if generics.params.is_empty() {
-            return (tcx.intern_substs(parent_substs), arg_count);
+            return (tcx.mk_substs(parent_substs), arg_count);
         }
 
         struct SubstsForAstPathCtxt<'a, 'tcx> {
@@ -429,7 +429,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }
                     if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) {
                         self.inferred_params.push(ty.span);
-                        tcx.ty_error().into()
+                        tcx.ty_error_misc().into()
                     } else {
                         self.astconv.ast_ty_to_ty(ty).into()
                     }
@@ -502,14 +502,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                 _ => false,
                             }) {
                                 // Avoid ICE #86756 when type error recovery goes awry.
-                                return tcx.ty_error().into();
+                                return tcx.ty_error_misc().into();
                             }
                             tcx.at(self.span).type_of(param.def_id).subst(tcx, substs).into()
                         } else if infer_args {
                             self.astconv.ty_infer(Some(param), self.span).into()
                         } else {
                             // We've already errored above about the mismatch.
-                            tcx.ty_error().into()
+                            tcx.ty_error_misc().into()
                         }
                     }
                     GenericParamDefKind::Const { has_default } => {
@@ -518,8 +518,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             .type_of(param.def_id)
                             .no_bound_vars()
                             .expect("const parameter types cannot be generic");
-                        if ty.references_error() {
-                            return tcx.const_error(ty).into();
+                        if let Err(guar) = ty.error_reported() {
+                            return tcx.const_error_with_guaranteed(ty, guar).into();
                         }
                         if !infer_args && has_default {
                             tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
@@ -1239,9 +1239,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         }
                         let reported = err.emit();
                         term = match def_kind {
-                            hir::def::DefKind::AssocTy => {
-                                tcx.ty_error_with_guaranteed(reported).into()
-                            }
+                            hir::def::DefKind::AssocTy => tcx.ty_error(reported).into(),
                             hir::def::DefKind::AssocConst => tcx
                                 .const_error_with_guaranteed(
                                     tcx.type_of(assoc_item_def_id)
@@ -1397,7 +1395,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 .map(|trait_ref| tcx.def_span(trait_ref));
             let reported =
                 tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
-            return tcx.ty_error_with_guaranteed(reported);
+            return tcx.ty_error(reported);
         }
 
         // Check that there are no gross object safety violations;
@@ -1414,7 +1412,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     &object_safety_violations,
                 )
                 .emit();
-                return tcx.ty_error_with_guaranteed(reported);
+                return tcx.ty_error(reported);
             }
         }
 
@@ -1523,15 +1521,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         if arg == dummy_self.into() {
                             let param = &generics.params[index];
                             missing_type_params.push(param.name);
-                            return tcx.ty_error().into();
+                            return tcx.ty_error_misc().into();
                         } else if arg.walk().any(|arg| arg == dummy_self.into()) {
                             references_self = true;
-                            return tcx.ty_error().into();
+                            return tcx.ty_error_misc().into();
                         }
                         arg
                     })
                     .collect();
-                let substs = tcx.intern_substs(&substs[..]);
+                let substs = tcx.mk_substs(&substs);
 
                 let span = i.bottom().1;
                 let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
@@ -1579,7 +1577,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     false
                 });
                 if references_self {
-                    tcx.sess
+                    let guar = tcx
+                        .sess
                         .delay_span_bug(span, "trait object projection bounds reference `Self`");
                     let substs: Vec<_> = b
                         .projection_ty
@@ -1587,12 +1586,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         .iter()
                         .map(|arg| {
                             if arg.walk().any(|arg| arg == dummy_self.into()) {
-                                return tcx.ty_error().into();
+                                return tcx.ty_error(guar).into();
                             }
                             arg
                         })
                         .collect();
-                    b.projection_ty.substs = tcx.intern_substs(&substs[..]);
+                    b.projection_ty.substs = tcx.mk_substs(&substs);
                 }
 
                 ty::ExistentialProjection::erase_self_ty(tcx, b)
@@ -1614,7 +1613,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
         v.dedup();
-        let existential_predicates = tcx.intern_poly_existential_predicates(&v);
+        let existential_predicates = tcx.mk_poly_existential_predicates(&v);
 
         // Use explicitly-specified region bound.
         let region_bound = if !lifetime.is_elided() {
@@ -2473,7 +2472,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 &[path_str],
                 item_segment.ident.name,
             );
-            return tcx.ty_error_with_guaranteed(reported)
+            return tcx.ty_error(reported)
         };
 
         debug!("qpath_to_ty: self_type={:?}", self_ty);
@@ -2811,7 +2810,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             var: ty::BoundVar::from_u32(index),
                             kind: ty::BoundTyKind::Param(def_id, name),
                         };
-                        tcx.mk_ty(ty::Bound(debruijn, br))
+                        tcx.mk_bound(debruijn, br)
                     }
                     Some(rbv::ResolvedArg::EarlyBound(_)) => {
                         let def_id = def_id.expect_local();
@@ -2820,7 +2819,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         let index = generics.param_def_id_to_index[&def_id.to_def_id()];
                         tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
                     }
-                    Some(rbv::ResolvedArg::Error(guar)) => tcx.ty_error_with_guaranteed(guar),
+                    Some(rbv::ResolvedArg::Error(guar)) => tcx.ty_error(guar),
                     arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
                 }
             }
@@ -2932,7 +2931,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     {
                         err.span_note(impl_.self_ty.span, "not a concrete type");
                     }
-                    tcx.ty_error_with_guaranteed(err.emit())
+                    tcx.ty_error(err.emit())
                 } else {
                     ty
                 }
@@ -2985,7 +2984,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     .sess
                     .delay_span_bug(path.span, "path with `Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
-                self.tcx().ty_error_with_guaranteed(e)
+                self.tcx().ty_error(e)
             }
             _ => span_bug!(span, "unexpected resolution: {:?}", path.res),
         }
@@ -3021,7 +3020,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
             }
             hir::TyKind::Never => tcx.types.never,
-            hir::TyKind::Tup(fields) => tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(t))),
+            hir::TyKind::Tup(fields) => {
+                tcx.mk_tup_from_iter(fields.iter().map(|t| self.ast_ty_to_ty(t)))
+            }
             hir::TyKind::BareFn(bf) => {
                 require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
 
@@ -3064,7 +3065,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let ty = self.ast_ty_to_ty_inner(qself, false, true);
                 self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
                     .map(|(ty, _, _)| ty)
-                    .unwrap_or_else(|_| tcx.ty_error())
+                    .unwrap_or_else(|guar| tcx.ty_error(guar))
             }
             &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
                 let def_id = tcx.require_lang_item(lang_item, Some(span));
@@ -3112,7 +3113,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // handled specially and will not descend into this routine.
                 self.ty_infer(None, ast_ty.span)
             }
-            hir::TyKind::Err => tcx.ty_error(),
+            hir::TyKind::Err(guar) => tcx.ty_error(*guar),
         };
 
         self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 50005582f7c..b0dc6b1dcac 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -196,7 +196,7 @@ fn compare_method_predicate_entailment<'tcx>(
     // the new hybrid bounds we computed.
     let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
     let param_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&hybrid_preds.predicates),
+        tcx.mk_predicates(&hybrid_preds.predicates),
         Reveal::UserFacing,
         hir::Constness::NotConst,
     );
@@ -648,6 +648,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
             tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
         )
         .fold_with(&mut collector);
+
+    debug_assert_ne!(
+        collector.types.len(),
+        0,
+        "expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`"
+    );
+
     let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
     trait_sig.error_reported()?;
     let trait_return_ty = trait_sig.output();
@@ -790,7 +797,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
                     return_span,
                     format!("could not fully resolve: {ty} => {err:?}"),
                 );
-                collected_tys.insert(def_id, tcx.ty_error_with_guaranteed(reported));
+                collected_tys.insert(def_id, tcx.ty_error(reported));
             }
         }
     }
@@ -1795,7 +1802,7 @@ fn compare_type_predicate_entailment<'tcx>(
     let impl_ty_span = tcx.def_span(impl_ty_def_id);
     let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id);
     let param_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&hybrid_preds.predicates),
+        tcx.mk_predicates(&hybrid_preds.predicates),
         Reveal::UserFacing,
         hir::Constness::NotConst,
     );
@@ -1937,8 +1944,8 @@ pub(super) fn check_type_bounds<'tcx>(
             .into()
         }
     });
-    let bound_vars = tcx.intern_bound_variable_kinds(&bound_vars);
-    let impl_ty_substs = tcx.intern_substs(&substs);
+    let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
+    let impl_ty_substs = tcx.mk_substs(&substs);
     let container_id = impl_ty.container_id(tcx);
 
     let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
@@ -1978,11 +1985,7 @@ pub(super) fn check_type_bounds<'tcx>(
                 .to_predicate(tcx),
             ),
         };
-        ty::ParamEnv::new(
-            tcx.intern_predicates(&predicates),
-            Reveal::UserFacing,
-            param_env.constness(),
-        )
+        ty::ParamEnv::new(tcx.mk_predicates(&predicates), Reveal::UserFacing, param_env.constness())
     };
     debug!(?normalize_param_env);
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 4720fea8ef4..054284cced5 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -137,7 +137,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     let intrinsic_name = tcx.item_name(intrinsic_id);
     let name_str = intrinsic_name.as_str();
 
-    let bound_vars = tcx.intern_bound_variable_kinds(&[
+    let bound_vars = tcx.mk_bound_variable_kinds(&[
         ty::BoundVariableKind::Region(ty::BrAnon(0, None)),
         ty::BoundVariableKind::Region(ty::BrEnv),
     ]);
@@ -165,7 +165,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             "cxchg" | "cxchgweak" => (
                 1,
                 vec![tcx.mk_mut_ptr(param(0)), param(0), param(0)],
-                tcx.intern_tup(&[param(0), tcx.types.bool]),
+                tcx.mk_tup(&[param(0), tcx.types.bool]),
             ),
             "load" => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)),
             "store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
@@ -317,7 +317,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             | sym::bitreverse => (1, vec![param(0)], param(0)),
 
             sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
-                (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
+                (1, vec![param(0), param(0)], tcx.mk_tup(&[param(0), tcx.types.bool]))
             }
 
             sym::ptr_guaranteed_cmp => {
@@ -372,7 +372,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 (
                     1,
                     vec![tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0))],
-                    tcx.mk_projection(discriminant_def_id, tcx.intern_substs(&[param(0).into()])),
+                    tcx.mk_projection(discriminant_def_id, tcx.mk_substs(&[param(0).into()])),
                 )
             }
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 25be62534a5..4cccdf30c5f 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -493,8 +493,9 @@ fn augment_param_env<'tcx>(
         return param_env;
     }
 
-    let bounds =
-        tcx.mk_predicates(param_env.caller_bounds().iter().chain(new_predicates.iter().cloned()));
+    let bounds = tcx.mk_predicates_from_iter(
+        param_env.caller_bounds().iter().chain(new_predicates.iter().cloned()),
+    );
     // FIXME(compiler-errors): Perhaps there is a case where we need to normalize this
     // i.e. traits::normalize_param_env_or_error
     ty::ParamEnv::new(bounds, param_env.reveal(), param_env.constness())
@@ -1476,7 +1477,7 @@ fn check_fn_or_method<'tcx>(
         |idx| hir_decl.inputs.get(idx).map_or(hir_decl.output.span(), |arg: &hir::Ty<'_>| arg.span);
 
     sig.inputs_and_output =
-        tcx.mk_type_list(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| {
+        tcx.mk_type_list_from_iter(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| {
             wfcx.normalize(
                 arg_span(idx),
                 Some(WellFormedLoc::Param {
diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 5716be4f1a9..f3f5851d8f9 100644
--- a/compiler/rustc_hir_analysis/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -1,12 +1,8 @@
-use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate};
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unord::UnordSet;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint;
-use rustc_span::{Span, Symbol};
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let mut used_trait_imports: UnordSet<LocalDefId> = Default::default();
@@ -43,131 +39,4 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
             |lint| lint,
         );
     }
-
-    unused_crates_lint(tcx);
-}
-
-fn unused_crates_lint(tcx: TyCtxt<'_>) {
-    let lint = lint::builtin::UNUSED_EXTERN_CRATES;
-
-    // Collect first the crates that are completely unused. These we
-    // can always suggest removing (no matter which edition we are
-    // in).
-    let unused_extern_crates: FxHashMap<LocalDefId, Span> = tcx
-        .maybe_unused_extern_crates(())
-        .iter()
-        .filter(|&&(def_id, _)| {
-            tcx.extern_mod_stmt_cnum(def_id).map_or(true, |cnum| {
-                !tcx.is_compiler_builtins(cnum)
-                    && !tcx.is_panic_runtime(cnum)
-                    && !tcx.has_global_allocator(cnum)
-                    && !tcx.has_panic_handler(cnum)
-            })
-        })
-        .cloned()
-        .collect();
-
-    // Collect all the extern crates (in a reliable order).
-    let mut crates_to_lint = vec![];
-
-    for id in tcx.hir().items() {
-        if matches!(tcx.def_kind(id.owner_id), DefKind::ExternCrate) {
-            let item = tcx.hir().item(id);
-            if let hir::ItemKind::ExternCrate(orig_name) = item.kind {
-                crates_to_lint.push(ExternCrateToLint {
-                    def_id: item.owner_id.to_def_id(),
-                    span: item.span,
-                    orig_name,
-                    warn_if_unused: !item.ident.as_str().starts_with('_'),
-                });
-            }
-        }
-    }
-
-    let extern_prelude = &tcx.resolutions(()).extern_prelude;
-
-    for extern_crate in &crates_to_lint {
-        let def_id = extern_crate.def_id.expect_local();
-        let item = tcx.hir().expect_item(def_id);
-
-        // If the crate is fully unused, we suggest removing it altogether.
-        // We do this in any edition.
-        if extern_crate.warn_if_unused {
-            if let Some(&span) = unused_extern_crates.get(&def_id) {
-                // Removal suggestion span needs to include attributes (Issue #54400)
-                let id = tcx.hir().local_def_id_to_hir_id(def_id);
-                let span_with_attrs = tcx
-                    .hir()
-                    .attrs(id)
-                    .iter()
-                    .map(|attr| attr.span)
-                    .fold(span, |acc, attr_span| acc.to(attr_span));
-
-                tcx.emit_spanned_lint(lint, id, span, UnusedExternCrate { span: span_with_attrs });
-                continue;
-            }
-        }
-
-        // If we are not in Rust 2018 edition, then we don't make any further
-        // suggestions.
-        if !tcx.sess.rust_2018() {
-            continue;
-        }
-
-        // If the extern crate isn't in the extern prelude,
-        // there is no way it can be written as a `use`.
-        let orig_name = extern_crate.orig_name.unwrap_or(item.ident.name);
-        if !extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) {
-            continue;
-        }
-
-        // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
-        // would not insert the new name into the prelude, where other imports in the crate may be
-        // expecting it.
-        if extern_crate.orig_name.is_some() {
-            continue;
-        }
-
-        let id = tcx.hir().local_def_id_to_hir_id(def_id);
-        // If the extern crate has any attributes, they may have funky
-        // semantics we can't faithfully represent using `use` (most
-        // notably `#[macro_use]`). Ignore it.
-        if !tcx.hir().attrs(id).is_empty() {
-            continue;
-        }
-
-        let base_replacement = match extern_crate.orig_name {
-            Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name),
-            None => format!("use {};", item.ident.name),
-        };
-        let vis = tcx.sess.source_map().span_to_snippet(item.vis_span).unwrap_or_default();
-        let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) };
-        tcx.emit_spanned_lint(
-            lint,
-            id,
-            extern_crate.span,
-            ExternCrateNotIdiomatic {
-                span: extern_crate.span,
-                msg_code: add_vis("use".to_string()),
-                suggestion_code: add_vis(base_replacement),
-            },
-        );
-    }
-}
-
-struct ExternCrateToLint {
-    /// `DefId` of the extern crate
-    def_id: DefId,
-
-    /// span from the item
-    span: Span,
-
-    /// if `Some`, then this is renamed (`extern crate orig_name as
-    /// crate_name`), and -- perhaps surprisingly -- this stores the
-    /// *original* name (`item.name` will contain the new name)
-    orig_name: Option<Symbol>,
-
-    /// if `false`, the original name started with `_`, so we shouldn't lint
-    /// about it going unused (but we should still emit idiom lints).
-    warn_if_unused: bool,
 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index ed3d50bfafa..604d54cafb5 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -499,7 +499,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
                 }
                 _ => {}
             }
-            self.tcx().ty_error_with_guaranteed(err.emit())
+            self.tcx().ty_error(err.emit())
         }
     }
 
@@ -905,7 +905,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtDef<'_> {
         }
         _ => bug!(),
     };
-    tcx.alloc_adt_def(def_id.to_def_id(), kind, variants, repr)
+    tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr)
 }
 
 fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 8d479f1c3e3..9cf3ff65a91 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -103,7 +103,7 @@ pub(super) fn item_bounds(
     tcx: TyCtxt<'_>,
     def_id: DefId,
 ) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
-    let bounds = tcx.mk_predicates(
+    let bounds = tcx.mk_predicates_from_iter(
         util::elaborate_predicates(
             tcx,
             tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index c013f1bdb31..50073d94ea5 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -319,8 +319,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
                 ItemKind::Impl(hir::Impl { self_ty, .. }) => {
                     match self_ty.find_self_aliases() {
                         spans if spans.len() > 0 => {
-                            tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: (), });
-                            tcx.ty_error()
+                            let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
+                            tcx.ty_error(guar)
                         },
                         _ => icx.to_ty(*self_ty),
                     }
@@ -599,8 +599,9 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
             // // constant does not contain interior mutability.
             // ```
             let tables = self.tcx.typeck(item_def_id);
-            if let Some(_) = tables.tainted_by_errors {
-                self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
+            if let Some(guar) = tables.tainted_by_errors {
+                self.found =
+                    Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) });
                 return;
             }
             let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else {
@@ -618,8 +619,8 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
                 debug!(?concrete_type, "found constraint");
                 if let Some(prev) = &mut self.found {
                     if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
-                        prev.report_mismatch(&concrete_type, self.tcx);
-                        prev.ty = self.tcx.ty_error();
+                        let guar = prev.report_mismatch(&concrete_type, self.tcx);
+                        prev.ty = self.tcx.ty_error(guar);
                     }
                 } else {
                     self.found = Some(concrete_type);
@@ -706,7 +707,7 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
                 _ => "item",
             },
         });
-        return tcx.ty_error_with_guaranteed(reported);
+        return tcx.ty_error(reported);
     };
 
     // Only check against typeck if we didn't already error
@@ -814,11 +815,11 @@ fn find_opaque_ty_constraints_for_rpit(
 
     concrete.map(|concrete| concrete.ty).unwrap_or_else(|| {
         let table = tcx.typeck(owner_def_id);
-        if let Some(_) = table.tainted_by_errors {
+        if let Some(guar) = table.tainted_by_errors {
             // Some error in the
             // owner fn prevented us from populating
             // the `concrete_opaque_types` table.
-            tcx.ty_error()
+            tcx.ty_error(guar)
         } else {
             table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| {
                 // We failed to resolve the opaque type or it
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index be3ef03192c..203e0f85cad 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -5,7 +5,7 @@ use rustc_errors::{
     error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
     MultiSpan,
 };
-use rustc_macros::{Diagnostic, LintDiagnostic};
+use rustc_macros::Diagnostic;
 use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 
@@ -247,26 +247,6 @@ pub struct SubstsOnOverriddenImpl {
     pub span: Span,
 }
 
-#[derive(LintDiagnostic)]
-#[diag(hir_analysis_unused_extern_crate)]
-pub struct UnusedExternCrate {
-    #[suggestion(applicability = "machine-applicable", code = "")]
-    pub span: Span,
-}
-
-#[derive(LintDiagnostic)]
-#[diag(hir_analysis_extern_crate_not_idiomatic)]
-pub struct ExternCrateNotIdiomatic {
-    #[suggestion(
-        style = "short",
-        applicability = "machine-applicable",
-        code = "{suggestion_code}"
-    )]
-    pub span: Span,
-    pub msg_code: String,
-    pub suggestion_code: String,
-}
-
 #[derive(Diagnostic)]
 #[diag(hir_analysis_const_impl_for_non_const_trait)]
 pub struct ConstImplForNonConstTrait {
@@ -317,10 +297,87 @@ pub struct AutoDerefReachedRecursionLimit<'a> {
 }
 
 #[derive(Diagnostic)]
+#[diag(hir_analysis_where_clause_on_main, code = "E0646")]
+pub(crate) struct WhereClauseOnMain {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub generics_span: Option<Span>,
+}
+
+#[derive(Diagnostic)]
 #[diag(hir_analysis_track_caller_on_main)]
 pub(crate) struct TrackCallerOnMain {
     #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect", code = "")]
     pub span: Span,
-    #[label]
+    #[label(hir_analysis_track_caller_on_main)]
     pub annotated: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_start_not_track_caller)]
+pub(crate) struct StartTrackCaller {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub start: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_start_not_async, code = "E0752")]
+pub(crate) struct StartAsync {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_start_function_where, code = "E0647")]
+pub(crate) struct StartFunctionWhere {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_start_function_parameters, code = "E0132")]
+pub(crate) struct StartFunctionParameters {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_main_function_return_type_generic, code = "E0131")]
+pub(crate) struct MainFunctionReturnTypeGeneric {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_main_function_async, code = "E0752")]
+pub(crate) struct MainFunctionAsync {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub asyncness: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_main_function_generic_parameters, code = "E0131")]
+pub(crate) struct MainFunctionGenericParameters {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub label_span: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_variadic_function_compatible_convention, code = "E0045")]
+pub(crate) struct VariadicFunctionCompatibleConvention<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub conventions: &'a str,
+}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index d54e569905f..33c132fd534 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -98,7 +98,7 @@ mod outlives;
 pub mod structured_errors;
 mod variance;
 
-use rustc_errors::{struct_span_err, ErrorGuaranteed};
+use rustc_errors::ErrorGuaranteed;
 use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir as hir;
 use rustc_hir::Node;
@@ -123,7 +123,6 @@ use bounds::Bounds;
 fluent_messages! { "../locales/en-US.ftl" }
 
 fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
-    const ERROR_HEAD: &str = "C-variadic function must have a compatible calling convention";
     const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
     const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
     const UNSTABLE_EXPLAIN: &str =
@@ -155,8 +154,7 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
         (true, false) => CONVENTIONS_UNSTABLE,
     };
 
-    let mut err = struct_span_err!(tcx.sess, span, E0045, "{}, like {}", ERROR_HEAD, conventions);
-    err.span_label(span, ERROR_HEAD).emit();
+    tcx.sess.emit_err(errors::VariadicFunctionCompatibleConvention { span, conventions });
 }
 
 fn require_same_types<'tcx>(
@@ -258,45 +256,25 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
     let main_fn_predicates = tcx.predicates_of(main_def_id);
     if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
         let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
-        let msg = "`main` function is not allowed to have generic \
-            parameters";
-        let mut diag =
-            struct_span_err!(tcx.sess, generics_param_span.unwrap_or(main_span), E0131, "{}", msg);
-        if let Some(generics_param_span) = generics_param_span {
-            let label = "`main` cannot have generic parameters";
-            diag.span_label(generics_param_span, label);
-        }
-        diag.emit();
+        tcx.sess.emit_err(errors::MainFunctionGenericParameters {
+            span: generics_param_span.unwrap_or(main_span),
+            label_span: generics_param_span,
+        });
         error = true;
     } else if !main_fn_predicates.predicates.is_empty() {
         // generics may bring in implicit predicates, so we skip this check if generics is present.
         let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
-        let mut diag = struct_span_err!(
-            tcx.sess,
-            generics_where_clauses_span.unwrap_or(main_span),
-            E0646,
-            "`main` function is not allowed to have a `where` clause"
-        );
-        if let Some(generics_where_clauses_span) = generics_where_clauses_span {
-            diag.span_label(generics_where_clauses_span, "`main` cannot have a `where` clause");
-        }
-        diag.emit();
+        tcx.sess.emit_err(errors::WhereClauseOnMain {
+            span: generics_where_clauses_span.unwrap_or(main_span),
+            generics_span: generics_where_clauses_span,
+        });
         error = true;
     }
 
     let main_asyncness = tcx.asyncness(main_def_id);
     if let hir::IsAsync::Async = main_asyncness {
-        let mut diag = struct_span_err!(
-            tcx.sess,
-            main_span,
-            E0752,
-            "`main` function is not allowed to be `async`"
-        );
         let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
-        if let Some(asyncness_span) = asyncness_span {
-            diag.span_label(asyncness_span, "`main` function is not allowed to be `async`");
-        }
-        diag.emit();
+        tcx.sess.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
         error = true;
     }
 
@@ -314,9 +292,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         let return_ty = main_fnsig.output();
         let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
         if !return_ty.bound_vars().is_empty() {
-            let msg = "`main` function return type is not allowed to have generic \
-                    parameters";
-            struct_span_err!(tcx.sess, return_ty_span, E0131, "{}", msg).emit();
+            tcx.sess.emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
             error = true;
         }
         let return_ty = return_ty.skip_binder();
@@ -373,56 +349,28 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                 if let hir::ItemKind::Fn(sig, generics, _) = &it.kind {
                     let mut error = false;
                     if !generics.params.is_empty() {
-                        struct_span_err!(
-                            tcx.sess,
-                            generics.span,
-                            E0132,
-                            "start function is not allowed to have type parameters"
-                        )
-                        .span_label(generics.span, "start function cannot have type parameters")
-                        .emit();
+                        tcx.sess.emit_err(errors::StartFunctionParameters { span: generics.span });
                         error = true;
                     }
                     if generics.has_where_clause_predicates {
-                        struct_span_err!(
-                            tcx.sess,
-                            generics.where_clause_span,
-                            E0647,
-                            "start function is not allowed to have a `where` clause"
-                        )
-                        .span_label(
-                            generics.where_clause_span,
-                            "start function cannot have a `where` clause",
-                        )
-                        .emit();
+                        tcx.sess.emit_err(errors::StartFunctionWhere {
+                            span: generics.where_clause_span,
+                        });
                         error = true;
                     }
                     if let hir::IsAsync::Async = sig.header.asyncness {
                         let span = tcx.def_span(it.owner_id);
-                        struct_span_err!(
-                            tcx.sess,
-                            span,
-                            E0752,
-                            "`start` is not allowed to be `async`"
-                        )
-                        .span_label(span, "`start` is not allowed to be `async`")
-                        .emit();
+                        tcx.sess.emit_err(errors::StartAsync { span: span });
                         error = true;
                     }
 
                     let attrs = tcx.hir().attrs(start_id);
                     for attr in attrs {
                         if attr.has_name(sym::track_caller) {
-                            tcx.sess
-                                .struct_span_err(
-                                    attr.span,
-                                    "`start` is not allowed to be `#[track_caller]`",
-                                )
-                                .span_label(
-                                    start_span,
-                                    "`start` is not allowed to be `#[track_caller]`",
-                                )
-                                .emit();
+                            tcx.sess.emit_err(errors::StartTrackCaller {
+                                span: attr.span,
+                                start: start_span,
+                            });
                             error = true;
                         }
                     }
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 2cb0d430ee3..cae884ae8fb 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -462,7 +462,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
 
         if self.gen_args.span_ext().is_some() {
             format!(
-                "this {} takes {}{} {} argument{} but {} {} supplied",
+                "{} takes {}{} {} argument{} but {} {} supplied",
                 def_kind,
                 quantifier,
                 bound,
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 7dcf9d8299f..c021fca7133 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -358,7 +358,7 @@ impl<'a> State<'a> {
                 self.print_anon_const(e);
                 self.word(")");
             }
-            hir::TyKind::Err => {
+            hir::TyKind::Err(_) => {
                 self.popen();
                 self.word("/*ERROR*/");
                 self.pclose();
@@ -1559,7 +1559,7 @@ impl<'a> State<'a> {
                 self.word_space("yield");
                 self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
             }
-            hir::ExprKind::Err => {
+            hir::ExprKind::Err(_) => {
                 self.popen();
                 self.word("/*ERROR*/");
                 self.pclose();
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 4ba78601ae8..6a0d5c01109 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -232,7 +232,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let Some(trait_def_id) = opt_trait_def_id else { continue };
 
             let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
-                self.tcx.mk_tup(arg_exprs.iter().map(|e| {
+                self.tcx.mk_tup_from_iter(arg_exprs.iter().map(|e| {
                     self.next_ty_var(TypeVariableOrigin {
                         kind: TypeVariableOriginKind::TypeInference,
                         span: e.span,
@@ -438,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 let err = self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
 
-                return self.tcx.ty_error_with_guaranteed(err);
+                return self.tcx.ty_error(err);
             }
         };
 
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 0eff3a2f9c2..d84fabb7834 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -3,6 +3,7 @@
 use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
 
 use hir::def::DefKind;
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir_analysis::astconv::AstConv;
@@ -126,7 +127,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // the `closures` table.
         let sig = bound_sig.map_bound(|sig| {
             self.tcx.mk_fn_sig(
-                [self.tcx.intern_tup(sig.inputs())],
+                [self.tcx.mk_tup(sig.inputs())],
                 sig.output(),
                 sig.c_variadic,
                 sig.unsafety,
@@ -488,17 +489,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             };
         let expected_span =
             expected_sig.cause_span.unwrap_or_else(|| self.tcx.def_span(expr_def_id));
-        self.report_arg_count_mismatch(
-            expected_span,
-            closure_span,
-            expected_args,
-            found_args,
-            true,
-            closure_arg_span,
-        )
-        .emit();
-
-        let error_sig = self.error_sig_of_closure(decl);
+        let guar = self
+            .report_arg_count_mismatch(
+                expected_span,
+                closure_span,
+                expected_args,
+                found_args,
+                true,
+                closure_arg_span,
+            )
+            .emit();
+
+        let error_sig = self.error_sig_of_closure(decl, guar);
 
         self.closure_sigs(expr_def_id, body, error_sig)
     }
@@ -792,13 +794,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Converts the types that the user supplied, in case that doing
     /// so should yield an error, but returns back a signature where
     /// all parameters are of type `TyErr`.
-    fn error_sig_of_closure(&self, decl: &hir::FnDecl<'_>) -> ty::PolyFnSig<'tcx> {
+    fn error_sig_of_closure(
+        &self,
+        decl: &hir::FnDecl<'_>,
+        guar: ErrorGuaranteed,
+    ) -> ty::PolyFnSig<'tcx> {
         let astconv: &dyn AstConv<'_> = self;
+        let err_ty = self.tcx.ty_error(guar);
 
         let supplied_arguments = decl.inputs.iter().map(|a| {
             // Convert the types that the user supplied (if any), but ignore them.
             astconv.ast_ty_to_ty(a);
-            self.tcx.ty_error()
+            err_ty
         });
 
         if let hir::FnRetTy::Return(ref output) = decl.output {
@@ -807,7 +814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let result = ty::Binder::dummy(self.tcx.mk_fn_sig(
             supplied_arguments,
-            self.tcx.ty_error(),
+            err_ty,
             decl.c_variadic,
             hir::Unsafety::Normal,
             Abi::RustCall,
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 706eb3f8647..00b86890b33 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -170,14 +170,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         debug!("Coerce.tys({:?} => {:?})", a, b);
 
         // Just ignore error types.
-        if a.references_error() || b.references_error() {
+        if let Err(guar) = (a, b).error_reported() {
             // Best-effort try to unify these types -- we're already on the error path,
             // so this will have the side-effect of making sure we have no ambiguities
             // due to `[type error]` and `_` not coercing together.
             let _ = self.commit_if_ok(|_| {
                 self.at(&self.cause, self.param_env).define_opaque_types(true).eq(a, b)
             });
-            return success(vec![], self.fcx.tcx.ty_error(), vec![]);
+            return success(vec![], self.fcx.tcx.ty_error(guar), vec![]);
         }
 
         // Coercing from `!` to any type is allowed:
@@ -997,7 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let (adjustments, _) = self.register_infer_ok_obligations(ok);
         self.apply_adjustments(expr, adjustments);
-        Ok(if expr_ty.references_error() { self.tcx.ty_error() } else { target })
+        Ok(if let Err(guar) = expr_ty.error_reported() { self.tcx.ty_error(guar) } else { target })
     }
 
     /// Same as `try_coerce()`, but without side-effects.
@@ -1434,8 +1434,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
 
         // If we see any error types, just propagate that error
         // upwards.
-        if expression_ty.references_error() || self.merged_ty().references_error() {
-            self.final_ty = Some(fcx.tcx.ty_error());
+        if let Err(guar) = (expression_ty, self.merged_ty()).error_reported() {
+            self.final_ty = Some(fcx.tcx.ty_error(guar));
             return;
         }
 
@@ -1620,7 +1620,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
 
                 let reported = err.emit_unless(unsized_return);
 
-                self.final_ty = Some(fcx.tcx.ty_error_with_guaranteed(reported));
+                self.final_ty = Some(fcx.tcx.ty_error(reported));
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index e90c4a4cb53..7fc4ccb04ee 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -88,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] {
                     target.to_owned()
                 } else {
-                    self.tcx().ty_error_with_guaranteed(reported)
+                    self.tcx().ty_error(reported)
                 };
             }
 
@@ -313,7 +313,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     tcx.types.never
                 } else {
                     // There was an error; make type-check fail.
-                    tcx.ty_error()
+                    tcx.ty_error_misc()
                 }
             }
             ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
@@ -354,7 +354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::Field(base, field) => self.check_field(expr, &base, field, expected),
             ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr),
             ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src),
-            hir::ExprKind::Err => tcx.ty_error(),
+            hir::ExprKind::Err(guar) => tcx.ty_error(guar),
         }
     }
 
@@ -402,7 +402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         {
                             err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
                         }
-                        oprnd_t = tcx.ty_error_with_guaranteed(err.emit());
+                        oprnd_t = tcx.ty_error(err.emit());
                     }
                 }
                 hir::UnOp::Not => {
@@ -452,7 +452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let tm = ty::TypeAndMut { ty, mutbl };
         match kind {
-            _ if tm.ty.references_error() => self.tcx.ty_error(),
+            _ if tm.ty.references_error() => self.tcx.ty_error_misc(),
             hir::BorrowKind::Raw => {
                 self.check_named_place_expr(oprnd);
                 self.tcx.mk_ptr(tm)
@@ -531,11 +531,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let e =
                     self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
-                tcx.ty_error_with_guaranteed(e)
+                tcx.ty_error(e)
             }
             Res::Def(DefKind::Variant, _) => {
                 let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, "E0533", "value");
-                tcx.ty_error_with_guaranteed(e)
+                tcx.ty_error(e)
             }
             _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0,
         };
@@ -634,7 +634,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // If the loop context is not a `loop { }`, then break with
                 // a value is illegal, and `opt_coerce_to` will be `None`.
                 // Just set expectation to error in that case.
-                let coerce_to = opt_coerce_to.unwrap_or_else(|| tcx.ty_error());
+                let coerce_to = opt_coerce_to.unwrap_or_else(|| tcx.ty_error_misc());
 
                 // Recurse without `enclosing_breakables` borrowed.
                 e_ty = self.check_expr_with_hint(e, coerce_to);
@@ -1033,7 +1033,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let result_ty = coerce.complete(self);
-        if cond_ty.references_error() { self.tcx.ty_error() } else { result_ty }
+        if let Err(guar) = cond_ty.error_reported() { self.tcx.ty_error(guar) } else { result_ty }
     }
 
     /// Type check assignment expression `expr` of form `lhs = rhs`.
@@ -1109,7 +1109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // If the assignment expression itself is ill-formed, don't
             // bother emitting another error
             let reported = err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error());
-            return self.tcx.ty_error_with_guaranteed(reported);
+            return self.tcx.ty_error(reported);
         }
 
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
@@ -1155,8 +1155,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
-        if lhs_ty.references_error() || rhs_ty.references_error() {
-            self.tcx.ty_error()
+        if let Err(guar) = (lhs_ty, rhs_ty).error_reported() {
+            self.tcx.ty_error(guar)
         } else {
             self.tcx.mk_unit()
         }
@@ -1274,8 +1274,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let t_expr = self.resolve_vars_if_possible(t_expr);
 
         // Eagerly check for some obvious errors.
-        if t_expr.references_error() || t_cast.references_error() {
-            self.tcx.ty_error()
+        if let Err(guar) = (t_expr, t_cast).error_reported() {
+            self.tcx.ty_error(guar)
         } else {
             // Defer other checks until we're done type checking.
             let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
@@ -1296,7 +1296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     deferred_cast_checks.push(cast_check);
                     t_cast
                 }
-                Err(_) => self.tcx.ty_error(),
+                Err(guar) => self.tcx.ty_error(guar),
             }
         }
     }
@@ -1423,8 +1423,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         };
 
-        if element_ty.references_error() {
-            return tcx.ty_error();
+        if let Err(guar) = element_ty.error_reported() {
+            return tcx.ty_error(guar);
         }
 
         self.check_repeat_element_needs_copy_bound(element, count, element_ty);
@@ -1492,9 +1492,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             _ => self.check_expr_with_expectation(&e, NoExpectation),
         });
-        let tuple = self.tcx.mk_tup(elt_ts_iter);
-        if tuple.references_error() {
-            self.tcx.ty_error()
+        let tuple = self.tcx.mk_tup_from_iter(elt_ts_iter);
+        if let Err(guar) = tuple.error_reported() {
+            self.tcx.ty_error(guar)
         } else {
             self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized);
             tuple
@@ -1510,9 +1510,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
     ) -> Ty<'tcx> {
         // Find the relevant variant
-        let Some((variant, adt_ty)) = self.check_struct_path(qpath, expr.hir_id) else {
-            self.check_struct_fields_on_error(fields, base_expr);
-            return self.tcx.ty_error();
+        let (variant, adt_ty) = match self.check_struct_path(qpath, expr.hir_id) {
+            Ok(data) => data,
+            Err(guar) => {
+                self.check_struct_fields_on_error(fields, base_expr);
+                return self.tcx.ty_error(guar);
+            }
         };
 
         // Prohibit struct expressions when non-exhaustive flag is set.
@@ -1594,12 +1597,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.field_ty(field.span, v_field, substs)
             } else {
                 error_happened = true;
-                if let Some(prev_span) = seen_fields.get(&ident) {
+                let guar = if let Some(prev_span) = seen_fields.get(&ident) {
                     tcx.sess.emit_err(FieldMultiplySpecifiedInInitializer {
                         span: field.ident.span,
                         prev_span: *prev_span,
                         ident,
-                    });
+                    })
                 } else {
                     self.report_unknown_field(
                         adt_ty,
@@ -1608,10 +1611,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ast_fields,
                         adt.variant_descr(),
                         expr_span,
-                    );
-                }
+                    )
+                };
 
-                tcx.ty_error()
+                tcx.ty_error(guar)
             };
 
             // Make sure to give a type to the field even if there's
@@ -1994,14 +1997,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         skip_fields: &[hir::ExprField<'_>],
         kind_name: &str,
         expr_span: Span,
-    ) {
+    ) -> ErrorGuaranteed {
         if variant.is_recovered() {
-            self.set_tainted_by_errors(
-                self.tcx
-                    .sess
-                    .delay_span_bug(expr_span, "parser recovered but no error was emitted"),
-            );
-            return;
+            let guar = self
+                .tcx
+                .sess
+                .delay_span_bug(expr_span, "parser recovered but no error was emitted");
+            self.set_tainted_by_errors(guar);
+            return guar;
         }
         let mut err = self.err_ctxt().type_error_struct_with_diag(
             field.ident.span,
@@ -2115,7 +2118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 };
             }
         }
-        err.emit();
+        err.emit()
     }
 
     // Return a hint about the closest match in field names
@@ -2256,11 +2259,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // (#90483) apply adjustments to avoid ExprUseVisitor from
             // creating erroneous projection.
             self.apply_adjustments(base, adjustments);
-            self.ban_private_field_access(expr, base_ty, field, did, expected.only_has_type(self));
-            return self.tcx().ty_error();
+            let guar = self.ban_private_field_access(
+                expr,
+                base_ty,
+                field,
+                did,
+                expected.only_has_type(self),
+            );
+            return self.tcx().ty_error(guar);
         }
 
-        if field.name == kw::Empty {
+        let guar = if field.name == kw::Empty {
+            self.tcx.sess.delay_span_bug(field.span, "field name with no name")
         } else if self.method_exists(
             field,
             base_ty,
@@ -2268,9 +2278,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             true,
             expected.only_has_type(self),
         ) {
-            self.ban_take_value_of_method(expr, base_ty, field);
+            self.ban_take_value_of_method(expr, base_ty, field)
         } else if !base_ty.is_primitive_ty() {
-            self.ban_nonexisting_field(field, base, expr, base_ty);
+            self.ban_nonexisting_field(field, base, expr, base_ty)
         } else {
             let field_name = field.to_string();
             let mut err = type_error_struct!(
@@ -2339,10 +2349,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     );
                 }
             }
-            err.emit();
-        }
+            err.emit()
+        };
 
-        self.tcx().ty_error()
+        self.tcx().ty_error(guar)
     }
 
     fn suggest_await_on_field_access(
@@ -2388,7 +2398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         base: &'tcx hir::Expr<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
         base_ty: Ty<'tcx>,
-    ) {
+    ) -> ErrorGuaranteed {
         debug!(
             "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, base_ty={:?}",
             ident, base, expr, base_ty
@@ -2436,7 +2446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             HelpUseLatestEdition::new().add_to_diagnostic(&mut err);
         }
 
-        err.emit();
+        err.emit()
     }
 
     fn ban_private_field_access(
@@ -2446,7 +2456,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         field: Ident,
         base_did: DefId,
         return_ty: Option<Ty<'tcx>>,
-    ) {
+    ) -> ErrorGuaranteed {
         let struct_path = self.tcx().def_path_str(base_did);
         let kind_name = self.tcx().def_descr(base_did);
         let mut err = struct_span_err!(
@@ -2469,10 +2479,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 None,
             );
         }
-        err.emit();
+        err.emit()
     }
 
-    fn ban_take_value_of_method(&self, expr: &hir::Expr<'tcx>, expr_t: Ty<'tcx>, field: Ident) {
+    fn ban_take_value_of_method(
+        &self,
+        expr: &hir::Expr<'tcx>,
+        expr_t: Ty<'tcx>,
+        field: Ident,
+    ) -> ErrorGuaranteed {
         let mut err = type_error_struct!(
             self.tcx().sess,
             field.span,
@@ -2544,7 +2559,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             err.help("methods are immutable and cannot be assigned to");
         }
 
-        err.emit();
+        err.emit()
     }
 
     fn point_at_param_definition(&self, err: &mut Diagnostic, param: ty::ParamTy) {
@@ -2829,7 +2844,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                     }
                     let reported = err.emit();
-                    self.tcx.ty_error_with_guaranteed(reported)
+                    self.tcx.ty_error(reported)
                 }
             }
         }
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index c8cda0dc90c..b9a058d6bba 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -301,7 +301,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
             hir::ExprKind::Continue(..)
             | hir::ExprKind::Lit(..)
             | hir::ExprKind::ConstBlock(..)
-            | hir::ExprKind::Err => {}
+            | hir::ExprKind::Err(_) => {}
 
             hir::ExprKind::Loop(blk, ..) => {
                 self.walk_block(blk);
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 943dc9b9646..b7ae621c685 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -104,7 +104,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         // type, `?T` is not considered unsolved, but `?I` is. The
         // same is true for float variables.)
         let fallback = match ty.kind() {
-            _ if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error_with_guaranteed(e),
+            _ if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error(e),
             ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
             ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
             _ => match diverging_fallback.get(&ty) {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 67de75301ad..60e55c7b0cf 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -451,7 +451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
         match self.typeck_results.borrow().node_types().get(id) {
             Some(&t) => t,
-            None if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error_with_guaranteed(e),
+            None if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error(e),
             None => {
                 bug!(
                     "no type for node {} in fcx {}",
@@ -465,7 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn node_ty_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
         match self.typeck_results.borrow().node_types().get(id) {
             Some(&t) => Some(t),
-            None if let Some(e) = self.tainted_by_errors() => Some(self.tcx.ty_error_with_guaranteed(e)),
+            None if let Some(e) = self.tainted_by_errors() => Some(self.tcx.ty_error(e)),
             None => None,
         }
     }
@@ -701,7 +701,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
-        vec![self.tcx.ty_error(); len]
+        let ty_error = self.tcx.ty_error_misc();
+        vec![ty_error; len]
     }
 
     /// Unifies the output type with the expected type early, for more coercions
@@ -1161,7 +1162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                     }
                     let reported = err.emit();
-                    return (tcx.ty_error_with_guaranteed(reported), res);
+                    return (tcx.ty_error(reported), res);
                 }
             }
         } else {
@@ -1417,7 +1418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
                     .emit()
             });
-            let err = self.tcx.ty_error_with_guaranteed(e);
+            let err = self.tcx.ty_error(e);
             self.demand_suptype(sp, err, ty);
             err
         }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 57b6c78a160..2e62e13648c 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -10,7 +10,9 @@ use crate::{
 };
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
+use rustc_errors::{
+    pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan,
+};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -72,7 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
                 let ty = self.resolve_vars_if_possible(ty);
                 if ty.has_non_region_infer() {
-                    self.tcx.ty_error()
+                    self.tcx.ty_error_misc()
                 } else {
                     self.tcx.erase_regions(ty)
                 }
@@ -100,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let err_inputs = match tuple_arguments {
                 DontTupleArguments => err_inputs,
-                TupleArguments => vec![self.tcx.intern_tup(&err_inputs)],
+                TupleArguments => vec![self.tcx.mk_tup(&err_inputs)],
             };
 
             self.check_argument_types(
@@ -113,7 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 tuple_arguments,
                 method.ok().map(|method| method.def_id),
             );
-            return self.tcx.ty_error();
+            return self.tcx.ty_error_misc();
         }
 
         let method = method.unwrap();
@@ -533,7 +535,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .typeck_results
                     .borrow()
                     .expr_ty_adjusted_opt(*expr)
-                    .unwrap_or_else(|| tcx.ty_error());
+                    .unwrap_or_else(|| tcx.ty_error_misc());
                 (self.resolve_vars_if_possible(ty), normalize_span(expr.span))
             })
             .collect();
@@ -640,7 +642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
             {
                 // Wrap up the N provided arguments starting at this position in a tuple.
-                let provided_as_tuple = tcx.mk_tup(
+                let provided_as_tuple = tcx.mk_tup_from_iter(
                     provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()),
                 );
 
@@ -1286,7 +1288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 opt_ty.unwrap_or_else(|| self.next_float_var())
             }
             ast::LitKind::Bool(_) => tcx.types.bool,
-            ast::LitKind::Err => tcx.ty_error(),
+            ast::LitKind::Err => tcx.ty_error_misc(),
         }
     }
 
@@ -1294,15 +1296,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         qpath: &QPath<'_>,
         hir_id: hir::HirId,
-    ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
+    ) -> Result<(&'tcx ty::VariantDef, Ty<'tcx>), ErrorGuaranteed> {
         let path_span = qpath.span();
         let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
         let variant = match def {
             Res::Err => {
-                self.set_tainted_by_errors(
-                    self.tcx.sess.delay_span_bug(path_span, "`Res::Err` but no error emitted"),
-                );
-                return None;
+                let guar =
+                    self.tcx.sess.delay_span_bug(path_span, "`Res::Err` but no error emitted");
+                self.set_tainted_by_errors(guar);
+                return Err(guar);
             }
             Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() {
                 Some(adt) => {
@@ -1330,28 +1332,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Check bounds on type arguments used in the path.
             self.add_required_obligations_for_hir(path_span, did, substs, hir_id);
 
-            Some((variant, ty.normalized))
+            Ok((variant, ty.normalized))
         } else {
-            match ty.normalized.kind() {
-                ty::Error(_) => {
+            Err(match *ty.normalized.kind() {
+                ty::Error(guar) => {
                     // E0071 might be caused by a spelling error, which will have
                     // already caused an error message and probably a suggestion
                     // elsewhere. Refrain from emitting more unhelpful errors here
                     // (issue #88844).
+                    guar
                 }
-                _ => {
-                    struct_span_err!(
-                        self.tcx.sess,
-                        path_span,
-                        E0071,
-                        "expected struct, variant or union type, found {}",
-                        ty.normalized.sort_string(self.tcx)
-                    )
-                    .span_label(path_span, "not a struct")
-                    .emit();
-                }
-            }
-            None
+                _ => struct_span_err!(
+                    self.tcx.sess,
+                    path_span,
+                    E0071,
+                    "expected struct, variant or union type, found {}",
+                    ty.normalized.sort_string(self.tcx)
+                )
+                .span_label(path_span, "not a struct")
+                .emit(),
+            })
         }
     }
 
@@ -1715,9 +1715,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         pat: &'tcx hir::Pat<'tcx>,
         ty: Ty<'tcx>,
     ) {
-        if ty.references_error() {
+        if let Err(guar) = ty.error_reported() {
             // Override the types everywhere with `err()` to avoid knock on errors.
-            let err = self.tcx.ty_error();
+            let err = self.tcx.ty_error(guar);
             self.write_ty(hir_id, err);
             self.write_ty(pat.hir_id, err);
             let local_ty = LocalTy { decl_ty: err, revealed_ty: err };
@@ -1746,7 +1746,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let result = self
                     .astconv()
                     .associated_path_to_ty(hir_id, path_span, ty.raw, qself, segment, true);
-                let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
+                let ty =
+                    result.map(|(ty, _, _)| ty).unwrap_or_else(|guar| self.tcx().ty_error(guar));
                 let ty = self.handle_raw_ty(path_span, ty);
                 let result = result.map(|(_, kind, def_id)| (kind, def_id));
 
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index adedb5b7428..7c0402b1c7f 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -219,7 +219,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
             | ExprKind::Struct(..)
             | ExprKind::Repeat(..)
             | ExprKind::Yield(..)
-            | ExprKind::Err => (),
+            | ExprKind::Err(_) => (),
         }
     }
 
@@ -483,7 +483,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
             | ExprKind::Closure { .. }
             | ExprKind::ConstBlock(..)
             | ExprKind::DropTemps(..)
-            | ExprKind::Err
+            | ExprKind::Err(_)
             | ExprKind::Field(..)
             | ExprKind::Index(..)
             | ExprKind::InlineAsm(..)
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index e5f9292290f..2e41c2041f8 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -311,8 +311,8 @@ pub fn resolve_interior<'a, 'tcx>(
     };
 
     // Extract type components to build the witness type.
-    let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
-    let bound_vars = fcx.tcx.intern_bound_variable_kinds(&bound_vars);
+    let type_list = fcx.tcx.mk_type_list_from_iter(type_causes.iter().map(|cause| cause.ty));
+    let bound_vars = fcx.tcx.mk_bound_variable_kinds(&bound_vars);
     let witness =
         fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
 
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 57c6c155a4d..91fd8fad73c 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -71,7 +71,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config;
 use rustc_session::Session;
 use rustc_span::def_id::{DefId, LocalDefId};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 fluent_messages! { "../locales/en-US.ftl" }
 
@@ -207,6 +207,11 @@ fn typeck_with_fallback<'tcx>(
 
     let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
         let param_env = tcx.param_env(def_id);
+        let param_env = if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) {
+            param_env.without_const()
+        } else {
+            param_env
+        };
         let mut fcx = FnCtxt::new(&inh, param_env, def_id);
 
         if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index e50f5c77552..bcfc61bffb2 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -383,7 +383,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             | hir::ExprKind::Repeat(..)
             | hir::ExprKind::InlineAsm(..)
             | hir::ExprKind::Box(..)
-            | hir::ExprKind::Err => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
+            | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index de8b24461b2..47a4d4e72df 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -574,7 +574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // `<Foo as Iterator>::Item = String`.
                         let projection_ty = pred.skip_binder().projection_ty;
 
-                        let substs_with_infer_self = tcx.mk_substs(
+                        let substs_with_infer_self = tcx.mk_substs_from_iter(
                             iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
                                 .chain(projection_ty.substs.iter().skip(1)),
                         );
@@ -1252,7 +1252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let ty::Adt(def, substs) = target_ty.kind() {
                 // If there are any inferred arguments, (`{integer}`), we should replace
                 // them with underscores to allow the compiler to infer them
-                let infer_substs = self.tcx.mk_substs(substs.into_iter().map(|arg| {
+                let infer_substs = self.tcx.mk_substs_from_iter(substs.into_iter().map(|arg| {
                     if !arg.is_suggestable(self.tcx, true) {
                         has_unsuggestable_args = true;
                         match arg.unpack() {
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index bb9d93d5057..a4b325a9b79 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -297,7 +297,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 method.sig.output()
             }
             // error types are considered "builtin"
-            Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(),
+            Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => {
+                self.tcx.ty_error_misc()
+            }
             Err(errors) => {
                 let (_, trait_def_id) =
                     lang_item_for_op(self.tcx, Op::Binary(op, is_assign), op.span);
@@ -518,7 +520,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
                 let reported = err.emit();
-                self.tcx.ty_error_with_guaranteed(reported)
+                self.tcx.ty_error(reported)
             }
         };
 
@@ -631,7 +633,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             Err(errors) => {
                 let actual = self.resolve_vars_if_possible(operand_ty);
-                if !actual.references_error() {
+                let guar = actual.error_reported().err().unwrap_or_else(|| {
                     let mut err = struct_span_err!(
                         self.tcx.sess,
                         ex.span,
@@ -701,9 +703,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             }
                         }
                     }
-                    err.emit();
-                }
-                self.tcx.ty_error()
+                    err.emit()
+                });
+                self.tcx.ty_error(guar)
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index b739324099d..c36c75e4443 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -475,8 +475,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
             // There exists a side that didn't meet our criteria that the end-point
             // be of a numeric or char type, as checked in `calc_side` above.
-            self.emit_err_pat_range(span, lhs, rhs);
-            return self.tcx.ty_error();
+            let guar = self.emit_err_pat_range(span, lhs, rhs);
+            return self.tcx.ty_error(guar);
         }
 
         // Unify each side with `expected`.
@@ -496,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         demand_eqtype(&mut rhs, lhs);
 
         if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
-            return self.tcx.ty_error();
+            return self.tcx.ty_error_misc();
         }
 
         // Find the unified type and check if it's of numeric or char type again.
@@ -511,8 +511,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let Some((ref mut fail, _, _)) = rhs {
                 *fail = true;
             }
-            self.emit_err_pat_range(span, lhs, rhs);
-            return self.tcx.ty_error();
+            let guar = self.emit_err_pat_range(span, lhs, rhs);
+            return self.tcx.ty_error(guar);
         }
         ty
     }
@@ -528,7 +528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         lhs: Option<(bool, Ty<'tcx>, Span)>,
         rhs: Option<(bool, Ty<'tcx>, Span)>,
-    ) {
+    ) -> ErrorGuaranteed {
         let span = match (lhs, rhs) {
             (Some((true, ..)), Some((true, ..))) => span,
             (Some((true, _, sp)), _) => sp,
@@ -573,7 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     type between two end-points, you can use a guard.",
             );
         }
-        err.emit();
+        err.emit()
     }
 
     fn check_pat_ident(
@@ -807,29 +807,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn check_dereferenceable(&self, span: Span, expected: Ty<'tcx>, inner: &Pat<'_>) -> bool {
+    pub fn check_dereferenceable(
+        &self,
+        span: Span,
+        expected: Ty<'tcx>,
+        inner: &Pat<'_>,
+    ) -> Result<(), ErrorGuaranteed> {
         if let PatKind::Binding(..) = inner.kind
             && let Some(mt) = self.shallow_resolve(expected).builtin_deref(true)
             && let ty::Dynamic(..) = mt.ty.kind()
         {
-                    // This is "x = SomeTrait" being reduced from
-                    // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
-                    let type_str = self.ty_to_string(expected);
-                    let mut err = struct_span_err!(
-                        self.tcx.sess,
-                        span,
-                        E0033,
-                        "type `{}` cannot be dereferenced",
-                        type_str
-                    );
-                    err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
-                    if self.tcx.sess.teach(&err.get_code().unwrap()) {
-                        err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
-                    }
-                    err.emit();
-                    return false;
-                }
-        true
+            // This is "x = SomeTrait" being reduced from
+            // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
+            let type_str = self.ty_to_string(expected);
+            let mut err = struct_span_err!(
+                self.tcx.sess,
+                span,
+                E0033,
+                "type `{}` cannot be dereferenced",
+                type_str
+            );
+            err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
+            if self.tcx.sess.teach(&err.get_code().unwrap()) {
+                err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
+            }
+            return Err(err.emit());
+        }
+        Ok(())
     }
 
     fn check_pat_struct(
@@ -843,13 +847,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         // Resolve the path and check the definition for errors.
-        let Some((variant, pat_ty)) = self.check_struct_path(qpath, pat.hir_id) else {
-            let err = self.tcx.ty_error();
-            for field in fields {
-                let ti = ti;
-                self.check_pat(field.pat, err, def_bm, ti);
+        let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
+            Ok(data) => data,
+            Err(guar) => {
+                let err = self.tcx.ty_error(guar);
+                for field in fields {
+                    let ti = ti;
+                    self.check_pat(field.pat, err, def_bm, ti);
+                }
+                return err;
             }
-            return err;
         };
 
         // Type-check the path.
@@ -859,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) {
             pat_ty
         } else {
-            self.tcx.ty_error()
+            self.tcx.ty_error_misc()
         }
     }
 
@@ -879,12 +886,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Res::Err => {
                 let e = tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
-                return tcx.ty_error_with_guaranteed(e);
+                return tcx.ty_error(e);
             }
             Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
                 let expected = "unit struct, unit variant or constant";
                 let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0533", expected);
-                return tcx.ty_error_with_guaranteed(e);
+                return tcx.ty_error(e);
             }
             Res::SelfCtor(..)
             | Res::Def(
@@ -1027,7 +1034,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let tcx = self.tcx;
         let on_error = |e| {
             for pat in subpats {
-                self.check_pat(pat, tcx.ty_error_with_guaranteed(e), def_bm, ti);
+                self.check_pat(pat, tcx.ty_error(e), def_bm, ti);
             }
         };
         let report_unexpected_res = |res: Res| {
@@ -1044,7 +1051,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted");
             self.set_tainted_by_errors(e);
             on_error(e);
-            return tcx.ty_error_with_guaranteed(e);
+            return tcx.ty_error(e);
         }
 
         // Type-check the path.
@@ -1052,7 +1059,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id);
         if !pat_ty.is_fn() {
             let e = report_unexpected_res(res);
-            return tcx.ty_error_with_guaranteed(e);
+            return tcx.ty_error(e);
         }
 
         let variant = match res {
@@ -1060,11 +1067,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
                 on_error(e);
-                return tcx.ty_error_with_guaranteed(e);
+                return tcx.ty_error(e);
             }
             Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
                 let e = report_unexpected_res(res);
-                return tcx.ty_error_with_guaranteed(e);
+                return tcx.ty_error(e);
             }
             Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
             _ => bug!("unexpected pattern resolution: {:?}", res),
@@ -1105,7 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Pattern has wrong number of fields.
             let e = self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
             on_error(e);
-            return tcx.ty_error_with_guaranteed(e);
+            return tcx.ty_error(e);
         }
         pat_ty
     }
@@ -1295,17 +1302,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span },
             )
         });
-        let element_tys = tcx.mk_type_list(element_tys_iter);
-        let pat_ty = tcx.intern_tup(element_tys);
+        let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
+        let pat_ty = tcx.mk_tup(element_tys);
         if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) {
             let reported = err.emit();
             // Walk subpatterns with an expected type of `err` in this case to silence
             // further errors being emitted when using the bindings. #50333
-            let element_tys_iter = (0..max_len).map(|_| tcx.ty_error_with_guaranteed(reported));
+            let element_tys_iter = (0..max_len).map(|_| tcx.ty_error(reported));
             for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
-                self.check_pat(elem, tcx.ty_error_with_guaranteed(reported), def_bm, ti);
+                self.check_pat(elem, tcx.ty_error(reported), def_bm, ti);
             }
-            tcx.mk_tup(element_tys_iter)
+            tcx.mk_tup_from_iter(element_tys_iter)
         } else {
             for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
                 self.check_pat(elem, element_tys[i], def_bm, ti);
@@ -1349,9 +1356,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let ident = tcx.adjust_ident(field.ident, variant.def_id);
             let field_ty = match used_fields.entry(ident) {
                 Occupied(occupied) => {
-                    self.error_field_already_bound(span, field.ident, *occupied.get());
                     no_field_errors = false;
-                    tcx.ty_error()
+                    let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
+                    tcx.ty_error(guar)
                 }
                 Vacant(vacant) => {
                     vacant.insert(span);
@@ -1365,7 +1372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .unwrap_or_else(|| {
                             inexistent_fields.push(field);
                             no_field_errors = false;
-                            tcx.ty_error()
+                            tcx.ty_error_misc()
                         })
                 }
             };
@@ -1536,7 +1543,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.emit();
     }
 
-    fn error_field_already_bound(&self, span: Span, ident: Ident, other_field: Span) {
+    fn error_field_already_bound(
+        &self,
+        span: Span,
+        ident: Ident,
+        other_field: Span,
+    ) -> ErrorGuaranteed {
         struct_span_err!(
             self.tcx.sess,
             span,
@@ -1546,7 +1558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )
         .span_label(span, format!("multiple uses of `{ident}` in pattern"))
         .span_label(other_field, format!("first use of `{ident}`"))
-        .emit();
+        .emit()
     }
 
     fn error_inexistent_fields(
@@ -1919,19 +1931,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, inner) {
-            // Here, `demand::subtype` is good enough, but I don't
-            // think any errors can be introduced by using `demand::eqtype`.
-            let inner_ty = self.next_ty_var(TypeVariableOrigin {
-                kind: TypeVariableOriginKind::TypeInference,
-                span: inner.span,
-            });
-            let box_ty = tcx.mk_box(inner_ty);
-            self.demand_eqtype_pat(span, expected, box_ty, ti);
-            (box_ty, inner_ty)
-        } else {
-            let err = tcx.ty_error();
-            (err, err)
+        let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) {
+            Ok(()) => {
+                // Here, `demand::subtype` is good enough, but I don't
+                // think any errors can be introduced by using `demand::eqtype`.
+                let inner_ty = self.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::TypeInference,
+                    span: inner.span,
+                });
+                let box_ty = tcx.mk_box(inner_ty);
+                self.demand_eqtype_pat(span, expected, box_ty, ti);
+                (box_ty, inner_ty)
+            }
+            Err(guar) => {
+                let err = tcx.ty_error(guar);
+                (err, err)
+            }
         };
         self.check_pat(inner, inner_ty, def_bm, ti);
         box_ty
@@ -1949,37 +1964,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let expected = self.shallow_resolve(expected);
-        let (ref_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, inner) {
-            // `demand::subtype` would be good enough, but using `eqtype` turns
-            // out to be equally general. See (note_1) for details.
-
-            // Take region, inner-type from expected type if we can,
-            // to avoid creating needless variables. This also helps with
-            // the bad interactions of the given hack detailed in (note_1).
-            debug!("check_pat_ref: expected={:?}", expected);
-            match *expected.kind() {
-                ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
-                _ => {
-                    let inner_ty = self.next_ty_var(TypeVariableOrigin {
-                        kind: TypeVariableOriginKind::TypeInference,
-                        span: inner.span,
-                    });
-                    let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
-                    debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
-                    let err = self.demand_eqtype_pat_diag(pat.span, expected, ref_ty, ti);
-
-                    // Look for a case like `fn foo(&foo: u32)` and suggest
-                    // `fn foo(foo: &u32)`
-                    if let Some(mut err) = err {
-                        self.borrow_pat_suggestion(&mut err, pat);
-                        err.emit();
+        let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
+            Ok(()) => {
+                // `demand::subtype` would be good enough, but using `eqtype` turns
+                // out to be equally general. See (note_1) for details.
+
+                // Take region, inner-type from expected type if we can,
+                // to avoid creating needless variables. This also helps with
+                // the bad interactions of the given hack detailed in (note_1).
+                debug!("check_pat_ref: expected={:?}", expected);
+                match *expected.kind() {
+                    ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
+                    _ => {
+                        let inner_ty = self.next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::TypeInference,
+                            span: inner.span,
+                        });
+                        let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
+                        debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
+                        let err = self.demand_eqtype_pat_diag(pat.span, expected, ref_ty, ti);
+
+                        // Look for a case like `fn foo(&foo: u32)` and suggest
+                        // `fn foo(foo: &u32)`
+                        if let Some(mut err) = err {
+                            self.borrow_pat_suggestion(&mut err, pat);
+                            err.emit();
+                        }
+                        (ref_ty, inner_ty)
                     }
-                    (ref_ty, inner_ty)
                 }
             }
-        } else {
-            let err = tcx.ty_error();
-            (err, err)
+            Err(guar) => {
+                let err = tcx.ty_error(guar);
+                (err, err)
+            }
         };
         self.check_pat(inner, inner_ty, def_bm, ti);
         ref_ty
@@ -2027,10 +2045,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty::Slice(element_ty) => (element_ty, Some(expected), expected),
             // The expected type must be an array or slice, but was neither, so error.
             _ => {
-                if !expected.references_error() {
-                    self.error_expected_array_or_slice(span, expected, ti);
-                }
-                let err = self.tcx.ty_error();
+                let guar = expected
+                    .error_reported()
+                    .err()
+                    .unwrap_or_else(|| self.error_expected_array_or_slice(span, expected, ti));
+                let err = self.tcx.ty_error(guar);
                 (err, Some(err), err)
             }
         };
@@ -2063,7 +2082,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         len: ty::Const<'tcx>,
         min_len: u64,
     ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
-        if let Some(len) = len.try_eval_target_usize(self.tcx, self.param_env) {
+        let guar = if let Some(len) = len.try_eval_target_usize(self.tcx, self.param_env) {
             // Now we know the length...
             if slice.is_none() {
                 // ...and since there is no variable-length pattern,
@@ -2073,7 +2092,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     return (None, arr_ty);
                 }
 
-                self.error_scrutinee_inconsistent_length(span, min_len, len);
+                self.error_scrutinee_inconsistent_length(span, min_len, len)
             } else if let Some(pat_len) = len.checked_sub(min_len) {
                 // The variable-length pattern was there,
                 // so it has an array type with the remaining elements left as its size...
@@ -2081,7 +2100,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 // ...however, in this case, there were no remaining elements.
                 // That is, the slice pattern requires more than the array type offers.
-                self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len);
+                self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len)
             }
         } else if slice.is_none() {
             // We have a pattern with a fixed length,
@@ -2093,14 +2112,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // We have a variable-length pattern and don't know the array length.
             // This happens if we have e.g.,
             // `let [a, b, ..] = arr` where `arr: [T; N]` where `const N: usize`.
-            self.error_scrutinee_unfixed_length(span);
-        }
+            self.error_scrutinee_unfixed_length(span)
+        };
 
         // If we get here, we must have emitted an error.
-        (Some(self.tcx.ty_error()), arr_ty)
+        (Some(self.tcx.ty_error(guar)), arr_ty)
     }
 
-    fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) {
+    fn error_scrutinee_inconsistent_length(
+        &self,
+        span: Span,
+        min_len: u64,
+        size: u64,
+    ) -> ErrorGuaranteed {
         struct_span_err!(
             self.tcx.sess,
             span,
@@ -2111,10 +2135,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             size,
         )
         .span_label(span, format!("expected {} element{}", size, pluralize!(size)))
-        .emit();
+        .emit()
     }
 
-    fn error_scrutinee_with_rest_inconsistent_length(&self, span: Span, min_len: u64, size: u64) {
+    fn error_scrutinee_with_rest_inconsistent_length(
+        &self,
+        span: Span,
+        min_len: u64,
+        size: u64,
+    ) -> ErrorGuaranteed {
         struct_span_err!(
             self.tcx.sess,
             span,
@@ -2128,20 +2157,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             span,
             format!("pattern cannot match array of {} element{}", size, pluralize!(size),),
         )
-        .emit();
+        .emit()
     }
 
-    fn error_scrutinee_unfixed_length(&self, span: Span) {
+    fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed {
         struct_span_err!(
             self.tcx.sess,
             span,
             E0730,
             "cannot pattern-match on an array without a fixed length",
         )
-        .emit();
+        .emit()
     }
 
-    fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: TopInfo<'tcx>) {
+    fn error_expected_array_or_slice(
+        &self,
+        span: Span,
+        expected_ty: Ty<'tcx>,
+        ti: TopInfo<'tcx>,
+    ) -> ErrorGuaranteed {
         let mut err = struct_span_err!(
             self.tcx.sess,
             span,
@@ -2185,7 +2219,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
         err.span_label(span, format!("pattern cannot match with input type `{expected_ty}`"));
-        err.emit();
+        err.emit()
     }
 
     fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index ae0df5aa8f1..8fcec3363c0 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -91,10 +91,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         }
         let reported = err.emit();
-        Some((
-            self.tcx.ty_error_with_guaranteed(reported),
-            self.tcx.ty_error_with_guaranteed(reported),
-        ))
+        Some((self.tcx.ty_error(reported), self.tcx.ty_error(reported)))
     }
 
     /// To type-check `base_expr[index_expr]`, we progressively autoderef
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 7c8abb4186f..3e27a78135e 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -301,7 +301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Build a tuple (U0..Un) of the final upvar types U0..Un
         // and unify the upvar tuple type in the closure with it:
-        let final_tupled_upvars_type = self.tcx.intern_tup(&final_upvar_tys);
+        let final_tupled_upvars_type = self.tcx.mk_tup(&final_upvar_tys);
         self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
 
         let fake_reads = delegate
@@ -315,8 +315,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.typeck_results.borrow_mut().closure_size_eval.insert(
                 closure_def_id,
                 ClosureSizeProfileData {
-                    before_feature_tys: self.tcx.intern_tup(&before_feature_tys),
-                    after_feature_tys: self.tcx.intern_tup(&after_feature_tys),
+                    before_feature_tys: self.tcx.mk_tup(&before_feature_tys),
+                    after_feature_tys: self.tcx.mk_tup(&after_feature_tys),
                 },
             );
         }
@@ -526,10 +526,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
                 base => bug!("Expected upvar, found={:?}", base),
             };
+            let var_ident = self.tcx.hir().ident(var_hir_id);
 
             let Some(min_cap_list) = root_var_min_capture_list.get_mut(&var_hir_id) else {
                 let mutability = self.determine_capture_mutability(&typeck_results, &place);
                 let min_cap_list = vec![ty::CapturedPlace {
+                    var_ident,
                     place,
                     info: capture_info,
                     mutability,
@@ -628,6 +630,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if !ancestor_found {
                 let mutability = self.determine_capture_mutability(&typeck_results, &place);
                 let captured_place = ty::CapturedPlace {
+                    var_ident,
                     place,
                     info: updated_capture_info,
                     mutability,
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 0394567cb09..00348f3afdc 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -797,7 +797,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
                 debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
                 let e = self.report_error(t);
                 self.replaced_with_error = Some(e);
-                self.interner().ty_error_with_guaranteed(e)
+                self.interner().ty_error(e)
             }
         }
     }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index f66f6bd4ae1..7ffd39de781 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -572,7 +572,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders());
 
         let canonical_variables =
-            tcx.intern_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
+            tcx.mk_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
 
         let max_universe = canonical_variables
             .iter()
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 4053546f00c..8c782a933a5 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -88,7 +88,7 @@ impl<'tcx> InferCtxt<'tcx> {
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> CanonicalVarValues<'tcx> {
         CanonicalVarValues {
-            var_values: self.tcx.mk_substs(
+            var_values: self.tcx.mk_substs_from_iter(
                 variables
                     .iter()
                     .map(|info| self.instantiate_canonical_var(span, info, &universe_map)),
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 07e7589fee4..832af91a431 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -474,8 +474,8 @@ impl<'tcx> InferCtxt<'tcx> {
         // given variable in the loop above, use that. Otherwise, use
         // a fresh inference variable.
         let result_subst = CanonicalVarValues {
-            var_values: self.tcx.mk_substs(query_response.variables.iter().enumerate().map(
-                |(index, info)| {
+            var_values: self.tcx.mk_substs_from_iter(
+                query_response.variables.iter().enumerate().map(|(index, info)| {
                     if info.is_existential() {
                         match opt_values[BoundVar::new(index)] {
                             Some(k) => k,
@@ -488,8 +488,8 @@ impl<'tcx> InferCtxt<'tcx> {
                             universe_map[u.as_usize()]
                         })
                     }
-                },
-            )),
+                }),
+            ),
         };
 
         let mut obligations = vec![];
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 243545640f9..33292e871b1 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -478,10 +478,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         self.obligations.extend(obligations.into_iter());
     }
 
-    pub fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
-    ) {
+    pub fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>) {
         self.obligations.extend(obligations.into_iter().map(|to_pred| {
             Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred)
         }))
@@ -814,10 +811,7 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
     /// Register predicates that must hold in order for this relation to hold. Uses
     /// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should
     /// be used if control over the obligaton causes is required.
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
-    );
+    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>);
 
     /// Register an obligation that both constants must be equal to each other.
     ///
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index f830e9b3c53..54a62326ef7 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -201,10 +201,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
 }
 
 impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
-    ) {
+    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 95635405f89..79efc1ce7bf 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -925,7 +925,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     ) -> Option<()> {
         // FIXME/HACK: Go back to `SubstsRef` to use its inherent methods,
         // ideally that shouldn't be necessary.
-        let sub = self.tcx.intern_substs(sub);
+        let sub = self.tcx.mk_substs(sub);
         for (i, ta) in sub.types().enumerate() {
             if ta == other_ty {
                 self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, other_ty);
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 37ef022f827..49df393d83b 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -148,10 +148,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
 }
 
 impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
-    ) {
+    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 335eb4c5406..a499018d3a2 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -438,7 +438,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
             }
             (VarValue::Value(a), VarValue::Empty(_)) => {
                 match *a {
-                    ReLateBound(..) | ReErased | ReError(_) => {
+                    // this is always on an error path,
+                    // so it doesn't really matter if it's shorter or longer than an empty region
+                    ReError(_) => false,
+
+                    ReLateBound(..) | ReErased => {
                         bug!("cannot relate region: {:?}", a);
                     }
 
@@ -467,7 +471,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
             }
             (VarValue::Empty(a_ui), VarValue::Value(b)) => {
                 match *b {
-                    ReLateBound(..) | ReErased | ReError(_) => {
+                    // this is always on an error path,
+                    // so it doesn't really matter if it's shorter or longer than an empty region
+                    ReError(_) => false,
+
+                    ReLateBound(..) | ReErased => {
                         bug!("cannot relate region: {:?}", b);
                     }
 
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index f541fcbceed..c871ccb21f8 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -148,10 +148,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
 }
 
 impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
-    ) {
+    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 214a5850fb6..6e413a7f412 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -763,10 +763,7 @@ impl<'tcx, D> ObligationEmittingRelation<'tcx> for TypeRelating<'_, 'tcx, D>
 where
     D: TypeRelatingDelegate<'tcx>,
 {
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
-    ) {
+    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
         self.delegate.register_obligations(
             obligations
                 .into_iter()
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index b4e647dcc9b..3e8c2052de8 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -126,7 +126,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
 
             (&ty::Error(e), _) | (_, &ty::Error(e)) => {
                 infcx.set_tainted_by_errors(e);
-                Ok(self.tcx().ty_error_with_guaranteed(e))
+                Ok(self.tcx().ty_error(e))
             }
 
             (
@@ -228,10 +228,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
 }
 
 impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
-    ) {
+    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index b03ecb59750..bdc313c2141 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -13,6 +13,7 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(extend_one)]
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index c1f0a6e9834..c07ff516579 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -116,11 +116,11 @@ pub fn elaborate_predicates_with_span<'tcx>(
 
 pub fn elaborate_obligations<'tcx>(
     tcx: TyCtxt<'tcx>,
-    mut obligations: Vec<PredicateObligation<'tcx>>,
+    obligations: Vec<PredicateObligation<'tcx>>,
 ) -> Elaborator<'tcx> {
-    let mut visited = PredicateSet::new(tcx);
-    obligations.retain(|obligation| visited.insert(obligation.predicate));
-    Elaborator { stack: obligations, visited }
+    let mut elaborator = Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx) };
+    elaborator.extend_deduped(obligations);
+    elaborator
 }
 
 fn predicate_obligation<'tcx>(
@@ -132,6 +132,15 @@ fn predicate_obligation<'tcx>(
 }
 
 impl<'tcx> Elaborator<'tcx> {
+    fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>) {
+        // Only keep those bounds that we haven't already seen.
+        // This is necessary to prevent infinite recursion in some
+        // cases. One common case is when people define
+        // `trait Sized: Sized { }` rather than `trait Sized { }`.
+        // let visited = &mut self.visited;
+        self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate)));
+    }
+
     pub fn filter_to_traits(self) -> FilterToTraits<Self> {
         FilterToTraits::new(self)
     }
@@ -172,15 +181,7 @@ impl<'tcx> Elaborator<'tcx> {
                         )
                     });
                 debug!(?data, ?obligations, "super_predicates");
-
-                // Only keep those bounds that we haven't already seen.
-                // This is necessary to prevent infinite recursion in some
-                // cases. One common case is when people define
-                // `trait Sized: Sized { }` rather than `trait Sized { }`.
-                let visited = &mut self.visited;
-                let obligations = obligations.filter(|o| visited.insert(o.predicate));
-
-                self.stack.extend(obligations);
+                self.extend_deduped(obligations);
             }
             ty::PredicateKind::WellFormed(..) => {
                 // Currently, we do not elaborate WF predicates,
@@ -237,10 +238,9 @@ impl<'tcx> Elaborator<'tcx> {
                     return;
                 }
 
-                let visited = &mut self.visited;
                 let mut components = smallvec![];
                 push_outlives_components(tcx, ty_max, &mut components);
-                self.stack.extend(
+                self.extend_deduped(
                     components
                         .into_iter()
                         .filter_map(|component| match component {
@@ -280,7 +280,6 @@ impl<'tcx> Elaborator<'tcx> {
                         .map(|predicate_kind| {
                             bound_predicate.rebind(predicate_kind).to_predicate(tcx)
                         })
-                        .filter(|&predicate| visited.insert(predicate))
                         .map(|predicate| {
                             predicate_obligation(
                                 predicate,
diff --git a/compiler/rustc_interface/locales/en-US.ftl b/compiler/rustc_interface/locales/en-US.ftl
index a7bc0e7af1f..da58492ccf2 100644
--- a/compiler/rustc_interface/locales/en-US.ftl
+++ b/compiler/rustc_interface/locales/en-US.ftl
@@ -11,10 +11,6 @@ interface_mixed_bin_crate =
 interface_mixed_proc_macro_crate =
     cannot mix `proc-macro` crate type with others
 
-interface_proc_macro_doc_without_arg =
-    Trying to document proc macro crate without passing '--crate-type proc-macro to rustdoc
-    .warn = The generated documentation may be incorrect
-
 interface_error_writing_dependencies =
     error writing dependencies to `{$path}`: {$error}
 
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index 29543fe2f93..0eedee25026 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -32,10 +32,6 @@ pub struct MixedBinCrate;
 pub struct MixedProcMacroCrate;
 
 #[derive(Diagnostic)]
-#[diag(interface_proc_macro_doc_without_arg)]
-pub struct ProcMacroDocWithoutArg;
-
-#[derive(Diagnostic)]
 #[diag(interface_error_writing_dependencies)]
 pub struct ErrorWritingDependencies<'a> {
     pub path: &'a Path,
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index aa59654099a..81c1d665ef0 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -287,28 +287,18 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
         sess.emit_warning(errors::ProcMacroCratePanicAbort);
     }
 
-    // For backwards compatibility, we don't try to run proc macro injection
-    // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
-    // specified. This should only affect users who manually invoke 'rustdoc', as
-    // 'cargo doc' will automatically pass the proper '--crate-type' flags.
-    // However, we do emit a warning, to let such users know that they should
-    // start passing '--crate-type proc-macro'
-    if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate {
-        sess.emit_warning(errors::ProcMacroDocWithoutArg);
-    } else {
-        krate = sess.time("maybe_create_a_macro_crate", || {
-            let is_test_crate = sess.opts.test;
-            rustc_builtin_macros::proc_macro_harness::inject(
-                sess,
-                resolver,
-                krate,
-                is_proc_macro_crate,
-                has_proc_macro_decls,
-                is_test_crate,
-                sess.diagnostic(),
-            )
-        });
-    }
+    krate = sess.time("maybe_create_a_macro_crate", || {
+        let is_test_crate = sess.opts.test;
+        rustc_builtin_macros::proc_macro_harness::inject(
+            sess,
+            resolver,
+            krate,
+            is_proc_macro_crate,
+            has_proc_macro_decls,
+            is_test_crate,
+            sess.diagnostic(),
+        )
+    });
 
     // Done with macro expansion!
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 71a72036994..18d84a7023a 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -756,6 +756,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(instrument_coverage, Some(InstrumentCoverage::All));
     tracked!(instrument_mcount, true);
     tracked!(instrument_xray, Some(InstrumentXRay::default()));
+    tracked!(link_directives, false);
     tracked!(link_only, true);
     tracked!(llvm_plugins, vec![String::from("plugin_name")]);
     tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
diff --git a/compiler/rustc_lint/locales/en-US.ftl b/compiler/rustc_lint/locales/en-US.ftl
index b1e7cc69a80..68e62c9789a 100644
--- a/compiler/rustc_lint/locales/en-US.ftl
+++ b/compiler/rustc_lint/locales/en-US.ftl
@@ -24,6 +24,13 @@ lint_for_loops_over_fallibles =
     .use_while_let = to check pattern in a loop use `while let`
     .use_question_mark = consider unwrapping the `Result` with `?` to iterate over its contents
 
+lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
+    .note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
+    .function_label = this function returns `()`, which is likely not what you wanted
+    .argument_label = called `Iterator::map` with callable that returns `()`
+    .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
+    .suggestion = you might have meant to use `Iterator::for_each`
+
 lint_non_binding_let_on_sync_lock =
     non-binding let on a synchronization lock
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 4da7f3f502f..59540aaf18f 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -677,21 +677,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
                     return;
                 }
                 let def = cx.tcx.adt_def(item.owner_id);
-                (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
+                (def, cx.tcx.mk_adt(def, ty::List::empty()))
             }
             hir::ItemKind::Union(_, ref ast_generics) => {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
                 let def = cx.tcx.adt_def(item.owner_id);
-                (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
+                (def, cx.tcx.mk_adt(def, ty::List::empty()))
             }
             hir::ItemKind::Enum(_, ref ast_generics) => {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
                 let def = cx.tcx.adt_def(item.owner_id);
-                (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
+                (def, cx.tcx.mk_adt(def, ty::List::empty()))
             }
             _ => return,
         };
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index aace4974cc9..f5a711315ea 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -893,6 +893,23 @@ pub trait LintContext: Sized {
                 BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => {
                     db.help("consider implementing the trait by hand, or remove the `packed` attribute");
                 }
+                BuiltinLintDiagnostics::UnusedExternCrate { removal_span }=> {
+                    db.span_suggestion(
+                        removal_span,
+                        "remove it",
+                        "",
+                        Applicability::MachineApplicable,
+                    );
+                }
+                BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span }=> {
+                    let suggestion_span = vis_span.between(ident_span);
+                    db.span_suggestion_verbose(
+                        suggestion_span,
+                        "convert it to a `use`",
+                        if vis_span.is_empty() { "use " } else { " use " },
+                        Applicability::MachineApplicable,
+                    );
+                }
             }
             // Rewrap `db`, and pass control to the user.
             decorate(db)
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 2070ffea4d9..35dc533e56c 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -63,6 +63,7 @@ mod late;
 mod let_underscore;
 mod levels;
 mod lints;
+mod map_unit_fn;
 mod methods;
 mod multiple_supertrait_upcastable;
 mod non_ascii_idents;
@@ -100,6 +101,7 @@ use for_loops_over_fallibles::*;
 use hidden_unicode_codepoints::*;
 use internal::*;
 use let_underscore::*;
+use map_unit_fn::*;
 use methods::*;
 use multiple_supertrait_upcastable::*;
 use non_ascii_idents::*;
@@ -239,6 +241,7 @@ late_lint_methods!(
             NamedAsmLabels: NamedAsmLabels,
             OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
             MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
+            MapUnitFn: MapUnitFn,
         ]
     ]
 );
@@ -298,7 +301,8 @@ fn register_builtins(store: &mut LintStore) {
         UNUSED_LABELS,
         UNUSED_PARENS,
         UNUSED_BRACES,
-        REDUNDANT_SEMICOLONS
+        REDUNDANT_SEMICOLONS,
+        MAP_UNIT_FN
     );
 
     add_lint_group!("let_underscore", LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK);
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 2d9aa9074be..20ab0af5856 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -748,6 +748,22 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub {
     }
 }
 
+// map_unit_fn.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_map_unit_fn)]
+#[note]
+pub struct MappingToUnit {
+    #[label(lint_function_label)]
+    pub function_label: Span,
+    #[label(lint_argument_label)]
+    pub argument_label: Span,
+    #[label(lint_map_label)]
+    pub map_label: Span,
+    #[suggestion(style = "verbose", code = "{replace}", applicability = "maybe-incorrect")]
+    pub suggestion: Span,
+    pub replace: String,
+}
+
 // internal.rs
 #[derive(LintDiagnostic)]
 #[diag(lint_default_hash_types)]
diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs
new file mode 100644
index 00000000000..62e8b4fe9e4
--- /dev/null
+++ b/compiler/rustc_lint/src/map_unit_fn.rs
@@ -0,0 +1,120 @@
+use crate::lints::MappingToUnit;
+use crate::{LateContext, LateLintPass, LintContext};
+
+use rustc_hir::{Expr, ExprKind, HirId, Stmt, StmtKind};
+use rustc_middle::{
+    query::Key,
+    ty::{self, Ty},
+};
+
+declare_lint! {
+    /// The `map_unit_fn` lint checks for `Iterator::map` receive
+    /// a callable that returns `()`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn foo(items: &mut Vec<u8>) {
+    ///     items.sort();
+    /// }
+    ///
+    /// fn main() {
+    ///     let mut x: Vec<Vec<u8>> = vec![
+    ///         vec![0, 2, 1],
+    ///         vec![5, 4, 3],
+    ///     ];
+    ///     x.iter_mut().map(foo);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Mapping to `()` is almost always a mistake.
+    pub MAP_UNIT_FN,
+    Warn,
+    "`Iterator::map` call that discard the iterator's values"
+}
+
+declare_lint_pass!(MapUnitFn => [MAP_UNIT_FN]);
+
+impl<'tcx> LateLintPass<'tcx> for MapUnitFn {
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) {
+        if stmt.span.from_expansion() {
+            return;
+        }
+
+        if let StmtKind::Semi(expr) = stmt.kind {
+            if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind {
+                if path.ident.name.as_str() == "map" {
+                    if receiver.span.from_expansion()
+                        || args.iter().any(|e| e.span.from_expansion())
+                        || !is_impl_slice(cx, receiver)
+                        || !is_diagnostic_name(cx, expr.hir_id, "IteratorMap")
+                    {
+                        return;
+                    }
+                    let arg_ty = cx.typeck_results().expr_ty(&args[0]);
+                    if let ty::FnDef(id, _) = arg_ty.kind() {
+                        let fn_ty = cx.tcx.fn_sig(id).skip_binder();
+                        let ret_ty = fn_ty.output().skip_binder();
+                        if is_unit_type(ret_ty) {
+                            cx.emit_spanned_lint(
+                                MAP_UNIT_FN,
+                                span,
+                                MappingToUnit {
+                                    function_label: cx.tcx.span_of_impl(*id).unwrap(),
+                                    argument_label: args[0].span,
+                                    map_label: arg_ty.default_span(cx.tcx),
+                                    suggestion: path.ident.span,
+                                    replace: "for_each".to_string(),
+                                },
+                            )
+                        }
+                    } else if let ty::Closure(id, subs) = arg_ty.kind() {
+                        let cl_ty = subs.as_closure().sig();
+                        let ret_ty = cl_ty.output().skip_binder();
+                        if is_unit_type(ret_ty) {
+                            cx.emit_spanned_lint(
+                                MAP_UNIT_FN,
+                                span,
+                                MappingToUnit {
+                                    function_label: cx.tcx.span_of_impl(*id).unwrap(),
+                                    argument_label: args[0].span,
+                                    map_label: arg_ty.default_span(cx.tcx),
+                                    suggestion: path.ident.span,
+                                    replace: "for_each".to_string(),
+                                },
+                            )
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+fn is_impl_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
+        if let Some(impl_id) = cx.tcx.impl_of_method(method_id) {
+            return cx.tcx.type_of(impl_id).skip_binder().is_slice();
+        }
+    }
+    false
+}
+
+fn is_unit_type(ty: Ty<'_>) -> bool {
+    ty.is_unit() || ty.is_never()
+}
+
+fn is_diagnostic_name(cx: &LateContext<'_>, id: HirId, name: &str) -> bool {
+    if let Some(def_id) = cx.typeck_results().type_dependent_def_id(id) {
+        if let Some(item) = cx.tcx.get_diagnostic_name(def_id) {
+            if item.as_str() == name {
+                return true;
+            }
+        }
+    }
+    false
+}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 9d8ad9d9ed9..46ec1a2dca1 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -4103,3 +4103,33 @@ declare_lint! {
     };
     report_in_external_macro
 }
+
+declare_lint! {
+    /// The `invalid_macro_export_arguments` lint detects cases where `#[macro_export]` is being used with invalid arguments.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(invalid_macro_export_arguments)]
+    ///
+    /// #[macro_export(invalid_parameter)]
+    /// macro_rules! myMacro {
+    ///    () => {
+    ///         // [...]
+    ///    }
+    /// }
+    ///
+    /// #[macro_export(too, many, items)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The only valid argument is `#[macro_export(local_inner_macros)]` or no argument (`#[macro_export]`).
+    /// You can't have multiple arguments in a `#[macro_export(..)]`, or mention arguments other than `local_inner_macros`.
+    ///
+    pub INVALID_MACRO_EXPORT_ARGUMENTS,
+    Warn,
+    "\"invalid_parameter\" isn't a valid argument for `#[macro_export]`",
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 6efbf5ce9ee..534aff7fb62 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -522,6 +522,13 @@ pub enum BuiltinLintDiagnostics {
         is_formatting_arg: bool,
     },
     ByteSliceInPackedStructWithDerive,
+    UnusedExternCrate {
+        removal_span: Span,
+    },
+    ExternCrateNotIdiomatic {
+        vis_span: Span,
+        ident_span: Span,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 82e6972d027..8d017d149f6 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -42,6 +42,12 @@ fn decodable_body(
     }
     let ty_name = s.ast().ident.to_string();
     let decode_body = match s.variants() {
+        [] => {
+            let message = format!("`{}` has no variants to decode", ty_name);
+            quote! {
+                panic!(#message)
+            }
+        }
         [vi] => vi.construct(|field, _index| decode_field(field)),
         variants => {
             let match_inner: TokenStream = variants
@@ -139,6 +145,11 @@ fn encodable_body(
     });
 
     let encode_body = match s.variants() {
+        [] => {
+            quote! {
+                match *self {}
+            }
+        }
         [_] => {
             let encode_inner = s.each_variant(|vi| {
                 vi.bindings()
@@ -160,6 +171,23 @@ fn encodable_body(
             }
         }
         _ => {
+            let disc = {
+                let mut variant_idx = 0usize;
+                let encode_inner = s.each_variant(|_| {
+                    let result = quote! {
+                        #variant_idx
+                    };
+                    variant_idx += 1;
+                    result
+                });
+                quote! {
+                    let disc = match *self {
+                        #encode_inner
+                    };
+                    ::rustc_serialize::Encoder::emit_usize(__encoder, disc);
+                }
+            };
+
             let mut variant_idx = 0usize;
             let encode_inner = s.each_variant(|vi| {
                 let encode_fields: TokenStream = vi
@@ -176,26 +204,11 @@ fn encodable_body(
                         result
                     })
                     .collect();
-
-                let result = if !vi.bindings().is_empty() {
-                    quote! {
-                        ::rustc_serialize::Encoder::emit_enum_variant(
-                            __encoder,
-                            #variant_idx,
-                            |__encoder| { #encode_fields }
-                        )
-                    }
-                } else {
-                    quote! {
-                        ::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>(
-                            __encoder,
-                        )
-                    }
-                };
                 variant_idx += 1;
-                result
+                encode_fields
             });
             quote! {
+                #disc
                 match *self {
                     #encode_inner
                 }
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index d823989bb02..d6f68b2e140 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -103,8 +103,13 @@ impl<'tcx> Collector<'tcx> {
         }
 
         // Process all of the #[link(..)]-style arguments
-        let sess = &self.tcx.sess;
+        let sess = self.tcx.sess;
         let features = self.tcx.features();
+
+        if !sess.opts.unstable_opts.link_directives {
+            return;
+        }
+
         for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) {
             let Some(items) = m.meta_item_list() else {
                 continue;
@@ -502,7 +507,7 @@ impl<'tcx> Collector<'tcx> {
                 .subst_identity()
                 .fn_sig(self.tcx)
                 .inputs()
-                .map_bound(|slice| self.tcx.intern_type_list(slice)),
+                .map_bound(|slice| self.tcx.mk_type_list(slice)),
         );
 
         argument_types
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 3457e51f8e6..b1e59b0a470 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -910,7 +910,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             std::iter::once(self.get_variant(&kind, item_id, did)).collect()
         };
 
-        tcx.alloc_adt_def(did, adt_kind, variants, repr)
+        tcx.mk_adt_def(did, adt_kind, variants, repr)
     }
 
     fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics {
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index d4019b5bf17..62e44b6298b 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -116,6 +116,7 @@ macro_rules! arena_types {
             [] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
             [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
             [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
+            [] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>),
         ]);
     )
 }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 2df851a7857..4b5bacac814 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -903,6 +903,11 @@ impl<'hir> Map<'hir> {
     }
 
     #[inline]
+    pub fn ident(self, id: HirId) -> Ident {
+        self.opt_ident(id).unwrap()
+    }
+
+    #[inline]
     pub fn opt_name(self, id: HirId) -> Option<Symbol> {
         self.opt_ident(id).map(|ident| ident.name)
     }
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 2e2ca6a2788..ad119c4e073 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -64,13 +64,17 @@ impl ModuleItems {
         self.foreign_items.iter().copied()
     }
 
-    pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
+    pub fn owners(&self) -> impl Iterator<Item = OwnerId> + '_ {
         self.items
             .iter()
-            .map(|id| id.owner_id.def_id)
-            .chain(self.trait_items.iter().map(|id| id.owner_id.def_id))
-            .chain(self.impl_items.iter().map(|id| id.owner_id.def_id))
-            .chain(self.foreign_items.iter().map(|id| id.owner_id.def_id))
+            .map(|id| id.owner_id)
+            .chain(self.trait_items.iter().map(|id| id.owner_id))
+            .chain(self.impl_items.iter().map(|id| id.owner_id))
+            .chain(self.foreign_items.iter().map(|id| id.owner_id))
+    }
+
+    pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
+        self.owners().map(|id| id.def_id)
     }
 
     pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) {
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index e134ef8489c..8712514a384 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -47,7 +47,7 @@ impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_canonical_var_infos(v))
+        ty::util::fold_list(self, folder, |tcx, v| tcx.mk_canonical_var_infos(v))
     }
 }
 
@@ -342,7 +342,7 @@ impl<'tcx> CanonicalVarValues<'tcx> {
         infos: CanonicalVarInfos<'tcx>,
     ) -> CanonicalVarValues<'tcx> {
         CanonicalVarValues {
-            var_values: tcx.mk_substs(infos.iter().enumerate().map(
+            var_values: tcx.mk_substs_from_iter(infos.iter().enumerate().map(
                 |(i, info)| -> ty::GenericArg<'tcx> {
                     match info.kind {
                         CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index ccd8a333866..0d78c6135b3 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1620,7 +1620,7 @@ impl<'tcx> Place<'tcx> {
             &v
         };
 
-        Place { local: self.local, projection: tcx.intern_place_elems(new_projections) }
+        Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
     }
 }
 
@@ -2530,13 +2530,14 @@ impl<'tcx> ConstantKind<'tcx> {
         {
             InternalSubsts::identity_for_item(tcx, parent_did.to_def_id())
         } else {
-            tcx.intern_substs(&[])
+            List::empty()
         };
         debug!(?parent_substs);
 
         let did = def.did.to_def_id();
         let child_substs = InternalSubsts::identity_for_item(tcx, did);
-        let substs = tcx.mk_substs(parent_substs.into_iter().chain(child_substs.into_iter()));
+        let substs =
+            tcx.mk_substs_from_iter(parent_substs.into_iter().chain(child_substs.into_iter()));
         debug!(?substs);
 
         let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index aa9f170477b..0aa2c500f51 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -194,14 +194,16 @@ impl<'tcx> Rvalue<'tcx> {
                 let lhs_ty = lhs.ty(local_decls, tcx);
                 let rhs_ty = rhs.ty(local_decls, tcx);
                 let ty = op.ty(tcx, lhs_ty, rhs_ty);
-                tcx.intern_tup(&[ty, tcx.types.bool])
+                tcx.mk_tup(&[ty, tcx.types.bool])
             }
             Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
             Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize,
             Rvalue::Aggregate(ref ak, ref ops) => match **ak {
                 AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64),
-                AggregateKind::Tuple => tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx))),
+                AggregateKind::Tuple => {
+                    tcx.mk_tup_from_iter(ops.iter().map(|op| op.ty(local_decls, tcx)))
+                }
                 AggregateKind::Adt(did, _, substs, _, _) => tcx.type_of(did).subst(tcx, substs),
                 AggregateKind::Closure(did, substs) => tcx.mk_closure(did, substs),
                 AggregateKind::Generator(did, substs, movability) => {
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index d0936d950b3..9881583214e 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -53,6 +53,6 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<PlaceElem<'tcx>> {
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v))
+        ty::util::fold_list(self, folder, |tcx, v| tcx.mk_place_elems(v))
     }
 }
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 7f0935fb149..5c056b29975 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1045,7 +1045,7 @@ macro_rules! visit_place_fns {
             self.visit_local(&mut place.local, context, location);
 
             if let Some(new_projection) = self.process_projection(&place.projection, location) {
-                place.projection = self.tcx().intern_place_elems(&new_projection);
+                place.projection = self.tcx().mk_place_elems(&new_projection);
             }
         }
 
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index dc02fd53ed0..111ea6b8cdd 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -4,8 +4,9 @@ use crate::infer::canonical::Canonical;
 use crate::mir;
 use crate::traits;
 use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::layout::{InitKind, TyAndLayout};
 use crate::ty::subst::{GenericArg, SubstsRef};
-use crate::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
+use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::hir_id::{HirId, OwnerId};
 use rustc_query_system::query::{DefaultCacheSelector, SingleCacheSelector, VecCacheSelector};
@@ -696,3 +697,24 @@ impl Key for HirId {
         None
     }
 }
+
+impl<'tcx> Key for (InitKind, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
+    // Just forward to `Ty<'tcx>`
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+
+    fn ty_adt_id(&self) -> Option<DefId> {
+        match self.1.value.kind() {
+            ty::Adt(adt, _) => Some(adt.did()),
+            _ => None,
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 6a34e5ede19..8fe5586723d 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -475,14 +475,10 @@ rustc_queries! {
         }
     }
 
-    query symbols_for_closure_captures(
-        key: (LocalDefId, LocalDefId)
-    ) -> &'tcx Vec<rustc_span::Symbol> {
-        arena_cache
+    query closure_typeinfo(key: LocalDefId) -> ty::ClosureTypeInfo<'tcx> {
         desc {
-            |tcx| "finding symbols for captures of closure `{}` in `{}`",
-            tcx.def_path_str(key.1.to_def_id()),
-            tcx.def_path_str(key.0.to_def_id())
+            |tcx| "finding symbols for captures of closure `{}`",
+            tcx.def_path_str(key.to_def_id())
         }
     }
 
@@ -1830,9 +1826,6 @@ rustc_queries! {
     query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> {
         desc { "fetching potentially unused trait imports" }
     }
-    query maybe_unused_extern_crates(_: ()) -> &'tcx [(LocalDefId, Span)] {
-        desc { "looking up all possibly unused extern crates" }
-    }
     query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxHashSet<Symbol> {
         desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
@@ -2173,12 +2166,8 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query permits_uninit_init(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<bool, ty::layout::LayoutError<'tcx>> {
-        desc { "checking to see if `{}` permits being left uninit", key.value }
-    }
-
-    query permits_zero_init(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<bool, ty::layout::LayoutError<'tcx>> {
-        desc { "checking to see if `{}` permits being left zeroed", key.value }
+    query check_validity_of_init(key: (InitKind, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, ty::layout::LayoutError<'tcx>> {
+        desc { "checking to see if `{}` permits being left {}", key.1.value, key.0 }
     }
 
     query compare_impl_const(
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 6f2dac46753..2b3601bec7b 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -20,7 +20,7 @@ use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp};
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts};
+use rustc_middle::ty::{self, AdtDef, FnSig, Ty, UpvarSubsts};
 use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
@@ -29,11 +29,15 @@ use rustc_target::asm::InlineAsmRegOrRegClass;
 use std::fmt;
 use std::ops::Index;
 
-pub mod print;
 pub mod visit;
 
 macro_rules! thir_with_elements {
-    ($($name:ident: $id:ty => $value:ty => $format:literal,)*) => {
+    (
+        $($field_name:ident: $field_ty:ty,)*
+
+    @elements:
+        $($name:ident: $id:ty => $value:ty => $format:literal,)*
+    ) => {
         $(
             newtype_index! {
                 #[derive(HashStable)]
@@ -48,14 +52,20 @@ macro_rules! thir_with_elements {
         #[derive(Debug, HashStable, Clone)]
         pub struct Thir<'tcx> {
             $(
+                pub $field_name: $field_ty,
+            )*
+            $(
                 pub $name: IndexVec<$id, $value>,
             )*
         }
 
         impl<'tcx> Thir<'tcx> {
-            pub fn new() -> Thir<'tcx> {
+            pub fn new($($field_name: $field_ty,)*) -> Thir<'tcx> {
                 Thir {
                     $(
+                        $field_name,
+                    )*
+                    $(
                         $name: IndexVec::new(),
                     )*
                 }
@@ -76,6 +86,9 @@ macro_rules! thir_with_elements {
 pub const UPVAR_ENV_PARAM: ParamId = ParamId::from_u32(0);
 
 thir_with_elements! {
+    body_type: BodyTy<'tcx>,
+
+@elements:
     arms: ArmId => Arm<'tcx> => "a{}",
     blocks: BlockId => Block => "b{}",
     exprs: ExprId => Expr<'tcx> => "e{}",
@@ -83,6 +96,12 @@ thir_with_elements! {
     params: ParamId => Param<'tcx> => "p{}",
 }
 
+#[derive(Debug, HashStable, Clone)]
+pub enum BodyTy<'tcx> {
+    Const(Ty<'tcx>),
+    Fn(FnSig<'tcx>),
+}
+
 /// Description of a type-checked function parameter.
 #[derive(Clone, Debug, HashStable)]
 pub struct Param<'tcx> {
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index aadbce9e2ff..c5bf9717f03 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -30,20 +30,18 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        Ok(FallibleTypeFolder::interner(folder).intern_external_constraints(
-            ExternalConstraintsData {
-                regions: (),
-                opaque_types: self
-                    .opaque_types
-                    .iter()
-                    .map(|opaque| opaque.try_fold_with(folder))
-                    .collect::<Result<_, F::Error>>()?,
-            },
-        ))
+        Ok(FallibleTypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData {
+            regions: (),
+            opaque_types: self
+                .opaque_types
+                .iter()
+                .map(|opaque| opaque.try_fold_with(folder))
+                .collect::<Result<_, F::Error>>()?,
+        }))
     }
 
     fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
-        TypeFolder::interner(folder).intern_external_constraints(ExternalConstraintsData {
+        TypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData {
             regions: (),
             opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
         })
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs
index b9c5a4e0d0d..df9aa765dc1 100644
--- a/compiler/rustc_middle/src/ty/_match.rs
+++ b/compiler/rustc_middle/src/ty/_match.rs
@@ -89,9 +89,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
                 Err(TypeError::Sorts(relate::expected_found(self, a, b)))
             }
 
-            (&ty::Error(guar), _) | (_, &ty::Error(guar)) => {
-                Ok(self.tcx().ty_error_with_guaranteed(guar))
-            }
+            (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(self.tcx().ty_error(guar)),
 
             _ => relate::super_relate_tys(self, a, b),
         }
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index f127b6275a2..ec21030b302 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -54,7 +54,7 @@ bitflags! {
 
 /// The definition of a user-defined type, e.g., a `struct`, `enum`, or `union`.
 ///
-/// These are all interned (by `alloc_adt_def`) into the global arena.
+/// These are all interned (by `mk_adt_def`) into the global arena.
 ///
 /// The initialism *ADT* stands for an [*algebraic data type (ADT)*][adt].
 /// This is slightly wrong because `union`s are not ADTs.
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 6ade8935fc8..dc2bd54b7fe 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -5,10 +5,10 @@ use crate::{mir, ty};
 
 use std::fmt::Write;
 
-use hir::LangItem;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{self as hir, LangItem};
+use rustc_span::symbol::Ident;
 use rustc_span::{Span, Symbol};
 
 use super::{Ty, TyCtxt};
@@ -129,6 +129,9 @@ impl<'tcx> ClosureKind {
 #[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub struct CapturedPlace<'tcx> {
+    /// Name and span where the binding happens.
+    pub var_ident: Ident,
+
     /// The `Place` that is captured.
     pub place: HirPlace<'tcx>,
 
@@ -148,12 +151,8 @@ impl<'tcx> CapturedPlace<'tcx> {
     }
 
     /// Returns a symbol of the captured upvar, which looks like `name__field1__field2`.
-    fn to_symbol(&self, tcx: TyCtxt<'tcx>) -> Symbol {
-        let hir_id = match self.place.base {
-            HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
-            base => bug!("Expected an upvar, found {:?}", base),
-        };
-        let mut symbol = tcx.hir().name(hir_id).as_str().to_string();
+    pub fn to_symbol(&self) -> Symbol {
+        let mut symbol = self.var_ident.to_string();
 
         let mut ty = self.place.base_ty;
         for proj in self.place.projections.iter() {
@@ -169,11 +168,7 @@ impl<'tcx> CapturedPlace<'tcx> {
                         .unwrap();
                     }
                     ty => {
-                        span_bug!(
-                            self.get_capture_kind_span(tcx),
-                            "Unexpected type {:?} for `Field` projection",
-                            ty
-                        )
+                        bug!("Unexpected type {:?} for `Field` projection", ty)
                     }
                 },
 
@@ -238,10 +233,39 @@ impl<'tcx> CapturedPlace<'tcx> {
     }
 }
 
-fn symbols_for_closure_captures(tcx: TyCtxt<'_>, def_id: (LocalDefId, LocalDefId)) -> Vec<Symbol> {
-    let typeck_results = tcx.typeck(def_id.0);
-    let captures = typeck_results.closure_min_captures_flattened(def_id.1);
-    captures.into_iter().map(|captured_place| captured_place.to_symbol(tcx)).collect()
+#[derive(Copy, Clone, Debug, HashStable)]
+pub struct ClosureTypeInfo<'tcx> {
+    user_provided_sig: ty::CanonicalPolyFnSig<'tcx>,
+    captures: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
+    kind_origin: Option<&'tcx (Span, HirPlace<'tcx>)>,
+}
+
+fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo<'tcx> {
+    debug_assert!(tcx.is_closure(def.to_def_id()));
+    let typeck_results = tcx.typeck(def);
+    let user_provided_sig = typeck_results.user_provided_sigs[&def];
+    let captures = typeck_results.closure_min_captures_flattened(def);
+    let captures = tcx.arena.alloc_from_iter(captures);
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def);
+    let kind_origin = typeck_results.closure_kind_origins().get(hir_id);
+    ClosureTypeInfo { user_provided_sig, captures, kind_origin }
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+    pub fn closure_kind_origin(self, def_id: LocalDefId) -> Option<&'tcx (Span, HirPlace<'tcx>)> {
+        self.closure_typeinfo(def_id).kind_origin
+    }
+
+    pub fn closure_user_provided_sig(self, def_id: LocalDefId) -> ty::CanonicalPolyFnSig<'tcx> {
+        self.closure_typeinfo(def_id).user_provided_sig
+    }
+
+    pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] {
+        if !self.is_closure(def_id.to_def_id()) {
+            return &[];
+        };
+        self.closure_typeinfo(def_id).captures
+    }
 }
 
 /// Return true if the `proj_possible_ancestor` represents an ancestor path
@@ -434,5 +458,5 @@ impl BorrowKind {
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { symbols_for_closure_captures, ..*providers }
+    *providers = ty::query::Providers { closure_typeinfo, ..*providers }
 }
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index b9a1e23879c..3ce80e06ad9 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -207,7 +207,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Ty<'tcx> {
             })
         } else {
             let tcx = decoder.interner();
-            tcx.mk_ty(rustc_type_ir::TyKind::decode(decoder))
+            tcx.mk_ty_from_kind(rustc_type_ir::TyKind::decode(decoder))
         }
     }
 }
@@ -244,7 +244,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for SubstsRef<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let len = decoder.read_usize();
         let tcx = decoder.interner();
-        tcx.mk_substs(
+        tcx.mk_substs_from_iter(
             (0..len).map::<ty::subst::GenericArg<'tcx>, _>(|_| Decodable::decode(decoder)),
         )
     }
@@ -254,7 +254,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for mir::Place<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let local: mir::Local = Decodable::decode(decoder);
         let len = decoder.read_usize();
-        let projection = decoder.interner().mk_place_elems(
+        let projection = decoder.interner().mk_place_elems_from_iter(
             (0..len).map::<mir::PlaceElem<'tcx>, _>(|_| Decodable::decode(decoder)),
         );
         mir::Place { local, projection }
@@ -263,16 +263,16 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for mir::Place<'tcx> {
 
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Region<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.interner().mk_region(Decodable::decode(decoder))
+        decoder.interner().mk_region_from_kind(Decodable::decode(decoder))
     }
 }
 
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for CanonicalVarInfos<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let len = decoder.read_usize();
-        let interned: Vec<CanonicalVarInfo<'tcx>> =
-            (0..len).map(|_| Decodable::decode(decoder)).collect();
-        decoder.interner().intern_canonical_var_infos(interned.as_slice())
+        decoder.interner().mk_canonical_var_infos_from_iter(
+            (0..len).map::<CanonicalVarInfo<'tcx>, _>(|_| Decodable::decode(decoder)),
+        )
     }
 }
 
@@ -310,7 +310,9 @@ macro_rules! impl_decodable_via_ref {
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder.interner().mk_type_list((0..len).map::<Ty<'tcx>, _>(|_| Decodable::decode(decoder)))
+        decoder
+            .interner()
+            .mk_type_list_from_iter((0..len).map::<Ty<'tcx>, _>(|_| Decodable::decode(decoder)))
     }
 }
 
@@ -319,7 +321,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
 {
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder.interner().mk_poly_existential_predicates(
+        decoder.interner().mk_poly_existential_predicates_from_iter(
             (0..len).map::<ty::Binder<'tcx, _>, _>(|_| Decodable::decode(decoder)),
         )
     }
@@ -342,13 +344,13 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTre
 
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ConstAllocation<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.interner().intern_const_alloc(Decodable::decode(decoder))
+        decoder.interner().mk_const_alloc(Decodable::decode(decoder))
     }
 }
 
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AdtDef<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.interner().intern_adt_def(Decodable::decode(decoder))
+        decoder.interner().mk_adt_def_from_data(Decodable::decode(decoder))
     }
 }
 
@@ -375,7 +377,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
 {
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder.interner().mk_bound_variable_kinds(
+        decoder.interner().mk_bound_variable_kinds_from_iter(
             (0..len).map::<ty::BoundVariableKind, _>(|_| Decodable::decode(decoder)),
         )
     }
@@ -384,18 +386,18 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Const<'tcx>> {
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder
-            .interner()
-            .mk_const_list((0..len).map::<ty::Const<'tcx>, _>(|_| Decodable::decode(decoder)))
+        decoder.interner().mk_const_list_from_iter(
+            (0..len).map::<ty::Const<'tcx>, _>(|_| Decodable::decode(decoder)),
+        )
     }
 }
 
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Predicate<'tcx>> {
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        let predicates: Vec<_> =
-            (0..len).map::<ty::Predicate<'tcx>, _>(|_| Decodable::decode(decoder)).collect();
-        decoder.interner().intern_predicates(&predicates)
+        decoder.interner().mk_predicates_from_iter(
+            (0..len).map::<ty::Predicate<'tcx>, _>(|_| Decodable::decode(decoder)),
+        )
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index f347604a2cd..0333198c203 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -6,7 +6,7 @@ pub mod tls;
 
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
-use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
+use crate::infer::canonical::CanonicalVarInfo;
 use crate::lint::struct_lint_level;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
 use crate::middle::resolve_bound_vars;
@@ -177,7 +177,7 @@ impl<'tcx> CtxtInterners<'tcx> {
         }
     }
 
-    /// Interns a type.
+    /// Interns a type. (Use `mk_*` functions instead, where possible.)
     #[allow(rustc::usage_of_ty_tykind)]
     #[inline(never)]
     fn intern_ty(&self, kind: TyKind<'tcx>, sess: &Session, untracked: &Untracked) -> Ty<'tcx> {
@@ -217,6 +217,7 @@ impl<'tcx> CtxtInterners<'tcx> {
         }
     }
 
+    /// Interns a predicate. (Use `mk_predicate` instead, where possible.)
     #[inline(never)]
     fn intern_predicate(
         &self,
@@ -615,21 +616,21 @@ impl<'tcx> TyCtxt<'tcx> {
         self.arena.alloc(Steal::new(promoted))
     }
 
-    pub fn alloc_adt_def(
+    pub fn mk_adt_def(
         self,
         did: DefId,
         kind: AdtKind,
         variants: IndexVec<VariantIdx, ty::VariantDef>,
         repr: ReprOptions,
     ) -> ty::AdtDef<'tcx> {
-        self.intern_adt_def(ty::AdtDefData::new(self, did, kind, variants, repr))
+        self.mk_adt_def_from_data(ty::AdtDefData::new(self, did, kind, variants, repr))
     }
 
     /// Allocates a read-only byte or string literal for `mir::interpret`.
     pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
         // Create an allocation that just contains these bytes.
         let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes);
-        let alloc = self.intern_const_alloc(alloc);
+        let alloc = self.mk_const_alloc(alloc);
         self.create_memory_alloc(alloc)
     }
 
@@ -718,13 +719,13 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed`
     #[track_caller]
-    pub fn ty_error_with_guaranteed(self, reported: ErrorGuaranteed) -> Ty<'tcx> {
-        self.mk_ty(Error(reported))
+    pub fn ty_error(self, reported: ErrorGuaranteed) -> Ty<'tcx> {
+        self.mk_ty_from_kind(Error(reported))
     }
 
     /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
     #[track_caller]
-    pub fn ty_error(self) -> Ty<'tcx> {
+    pub fn ty_error_misc(self) -> Ty<'tcx> {
         self.ty_error_with_message(DUMMY_SP, "TyKind::Error constructed but no error reported")
     }
 
@@ -733,7 +734,7 @@ impl<'tcx> TyCtxt<'tcx> {
     #[track_caller]
     pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> {
         let reported = self.sess.delay_span_bug(span, msg);
-        self.mk_ty(Error(reported))
+        self.mk_ty_from_kind(Error(reported))
     }
 
     /// Constructs a `RegionKind::ReError` lifetime.
@@ -1011,6 +1012,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
+    #[inline]
     pub fn cstore_untracked(self) -> MappedReadGuard<'tcx, CrateStoreDyn> {
         ReadGuard::map(self.untracked.cstore.read(), |c| &**c)
     }
@@ -1194,7 +1196,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self.mk_imm_ref(
             self.lifetimes.re_static,
             self.type_of(self.require_lang_item(LangItem::PanicLocation, None))
-                .subst(self, self.intern_substs(&[self.lifetimes.re_static.into()])),
+                .subst(self, self.mk_substs(&[self.lifetimes.re_static.into()])),
         )
     }
 
@@ -1276,7 +1278,7 @@ macro_rules! nop_lift {
 
 // Can't use the macros as we have reuse the `substs` here.
 //
-// See `intern_type_list` for more info.
+// See `mk_type_list` for more info.
 impl<'a, 'tcx> Lift<'tcx> for &'a List<Ty<'a>> {
     type Lifted = &'tcx List<Ty<'tcx>>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -1517,7 +1519,7 @@ impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, List<T>> {
 }
 
 macro_rules! direct_interners {
-    ($($name:ident: $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => {
+    ($($name:ident: $vis:vis $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => {
         $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
             fn borrow<'a>(&'a self) -> &'a $ty {
                 &self.0
@@ -1543,7 +1545,7 @@ macro_rules! direct_interners {
         }
 
         impl<'tcx> TyCtxt<'tcx> {
-            pub fn $method(self, v: $ty) -> $ret_ty {
+            $vis fn $method(self, v: $ty) -> $ret_ty {
                 $ret_ctor(Interned::new_unchecked(self.interners.$name.intern(v, |v| {
                     InternedInSet(self.interners.arena.alloc(v))
                 }).0))
@@ -1552,37 +1554,47 @@ macro_rules! direct_interners {
     }
 }
 
+// Functions with a `mk_` prefix are intended for use outside this file and
+// crate. Functions with an `intern_` prefix are intended for use within this
+// file only, and have a corresponding `mk_` function.
 direct_interners! {
     region: intern_region(RegionKind<'tcx>): Region -> Region<'tcx>,
-    const_: mk_const_internal(ConstData<'tcx>): Const -> Const<'tcx>,
-    const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
-    layout: intern_layout(LayoutS): Layout -> Layout<'tcx>,
-    adt_def: intern_adt_def(AdtDefData): AdtDef -> AdtDef<'tcx>,
-    external_constraints: intern_external_constraints(ExternalConstraintsData<'tcx>): ExternalConstraints -> ExternalConstraints<'tcx>,
+    const_: intern_const(ConstData<'tcx>): Const -> Const<'tcx>,
+    const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
+    layout: pub mk_layout(LayoutS): Layout -> Layout<'tcx>,
+    adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
+    external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>):
+        ExternalConstraints -> ExternalConstraints<'tcx>,
 }
 
 macro_rules! slice_interners {
-    ($($field:ident: $method:ident($ty:ty)),+ $(,)?) => (
+    ($($field:ident: $vis:vis $method:ident($ty:ty)),+ $(,)?) => (
         impl<'tcx> TyCtxt<'tcx> {
-            $(pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
-                self.interners.$field.intern_ref(v, || {
-                    InternedInSet(List::from_arena(&*self.arena, v))
-                }).0
+            $($vis fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
+                if v.is_empty() {
+                    List::empty()
+                } else {
+                    self.interners.$field.intern_ref(v, || {
+                        InternedInSet(List::from_arena(&*self.arena, v))
+                    }).0
+                }
             })+
         }
     );
 }
 
+// These functions intern slices. They all have a corresponding
+// `mk_foo_from_iter` function that interns an iterator. The slice version
+// should be used when possible, because it's faster.
 slice_interners!(
-    const_lists: _intern_const_list(Const<'tcx>),
-    substs: _intern_substs(GenericArg<'tcx>),
-    canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo<'tcx>),
-    poly_existential_predicates:
-        _intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
-    predicates: _intern_predicates(Predicate<'tcx>),
-    projs: _intern_projs(ProjectionKind),
-    place_elems: _intern_place_elems(PlaceElem<'tcx>),
-    bound_variable_kinds: _intern_bound_variable_kinds(ty::BoundVariableKind),
+    const_lists: pub mk_const_list(Const<'tcx>),
+    substs: pub mk_substs(GenericArg<'tcx>),
+    canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>),
+    poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
+    predicates: intern_predicates(Predicate<'tcx>),
+    projs: pub mk_projs(ProjectionKind),
+    place_elems: pub mk_place_elems(PlaceElem<'tcx>),
+    bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
 );
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -1670,7 +1682,7 @@ impl<'tcx> TyCtxt<'tcx> {
     // Avoid this in favour of more specific `mk_*` methods, where possible.
     #[allow(rustc::usage_of_ty_tykind)]
     #[inline]
-    pub fn mk_ty(self, st: TyKind<'tcx>) -> Ty<'tcx> {
+    pub fn mk_ty_from_kind(self, st: TyKind<'tcx>) -> Ty<'tcx> {
         self.interners.intern_ty(
             st,
             self.sess,
@@ -1735,12 +1747,12 @@ impl<'tcx> TyCtxt<'tcx> {
     #[inline]
     pub fn mk_adt(self, def: AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
         // Take a copy of substs so that we own the vectors inside.
-        self.mk_ty(Adt(def, substs))
+        self.mk_ty_from_kind(Adt(def, substs))
     }
 
     #[inline]
     pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> {
-        self.mk_ty(Foreign(def_id))
+        self.mk_ty_from_kind(Foreign(def_id))
     }
 
     fn mk_generic_adt(self, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> {
@@ -1757,7 +1769,7 @@ impl<'tcx> TyCtxt<'tcx> {
                     }
                 }
             });
-        self.mk_ty(Adt(adt_def, substs))
+        self.mk_ty_from_kind(Adt(adt_def, substs))
     }
 
     #[inline]
@@ -1786,12 +1798,12 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(RawPtr(tm))
+        self.mk_ty_from_kind(RawPtr(tm))
     }
 
     #[inline]
     pub fn mk_ref(self, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(Ref(r, tm.ty, tm.mutbl))
+        self.mk_ty_from_kind(Ref(r, tm.ty, tm.mutbl))
     }
 
     #[inline]
@@ -1816,30 +1828,34 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
-        self.mk_ty(Array(ty, ty::Const::from_target_usize(self, n)))
+        self.mk_ty_from_kind(Array(ty, ty::Const::from_target_usize(self, n)))
     }
 
     #[inline]
     pub fn mk_array_with_const_len(self, ty: Ty<'tcx>, ct: Const<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(Array(ty, ct))
+        self.mk_ty_from_kind(Array(ty, ct))
     }
 
     #[inline]
     pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(Slice(ty))
+        self.mk_ty_from_kind(Slice(ty))
     }
 
     #[inline]
-    pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
-        if ts.is_empty() { self.types.unit } else { self.mk_ty(Tuple(self.intern_type_list(&ts))) }
+    pub fn mk_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
+        if ts.is_empty() {
+            self.types.unit
+        } else {
+            self.mk_ty_from_kind(Tuple(self.mk_type_list(&ts)))
+        }
     }
 
-    pub fn mk_tup<I, T>(self, iter: I) -> T::Output
+    pub fn mk_tup_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
         T: CollectAndApply<Ty<'tcx>, Ty<'tcx>>,
     {
-        T::collect_and_apply(iter, |ts| self.intern_tup(ts))
+        T::collect_and_apply(iter, |ts| self.mk_tup(ts))
     }
 
     #[inline]
@@ -1856,17 +1872,17 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn mk_fn_def(
         self,
         def_id: DefId,
-        substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+        substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
     ) -> Ty<'tcx> {
-        let substs = self.check_substs(def_id, substs);
-        self.mk_ty(FnDef(def_id, substs))
+        let substs = self.check_and_mk_substs(def_id, substs);
+        self.mk_ty_from_kind(FnDef(def_id, substs))
     }
 
     #[inline(always)]
-    fn check_substs(
+    fn check_and_mk_substs(
         self,
         _def_id: DefId,
-        substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+        substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
     ) -> SubstsRef<'tcx> {
         let substs = substs.into_iter().map(Into::into);
         #[cfg(debug_assertions)]
@@ -1879,12 +1895,12 @@ impl<'tcx> TyCtxt<'tcx> {
                 substs.collect::<Vec<_>>(),
             );
         }
-        self.mk_substs(substs)
+        self.mk_substs_from_iter(substs)
     }
 
     #[inline]
     pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(FnPtr(fty))
+        self.mk_ty_from_kind(FnPtr(fty))
     }
 
     #[inline]
@@ -1894,21 +1910,21 @@ impl<'tcx> TyCtxt<'tcx> {
         reg: ty::Region<'tcx>,
         repr: DynKind,
     ) -> Ty<'tcx> {
-        self.mk_ty(Dynamic(obj, reg, repr))
+        self.mk_ty_from_kind(Dynamic(obj, reg, repr))
     }
 
     #[inline]
     pub fn mk_projection(
         self,
         item_def_id: DefId,
-        substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+        substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
     ) -> Ty<'tcx> {
         self.mk_alias(ty::Projection, self.mk_alias_ty(item_def_id, substs))
     }
 
     #[inline]
     pub fn mk_closure(self, closure_id: DefId, closure_substs: SubstsRef<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(Closure(closure_id, closure_substs))
+        self.mk_ty_from_kind(Closure(closure_id, closure_substs))
     }
 
     #[inline]
@@ -1918,47 +1934,51 @@ impl<'tcx> TyCtxt<'tcx> {
         generator_substs: SubstsRef<'tcx>,
         movability: hir::Movability,
     ) -> Ty<'tcx> {
-        self.mk_ty(Generator(id, generator_substs, movability))
+        self.mk_ty_from_kind(Generator(id, generator_substs, movability))
     }
 
     #[inline]
     pub fn mk_generator_witness(self, types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>) -> Ty<'tcx> {
-        self.mk_ty(GeneratorWitness(types))
+        self.mk_ty_from_kind(GeneratorWitness(types))
     }
 
     /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes.
     pub fn mk_task_context(self) -> Ty<'tcx> {
         let context_did = self.require_lang_item(LangItem::Context, None);
         let context_adt_ref = self.adt_def(context_did);
-        let context_substs = self.intern_substs(&[self.lifetimes.re_erased.into()]);
+        let context_substs = self.mk_substs(&[self.lifetimes.re_erased.into()]);
         let context_ty = self.mk_adt(context_adt_ref, context_substs);
         self.mk_mut_ref(self.lifetimes.re_erased, context_ty)
     }
 
     #[inline]
     pub fn mk_generator_witness_mir(self, id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(GeneratorWitnessMIR(id, substs))
+        self.mk_ty_from_kind(GeneratorWitnessMIR(id, substs))
     }
 
     #[inline]
     pub fn mk_const(self, kind: impl Into<ty::ConstKind<'tcx>>, ty: Ty<'tcx>) -> Const<'tcx> {
-        self.mk_const_internal(ty::ConstData { kind: kind.into(), ty })
+        self.intern_const(ty::ConstData { kind: kind.into(), ty })
     }
 
     #[inline]
     pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> {
         // Use a pre-interned one when possible.
-        self.types.ty_vars.get(v.as_usize()).copied().unwrap_or_else(|| self.mk_ty(Infer(TyVar(v))))
+        self.types
+            .ty_vars
+            .get(v.as_usize())
+            .copied()
+            .unwrap_or_else(|| self.mk_ty_from_kind(Infer(TyVar(v))))
     }
 
     #[inline]
     pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> {
-        self.mk_ty(Infer(IntVar(v)))
+        self.mk_ty_from_kind(Infer(IntVar(v)))
     }
 
     #[inline]
     pub fn mk_float_var(self, v: FloatVid) -> Ty<'tcx> {
-        self.mk_ty(Infer(FloatVar(v)))
+        self.mk_ty_from_kind(Infer(FloatVar(v)))
     }
 
     #[inline]
@@ -1968,7 +1988,7 @@ impl<'tcx> TyCtxt<'tcx> {
             .fresh_tys
             .get(n as usize)
             .copied()
-            .unwrap_or_else(|| self.mk_ty(Infer(ty::FreshTy(n))))
+            .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshTy(n))))
     }
 
     #[inline]
@@ -1978,7 +1998,7 @@ impl<'tcx> TyCtxt<'tcx> {
             .fresh_int_tys
             .get(n as usize)
             .copied()
-            .unwrap_or_else(|| self.mk_ty(Infer(ty::FreshIntTy(n))))
+            .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshIntTy(n))))
     }
 
     #[inline]
@@ -1988,12 +2008,12 @@ impl<'tcx> TyCtxt<'tcx> {
             .fresh_float_tys
             .get(n as usize)
             .copied()
-            .unwrap_or_else(|| self.mk_ty(Infer(ty::FreshFloatTy(n))))
+            .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshFloatTy(n))))
     }
 
     #[inline]
     pub fn mk_ty_param(self, index: u32, name: Symbol) -> Ty<'tcx> {
-        self.mk_ty(Param(ParamTy { index, name }))
+        self.mk_ty_from_kind(Param(ParamTy { index, name }))
     }
 
     pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
@@ -2015,17 +2035,17 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn mk_bound(self, index: ty::DebruijnIndex, bound_ty: ty::BoundTy) -> Ty<'tcx> {
-        self.mk_ty(Bound(index, bound_ty))
+        self.mk_ty_from_kind(Bound(index, bound_ty))
     }
 
     #[inline]
     pub fn mk_placeholder(self, placeholder: ty::PlaceholderType) -> Ty<'tcx> {
-        self.mk_ty(Placeholder(placeholder))
+        self.mk_ty_from_kind(Placeholder(placeholder))
     }
 
     #[inline]
     pub fn mk_alias(self, kind: ty::AliasKind, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(Alias(kind, alias_ty))
+        self.mk_ty_from_kind(Alias(kind, alias_ty))
     }
 
     #[inline]
@@ -2078,7 +2098,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     // Avoid this in favour of more specific `mk_re_*` methods, where possible,
     // to avoid the cost of the `match`.
-    pub fn mk_region(self, kind: ty::RegionKind<'tcx>) -> Region<'tcx> {
+    pub fn mk_region_from_kind(self, kind: ty::RegionKind<'tcx>) -> Region<'tcx> {
         match kind {
             ty::ReEarlyBound(region) => self.mk_re_early_bound(region),
             ty::ReLateBound(debruijn, region) => self.mk_re_late_bound(debruijn, region),
@@ -2132,10 +2152,10 @@ impl<'tcx> TyCtxt<'tcx> {
         let mut projection = place.projection.to_vec();
         projection.push(elem);
 
-        Place { local: place.local, projection: self.intern_place_elems(&projection) }
+        Place { local: place.local, projection: self.mk_place_elems(&projection) }
     }
 
-    pub fn intern_poly_existential_predicates(
+    pub fn mk_poly_existential_predicates(
         self,
         eps: &[PolyExistentialPredicate<'tcx>],
     ) -> &'tcx List<PolyExistentialPredicate<'tcx>> {
@@ -2145,80 +2165,40 @@ impl<'tcx> TyCtxt<'tcx> {
                 .all(|[a, b]| a.skip_binder().stable_cmp(self, &b.skip_binder())
                     != Ordering::Greater)
         );
-        self._intern_poly_existential_predicates(eps)
+        self.intern_poly_existential_predicates(eps)
     }
 
-    pub fn intern_predicates(self, preds: &[Predicate<'tcx>]) -> &'tcx List<Predicate<'tcx>> {
+    pub fn mk_predicates(self, preds: &[Predicate<'tcx>]) -> &'tcx List<Predicate<'tcx>> {
         // FIXME consider asking the input slice to be sorted to avoid
         // re-interning permutations, in which case that would be asserted
         // here.
-        if preds.is_empty() {
-            // The macro-generated method below asserts we don't intern an empty slice.
-            List::empty()
-        } else {
-            self._intern_predicates(preds)
-        }
+        self.intern_predicates(preds)
     }
 
-    pub fn mk_const_list<I, T>(self, iter: I) -> T::Output
+    pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
         T: CollectAndApply<ty::Const<'tcx>, &'tcx List<ty::Const<'tcx>>>,
     {
-        T::collect_and_apply(iter, |xs| self.intern_const_list(xs))
-    }
-
-    pub fn intern_const_list(self, cs: &[ty::Const<'tcx>]) -> &'tcx List<ty::Const<'tcx>> {
-        if cs.is_empty() { List::empty() } else { self._intern_const_list(cs) }
-    }
-
-    pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx List<Ty<'tcx>> {
-        if ts.is_empty() {
-            List::empty()
-        } else {
-            // Actually intern type lists as lists of `GenericArg`s.
-            //
-            // Transmuting from `Ty<'tcx>` to `GenericArg<'tcx>` is sound
-            // as explained in ty_slice_as_generic_arg`. With this,
-            // we guarantee that even when transmuting between `List<Ty<'tcx>>`
-            // and `List<GenericArg<'tcx>>`, the uniqueness requirement for
-            // lists is upheld.
-            let substs = self._intern_substs(ty::subst::ty_slice_as_generic_args(ts));
-            substs.try_as_type_list().unwrap()
-        }
+        T::collect_and_apply(iter, |xs| self.mk_const_list(xs))
     }
 
-    pub fn intern_substs(self, ts: &[GenericArg<'tcx>]) -> &'tcx List<GenericArg<'tcx>> {
-        if ts.is_empty() { List::empty() } else { self._intern_substs(ts) }
-    }
-
-    pub fn intern_projs(self, ps: &[ProjectionKind]) -> &'tcx List<ProjectionKind> {
-        if ps.is_empty() { List::empty() } else { self._intern_projs(ps) }
-    }
-
-    pub fn intern_place_elems(self, ts: &[PlaceElem<'tcx>]) -> &'tcx List<PlaceElem<'tcx>> {
-        if ts.is_empty() { List::empty() } else { self._intern_place_elems(ts) }
-    }
-
-    pub fn intern_canonical_var_infos(
-        self,
-        ts: &[CanonicalVarInfo<'tcx>],
-    ) -> CanonicalVarInfos<'tcx> {
-        if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) }
-    }
-
-    pub fn intern_bound_variable_kinds(
-        self,
-        ts: &[ty::BoundVariableKind],
-    ) -> &'tcx List<ty::BoundVariableKind> {
-        if ts.is_empty() { List::empty() } else { self._intern_bound_variable_kinds(ts) }
-    }
-
-    // Unlike various other `mk_*` functions, this one uses `I: IntoIterator`
-    // instead of `I: Iterator`. Unlike those other functions, this one doesn't
-    // have a `intern_fn_sig` variant that can be used for cases where `I` is
-    // something like a `Vec`. That's because of the need to combine `inputs`
-    // and `output`.
+    pub fn mk_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx List<Ty<'tcx>> {
+        // Actually intern type lists as lists of `GenericArg`s.
+        //
+        // Transmuting from `Ty<'tcx>` to `GenericArg<'tcx>` is sound
+        // as explained in ty_slice_as_generic_arg`. With this,
+        // we guarantee that even when transmuting between `List<Ty<'tcx>>`
+        // and `List<GenericArg<'tcx>>`, the uniqueness requirement for
+        // lists is upheld.
+        let substs = self.mk_substs(ty::subst::ty_slice_as_generic_args(ts));
+        substs.try_as_type_list().unwrap()
+    }
+
+    // Unlike various other `mk_*_from_iter` functions, this one uses `I:
+    // IntoIterator` instead of `I: Iterator`, and it doesn't have a slice
+    // variant, because of the need to combine `inputs` and `output`. This
+    // explains the lack of `_from_iter` suffix.
     pub fn mk_fn_sig<I, T>(
         self,
         inputs: I,
@@ -2232,14 +2212,14 @@ impl<'tcx> TyCtxt<'tcx> {
         T: CollectAndApply<Ty<'tcx>, ty::FnSig<'tcx>>,
     {
         T::collect_and_apply(inputs.into_iter().chain(iter::once(output)), |xs| ty::FnSig {
-            inputs_and_output: self.intern_type_list(xs),
+            inputs_and_output: self.mk_type_list(xs),
             c_variadic,
             unsafety,
             abi,
         })
     }
 
-    pub fn mk_poly_existential_predicates<I, T>(self, iter: I) -> T::Output
+    pub fn mk_poly_existential_predicates_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
         T: CollectAndApply<
@@ -2247,39 +2227,47 @@ impl<'tcx> TyCtxt<'tcx> {
                 &'tcx List<PolyExistentialPredicate<'tcx>>,
             >,
     {
-        T::collect_and_apply(iter, |xs| self.intern_poly_existential_predicates(xs))
+        T::collect_and_apply(iter, |xs| self.mk_poly_existential_predicates(xs))
     }
 
-    pub fn mk_predicates<I, T>(self, iter: I) -> T::Output
+    pub fn mk_predicates_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
         T: CollectAndApply<Predicate<'tcx>, &'tcx List<Predicate<'tcx>>>,
     {
-        T::collect_and_apply(iter, |xs| self.intern_predicates(xs))
+        T::collect_and_apply(iter, |xs| self.mk_predicates(xs))
     }
 
-    pub fn mk_type_list<I, T>(self, iter: I) -> T::Output
+    pub fn mk_type_list_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
         T: CollectAndApply<Ty<'tcx>, &'tcx List<Ty<'tcx>>>,
     {
-        T::collect_and_apply(iter, |xs| self.intern_type_list(xs))
+        T::collect_and_apply(iter, |xs| self.mk_type_list(xs))
     }
 
-    pub fn mk_substs<I, T>(self, iter: I) -> T::Output
+    pub fn mk_substs_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
         T: CollectAndApply<GenericArg<'tcx>, &'tcx List<GenericArg<'tcx>>>,
     {
-        T::collect_and_apply(iter, |xs| self.intern_substs(xs))
+        T::collect_and_apply(iter, |xs| self.mk_substs(xs))
+    }
+
+    pub fn mk_canonical_var_infos_from_iter<I, T>(self, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: CollectAndApply<CanonicalVarInfo<'tcx>, &'tcx List<CanonicalVarInfo<'tcx>>>,
+    {
+        T::collect_and_apply(iter, |xs| self.mk_canonical_var_infos(xs))
     }
 
-    pub fn mk_place_elems<I, T>(self, iter: I) -> T::Output
+    pub fn mk_place_elems_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
         T: CollectAndApply<PlaceElem<'tcx>, &'tcx List<PlaceElem<'tcx>>>,
     {
-        T::collect_and_apply(iter, |xs| self.intern_place_elems(xs))
+        T::collect_and_apply(iter, |xs| self.mk_place_elems(xs))
     }
 
     pub fn mk_substs_trait(
@@ -2287,33 +2275,33 @@ impl<'tcx> TyCtxt<'tcx> {
         self_ty: Ty<'tcx>,
         rest: impl IntoIterator<Item = GenericArg<'tcx>>,
     ) -> SubstsRef<'tcx> {
-        self.mk_substs(iter::once(self_ty.into()).chain(rest))
+        self.mk_substs_from_iter(iter::once(self_ty.into()).chain(rest))
     }
 
     pub fn mk_trait_ref(
         self,
         trait_def_id: DefId,
-        substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+        substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
     ) -> ty::TraitRef<'tcx> {
-        let substs = self.check_substs(trait_def_id, substs);
+        let substs = self.check_and_mk_substs(trait_def_id, substs);
         ty::TraitRef { def_id: trait_def_id, substs, _use_mk_trait_ref_instead: () }
     }
 
     pub fn mk_alias_ty(
         self,
         def_id: DefId,
-        substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+        substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
     ) -> ty::AliasTy<'tcx> {
-        let substs = self.check_substs(def_id, substs);
+        let substs = self.check_and_mk_substs(def_id, substs);
         ty::AliasTy { def_id, substs, _use_mk_alias_ty_instead: () }
     }
 
-    pub fn mk_bound_variable_kinds<I, T>(self, iter: I) -> T::Output
+    pub fn mk_bound_variable_kinds_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
         T: CollectAndApply<ty::BoundVariableKind, &'tcx List<ty::BoundVariableKind>>,
     {
-        T::collect_and_apply(iter, |xs| self.intern_bound_variable_kinds(xs))
+        T::collect_and_apply(iter, |xs| self.mk_bound_variable_kinds(xs))
     }
 
     /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`,
@@ -2398,7 +2386,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
-        self.intern_bound_variable_kinds(
+        self.mk_bound_variable_kinds(
             &self
                 .late_bound_vars_map(id.owner)
                 .and_then(|map| map.get(&id.local_id).cloned())
@@ -2458,7 +2446,7 @@ impl<'tcx> TyCtxt<'tcx> {
 impl<'tcx> TyCtxtAt<'tcx> {
     /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
     #[track_caller]
-    pub fn ty_error(self) -> Ty<'tcx> {
+    pub fn ty_error_misc(self) -> Ty<'tcx> {
         self.tcx.ty_error_with_message(self.span, "TyKind::Error constructed but no error reported")
     }
 
@@ -2472,7 +2460,7 @@ impl<'tcx> TyCtxtAt<'tcx> {
     pub fn mk_trait_ref(
         self,
         trait_lang_item: LangItem,
-        substs: impl IntoIterator<Item = impl Into<ty::GenericArg<'tcx>>>,
+        substs: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
     ) -> ty::TraitRef<'tcx> {
         let trait_def_id = self.require_lang_item(trait_lang_item, Some(self.span));
         self.tcx.mk_trait_ref(trait_def_id, substs)
@@ -2499,8 +2487,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
     providers.maybe_unused_trait_imports =
         |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
-    providers.maybe_unused_extern_crates =
-        |tcx, ()| &tcx.resolutions(()).maybe_unused_extern_crates[..];
     providers.names_imported_by_glob_use = |tcx, id| {
         tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default())
     };
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index e8a73832ce4..d66f436f947 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -422,7 +422,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let mut map = Default::default();
         let delegate = Anonymize { tcx: self, map: &mut map };
         let inner = self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate);
-        let bound_vars = self.mk_bound_variable_kinds(map.into_values());
+        let bound_vars = self.mk_bound_variable_kinds_from_iter(map.into_values());
         Binder::bind_with_vars(inner, bound_vars)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 35c036fef2d..baef4ffeda7 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -101,7 +101,7 @@ impl GenericParamDef {
     ) -> ty::GenericArg<'tcx> {
         match &self.kind {
             ty::GenericParamDefKind::Lifetime => tcx.mk_re_error_misc().into(),
-            ty::GenericParamDefKind::Type { .. } => tcx.ty_error().into(),
+            ty::GenericParamDefKind::Type { .. } => tcx.ty_error_misc().into(),
             ty::GenericParamDefKind::Const { .. } => {
                 tcx.const_error(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into()
             }
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index 3e59c0b967c..4c7822acdf7 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -79,7 +79,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::subst::GenericArgKin
             // WARNING: We dedup cache the `HashStable` results for `List`
             // while ignoring types and freely transmute
             // between `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>`.
-            // See `fn intern_type_list` for more details.
+            // See `fn mk_type_list` for more details.
             //
             // We therefore hash types without adding a hash for their discriminant.
             //
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index d07fa0e546f..f4028a5a9f6 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -540,7 +540,7 @@ impl<'tcx> Instance<'tcx> {
 
     pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
         let def_id = tcx.require_lang_item(LangItem::DropInPlace, None);
-        let substs = tcx.intern_substs(&[ty.into()]);
+        let substs = tcx.mk_substs(&[ty.into()]);
         Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs)
     }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 146803df02b..f0b52455889 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -169,6 +169,23 @@ pub const FAT_PTR_EXTRA: usize = 1;
 /// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
 pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
 
+/// Used in `might_permit_raw_init` to indicate the kind of initialisation
+/// that is checked to be valid
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+pub enum InitKind {
+    Zero,
+    UninitMitigated0x01Fill,
+}
+
+impl fmt::Display for InitKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Zero => f.write_str("zeroed"),
+            Self::UninitMitigated0x01Fill => f.write_str("filled with 0x01"),
+        }
+    }
+}
+
 #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
 pub enum LayoutError<'tcx> {
     Unknown(Ty<'tcx>),
@@ -596,7 +613,7 @@ where
                     ty::Adt(def, _) => def.variant(variant_index).fields.len(),
                     _ => bug!(),
                 };
-                tcx.intern_layout(LayoutS {
+                tcx.mk_layout(LayoutS {
                     variants: Variants::Single { index: variant_index },
                     fields: match NonZeroUsize::new(fields) {
                         Some(fields) => FieldsShape::Union(fields),
@@ -609,7 +626,7 @@ where
                 })
             }
 
-            Variants::Multiple { ref variants, .. } => cx.tcx().intern_layout(variants[variant_index].clone()),
+            Variants::Multiple { ref variants, .. } => cx.tcx().mk_layout(variants[variant_index].clone()),
         };
 
         assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
@@ -631,7 +648,7 @@ where
             let tcx = cx.tcx();
             let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
                 TyAndLayout {
-                    layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
+                    layout: tcx.mk_layout(LayoutS::scalar(cx, tag)),
                     ty: tag.primitive().to_ty(tcx),
                 }
             };
@@ -687,7 +704,7 @@ where
                         Increase this counter if you tried to implement this but
                         failed to do it without duplicating a lot of code from
                         other places in the compiler: 2
-                        tcx.intern_tup(&[
+                        tcx.mk_tup(&[
                             tcx.mk_array(tcx.types.usize, 3),
                             tcx.mk_array(Option<fn()>),
                         ])
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 7dcc3ff4e7b..fc5757564a7 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -35,6 +35,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
@@ -72,7 +73,7 @@ pub use self::binding::BindingMode;
 pub use self::binding::BindingMode::*;
 pub use self::closure::{
     is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo,
-    CapturedPlace, ClosureKind, MinCaptureInformationMap, MinCaptureList,
+    CapturedPlace, ClosureKind, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList,
     RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath,
     CAPTURE_STRUCT_LOCAL,
 };
@@ -164,12 +165,8 @@ pub struct ResolverGlobalCtxt {
     pub effective_visibilities: EffectiveVisibilities,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
-    pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
     pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
     pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
-    /// Extern prelude entries. The value is `true` if the entry was introduced
-    /// via `extern crate` item and not `--extern` option or compiler built-in.
-    pub extern_prelude: FxHashMap<Symbol, bool>,
     pub main_def: Option<MainDefinition>,
     pub trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
     /// A list of proc macro LocalDefIds, written out in the order in which
@@ -756,7 +753,7 @@ impl<'tcx> Predicate<'tcx> {
         let new = EarlyBinder(shifted_pred).subst(tcx, trait_ref.skip_binder().substs);
         // 3) ['x] + ['b] -> ['x, 'b]
         let bound_vars =
-            tcx.mk_bound_variable_kinds(trait_bound_vars.iter().chain(pred_bound_vars));
+            tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars));
         tcx.reuse_or_mk_predicate(self, ty::Binder::bind_with_vars(new, bound_vars))
     }
 }
@@ -1358,7 +1355,7 @@ pub struct OpaqueHiddenType<'tcx> {
 }
 
 impl<'tcx> OpaqueHiddenType<'tcx> {
-    pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) {
+    pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) -> ErrorGuaranteed {
         // Found different concrete types for the opaque type.
         let sub_diag = if self.span == other.span {
             TypeMismatchReason::ConflictType { span: self.span }
@@ -1370,7 +1367,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
             other_ty: other.ty,
             other_span: other.span,
             sub: sub_diag,
-        });
+        })
     }
 
     #[instrument(level = "debug", skip(tcx), ret)]
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index 195bd8a3818..751f3066c9c 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -79,7 +79,7 @@ impl<'tcx> ReverseMapper<'tcx> {
         // during codegen.
 
         let generics = self.tcx.generics_of(def_id);
-        self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
+        self.tcx.mk_substs_from_iter(substs.iter().enumerate().map(|(index, kind)| {
             if index < generics.parent_count {
                 // Accommodate missing regions in the parent kinds...
                 self.fold_kind_no_missing_regions_error(kind)
@@ -186,7 +186,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                                 .emit();
                         }
 
-                        self.interner().ty_error()
+                        self.interner().ty_error_misc()
                     }
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 5b3f3870429..d743c306849 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -32,6 +32,7 @@ use crate::traits::specialization_graph;
 use crate::traits::{self, ImplSource};
 use crate::ty::context::TyCtxtFeed;
 use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::layout::InitKind;
 use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::GeneratorDiagnosticData;
@@ -328,8 +329,9 @@ macro_rules! define_callbacks {
 
                 Providers {
                     $($name: |_, key| bug!(
-                        "`tcx.{}({:?})` is not supported for {} crate;\n
-                        hint: Queries can be either made to the local crate, or the external crate. This error means you tried to use it for one that's not supported.\n
+                        "`tcx.{}({:?})` is not supported for {} crate;\n\
+                        hint: Queries can be either made to the local crate, or the external crate. \
+                        This error means you tried to use it for one that's not supported.\n\
                         If that's not the case, {} was likely never assigned to a provider function.\n",
                         stringify!($name),
                         key,
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 3dfa5e953b5..3fc5f5bed8f 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -144,7 +144,7 @@ pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>(
     a_subst: SubstsRef<'tcx>,
     b_subst: SubstsRef<'tcx>,
 ) -> RelateResult<'tcx, SubstsRef<'tcx>> {
-    relation.tcx().mk_substs(iter::zip(a_subst, b_subst).map(|(a, b)| {
+    relation.tcx().mk_substs_from_iter(iter::zip(a_subst, b_subst).map(|(a, b)| {
         relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)
     }))
 }
@@ -171,7 +171,7 @@ pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>(
         relation.relate_with_variance(variance, variance_info, a, b)
     });
 
-    tcx.mk_substs(params)
+    tcx.mk_substs_from_iter(params)
 }
 
 impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
@@ -222,7 +222,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
                 r => r,
             });
         Ok(ty::FnSig {
-            inputs_and_output: tcx.mk_type_list(inputs_and_output)?,
+            inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?,
             c_variadic: a.c_variadic,
             unsafety,
             abi,
@@ -352,7 +352,8 @@ impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> {
     ) -> RelateResult<'tcx, GeneratorWitness<'tcx>> {
         assert_eq!(a.0.len(), b.0.len());
         let tcx = relation.tcx();
-        let types = tcx.mk_type_list(iter::zip(a.0, b.0).map(|(a, b)| relation.relate(a, b)))?;
+        let types =
+            tcx.mk_type_list_from_iter(iter::zip(a.0, b.0).map(|(a, b)| relation.relate(a, b)))?;
         Ok(GeneratorWitness(types))
     }
 }
@@ -412,7 +413,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             bug!("bound types encountered in super_relate_tys")
         }
 
-        (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error_with_guaranteed(guar)),
+        (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error(guar)),
 
         (&ty::Never, _)
         | (&ty::Char, _)
@@ -528,7 +529,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
 
         (&ty::Tuple(as_), &ty::Tuple(bs)) => {
             if as_.len() == bs.len() {
-                Ok(tcx.mk_tup(iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)))?)
+                Ok(tcx.mk_tup_from_iter(iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)))?)
             } else if !(as_.is_empty() || bs.is_empty()) {
                 Err(TypeError::TupleSize(expected_found(relation, as_.len(), bs.len())))
             } else {
@@ -673,7 +674,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
                     for (a_arg, b_arg) in aa.iter().zip(ba.iter()) {
                         related_args.push(r.consts(a_arg, b_arg)?);
                     }
-                    let related_args = tcx.intern_const_list(&related_args);
+                    let related_args = tcx.mk_const_list(&related_args);
                     Expr::FunctionCall(func, related_args)
                 }
                 _ => return Err(TypeError::ConstMismatch(expected_found(r, a, b))),
@@ -720,7 +721,7 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
                 _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))),
             }
         });
-        tcx.mk_poly_existential_predicates(v)
+        tcx.mk_poly_existential_predicates_from_iter(v)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index fbe5d8ccff5..ef643531bb2 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -263,6 +263,7 @@ TrivialTypeTraversalAndLiftImpls! {
     crate::ty::UniverseIndex,
     crate::ty::Variance,
     ::rustc_span::Span,
+    ::rustc_span::symbol::Ident,
     ::rustc_errors::ErrorGuaranteed,
     Field,
     interpret::Scalar,
@@ -430,7 +431,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPred
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v))
+        ty::util::fold_list(self, folder, |tcx, v| tcx.mk_poly_existential_predicates(v))
     }
 }
 
@@ -439,7 +440,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Const<'tcx>> {
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_const_list(v))
+        ty::util::fold_list(self, folder, |tcx, v| tcx.mk_const_list(v))
     }
 }
 
@@ -448,7 +449,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ProjectionKind> {
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
+        ty::util::fold_list(self, folder, |tcx, v| tcx.mk_projs(v))
     }
 }
 
@@ -513,7 +514,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
             | ty::Foreign(..) => return Ok(self),
         };
 
-        Ok(if *self.kind() == kind { self } else { folder.interner().mk_ty(kind) })
+        Ok(if *self.kind() == kind { self } else { folder.interner().mk_ty_from_kind(kind) })
     }
 }
 
@@ -636,7 +637,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Predicate<'tcx>> {
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
+        ty::util::fold_list(self, folder, |tcx, v| tcx.mk_predicates(v))
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 7563656f91b..ba714541c9e 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -250,7 +250,7 @@ impl<'tcx> ClosureSubsts<'tcx> {
         parts: ClosureSubstsParts<'tcx, Ty<'tcx>>,
     ) -> ClosureSubsts<'tcx> {
         ClosureSubsts {
-            substs: tcx.mk_substs(
+            substs: tcx.mk_substs_from_iter(
                 parts.parent_substs.iter().copied().chain(
                     [parts.closure_kind_ty, parts.closure_sig_as_fn_ptr_ty, parts.tupled_upvars_ty]
                         .iter()
@@ -377,7 +377,7 @@ impl<'tcx> GeneratorSubsts<'tcx> {
         parts: GeneratorSubstsParts<'tcx, Ty<'tcx>>,
     ) -> GeneratorSubsts<'tcx> {
         GeneratorSubsts {
-            substs: tcx.mk_substs(
+            substs: tcx.mk_substs_from_iter(
                 parts.parent_substs.iter().copied().chain(
                     [
                         parts.resume_ty,
@@ -568,7 +568,7 @@ impl<'tcx> GeneratorSubsts<'tcx> {
         self,
         def_id: DefId,
         tcx: TyCtxt<'tcx>,
-    ) -> impl Iterator<Item = impl Iterator<Item = Ty<'tcx>> + Captures<'tcx>> {
+    ) -> impl Iterator<Item: Iterator<Item = Ty<'tcx>> + Captures<'tcx>> {
         let layout = tcx.generator_layout(def_id).unwrap();
         layout.variant_fields.iter().map(move |variant| {
             variant.iter().map(move |field| {
@@ -655,7 +655,7 @@ impl<'tcx> InlineConstSubsts<'tcx> {
         parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>,
     ) -> InlineConstSubsts<'tcx> {
         InlineConstSubsts {
-            substs: tcx.mk_substs(
+            substs: tcx.mk_substs_from_iter(
                 parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())),
             ),
         }
@@ -853,7 +853,7 @@ impl<'tcx> TraitRef<'tcx> {
         substs: SubstsRef<'tcx>,
     ) -> ty::TraitRef<'tcx> {
         let defs = tcx.generics_of(trait_id);
-        tcx.mk_trait_ref(trait_id, tcx.intern_substs(&substs[..defs.params.len()]))
+        tcx.mk_trait_ref(trait_id, tcx.mk_substs(&substs[..defs.params.len()]))
     }
 }
 
@@ -899,7 +899,7 @@ impl<'tcx> ExistentialTraitRef<'tcx> {
 
         ty::ExistentialTraitRef {
             def_id: trait_ref.def_id,
-            substs: tcx.intern_substs(&trait_ref.substs[1..]),
+            substs: tcx.mk_substs(&trait_ref.substs[1..]),
         }
     }
 
@@ -1551,7 +1551,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
     pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
         let def_id = tcx.parent(self.def_id);
         let subst_count = tcx.generics_of(def_id).count() - 1;
-        let substs = tcx.intern_substs(&self.substs[..subst_count]);
+        let substs = tcx.mk_substs(&self.substs[..subst_count]);
         ty::ExistentialTraitRef { def_id, substs }
     }
 
@@ -1579,7 +1579,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
 
         Self {
             def_id: projection_predicate.projection_ty.def_id,
-            substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
+            substs: tcx.mk_substs(&projection_predicate.projection_ty.substs[1..]),
             term: projection_predicate.term,
         }
     }
@@ -2209,7 +2209,7 @@ impl<'tcx> Ty<'tcx> {
                 let assoc_items = tcx.associated_item_def_ids(
                     tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
                 );
-                tcx.mk_projection(assoc_items[0], tcx.intern_substs(&[self.into()]))
+                tcx.mk_projection(assoc_items[0], tcx.mk_substs(&[self.into()]))
             }
 
             ty::Bool
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 1ed3ef5745b..b090bd9d807 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -71,7 +71,7 @@ impl<'tcx> List<Ty<'tcx>> {
     /// Allows to freely switch between `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>`.
     ///
     /// As lists are interned, `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>` have
-    /// be interned together, see `intern_type_list` for more details.
+    /// be interned together, see `mk_type_list` for more details.
     #[inline]
     pub fn as_substs(&'tcx self) -> SubstsRef<'tcx> {
         assert_eq!(TYPE_TAG, 0);
@@ -319,7 +319,7 @@ impl<'tcx> InternalSubsts<'tcx> {
         let count = defs.count();
         let mut substs = SmallVec::with_capacity(count);
         Self::fill_item(&mut substs, tcx, defs, &mut mk_kind);
-        tcx.intern_substs(&substs)
+        tcx.mk_substs(&substs)
     }
 
     pub fn extend_to<F>(&self, tcx: TyCtxt<'tcx>, def_id: DefId, mut mk_kind: F) -> SubstsRef<'tcx>
@@ -468,11 +468,11 @@ impl<'tcx> InternalSubsts<'tcx> {
         target_substs: SubstsRef<'tcx>,
     ) -> SubstsRef<'tcx> {
         let defs = tcx.generics_of(source_ancestor);
-        tcx.mk_substs(target_substs.iter().chain(self.iter().skip(defs.params.len())))
+        tcx.mk_substs_from_iter(target_substs.iter().chain(self.iter().skip(defs.params.len())))
     }
 
     pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> {
-        tcx.mk_substs(self.iter().take(generics.count()))
+        tcx.mk_substs_from_iter(self.iter().take(generics.count()))
     }
 }
 
@@ -486,14 +486,14 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for SubstsRef<'tcx> {
         // The match arms are in order of frequency. The 1, 2, and 0 cases are
         // typically hit in 90--99.99% of cases. When folding doesn't change
         // the substs, it's faster to reuse the existing substs rather than
-        // calling `intern_substs`.
+        // calling `mk_substs`.
         match self.len() {
             1 => {
                 let param0 = self[0].try_fold_with(folder)?;
                 if param0 == self[0] {
                     Ok(self)
                 } else {
-                    Ok(folder.interner().intern_substs(&[param0]))
+                    Ok(folder.interner().mk_substs(&[param0]))
                 }
             }
             2 => {
@@ -502,11 +502,11 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for SubstsRef<'tcx> {
                 if param0 == self[0] && param1 == self[1] {
                     Ok(self)
                 } else {
-                    Ok(folder.interner().intern_substs(&[param0, param1]))
+                    Ok(folder.interner().mk_substs(&[param0, param1]))
                 }
             }
             0 => Ok(self),
-            _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_substs(v)),
+            _ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_substs(v)),
         }
     }
 }
@@ -538,10 +538,10 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
                 if param0 == self[0] && param1 == self[1] {
                     Ok(self)
                 } else {
-                    Ok(folder.interner().intern_type_list(&[param0, param1]))
+                    Ok(folder.interner().mk_type_list(&[param0, param1]))
                 }
             }
-            _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v)),
+            _ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 9beaac87183..586958247fc 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -569,7 +569,7 @@ impl<'a, V> LocalTableInContext<'a, V> {
         self.data.contains_key(&id.local_id)
     }
 
-    pub fn get(&self, id: hir::HirId) -> Option<&V> {
+    pub fn get(&self, id: hir::HirId) -> Option<&'a V> {
         validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.data.get(&id.local_id)
     }
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index f77bd9f0c6f..b9b1cd73a8b 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -112,5 +112,5 @@ pub(super) fn vtable_allocation_provider<'tcx>(
     }
 
     vtable.mutability = Mutability::Not;
-    tcx.create_memory_alloc(tcx.intern_const_alloc(vtable))
+    tcx.create_memory_alloc(tcx.mk_const_alloc(vtable))
 }
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 21f3ef9267f..c4f526dbdc8 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -16,7 +16,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> {
     fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self {
         // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
-        unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
+        unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error_misc()) }
     }
 }
 
@@ -34,7 +34,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
 
 impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
     fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo<DepKind>]) -> Self {
-        let err = tcx.ty_error();
+        let err = tcx.ty_error_misc();
 
         let arity = if let Some(frame) = stack.get(0)
             && frame.query.dep_kind == DepKind::fn_sig
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 1d96893c7a3..2f63333d46b 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -132,14 +132,14 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
         (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
             let s = s.as_str();
             let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
-            let allocation = tcx.intern_const_alloc(allocation);
+            let allocation = tcx.mk_const_alloc(allocation);
             ConstValue::Slice { data: allocation, start: 0, end: s.len() }
         }
         (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _))
             if matches!(inner_ty.kind(), ty::Slice(_)) =>
         {
             let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
-            let allocation = tcx.intern_const_alloc(allocation);
+            let allocation = tcx.mk_const_alloc(allocation);
             ConstValue::Slice { data: allocation, start: 0, end: data.len() }
         }
         (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index c621efb3b3a..ff3198847df 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -170,7 +170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     // Return the operand *tmp0 to be used as the call argument
                     let place = Place {
                         local: operand,
-                        projection: tcx.intern_place_elems(&[PlaceElem::Deref]),
+                        projection: tcx.mk_place_elems(&[PlaceElem::Deref]),
                     };
 
                     return block.and(Operand::Move(place));
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index e22fa6365dc..eb20b2308c0 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -263,7 +263,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
         let resolved = self.resolve_upvar(cx);
         let builder = resolved.as_ref().unwrap_or(self);
         let PlaceBase::Local(local) = builder.base else { return None };
-        let projection = cx.tcx.intern_place_elems(&builder.projection);
+        let projection = cx.tcx.mk_place_elems(&builder.projection);
         Some(Place { local, projection })
     }
 
@@ -692,7 +692,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
                         let fake_borrow_temp =
                             self.local_decls.push(LocalDecl::new(fake_borrow_ty, expr_span));
-                        let projection = tcx.intern_place_elems(&base_place.projection[..idx]);
+                        let projection = tcx.mk_place_elems(&base_place.projection[..idx]);
                         self.cfg.push_assign(
                             block,
                             source_info,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index fb0e9181b52..a4e48c1545d 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -520,7 +520,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let source_info = self.source_info(span);
         let bool_ty = self.tcx.types.bool;
         if self.check_overflow && op.is_checkable() && ty.is_integral() {
-            let result_tup = self.tcx.intern_tup(&[ty, bool_ty]);
+            let result_tup = self.tcx.mk_tup(&[ty, bool_ty]);
             let result_value = self.temp(result_tup, span);
 
             self.cfg.push_assign(
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 6b960ebdb16..de2851a1af9 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1206,7 +1206,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                     fake_borrows.insert(Place {
                         local: source.local,
-                        projection: self.tcx.intern_place_elems(proj_base),
+                        projection: self.tcx.mk_place_elems(proj_base),
                     });
                 }
             }
@@ -1743,7 +1743,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             .map(|matched_place_ref| {
                 let matched_place = Place {
                     local: matched_place_ref.local,
-                    projection: tcx.intern_place_elems(matched_place_ref.projection),
+                    projection: tcx.mk_place_elems(matched_place_ref.projection),
                 };
                 let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
                 let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 8859f5002e4..2de89f67dfd 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -832,7 +832,7 @@ fn trait_method<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_def_id: DefId,
     method_name: Symbol,
-    substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+    substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
 ) -> ConstantKind<'tcx> {
     // The unhygienic comparison here is acceptable because this is only
     // used on known traits.
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 53bef1eb772..b3f9d82829f 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -20,7 +20,7 @@ use rustc_middle::mir::*;
 use rustc_middle::thir::{
     self, BindingMode, Expr, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir,
 };
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_span::Symbol;
@@ -47,8 +47,6 @@ pub(crate) fn mir_built(
 
 /// Construct the MIR for a given `DefId`.
 fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
-    let body_owner_kind = tcx.hir().body_owner_kind(def.did);
-
     // Ensure unsafeck and abstract const building is ran before we steal the THIR.
     // We can't use `ensure()` for `thir_abstract_const` as it doesn't compute the query
     // if inputs are green. This can cause ICEs when calling `thir_abstract_const` after
@@ -65,16 +63,15 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
     }
 
     let body = match tcx.thir_body(def) {
-        Err(error_reported) => construct_error(tcx, def.did, body_owner_kind, error_reported),
+        Err(error_reported) => construct_error(tcx, def.did, error_reported),
         Ok((thir, expr)) => {
             // We ran all queries that depended on THIR at the beginning
             // of `mir_build`, so now we can steal it
             let thir = thir.steal();
 
-            if body_owner_kind.is_fn_or_closure() {
-                construct_fn(tcx, def, &thir, expr)
-            } else {
-                construct_const(tcx, def, &thir, expr)
+            match thir.body_type {
+                thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig),
+                thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty),
             }
         }
     };
@@ -158,13 +155,13 @@ struct BlockContext(Vec<BlockFrame>);
 struct Builder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     infcx: InferCtxt<'tcx>,
-    typeck_results: &'tcx TypeckResults<'tcx>,
     region_scope_tree: &'tcx region::ScopeTree,
     param_env: ty::ParamEnv<'tcx>,
 
     thir: &'a Thir<'tcx>,
     cfg: CFG<'tcx>,
 
+    def: ty::WithOptConstParam<LocalDefId>,
     def_id: DefId,
     hir_id: hir::HirId,
     parent_module: DefId,
@@ -434,6 +431,7 @@ fn construct_fn<'tcx>(
     fn_def: ty::WithOptConstParam<LocalDefId>,
     thir: &Thir<'tcx>,
     expr: ExprId,
+    fn_sig: ty::FnSig<'tcx>,
 ) -> Body<'tcx> {
     let span = tcx.def_span(fn_def.did);
     let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did);
@@ -453,11 +451,6 @@ fn construct_fn<'tcx>(
         .output
         .span();
 
-    // fetch the fully liberated fn signature (that is, all bound
-    // types/lifetimes replaced)
-    let typeck_results = tcx.typeck_opt_const_arg(fn_def);
-    let fn_sig = typeck_results.liberated_fn_sigs()[fn_id];
-
     let safety = match fn_sig.unsafety {
         hir::Unsafety::Normal => Safety::Safe,
         hir::Unsafety::Unsafe => Safety::FnUnsafe,
@@ -529,13 +522,7 @@ fn construct_fn<'tcx>(
         let return_block =
             unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
                 Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
-                    builder.args_and_body(
-                        START_BLOCK,
-                        fn_def.did,
-                        arguments,
-                        arg_scope,
-                        &thir[expr],
-                    )
+                    builder.args_and_body(START_BLOCK, arguments, arg_scope, &thir[expr])
                 }))
             }));
         let source_info = builder.source_info(fn_end);
@@ -563,6 +550,7 @@ fn construct_const<'a, 'tcx>(
     def: ty::WithOptConstParam<LocalDefId>,
     thir: &'a Thir<'tcx>,
     expr: ExprId,
+    const_ty: Ty<'tcx>,
 ) -> Body<'tcx> {
     let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
 
@@ -586,20 +574,6 @@ fn construct_const<'a, 'tcx>(
         _ => span_bug!(tcx.def_span(def.did), "can't build MIR for {:?}", def.did),
     };
 
-    // Get the revealed type of this const. This is *not* the adjusted
-    // type of its body, which may be a subtype of this type. For
-    // example:
-    //
-    // fn foo(_: &()) {}
-    // static X: fn(&'static ()) = foo;
-    //
-    // The adjusted type of the body of X is `for<'a> fn(&'a ())` which
-    // is not the same as the type of X. We need the type of the return
-    // place to be the type of the constant because NLL typeck will
-    // equate them.
-    let typeck_results = tcx.typeck_opt_const_arg(def);
-    let const_ty = typeck_results.node_type(hir_id);
-
     let infcx = tcx.infer_ctxt().build();
     let mut builder = Builder::new(
         thir,
@@ -629,17 +603,13 @@ fn construct_const<'a, 'tcx>(
 ///
 /// This is required because we may still want to run MIR passes on an item
 /// with type errors, but normal MIR construction can't handle that in general.
-fn construct_error(
-    tcx: TyCtxt<'_>,
-    def: LocalDefId,
-    body_owner_kind: hir::BodyOwnerKind,
-    err: ErrorGuaranteed,
-) -> Body<'_> {
+fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Body<'_> {
     let span = tcx.def_span(def);
     let hir_id = tcx.hir().local_def_id_to_hir_id(def);
     let generator_kind = tcx.generator_kind(def);
+    let body_owner_kind = tcx.hir().body_owner_kind(def);
 
-    let ty = tcx.ty_error();
+    let ty = tcx.ty_error(err);
     let num_params = match body_owner_kind {
         hir::BodyOwnerKind::Fn => tcx.fn_sig(def).skip_binder().inputs().skip_binder().len(),
         hir::BodyOwnerKind::Closure => {
@@ -728,9 +698,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             thir,
             tcx,
             infcx,
-            typeck_results: tcx.typeck_opt_const_arg(def),
             region_scope_tree: tcx.region_scope_tree(def.did),
             param_env,
+            def,
             def_id: def.did.to_def_id(),
             hir_id,
             parent_module: tcx.parent_module(hir_id).to_def_id(),
@@ -780,14 +750,78 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             self.var_debug_info,
             self.fn_span,
             self.generator_kind,
-            self.typeck_results.tainted_by_errors,
+            None,
         )
     }
 
+    fn insert_upvar_arg(&mut self) {
+        let Some(closure_arg) = self.local_decls.get(ty::CAPTURE_STRUCT_LOCAL) else { return };
+
+        let mut closure_ty = closure_arg.ty;
+        let mut closure_env_projs = vec![];
+        if let ty::Ref(_, ty, _) = closure_ty.kind() {
+            closure_env_projs.push(ProjectionElem::Deref);
+            closure_ty = *ty;
+        }
+
+        let upvar_substs = match closure_ty.kind() {
+            ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
+            ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
+            _ => return,
+        };
+
+        // In analyze_closure() in upvar.rs we gathered a list of upvars used by an
+        // indexed closure and we stored in a map called closure_min_captures in TypeckResults
+        // with the closure's DefId. Here, we run through that vec of UpvarIds for
+        // the given closure and use the necessary information to create upvar
+        // debuginfo and to fill `self.upvars`.
+        let capture_tys = upvar_substs.upvar_tys();
+
+        let tcx = self.tcx;
+        self.upvars = tcx
+            .closure_captures(self.def.did)
+            .iter()
+            .zip(capture_tys)
+            .enumerate()
+            .map(|(i, (captured_place, ty))| {
+                let name = captured_place.to_symbol();
+
+                let capture = captured_place.info.capture_kind;
+                let var_id = match captured_place.place.base {
+                    HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+                    _ => bug!("Expected an upvar"),
+                };
+
+                let mutability = captured_place.mutability;
+
+                let mut projs = closure_env_projs.clone();
+                projs.push(ProjectionElem::Field(Field::new(i), ty));
+                match capture {
+                    ty::UpvarCapture::ByValue => {}
+                    ty::UpvarCapture::ByRef(..) => {
+                        projs.push(ProjectionElem::Deref);
+                    }
+                };
+
+                let use_place = Place {
+                    local: ty::CAPTURE_STRUCT_LOCAL,
+                    projection: tcx.mk_place_elems(&projs),
+                };
+                self.var_debug_info.push(VarDebugInfo {
+                    name,
+                    source_info: SourceInfo::outermost(captured_place.var_ident.span),
+                    value: VarDebugInfoContents::Place(use_place),
+                });
+
+                let capture = Capture { captured_place, use_place, mutability };
+                (var_id, capture)
+            })
+            .collect();
+    }
+
     fn args_and_body(
         &mut self,
         mut block: BasicBlock,
-        fn_def_id: LocalDefId,
         arguments: &IndexVec<ParamId, Param<'tcx>>,
         argument_scope: region::Scope,
         expr: &Expr<'tcx>,
@@ -809,69 +843,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         }
 
-        let tcx = self.tcx;
-        let tcx_hir = tcx.hir();
-        let hir_typeck_results = self.typeck_results;
-
-        // In analyze_closure() in upvar.rs we gathered a list of upvars used by an
-        // indexed closure and we stored in a map called closure_min_captures in TypeckResults
-        // with the closure's DefId. Here, we run through that vec of UpvarIds for
-        // the given closure and use the necessary information to create upvar
-        // debuginfo and to fill `self.upvars`.
-        if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() {
-            let mut closure_env_projs = vec![];
-            let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
-            if let ty::Ref(_, ty, _) = closure_ty.kind() {
-                closure_env_projs.push(ProjectionElem::Deref);
-                closure_ty = *ty;
-            }
-            let upvar_substs = match closure_ty.kind() {
-                ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
-                ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
-                _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty),
-            };
-            let def_id = self.def_id.as_local().unwrap();
-            let capture_syms = tcx.symbols_for_closure_captures((def_id, fn_def_id));
-            let capture_tys = upvar_substs.upvar_tys();
-            let captures_with_tys = hir_typeck_results
-                .closure_min_captures_flattened(fn_def_id)
-                .zip(capture_tys.zip(capture_syms));
-
-            self.upvars = captures_with_tys
-                .enumerate()
-                .map(|(i, (captured_place, (ty, sym)))| {
-                    let capture = captured_place.info.capture_kind;
-                    let var_id = match captured_place.place.base {
-                        HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
-                        _ => bug!("Expected an upvar"),
-                    };
-
-                    let mutability = captured_place.mutability;
-
-                    let mut projs = closure_env_projs.clone();
-                    projs.push(ProjectionElem::Field(Field::new(i), ty));
-                    match capture {
-                        ty::UpvarCapture::ByValue => {}
-                        ty::UpvarCapture::ByRef(..) => {
-                            projs.push(ProjectionElem::Deref);
-                        }
-                    };
-
-                    let use_place = Place {
-                        local: ty::CAPTURE_STRUCT_LOCAL,
-                        projection: tcx.intern_place_elems(&projs),
-                    };
-                    self.var_debug_info.push(VarDebugInfo {
-                        name: *sym,
-                        source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
-                        value: VarDebugInfoContents::Place(use_place),
-                    });
-
-                    let capture = Capture { captured_place, use_place, mutability };
-                    (var_id, capture)
-                })
-                .collect();
-        }
+        self.insert_upvar_arg();
 
         let mut scope = None;
         // Bind the argument patterns
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index fbc130501f9..e10a264d385 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -38,6 +38,6 @@ pub fn provide(providers: &mut Providers) {
     providers.thir_check_unsafety = check_unsafety::thir_check_unsafety;
     providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
     providers.thir_body = thir::cx::thir_body;
-    providers.thir_tree = thir::cx::thir_tree;
-    providers.thir_flat = thir::cx::thir_flat;
+    providers.thir_tree = thir::print::thir_tree;
+    providers.thir_flat = thir::print::thir_flat;
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 261b95ba95b..d510a5fc76f 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -307,7 +307,7 @@ impl<'tcx> Cx<'tcx> {
 
                     let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e));
                     let tupled_args = Expr {
-                        ty: tcx.mk_tup(arg_tys),
+                        ty: tcx.mk_tup_from_iter(arg_tys),
                         temp_lifetime,
                         span: expr.span,
                         kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
@@ -541,8 +541,9 @@ impl<'tcx> Cx<'tcx> {
                 let def_id = def_id.expect_local();
 
                 let upvars = self
-                    .typeck_results
-                    .closure_min_captures_flattened(def_id)
+                    .tcx
+                    .closure_captures(def_id)
+                    .iter()
                     .zip(substs.upvar_tys())
                     .map(|(captured_place, ty)| {
                         let upvars = self.capture_upvar(expr, captured_place, ty);
@@ -758,7 +759,7 @@ impl<'tcx> Cx<'tcx> {
             hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },
 
             hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: self.mirror_expr(v) },
-            hir::ExprKind::Err => unreachable!(),
+            hir::ExprKind::Err(_) => unreachable!(),
         };
 
         Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 74c35ef0fc2..070544446e3 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -52,23 +52,6 @@ pub(crate) fn thir_body(
     Ok((tcx.alloc_steal_thir(cx.thir), expr))
 }
 
-pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
-    match thir_body(tcx, owner_def) {
-        Ok((thir, _)) => {
-            let thir = thir.steal();
-            tcx.thir_tree_representation(&thir)
-        }
-        Err(_) => "error".into(),
-    }
-}
-
-pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
-    match thir_body(tcx, owner_def) {
-        Ok((thir, _)) => format!("{:#?}", thir.steal()),
-        Err(_) => "error".into(),
-    }
-}
-
 struct Cx<'tcx> {
     tcx: TyCtxt<'tcx>,
     thir: Thir<'tcx>,
@@ -99,9 +82,30 @@ impl<'tcx> Cx<'tcx> {
         let typeck_results = tcx.typeck_opt_const_arg(def);
         let did = def.did;
         let hir = tcx.hir();
+        let hir_id = hir.local_def_id_to_hir_id(did);
+
+        let body_type = if hir.body_owner_kind(did).is_fn_or_closure() {
+            // fetch the fully liberated fn signature (that is, all bound
+            // types/lifetimes replaced)
+            BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
+        } else {
+            // Get the revealed type of this const. This is *not* the adjusted
+            // type of its body, which may be a subtype of this type. For
+            // example:
+            //
+            // fn foo(_: &()) {}
+            // static X: fn(&'static ()) = foo;
+            //
+            // The adjusted type of the body of X is `for<'a> fn(&'a ())` which
+            // is not the same as the type of X. We need the type of the return
+            // place to be the type of the constant because NLL typeck will
+            // equate them.
+            BodyTy::Const(typeck_results.node_type(hir_id))
+        };
+
         Cx {
             tcx,
-            thir: Thir::new(),
+            thir: Thir::new(body_type),
             param_env: tcx.param_env(def.did),
             region_scope_tree: tcx.region_scope_tree(def.did),
             typeck_results,
@@ -109,7 +113,7 @@ impl<'tcx> Cx<'tcx> {
             body_owner: did.to_def_id(),
             adjustment_span: None,
             apply_adjustments: hir
-                .attrs(hir.local_def_id_to_hir_id(did))
+                .attrs(hir_id)
                 .iter()
                 .all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir),
         }
@@ -133,9 +137,8 @@ impl<'tcx> Cx<'tcx> {
                     bug!("closure expr does not have closure type: {:?}", closure_ty);
                 };
 
-                let bound_vars = self
-                    .tcx
-                    .intern_bound_variable_kinds(&[ty::BoundVariableKind::Region(ty::BrEnv)]);
+                let bound_vars =
+                    self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region(ty::BrEnv)]);
                 let br = ty::BoundRegion {
                     var: ty::BoundVar::from_usize(bound_vars.len() - 1),
                     kind: ty::BrEnv,
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index e0e6ac26654..ca26cc13b5e 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -5,9 +5,7 @@
 //! structures.
 
 pub(crate) mod constant;
-
 pub(crate) mod cx;
-
 pub(crate) mod pattern;
-
+pub(crate) mod print;
 mod util;
diff --git a/compiler/rustc_middle/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 60b903e9906..8028227aafd 100644
--- a/compiler/rustc_middle/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -1,13 +1,24 @@
-use crate::thir::*;
-use crate::ty::{self, TyCtxt};
-
+use rustc_middle::thir::*;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::def_id::LocalDefId;
 use std::fmt::{self, Write};
 
-impl<'tcx> TyCtxt<'tcx> {
-    pub fn thir_tree_representation<'a>(self, thir: &'a Thir<'tcx>) -> String {
-        let mut printer = ThirPrinter::new(thir);
-        printer.print();
-        printer.into_buffer()
+pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+    match super::cx::thir_body(tcx, owner_def) {
+        Ok((thir, _)) => {
+            let thir = thir.steal();
+            let mut printer = ThirPrinter::new(&thir);
+            printer.print();
+            printer.into_buffer()
+        }
+        Err(_) => "error".into(),
+    }
+}
+
+pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+    match super::cx::thir_body(tcx, owner_def) {
+        Ok((thir, _)) => format!("{:#?}", thir.steal()),
+        Err(_) => "error".into(),
     }
 }
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 077a21fc8af..2ae3ae02fcc 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -1,4 +1,3 @@
-use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets};
 use rustc_middle::ty::TyCtxt;
 use std::ops::RangeInclusive;
@@ -54,7 +53,6 @@ pub trait Direction {
         analysis: &A,
         tcx: TyCtxt<'tcx>,
         body: &mir::Body<'tcx>,
-        dead_unwinds: Option<&BitSet<BasicBlock>>,
         exit_state: &mut A::Domain,
         block: (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
         propagate: impl FnMut(BasicBlock, &A::Domain),
@@ -221,7 +219,6 @@ impl Direction for Backward {
         analysis: &A,
         _tcx: TyCtxt<'tcx>,
         body: &mir::Body<'tcx>,
-        dead_unwinds: Option<&BitSet<BasicBlock>>,
         exit_state: &mut A::Domain,
         (bb, _bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
         mut propagate: impl FnMut(BasicBlock, &A::Domain),
@@ -278,20 +275,6 @@ impl Direction for Backward {
                     }
                 }
 
-                // Ignore dead unwinds.
-                mir::TerminatorKind::Call { cleanup: Some(unwind), .. }
-                | mir::TerminatorKind::Assert { cleanup: Some(unwind), .. }
-                | mir::TerminatorKind::Drop { unwind: Some(unwind), .. }
-                | mir::TerminatorKind::DropAndReplace { unwind: Some(unwind), .. }
-                | mir::TerminatorKind::FalseUnwind { unwind: Some(unwind), .. }
-                | mir::TerminatorKind::InlineAsm { cleanup: Some(unwind), .. }
-                    if unwind == bb =>
-                {
-                    if dead_unwinds.map_or(true, |dead| !dead.contains(pred)) {
-                        propagate(pred, exit_state);
-                    }
-                }
-
                 _ => propagate(pred, exit_state),
             }
         }
@@ -304,7 +287,6 @@ struct BackwardSwitchIntEdgeEffectsApplier<'a, 'tcx, D, F> {
     exit_state: &'a mut D,
     bb: BasicBlock,
     propagate: &'a mut F,
-
     effects_applied: bool,
 }
 
@@ -484,7 +466,6 @@ impl Direction for Forward {
         analysis: &A,
         _tcx: TyCtxt<'tcx>,
         _body: &mir::Body<'tcx>,
-        dead_unwinds: Option<&BitSet<BasicBlock>>,
         exit_state: &mut A::Domain,
         (bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>),
         mut propagate: impl FnMut(BasicBlock, &A::Domain),
@@ -502,9 +483,7 @@ impl Direction for Forward {
             | DropAndReplace { target, unwind, value: _, place: _ }
             | FalseUnwind { real_target: target, unwind } => {
                 if let Some(unwind) = unwind {
-                    if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
-                        propagate(unwind, exit_state);
-                    }
+                    propagate(unwind, exit_state);
                 }
 
                 propagate(target, exit_state);
@@ -534,9 +513,7 @@ impl Direction for Forward {
                 fn_span: _,
             } => {
                 if let Some(unwind) = cleanup {
-                    if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
-                        propagate(unwind, exit_state);
-                    }
+                    propagate(unwind, exit_state);
                 }
 
                 if let Some(target) = target {
@@ -560,9 +537,7 @@ impl Direction for Forward {
                 cleanup,
             } => {
                 if let Some(unwind) = cleanup {
-                    if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
-                        propagate(unwind, exit_state);
-                    }
+                    propagate(unwind, exit_state);
                 }
 
                 if let Some(target) = destination {
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 6ddbe69e17e..91c3bf0ad21 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -12,7 +12,6 @@ use rustc_ast as ast;
 use rustc_data_structures::work_queue::WorkQueue;
 use rustc_graphviz as dot;
 use rustc_hir::def_id::DefId;
-use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::{self, traversal, BasicBlock};
 use rustc_middle::mir::{create_dump_file, dump_enabled};
@@ -78,7 +77,6 @@ where
 {
     tcx: TyCtxt<'tcx>,
     body: &'a mir::Body<'tcx>,
-    dead_unwinds: Option<&'a BitSet<BasicBlock>>,
     entry_sets: IndexVec<BasicBlock, A::Domain>,
     pass_name: Option<&'static str>,
     analysis: A,
@@ -154,25 +152,7 @@ where
             bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
         }
 
-        Engine {
-            analysis,
-            tcx,
-            body,
-            dead_unwinds: None,
-            pass_name: None,
-            entry_sets,
-            apply_trans_for_block,
-        }
-    }
-
-    /// Signals that we do not want dataflow state to propagate across unwind edges for these
-    /// `BasicBlock`s.
-    ///
-    /// You must take care that `dead_unwinds` does not contain a `BasicBlock` that *can* actually
-    /// unwind during execution. Otherwise, your dataflow results will not be correct.
-    pub fn dead_unwinds(mut self, dead_unwinds: &'a BitSet<BasicBlock>) -> Self {
-        self.dead_unwinds = Some(dead_unwinds);
-        self
+        Engine { analysis, tcx, body, pass_name: None, entry_sets, apply_trans_for_block }
     }
 
     /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis.
@@ -190,14 +170,7 @@ where
         A::Domain: DebugWithContext<A>,
     {
         let Engine {
-            analysis,
-            body,
-            dead_unwinds,
-            mut entry_sets,
-            tcx,
-            apply_trans_for_block,
-            pass_name,
-            ..
+            analysis, body, mut entry_sets, tcx, apply_trans_for_block, pass_name, ..
         } = self;
 
         let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
@@ -236,7 +209,6 @@ where
                 &analysis,
                 tcx,
                 body,
-                dead_unwinds,
                 &mut state,
                 (bb, bb_data),
                 |target: BasicBlock, state: &A::Domain| {
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 6d30276aeab..4a163028fcf 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -126,7 +126,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                         BorrowedContent {
                             target_place: Place {
                                 local: place.local,
-                                projection: tcx.intern_place_elems(proj),
+                                projection: tcx.mk_place_elems(proj),
                             },
                         },
                     ));
@@ -165,7 +165,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             if union_path.is_none() {
                 base = self.add_move_path(base, elem, |tcx| Place {
                     local: place.local,
-                    projection: tcx.intern_place_elems(&place.projection[..i + 1]),
+                    projection: tcx.mk_place_elems(&place.projection[..i + 1]),
                 });
             }
         }
@@ -476,7 +476,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             // `ConstIndex` patterns. This is done to ensure that all move paths
             // are disjoint, which is expected by drop elaboration.
             let base_place =
-                Place { local: place.local, projection: self.builder.tcx.intern_place_elems(base) };
+                Place { local: place.local, projection: self.builder.tcx.mk_place_elems(base) };
             let base_path = match self.move_path_for(base_place) {
                 Ok(path) => path,
                 Err(MoveError::UnionMove { path }) => {
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index c57ec137d4b..f27beb64a14 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -124,7 +124,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
 
     fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
         if let Some(new_projection) = self.process_projection(&place.projection, loc) {
-            place.projection = self.tcx().intern_place_elems(&new_projection);
+            place.projection = self.tcx().mk_place_elems(&new_projection);
         }
 
         let observes_address = match ctxt {
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 19019e3ef74..49ded10ba1f 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -122,7 +122,10 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
     ) {
         match rvalue {
             Rvalue::Aggregate(kind, operands) => {
-                state.flood_with(target.as_ref(), self.map(), FlatSet::Bottom);
+                // If we assign `target = Enum::Variant#0(operand)`,
+                // we must make sure that all `target as Variant#i` are `Top`.
+                state.flood(target.as_ref(), self.map());
+
                 if let Some(target_idx) = self.map().find(target.as_ref()) {
                     let (variant_target, variant_index) = match **kind {
                         AggregateKind::Tuple | AggregateKind::Closure(..) => {
@@ -131,18 +134,21 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                         AggregateKind::Adt(def_id, variant_index, ..) => {
                             match self.tcx.def_kind(def_id) {
                                 DefKind::Struct => (Some(target_idx), None),
-                                DefKind::Enum => (Some(target_idx), Some(variant_index)),
+                                DefKind::Enum => (
+                                    self.map.apply(target_idx, TrackElem::Variant(variant_index)),
+                                    Some(variant_index),
+                                ),
                                 _ => (None, None),
                             }
                         }
                         _ => (None, None),
                     };
-                    if let Some(target) = variant_target {
+                    if let Some(variant_target_idx) = variant_target {
                         for (field_index, operand) in operands.iter().enumerate() {
-                            if let Some(field) = self
-                                .map()
-                                .apply(target, TrackElem::Field(Field::from_usize(field_index)))
-                            {
+                            if let Some(field) = self.map().apply(
+                                variant_target_idx,
+                                TrackElem::Field(Field::from_usize(field_index)),
+                            ) {
                                 let result = self.handle_operand(operand, state);
                                 state.insert_idx(field, result, self.map());
                             }
@@ -151,6 +157,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     if let Some(variant_index) = variant_index
                         && let Some(discr_idx) = self.map().apply(target_idx, TrackElem::Discriminant)
                     {
+                        // We are assigning the discriminant as part of an aggregate.
+                        // This discriminant can only alias a variant field's value if the operand
+                        // had an invalid value for that type.
+                        // Using invalid values is UB, so we are allowed to perform the assignment
+                        // without extra flooding.
                         let enum_ty = target.ty(self.local_decls, self.tcx).ty;
                         if let Some(discr_val) = self.eval_discriminant(enum_ty, variant_index) {
                             state.insert_value_idx(discr_idx, FlatSet::Elem(discr_val), &self.map);
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index dc583471c89..954bb5aff8d 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -17,7 +17,7 @@ pub fn build_ptr_tys<'tcx>(
     unique_did: DefId,
     nonnull_did: DefId,
 ) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) {
-    let substs = tcx.intern_substs(&[pointee.into()]);
+    let substs = tcx.mk_substs(&[pointee.into()]);
     let unique_ty = tcx.type_of(unique_did).subst(tcx, substs);
     let nonnull_ty = tcx.type_of(nonnull_did).subst(tcx, substs);
     let ptr_ty = tcx.mk_imm_ptr(pointee);
@@ -138,7 +138,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
 
                     if let Some(mut new_projections) = new_projections {
                         new_projections.extend_from_slice(&place.projection[last_deref..]);
-                        place.projection = tcx.intern_place_elems(&new_projections);
+                        place.projection = tcx.mk_place_elems(&new_projections);
                     }
                 }
             }
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index c2ff8645635..bdfd8dc6e99 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -67,13 +67,11 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
         };
         let un_derefer = UnDerefer { tcx: tcx, derefer_sidetable: side_table };
         let elaborate_patch = {
-            let body = &*body;
             let env = MoveDataParamEnv { move_data, param_env };
-            let dead_unwinds = find_dead_unwinds(tcx, body, &env, &un_derefer);
+            remove_dead_unwinds(tcx, body, &env, &un_derefer);
 
             let inits = MaybeInitializedPlaces::new(tcx, body, &env)
                 .into_engine(tcx, body)
-                .dead_unwinds(&dead_unwinds)
                 .pass_name("elaborate_drops")
                 .iterate_to_fixpoint()
                 .into_results_cursor(body);
@@ -81,11 +79,12 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
             let uninits = MaybeUninitializedPlaces::new(tcx, body, &env)
                 .mark_inactive_variants_as_uninit()
                 .into_engine(tcx, body)
-                .dead_unwinds(&dead_unwinds)
                 .pass_name("elaborate_drops")
                 .iterate_to_fixpoint()
                 .into_results_cursor(body);
 
+            let reachable = traversal::reachable_as_bitset(body);
+
             ElaborateDropsCtxt {
                 tcx,
                 body,
@@ -94,6 +93,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
                 drop_flags: Default::default(),
                 patch: MirPatch::new(body),
                 un_derefer: un_derefer,
+                reachable,
             }
             .elaborate()
         };
@@ -102,22 +102,21 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
     }
 }
 
-/// Returns the set of basic blocks whose unwind edges are known
-/// to not be reachable, because they are `drop` terminators
+/// Removes unwind edges which are known to be unreachable, because they are in `drop` terminators
 /// that can't drop anything.
-fn find_dead_unwinds<'tcx>(
+fn remove_dead_unwinds<'tcx>(
     tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
+    body: &mut Body<'tcx>,
     env: &MoveDataParamEnv<'tcx>,
     und: &UnDerefer<'tcx>,
-) -> BitSet<BasicBlock> {
-    debug!("find_dead_unwinds({:?})", body.span);
+) {
+    debug!("remove_dead_unwinds({:?})", body.span);
     // We only need to do this pass once, because unwind edges can only
     // reach cleanup blocks, which can't have unwind edges themselves.
-    let mut dead_unwinds = BitSet::new_empty(body.basic_blocks.len());
+    let mut dead_unwinds = Vec::new();
     let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env)
         .into_engine(tcx, body)
-        .pass_name("find_dead_unwinds")
+        .pass_name("remove_dead_unwinds")
         .iterate_to_fixpoint()
         .into_results_cursor(body);
     for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
@@ -129,16 +128,16 @@ fn find_dead_unwinds<'tcx>(
             _ => continue,
         };
 
-        debug!("find_dead_unwinds @ {:?}: {:?}", bb, bb_data);
+        debug!("remove_dead_unwinds @ {:?}: {:?}", bb, bb_data);
 
         let LookupResult::Exact(path) = env.move_data.rev_lookup.find(place.as_ref()) else {
-            debug!("find_dead_unwinds: has parent; skipping");
+            debug!("remove_dead_unwinds: has parent; skipping");
             continue;
         };
 
         flow_inits.seek_before_primary_effect(body.terminator_loc(bb));
         debug!(
-            "find_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}",
+            "remove_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}",
             bb,
             place,
             path,
@@ -150,13 +149,22 @@ fn find_dead_unwinds<'tcx>(
             maybe_live |= flow_inits.contains(child);
         });
 
-        debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live);
+        debug!("remove_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live);
         if !maybe_live {
-            dead_unwinds.insert(bb);
+            dead_unwinds.push(bb);
         }
     }
 
-    dead_unwinds
+    if dead_unwinds.is_empty() {
+        return;
+    }
+
+    let basic_blocks = body.basic_blocks.as_mut();
+    for &bb in dead_unwinds.iter() {
+        if let Some(unwind) = basic_blocks[bb].terminator_mut().unwind_mut() {
+            *unwind = None;
+        }
+    }
 }
 
 struct InitializationData<'mir, 'tcx> {
@@ -290,6 +298,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> {
     drop_flags: FxHashMap<MovePathIndex, Local>,
     patch: MirPatch<'tcx>,
     un_derefer: UnDerefer<'tcx>,
+    reachable: BitSet<BasicBlock>,
 }
 
 impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
@@ -329,6 +338,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
     fn collect_drop_flags(&mut self) {
         for (bb, data) in self.body.basic_blocks.iter_enumerated() {
+            if !self.reachable.contains(bb) {
+                continue;
+            }
             let terminator = data.terminator();
             let place = match terminator.kind {
                 TerminatorKind::Drop { ref place, .. }
@@ -384,6 +396,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
     fn elaborate_drops(&mut self) {
         for (bb, data) in self.body.basic_blocks.iter_enumerated() {
+            if !self.reachable.contains(bb) {
+                continue;
+            }
             let loc = Location { block: bb, statement_index: data.statements.len() };
             let terminator = data.terminator();
 
@@ -541,6 +556,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
     fn drop_flags_for_fn_rets(&mut self) {
         for (bb, data) in self.body.basic_blocks.iter_enumerated() {
+            if !self.reachable.contains(bb) {
+                continue;
+            }
             if let TerminatorKind::Call {
                 destination, target: Some(tgt), cleanup: Some(_), ..
             } = data.terminator().kind
@@ -576,6 +594,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         // clobbered before they are read.
 
         for (bb, data) in self.body.basic_blocks.iter_enumerated() {
+            if !self.reachable.contains(bb) {
+                continue;
+            }
             debug!("drop_flags_for_locs({:?})", data);
             for i in 0..(data.statements.len() + 1) {
                 debug!("drop_flag_for_locs: stmt {}", i);
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index dc5f88f24f8..2e97312ee50 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -126,7 +126,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> {
                 place,
                 Place {
                     local: SELF_ARG,
-                    projection: self.tcx().intern_place_elems(&[ProjectionElem::Deref]),
+                    projection: self.tcx().mk_place_elems(&[ProjectionElem::Deref]),
                 },
                 self.tcx,
             );
@@ -162,10 +162,9 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
                 place,
                 Place {
                     local: SELF_ARG,
-                    projection: self.tcx().intern_place_elems(&[ProjectionElem::Field(
-                        Field::new(0),
-                        self.ref_gen_ty,
-                    )]),
+                    projection: self
+                        .tcx()
+                        .mk_place_elems(&[ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]),
                 },
                 self.tcx,
             );
@@ -187,7 +186,7 @@ fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtx
     let mut new_projection = new_base.projection.to_vec();
     new_projection.append(&mut place.projection.to_vec());
 
-    place.projection = tcx.intern_place_elems(&new_projection);
+    place.projection = tcx.mk_place_elems(&new_projection);
 }
 
 const SELF_ARG: Local = Local::from_u32(1);
@@ -300,7 +299,7 @@ impl<'tcx> TransformVisitor<'tcx> {
         let mut projection = base.projection.to_vec();
         projection.push(ProjectionElem::Field(Field::new(idx), ty));
 
-        Place { local: base.local, projection: self.tcx.intern_place_elems(&projection) }
+        Place { local: base.local, projection: self.tcx.mk_place_elems(&projection) }
     }
 
     // Create a statement which changes the discriminant
@@ -427,7 +426,7 @@ fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body
 
     let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span));
     let pin_adt_ref = tcx.adt_def(pin_did);
-    let substs = tcx.intern_substs(&[ref_gen_ty.into()]);
+    let substs = tcx.mk_substs(&[ref_gen_ty.into()]);
     let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs);
 
     // Replace the by ref generator argument
@@ -1450,13 +1449,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
             // Compute Poll<return_ty>
             let poll_did = tcx.require_lang_item(LangItem::Poll, None);
             let poll_adt_ref = tcx.adt_def(poll_did);
-            let poll_substs = tcx.intern_substs(&[body.return_ty().into()]);
+            let poll_substs = tcx.mk_substs(&[body.return_ty().into()]);
             (poll_adt_ref, poll_substs)
         } else {
             // Compute GeneratorState<yield_ty, return_ty>
             let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
             let state_adt_ref = tcx.adt_def(state_did);
-            let state_substs = tcx.intern_substs(&[yield_ty.into(), body.return_ty().into()]);
+            let state_substs = tcx.mk_substs(&[yield_ty.into(), body.return_ty().into()]);
             (state_adt_ref, state_substs)
         };
         let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 8c6b0463a73..6e6d6566f4b 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -888,7 +888,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
         location: Location,
     ) {
         if let ProjectionElem::Field(f, ty) = elem {
-            let parent = Place { local, projection: self.tcx.intern_place_elems(proj_base) };
+            let parent = Place { local, projection: self.tcx.mk_place_elems(proj_base) };
             let parent_ty = parent.ty(&self.callee_body.local_decls, self.tcx);
             let check_equal = |this: &mut Self, f_ty| {
                 if !util::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) {
diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs
index 3896f0e57ea..05286b71d47 100644
--- a/compiler/rustc_mir_transform/src/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instcombine.rs
@@ -6,8 +6,8 @@ use rustc_middle::mir::{
     BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue,
     SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp,
 };
-use rustc_middle::ty::layout::LayoutError;
-use rustc_middle::ty::{self, ParamEnv, ParamEnvAnd, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::layout::InitKind;
+use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 
 pub struct InstCombine;
@@ -121,7 +121,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
 
                 *rvalue = Rvalue::Use(Operand::Copy(Place {
                     local: base.local,
-                    projection: self.tcx.intern_place_elems(base.projection),
+                    projection: self.tcx.mk_place_elems(base.projection),
                 }));
             }
         }
@@ -234,16 +234,15 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
         }
         let ty = substs.type_at(0);
 
-        // Check this is a foldable intrinsic before we query the layout of our generic parameter
-        let Some(assert_panics) = intrinsic_assert_panics(intrinsic_name) else { return; };
-        match assert_panics(self.tcx, self.param_env.and(ty)) {
-            // We don't know the layout, don't touch the assertion
-            Err(_) => {}
-            Ok(true) => {
+        let known_is_valid = intrinsic_assert_panics(self.tcx, self.param_env, ty, intrinsic_name);
+        match known_is_valid {
+            // We don't know the layout or it's not validity assertion at all, don't touch it
+            None => {}
+            Some(true) => {
                 // If we know the assert panics, indicate to later opts that the call diverges
                 *target = None;
             }
-            Ok(false) => {
+            Some(false) => {
                 // If we know the assert does not panic, turn the call into a Goto
                 terminator.kind = TerminatorKind::Goto { target: *target_block };
             }
@@ -252,33 +251,21 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
 }
 
 fn intrinsic_assert_panics<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
     intrinsic_name: Symbol,
-) -> Option<fn(TyCtxt<'tcx>, ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<bool, LayoutError<'tcx>>> {
-    fn inhabited_predicate<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
-    ) -> Result<bool, LayoutError<'tcx>> {
-        Ok(tcx.layout_of(param_env_and_ty)?.abi.is_uninhabited())
-    }
-    fn zero_valid_predicate<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
-    ) -> Result<bool, LayoutError<'tcx>> {
-        Ok(!tcx.permits_zero_init(param_env_and_ty)?)
-    }
-    fn mem_uninitialized_valid_predicate<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
-    ) -> Result<bool, LayoutError<'tcx>> {
-        Ok(!tcx.permits_uninit_init(param_env_and_ty)?)
-    }
-
-    match intrinsic_name {
-        sym::assert_inhabited => Some(inhabited_predicate),
-        sym::assert_zero_valid => Some(zero_valid_predicate),
-        sym::assert_mem_uninitialized_valid => Some(mem_uninitialized_valid_predicate),
-        _ => None,
-    }
+) -> Option<bool> {
+    Some(match intrinsic_name {
+        sym::assert_inhabited => tcx.layout_of(param_env.and(ty)).ok()?.abi.is_uninhabited(),
+        sym::assert_zero_valid => {
+            !tcx.check_validity_of_init((InitKind::Zero, param_env.and(ty))).ok()?
+        }
+        sym::assert_mem_uninitialized_valid => !tcx
+            .check_validity_of_init((InitKind::UninitMitigated0x01Fill, param_env.and(ty)))
+            .ok()?,
+        _ => return None,
+    })
 }
 
 fn resolve_rust_intrinsic<'tcx>(
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index 2ca33a624e2..89e0a007dac 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -114,7 +114,7 @@ impl EnumSizeOpt {
             tcx.data_layout.ptr_sized_integer().align(&tcx.data_layout).abi,
             Mutability::Not,
         );
-        let alloc = tcx.create_memory_alloc(tcx.intern_const_alloc(alloc));
+        let alloc = tcx.create_memory_alloc(tcx.mk_const_alloc(alloc));
         Some((*adt_def, num_discrs, *alloc_cache.entry(ty).or_insert(alloc)))
     }
     fn optim<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -197,9 +197,8 @@ impl EnumSizeOpt {
                             size_place,
                             Rvalue::Use(Operand::Copy(Place {
                                 local: size_array_local,
-                                projection: tcx.intern_place_elems(&[PlaceElem::Index(
-                                    discr_cast_place.local,
-                                )]),
+                                projection: tcx
+                                    .mk_place_elems(&[PlaceElem::Index(discr_cast_place.local)]),
                             })),
                         )),
                     };
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index bdd1e8fb98f..4193eb7d6e8 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -192,7 +192,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
                 let arguments = (0..num_args).map(|x| {
                     let mut place_elems = place_elems.to_vec();
                     place_elems.push(ProjectionElem::Field(x.into(), fields[x]));
-                    let projection = tcx.intern_place_elems(&place_elems);
+                    let projection = tcx.mk_place_elems(&place_elems);
                     let place = Place {
                         local: place.local,
                         projection,
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 682ad081f5c..ebe63d6cb7e 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -147,7 +147,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
     assert!(!matches!(ty, Some(ty) if ty.is_generator()));
 
     let substs = if let Some(ty) = ty {
-        tcx.intern_substs(&[ty.into()])
+        tcx.mk_substs(&[ty.into()])
     } else {
         InternalSubsts::identity_for_item(tcx, def_id)
     };
@@ -597,7 +597,7 @@ fn build_call_shim<'tcx>(
         let untuple_args = sig.inputs();
 
         // Create substitutions for the `Self` and `Args` generic parameters of the shim body.
-        let arg_tup = tcx.intern_tup(untuple_args);
+        let arg_tup = tcx.mk_tup(untuple_args);
 
         (Some([ty.into(), arg_tup.into()]), Some(untuple_args))
     } else {
@@ -632,7 +632,7 @@ fn build_call_shim<'tcx>(
             Adjustment::Deref => tcx.mk_imm_ptr(fnty),
             Adjustment::RefMut => tcx.mk_mut_ptr(fnty),
         };
-        sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
+        sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
     }
 
     // FIXME(eddyb) avoid having this snippet both here and in
@@ -643,7 +643,7 @@ fn build_call_shim<'tcx>(
         let self_arg = &mut inputs_and_output[0];
         debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param);
         *self_arg = tcx.mk_mut_ptr(*self_arg);
-        sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
+        sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
     }
 
     let span = tcx.def_span(def_id);
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 8a37423b2a0..13168e9a268 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -122,7 +122,7 @@ impl<'tcx> ReplacementMap<'tcx> {
         let &[PlaceElem::Field(f, _), ref rest @ ..] = place.projection else { return None; };
         let fields = self.fragments[place.local].as_ref()?;
         let (_, new_local) = fields[f]?;
-        Some(Place { local: new_local, projection: tcx.intern_place_elems(&rest) })
+        Some(Place { local: new_local, projection: tcx.mk_place_elems(&rest) })
     }
 
     fn place_fragments(
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index ff409a80716..45e659eab6c 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1298,7 +1298,7 @@ impl<'v> RootCollector<'_, 'v> {
             self.tcx,
             ty::ParamEnv::reveal_all(),
             start_def_id,
-            self.tcx.intern_substs(&[main_ret_ty.into()]),
+            self.tcx.mk_substs(&[main_ret_ty.into()]),
         )
         .unwrap()
         .unwrap();
diff --git a/compiler/rustc_parse/locales/en-US.ftl b/compiler/rustc_parse/locales/en-US.ftl
index a31b1f6ac1a..4ddeeed5b7e 100644
--- a/compiler/rustc_parse/locales/en-US.ftl
+++ b/compiler/rustc_parse/locales/en-US.ftl
@@ -220,7 +220,7 @@ parse_match_arm_body_without_braces = `match` arm body without braces
             [one] statement
            *[other] statements
         } with a body
-    .suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression
+    .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression
 
 parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
     .suggestion_remove_eq = use `..=` instead
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index d235b8a8176..b4948dddcc9 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -693,7 +693,7 @@ impl<'a> Parser<'a> {
                 span: self.prev_token.span.shrink_to_lo(),
                 tokens: None,
             };
-            let struct_expr = snapshot.parse_struct_expr(None, path, false);
+            let struct_expr = snapshot.parse_expr_struct(None, path, false);
             let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No);
             return Some(match (struct_expr, block_tail) {
                 (Ok(expr), Err(mut err)) => {
@@ -1624,7 +1624,7 @@ impl<'a> Parser<'a> {
             // Handle `await { <expr> }`.
             // This needs to be handled separately from the next arm to avoid
             // interpreting `await { <expr> }?` as `<expr>?.await`.
-            self.parse_block_expr(None, self.token.span, BlockCheckMode::Default)
+            self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)
         } else {
             self.parse_expr()
         }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 12f65a436e3..33254d034c9 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -103,7 +103,7 @@ impl<'a> Parser<'a> {
         self.collect_tokens_no_attrs(|this| this.parse_expr())
     }
 
-    pub fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> {
+    pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> {
         self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value })
     }
 
@@ -125,7 +125,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a sequence of expressions delimited by parentheses.
-    fn parse_paren_expr_seq(&mut self) -> PResult<'a, ThinVec<P<Expr>>> {
+    fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<P<Expr>>> {
         self.parse_paren_comma_seq(|p| p.parse_expr_catch_underscore()).map(|(r, _)| r)
     }
 
@@ -136,7 +136,7 @@ impl<'a> Parser<'a> {
         r: Restrictions,
         already_parsed_attrs: Option<AttrWrapper>,
     ) -> PResult<'a, P<Expr>> {
-        self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs))
+        self.with_res(r, |this| this.parse_expr_assoc(already_parsed_attrs))
     }
 
     /// Parses an associative expression.
@@ -144,15 +144,15 @@ impl<'a> Parser<'a> {
     /// This parses an expression accounting for associativity and precedence of the operators in
     /// the expression.
     #[inline]
-    fn parse_assoc_expr(
+    fn parse_expr_assoc(
         &mut self,
         already_parsed_attrs: Option<AttrWrapper>,
     ) -> PResult<'a, P<Expr>> {
-        self.parse_assoc_expr_with(0, already_parsed_attrs.into())
+        self.parse_expr_assoc_with(0, already_parsed_attrs.into())
     }
 
     /// Parses an associative expression with operators of at least `min_prec` precedence.
-    pub(super) fn parse_assoc_expr_with(
+    pub(super) fn parse_expr_assoc_with(
         &mut self,
         min_prec: usize,
         lhs: LhsExpr,
@@ -167,9 +167,9 @@ impl<'a> Parser<'a> {
                 _ => None,
             };
             if self.token.is_range_separator() {
-                return self.parse_prefix_range_expr(attrs);
+                return self.parse_expr_prefix_range(attrs);
             } else {
-                self.parse_prefix_expr(attrs)?
+                self.parse_expr_prefix(attrs)?
             }
         };
         let last_type_ascription_set = self.last_type_ascription.is_some();
@@ -293,7 +293,7 @@ impl<'a> Parser<'a> {
             } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq {
                 // If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
                 // generalise it to the Fixity::None code.
-                lhs = self.parse_range_expr(prec, lhs, op, cur_op_span)?;
+                lhs = self.parse_expr_range(prec, lhs, op, cur_op_span)?;
                 break;
             }
 
@@ -306,7 +306,7 @@ impl<'a> Parser<'a> {
                 Fixity::None => 1,
             };
             let rhs = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
-                this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed)
+                this.parse_expr_assoc_with(prec + prec_adjustment, LhsExpr::NotYetParsed)
             })?;
 
             let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
@@ -458,7 +458,7 @@ impl<'a> Parser<'a> {
 
     /// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
     /// The other two variants are handled in `parse_prefix_range_expr` below.
-    fn parse_range_expr(
+    fn parse_expr_range(
         &mut self,
         prec: usize,
         lhs: P<Expr>,
@@ -466,7 +466,7 @@ impl<'a> Parser<'a> {
         cur_op_span: Span,
     ) -> PResult<'a, P<Expr>> {
         let rhs = if self.is_at_start_of_range_notation_rhs() {
-            Some(self.parse_assoc_expr_with(prec + 1, LhsExpr::NotYetParsed)?)
+            Some(self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed)?)
         } else {
             None
         };
@@ -491,7 +491,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.
-    fn parse_prefix_range_expr(&mut self, attrs: Option<AttrWrapper>) -> PResult<'a, P<Expr>> {
+    fn parse_expr_prefix_range(&mut self, attrs: Option<AttrWrapper>) -> PResult<'a, P<Expr>> {
         // Check for deprecated `...` syntax.
         if self.token == token::DotDotDot {
             self.err_dotdotdot_syntax(self.token.span);
@@ -518,7 +518,7 @@ impl<'a> Parser<'a> {
             this.bump();
             let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
                 // RHS must be parsed with more associativity than the dots.
-                this.parse_assoc_expr_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed)
+                this.parse_expr_assoc_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed)
                     .map(|x| (lo.to(x.span), Some(x)))?
             } else {
                 (lo, None)
@@ -529,7 +529,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a prefix-unary-operator expr.
-    fn parse_prefix_expr(&mut self, attrs: Option<AttrWrapper>) -> PResult<'a, P<Expr>> {
+    fn parse_expr_prefix(&mut self, attrs: Option<AttrWrapper>) -> PResult<'a, P<Expr>> {
         let attrs = self.parse_or_use_outer_attributes(attrs)?;
         let lo = self.token.span;
 
@@ -547,20 +547,20 @@ impl<'a> Parser<'a> {
         // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
         match this.token.uninterpolate().kind {
             // `!expr`
-            token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)),
+            token::Not => make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Not)),
             // `~expr`
             token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),
             // `-expr`
             token::BinOp(token::Minus) => {
-                make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Neg))
+                make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Neg))
             }
             // `*expr`
             token::BinOp(token::Star) => {
-                make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Deref))
+                make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Deref))
             }
             // `&expr` and `&&expr`
             token::BinOp(token::And) | token::AndAnd => {
-                make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
+                make_it!(this, attrs, |this, _| this.parse_expr_borrow(lo))
             }
             // `+lit`
             token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
@@ -579,7 +579,7 @@ impl<'a> Parser<'a> {
                 this.sess.emit_err(err);
 
                 this.bump();
-                this.parse_prefix_expr(None)
+                this.parse_expr_prefix(None)
             }
             // Recover from `++x`:
             token::BinOp(token::Plus)
@@ -592,28 +592,28 @@ impl<'a> Parser<'a> {
                 this.bump();
                 this.bump();
 
-                let operand_expr = this.parse_dot_or_call_expr(Default::default())?;
+                let operand_expr = this.parse_expr_dot_or_call(Default::default())?;
                 this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt)
             }
             token::Ident(..) if this.token.is_keyword(kw::Box) => {
-                make_it!(this, attrs, |this, _| this.parse_box_expr(lo))
+                make_it!(this, attrs, |this, _| this.parse_expr_box(lo))
             }
             token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {
                 make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
             }
-            _ => return this.parse_dot_or_call_expr(Some(attrs)),
+            _ => return this.parse_expr_dot_or_call(Some(attrs)),
         }
     }
 
-    fn parse_prefix_expr_common(&mut self, lo: Span) -> PResult<'a, (Span, P<Expr>)> {
+    fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, P<Expr>)> {
         self.bump();
-        let expr = self.parse_prefix_expr(None);
+        let expr = self.parse_expr_prefix(None);
         let (span, expr) = self.interpolated_or_expr_span(expr)?;
         Ok((lo.to(span), expr))
     }
 
-    fn parse_unary_expr(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {
-        let (span, expr) = self.parse_prefix_expr_common(lo)?;
+    fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {
+        let (span, expr) = self.parse_expr_prefix_common(lo)?;
         Ok((span, self.mk_unary(op, expr)))
     }
 
@@ -621,12 +621,12 @@ impl<'a> Parser<'a> {
     fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
         self.sess.emit_err(errors::TildeAsUnaryOperator(lo));
 
-        self.parse_unary_expr(lo, UnOp::Not)
+        self.parse_expr_unary(lo, UnOp::Not)
     }
 
     /// Parse `box expr`.
-    fn parse_box_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
-        let (span, expr) = self.parse_prefix_expr_common(lo)?;
+    fn parse_expr_box(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
+        let (span, expr) = self.parse_expr_prefix_common(lo)?;
         self.sess.gated_spans.gate(sym::box_syntax, span);
         Ok((span, ExprKind::Box(expr)))
     }
@@ -664,7 +664,7 @@ impl<'a> Parser<'a> {
             ),
         });
 
-        self.parse_unary_expr(lo, UnOp::Not)
+        self.parse_expr_unary(lo, UnOp::Not)
     }
 
     /// Returns the span of expr, if it was not interpolated or the span of the interpolated token.
@@ -722,7 +722,7 @@ impl<'a> Parser<'a> {
                                 segments[0].ident.span,
                             ),
                         };
-                        match self.parse_labeled_expr(label, false) {
+                        match self.parse_expr_labeled(label, false) {
                             Ok(expr) => {
                                 type_err.cancel();
                                 self.sess.emit_err(errors::MalformedLoopLabel {
@@ -816,7 +816,7 @@ impl<'a> Parser<'a> {
                 ("cast", None)
             };
 
-        let with_postfix = self.parse_dot_or_call_expr_with_(cast_expr, span)?;
+        let with_postfix = self.parse_expr_dot_or_call_with_(cast_expr, span)?;
 
         // Check if an illegal postfix operator has been added after the cast.
         // If the resulting expression is not a cast, it is an illegal postfix operator.
@@ -887,15 +887,15 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
-    fn parse_borrow_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
+    fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
         self.expect_and()?;
         let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);
         let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below.
         let (borrow_kind, mutbl) = self.parse_borrow_modifiers(lo);
         let expr = if self.token.is_range_separator() {
-            self.parse_prefix_range_expr(None)
+            self.parse_expr_prefix_range(None)
         } else {
-            self.parse_prefix_expr(None)
+            self.parse_expr_prefix(None)
         };
         let (hi, expr) = self.interpolated_or_expr_span(expr)?;
         let span = lo.to(hi);
@@ -925,16 +925,16 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses `a.b` or `a(13)` or `a[4]` or just `a`.
-    fn parse_dot_or_call_expr(&mut self, attrs: Option<AttrWrapper>) -> PResult<'a, P<Expr>> {
+    fn parse_expr_dot_or_call(&mut self, attrs: Option<AttrWrapper>) -> PResult<'a, P<Expr>> {
         let attrs = self.parse_or_use_outer_attributes(attrs)?;
         self.collect_tokens_for_expr(attrs, |this, attrs| {
-            let base = this.parse_bottom_expr();
+            let base = this.parse_expr_bottom();
             let (span, base) = this.interpolated_or_expr_span(base)?;
-            this.parse_dot_or_call_expr_with(base, span, attrs)
+            this.parse_expr_dot_or_call_with(base, span, attrs)
         })
     }
 
-    pub(super) fn parse_dot_or_call_expr_with(
+    pub(super) fn parse_expr_dot_or_call_with(
         &mut self,
         e0: P<Expr>,
         lo: Span,
@@ -943,7 +943,7 @@ impl<'a> Parser<'a> {
         // Stitch the list of outer attributes onto the return value.
         // A little bit ugly, but the best way given the current code
         // structure
-        let res = self.parse_dot_or_call_expr_with_(e0, lo);
+        let res = self.parse_expr_dot_or_call_with_(e0, lo);
         if attrs.is_empty() {
             res
         } else {
@@ -957,7 +957,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_dot_or_call_expr_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
+    fn parse_expr_dot_or_call_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
         loop {
             let has_question = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) {
                 // we are using noexpect here because we don't expect a `?` directly after a `return`
@@ -980,15 +980,15 @@ impl<'a> Parser<'a> {
             };
             if has_dot {
                 // expr.f
-                e = self.parse_dot_suffix_expr(lo, e)?;
+                e = self.parse_expr_dot_suffix(lo, e)?;
                 continue;
             }
             if self.expr_is_complete(&e) {
                 return Ok(e);
             }
             e = match self.token.kind {
-                token::OpenDelim(Delimiter::Parenthesis) => self.parse_fn_call_expr(lo, e),
-                token::OpenDelim(Delimiter::Bracket) => self.parse_index_expr(lo, e)?,
+                token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e),
+                token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?,
                 _ => return Ok(e),
             }
         }
@@ -1000,14 +1000,14 @@ impl<'a> Parser<'a> {
             && self.look_ahead(3, |t| t.can_begin_expr())
     }
 
-    fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
+    fn parse_expr_dot_suffix(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
         match self.token.uninterpolate().kind {
             token::Ident(..) => self.parse_dot_suffix(base, lo),
             token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
-                Ok(self.parse_tuple_field_access_expr(lo, base, symbol, suffix, None))
+                Ok(self.parse_expr_tuple_field_access(lo, base, symbol, suffix, None))
             }
             token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => {
-                Ok(self.parse_tuple_field_access_expr_float(lo, base, symbol, suffix))
+                Ok(self.parse_expr_tuple_field_access_float(lo, base, symbol, suffix))
             }
             _ => {
                 self.error_unexpected_after_dot();
@@ -1029,7 +1029,7 @@ impl<'a> Parser<'a> {
     // support pushing "future tokens" (would be also helpful to `break_and_eat`), or
     // we should break everything including floats into more basic proc-macro style
     // tokens in the lexer (probably preferable).
-    fn parse_tuple_field_access_expr_float(
+    fn parse_expr_tuple_field_access_float(
         &mut self,
         lo: Span,
         base: P<Expr>,
@@ -1072,7 +1072,7 @@ impl<'a> Parser<'a> {
         match &*components {
             // 1e2
             [IdentLike(i)] => {
-                self.parse_tuple_field_access_expr(lo, base, Symbol::intern(&i), suffix, None)
+                self.parse_expr_tuple_field_access(lo, base, Symbol::intern(&i), suffix, None)
             }
             // 1.
             [IdentLike(i), Punct('.')] => {
@@ -1088,7 +1088,7 @@ impl<'a> Parser<'a> {
                 let symbol = Symbol::intern(&i);
                 self.token = Token::new(token::Ident(symbol, false), ident_span);
                 let next_token = (Token::new(token::Dot, dot_span), self.token_spacing);
-                self.parse_tuple_field_access_expr(lo, base, symbol, None, Some(next_token))
+                self.parse_expr_tuple_field_access(lo, base, symbol, None, Some(next_token))
             }
             // 1.2 | 1.2e3
             [IdentLike(i1), Punct('.'), IdentLike(i2)] => {
@@ -1109,11 +1109,11 @@ impl<'a> Parser<'a> {
                 // See issue #76399 and PR #76285 for more details
                 let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone);
                 let base1 =
-                    self.parse_tuple_field_access_expr(lo, base, symbol1, None, Some(next_token1));
+                    self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1));
                 let symbol2 = Symbol::intern(&i2);
                 let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
                 self.bump_with((next_token2, self.token_spacing)); // `.`
-                self.parse_tuple_field_access_expr(lo, base1, symbol2, suffix, None)
+                self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None)
             }
             // 1e+ | 1e- (recovered)
             [IdentLike(_), Punct('+' | '-')] |
@@ -1131,7 +1131,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_tuple_field_access_expr(
+    fn parse_expr_tuple_field_access(
         &mut self,
         lo: Span,
         base: P<Expr>,
@@ -1152,7 +1152,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a function call expression, `expr(...)`.
-    fn parse_fn_call_expr(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
+    fn parse_expr_fn_call(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
         let snapshot = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis)
             && self.look_ahead_type_ascription_as_field()
         {
@@ -1163,7 +1163,7 @@ impl<'a> Parser<'a> {
         let open_paren = self.token.span;
 
         let mut seq = self
-            .parse_paren_expr_seq()
+            .parse_expr_paren_seq()
             .map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args)));
         if let Some(expr) =
             self.maybe_recover_struct_lit_bad_delims(lo, open_paren, &mut seq, snapshot)
@@ -1236,7 +1236,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse an indexing expression `expr[...]`.
-    fn parse_index_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
+    fn parse_expr_index(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
         let prev_span = self.prev_token.span;
         let open_delim_span = self.token.span;
         self.bump(); // `[`
@@ -1259,7 +1259,7 @@ impl<'a> Parser<'a> {
 
         if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             // Method call `expr.f()`
-            let args = self.parse_paren_expr_seq()?;
+            let args = self.parse_expr_paren_seq()?;
             let fn_span = fn_span_lo.to(self.prev_token.span);
             let span = lo.to(self.prev_token.span);
             Ok(self.mk_expr(
@@ -1287,7 +1287,7 @@ impl<'a> Parser<'a> {
     ///
     /// N.B., this does not parse outer attributes, and is private because it only works
     /// correctly if called from `parse_dot_or_call_expr()`.
-    fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> {
         maybe_recover_from_interpolated_ty_qpath!(self, true);
         maybe_whole_expr!(self);
 
@@ -1300,13 +1300,13 @@ impl<'a> Parser<'a> {
             // This match arm is a special-case of the `_` match arm below and
             // could be removed without changing functionality, but it's faster
             // to have it here, especially for programs with large constants.
-            self.parse_lit_expr()
+            self.parse_expr_lit()
         } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
-            self.parse_tuple_parens_expr()
+            self.parse_expr_tuple_parens()
         } else if self.check(&token::OpenDelim(Delimiter::Brace)) {
-            self.parse_block_expr(None, lo, BlockCheckMode::Default)
+            self.parse_expr_block(None, lo, BlockCheckMode::Default)
         } else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) {
-            self.parse_closure_expr().map_err(|mut err| {
+            self.parse_expr_closure().map_err(|mut err| {
                 // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
                 // then suggest parens around the lhs.
                 if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
@@ -1315,42 +1315,42 @@ impl<'a> Parser<'a> {
                 err
             })
         } else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
-            self.parse_array_or_repeat_expr(Delimiter::Bracket)
+            self.parse_expr_array_or_repeat(Delimiter::Bracket)
         } else if self.check_path() {
-            self.parse_path_start_expr()
+            self.parse_expr_path_start()
         } else if self.check_keyword(kw::Move)
             || self.check_keyword(kw::Static)
             || self.check_const_closure()
         {
-            self.parse_closure_expr()
+            self.parse_expr_closure()
         } else if self.eat_keyword(kw::If) {
-            self.parse_if_expr()
+            self.parse_expr_if()
         } else if self.check_keyword(kw::For) {
             if self.choose_generics_over_qpath(1) {
-                self.parse_closure_expr()
+                self.parse_expr_closure()
             } else {
                 assert!(self.eat_keyword(kw::For));
-                self.parse_for_expr(None, self.prev_token.span)
+                self.parse_expr_for(None, self.prev_token.span)
             }
         } else if self.eat_keyword(kw::While) {
-            self.parse_while_expr(None, self.prev_token.span)
+            self.parse_expr_while(None, self.prev_token.span)
         } else if let Some(label) = self.eat_label() {
-            self.parse_labeled_expr(label, true)
+            self.parse_expr_labeled(label, true)
         } else if self.eat_keyword(kw::Loop) {
             let sp = self.prev_token.span;
-            self.parse_loop_expr(None, self.prev_token.span).map_err(|mut err| {
+            self.parse_expr_loop(None, self.prev_token.span).map_err(|mut err| {
                 err.span_label(sp, "while parsing this `loop` expression");
                 err
             })
         } else if self.eat_keyword(kw::Match) {
             let match_sp = self.prev_token.span;
-            self.parse_match_expr().map_err(|mut err| {
+            self.parse_expr_match().map_err(|mut err| {
                 err.span_label(match_sp, "while parsing this `match` expression");
                 err
             })
         } else if self.eat_keyword(kw::Unsafe) {
             let sp = self.prev_token.span;
-            self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(
+            self.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(
                 |mut err| {
                     err.span_label(sp, "while parsing this `unsafe` expression");
                     err
@@ -1364,17 +1364,17 @@ impl<'a> Parser<'a> {
             self.expect_keyword(kw::Try)?;
             self.parse_try_block(lo)
         } else if self.eat_keyword(kw::Return) {
-            self.parse_return_expr()
+            self.parse_expr_return()
         } else if self.eat_keyword(kw::Continue) {
-            self.parse_continue_expr(lo)
+            self.parse_expr_continue(lo)
         } else if self.eat_keyword(kw::Break) {
-            self.parse_break_expr()
+            self.parse_expr_break()
         } else if self.eat_keyword(kw::Yield) {
-            self.parse_yield_expr()
+            self.parse_expr_yield()
         } else if self.is_do_yeet() {
-            self.parse_yeet_expr()
+            self.parse_expr_yeet()
         } else if self.check_keyword(kw::Let) {
-            self.parse_let_expr()
+            self.parse_expr_let()
         } else if self.eat_keyword(kw::Underscore) {
             Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore))
         } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) {
@@ -1397,19 +1397,19 @@ impl<'a> Parser<'a> {
                     // Check for `async {` and `async move {`.
                     self.parse_async_block()
                 } else {
-                    self.parse_closure_expr()
+                    self.parse_expr_closure()
                 }
             } else if self.eat_keyword(kw::Await) {
                 self.recover_incorrect_await_syntax(lo, self.prev_token.span)
             } else {
-                self.parse_lit_expr()
+                self.parse_expr_lit()
             }
         } else {
-            self.parse_lit_expr()
+            self.parse_expr_lit()
         }
     }
 
-    fn parse_lit_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_lit(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         match self.parse_opt_token_lit() {
             Some((token_lit, _)) => {
@@ -1420,7 +1420,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_tuple_parens_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_tuple_parens(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
         let (es, trailing_comma) = match self.parse_seq_to_end(
@@ -1444,7 +1444,7 @@ impl<'a> Parser<'a> {
         self.maybe_recover_from_bad_qpath(expr)
     }
 
-    fn parse_array_or_repeat_expr(&mut self, close_delim: Delimiter) -> PResult<'a, P<Expr>> {
+    fn parse_expr_array_or_repeat(&mut self, close_delim: Delimiter) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         self.bump(); // `[` or other open delim
 
@@ -1457,7 +1457,7 @@ impl<'a> Parser<'a> {
             let first_expr = self.parse_expr()?;
             if self.eat(&token::Semi) {
                 // Repeating array syntax: `[ 0; 512 ]`
-                let count = self.parse_anon_const_expr()?;
+                let count = self.parse_expr_anon_const()?;
                 self.expect(close)?;
                 ExprKind::Repeat(first_expr, count)
             } else if self.eat(&token::Comma) {
@@ -1476,7 +1476,7 @@ impl<'a> Parser<'a> {
         self.maybe_recover_from_bad_qpath(expr)
     }
 
-    fn parse_path_start_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_path_start(&mut self) -> PResult<'a, P<Expr>> {
         let (qself, path) = if self.eat_lt() {
             let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
             (Some(qself), path)
@@ -1513,7 +1513,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse `'label: $expr`. The label is already parsed.
-    fn parse_labeled_expr(
+    fn parse_expr_labeled(
         &mut self,
         label_: Label,
         mut consume_colon: bool,
@@ -1522,15 +1522,15 @@ impl<'a> Parser<'a> {
         let label = Some(label_);
         let ate_colon = self.eat(&token::Colon);
         let expr = if self.eat_keyword(kw::While) {
-            self.parse_while_expr(label, lo)
+            self.parse_expr_while(label, lo)
         } else if self.eat_keyword(kw::For) {
-            self.parse_for_expr(label, lo)
+            self.parse_expr_for(label, lo)
         } else if self.eat_keyword(kw::Loop) {
-            self.parse_loop_expr(label, lo)
+            self.parse_expr_loop(label, lo)
         } else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace))
             || self.token.is_whole_block()
         {
-            self.parse_block_expr(label, lo, BlockCheckMode::Default)
+            self.parse_expr_block(label, lo, BlockCheckMode::Default)
         } else if !ate_colon
             && self.may_recover()
             && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma)
@@ -1670,7 +1670,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse `"return" expr?`.
-    fn parse_return_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_return(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
         let kind = ExprKind::Ret(self.parse_expr_opt()?);
         let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
@@ -1678,7 +1678,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse `"do" "yeet" expr?`.
-    fn parse_yeet_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_yeet(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
 
         self.bump(); // `do`
@@ -1700,13 +1700,13 @@ impl<'a> Parser<'a> {
     /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value
     /// expression only gets a warning for compatibility reasons; and a labeled break
     /// with a labeled loop does not even get a warning because there is no ambiguity.
-    fn parse_break_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_break(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
         let mut label = self.eat_label();
         let kind = if self.token == token::Colon && let Some(label) = label.take() {
             // The value expression can be a labeled loop, see issue #86948, e.g.:
             // `loop { break 'label: loop { break 'label 42; }; }`
-            let lexpr = self.parse_labeled_expr(label, true)?;
+            let lexpr = self.parse_expr_labeled(label, true)?;
             self.sess.emit_err(errors::LabeledLoopInBreak {
                 span: lexpr.span,
                 sub: errors::WrapExpressionInParentheses {
@@ -1759,7 +1759,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse `"continue" label?`.
-    fn parse_continue_expr(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
+    fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
         let mut label = self.eat_label();
 
         // Recover `continue label` -> `continue 'label`
@@ -1776,7 +1776,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse `"yield" expr?`.
-    fn parse_yield_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_yield(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
         let kind = ExprKind::Yield(self.parse_expr_opt()?);
         let span = lo.to(self.prev_token.span);
@@ -1993,7 +1993,7 @@ impl<'a> Parser<'a> {
     /// expression.
     fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<P<Expr>> {
         let mut snapshot = self.create_snapshot_for_diagnostic();
-        match snapshot.parse_array_or_repeat_expr(Delimiter::Brace) {
+        match snapshot.parse_expr_array_or_repeat(Delimiter::Brace) {
             Ok(arr) => {
                 self.sess.emit_err(errors::ArrayBracketsInsteadOfSpaces {
                     span: arr.span,
@@ -2056,7 +2056,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a block or unsafe block.
-    pub(super) fn parse_block_expr(
+    pub(super) fn parse_expr_block(
         &mut self,
         opt_label: Option<Label>,
         lo: Span,
@@ -2086,7 +2086,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a closure expression (e.g., `move |args| expr`).
-    fn parse_closure_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
 
         let binder = if self.check_keyword(kw::For) {
@@ -2123,7 +2123,7 @@ impl<'a> Parser<'a> {
             _ => {
                 // If an explicit return type is given, require a block to appear (RFC 968).
                 let body_lo = self.token.span;
-                self.parse_block_expr(None, body_lo, BlockCheckMode::Default)?
+                self.parse_expr_block(None, body_lo, BlockCheckMode::Default)?
             }
         };
 
@@ -2236,9 +2236,9 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses an `if` expression (`if` token already eaten).
-    fn parse_if_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_if(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
-        let cond = self.parse_cond_expr()?;
+        let cond = self.parse_expr_cond()?;
         self.parse_if_after_cond(lo, cond)
     }
 
@@ -2316,12 +2316,12 @@ impl<'a> Parser<'a> {
             self.error_on_if_block_attrs(lo, false, block.span, attrs);
             block
         };
-        let els = if self.eat_keyword(kw::Else) { Some(self.parse_else_expr()?) } else { None };
+        let els = if self.eat_keyword(kw::Else) { Some(self.parse_expr_else()?) } else { None };
         Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
     }
 
     /// Parses the condition of a `if` or `while` expression.
-    fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_cond(&mut self) -> PResult<'a, P<Expr>> {
         let cond =
             self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)?;
 
@@ -2334,7 +2334,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a `let $pat = $expr` pseudo-expression.
-    fn parse_let_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_let(&mut self) -> PResult<'a, P<Expr>> {
         // This is a *approximate* heuristic that detects if `let` chains are
         // being parsed in the right position. It's approximate because it
         // doesn't deny all invalid `let` expressions, just completely wrong usages.
@@ -2364,7 +2364,7 @@ impl<'a> Parser<'a> {
             self.expect(&token::Eq)?;
         }
         let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| {
-            this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
+            this.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), None.into())
         })?;
         let span = lo.to(expr.span);
         self.sess.gated_spans.gate(sym::let_chains, span);
@@ -2372,11 +2372,11 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses an `else { ... }` expression (`else` token already eaten).
-    fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_else(&mut self) -> PResult<'a, P<Expr>> {
         let else_span = self.prev_token.span; // `else`
         let attrs = self.parse_outer_attributes()?; // For recovery.
         let expr = if self.eat_keyword(kw::If) {
-            self.parse_if_expr()?
+            self.parse_expr_if()?
         } else if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) {
             self.parse_simple_block()?
         } else {
@@ -2450,7 +2450,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
-    fn parse_for_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
+    fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
         // Record whether we are about to parse `for (`.
         // This is used below for recovery in case of `for ( $stuff ) $block`
         // in which case we will suggest `for $stuff $block`.
@@ -2508,8 +2508,8 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a `while` or `while let` expression (`while` token already eaten).
-    fn parse_while_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
-        let cond = self.parse_cond_expr().map_err(|mut err| {
+    fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
+        let cond = self.parse_expr_cond().map_err(|mut err| {
             err.span_label(lo, "while parsing the condition of this `while` expression");
             err
         })?;
@@ -2526,7 +2526,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses `loop { ... }` (`loop` token already eaten).
-    fn parse_loop_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
+    fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
         let loop_span = self.prev_token.span;
         let (attrs, body) = self.parse_inner_attrs_and_block()?;
         Ok(self.mk_expr_with_attrs(
@@ -2544,7 +2544,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a `match ... { ... }` expression (`match` token already eaten).
-    fn parse_match_expr(&mut self) -> PResult<'a, P<Expr>> {
+    fn parse_expr_match(&mut self) -> PResult<'a, P<Expr>> {
         let match_span = self.prev_token.span;
         let lo = self.prev_token.span;
         let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
@@ -2914,7 +2914,7 @@ impl<'a> Parser<'a> {
             if let Err(err) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
                 return Some(Err(err));
             }
-            let expr = self.parse_struct_expr(qself.clone(), path.clone(), true);
+            let expr = self.parse_expr_struct(qself.clone(), path.clone(), true);
             if let (Ok(expr), false) = (&expr, struct_allowed) {
                 // This is a struct literal, but we don't can't accept them here.
                 self.sess.emit_err(errors::StructLiteralNotAllowedHere {
@@ -3043,7 +3043,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Precondition: already parsed the '{'.
-    pub(super) fn parse_struct_expr(
+    pub(super) fn parse_expr_struct(
         &mut self,
         qself: Option<P<ast::QSelf>>,
         pth: ast::Path,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index c0aed6a3789..9d9ae154ad4 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1331,7 +1331,7 @@ impl<'a> Parser<'a> {
                 };
 
                 let disr_expr =
-                    if this.eat(&token::Eq) { Some(this.parse_anon_const_expr()?) } else { None };
+                    if this.eat(&token::Eq) { Some(this.parse_expr_anon_const()?) } else { None };
 
                 let vr = ast::Variant {
                     ident,
@@ -1722,7 +1722,7 @@ impl<'a> Parser<'a> {
         }
         if self.token.kind == token::Eq {
             self.bump();
-            let const_expr = self.parse_anon_const_expr()?;
+            let const_expr = self.parse_expr_anon_const()?;
             let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
             self.struct_span_err(sp, "default values on `struct` fields aren't supported")
                 .span_suggestion(
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 623c82b37e0..fda9151478f 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -982,7 +982,11 @@ impl<'a> Parser<'a> {
         let initial_semicolon = self.token.span;
 
         while self.eat(&TokenKind::Semi) {
-            let _ = self.parse_stmt(ForceCollect::Yes)?;
+            let _ =
+                self.parse_stmt_without_recovery(false, ForceCollect::Yes).unwrap_or_else(|e| {
+                    e.cancel();
+                    None
+                });
         }
 
         expect_err.set_primary_message(
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 99416c3b204..b50d2984a4e 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -653,7 +653,7 @@ impl<'a> Parser<'a> {
     pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
         // Parse const argument.
         let value = if let token::OpenDelim(Delimiter::Brace) = self.token.kind {
-            self.parse_block_expr(None, self.token.span, BlockCheckMode::Default)?
+            self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?
         } else {
             self.handle_unambiguous_unbraced_const_arg()?
         };
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 8ef16ff43e1..92a22ffc2b0 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -146,14 +146,14 @@ impl<'a> Parser<'a> {
             }
 
             let expr = if this.eat(&token::OpenDelim(Delimiter::Brace)) {
-                this.parse_struct_expr(None, path, true)?
+                this.parse_expr_struct(None, path, true)?
             } else {
                 let hi = this.prev_token.span;
                 this.mk_expr(lo.to(hi), ExprKind::Path(None, path))
             };
 
             let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
-                this.parse_dot_or_call_expr_with(expr, lo, attrs)
+                this.parse_expr_dot_or_call_with(expr, lo, attrs)
             })?;
             // `DUMMY_SP` will get overwritten later in this function
             Ok((this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)), TrailingToken::None))
@@ -163,7 +163,7 @@ impl<'a> Parser<'a> {
             // Perform this outside of the `collect_tokens_trailing_token` closure,
             // since our outer attributes do not apply to this part of the expression
             let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
-                this.parse_assoc_expr_with(
+                this.parse_expr_assoc_with(
                     0,
                     LhsExpr::AlreadyParsed { expr, starts_statement: true },
                 )
@@ -199,8 +199,8 @@ impl<'a> Parser<'a> {
             // Since none of the above applied, this is an expression statement macro.
             let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
             let e = self.maybe_recover_from_bad_qpath(e)?;
-            let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
-            let e = self.parse_assoc_expr_with(
+            let e = self.parse_expr_dot_or_call_with(e, lo, attrs)?;
+            let e = self.parse_expr_assoc_with(
                 0,
                 LhsExpr::AlreadyParsed { expr: e, starts_statement: false },
             )?;
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 989a2bdca6d..6fe4da71f6b 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -433,7 +433,7 @@ impl<'a> Parser<'a> {
         };
 
         let ty = if self.eat(&token::Semi) {
-            let mut length = self.parse_anon_const_expr()?;
+            let mut length = self.parse_expr_anon_const()?;
             if let Err(e) = self.expect(&token::CloseDelim(Delimiter::Bracket)) {
                 // Try to recover from `X<Y, ...>` when `X::<Y, ...>` works
                 self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?;
@@ -494,7 +494,7 @@ impl<'a> Parser<'a> {
     // To avoid ambiguity, the type is surrounded by parentheses.
     fn parse_typeof_ty(&mut self) -> PResult<'a, TyKind> {
         self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
-        let expr = self.parse_anon_const_expr()?;
+        let expr = self.parse_expr_anon_const()?;
         self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
         Ok(TyKind::Typeof(expr))
     }
diff --git a/compiler/rustc_passes/locales/en-US.ftl b/compiler/rustc_passes/locales/en-US.ftl
index 0c7e02912d4..3fa78efc290 100644
--- a/compiler/rustc_passes/locales/en-US.ftl
+++ b/compiler/rustc_passes/locales/en-US.ftl
@@ -402,15 +402,12 @@ passes_invalid_attr_at_crate_level =
     `{$name}` attribute cannot be used at crate level
     .suggestion = perhaps you meant to use an outer attribute
 
-passes_duplicate_diagnostic_item =
-    duplicate diagnostic item found: `{$name}`.
-
 passes_duplicate_diagnostic_item_in_crate =
     duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
+    .note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
 
 passes_diagnostic_item_first_defined =
     the diagnostic item is first defined here
-    .note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
 
 passes_abi =
     abi: {$abi}
@@ -745,3 +742,7 @@ passes_proc_macro_invalid_abi = proc macro functions may not be `extern "{$abi}"
 passes_proc_macro_unsafe = proc macro functions may not be `unsafe`
 
 passes_skipping_const_checks = skipping const checks
+
+passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
+
+passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index bb09dcbdd69..5ef3e13eff8 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -23,7 +23,8 @@ use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{ParamEnv, TyCtxt};
 use rustc_session::lint::builtin::{
-    CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
+    CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
+    UNUSED_ATTRIBUTES,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -2102,7 +2103,33 @@ impl CheckAttrVisitor<'_> {
 
     fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
         if target != Target::MacroDef {
-            self.tcx.emit_spanned_lint(UNUSED_ATTRIBUTES, hir_id, attr.span, errors::MacroExport);
+            self.tcx.emit_spanned_lint(
+                UNUSED_ATTRIBUTES,
+                hir_id,
+                attr.span,
+                errors::MacroExport::Normal,
+            );
+        } else if let Some(meta_item_list) = attr.meta_item_list() &&
+        !meta_item_list.is_empty() {
+            if meta_item_list.len() > 1 {
+                self.tcx.emit_spanned_lint(
+                    INVALID_MACRO_EXPORT_ARGUMENTS,
+                    hir_id,
+                    attr.span,
+                    errors::MacroExport::TooManyItems,
+                );
+            } else {
+                if meta_item_list[0].name_or_empty() != sym::local_inner_macros {
+                    self.tcx.emit_spanned_lint(
+                        INVALID_MACRO_EXPORT_ARGUMENTS,
+                        hir_id,
+                        meta_item_list[0].span(),
+                        errors::MacroExport::UnknownItem {
+                            name: meta_item_list[0].name_or_empty(),
+                        },
+                    );
+                }
+            }
         }
     }
 
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index 0ae7096642c..110eb210df9 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -11,19 +11,19 @@
 
 use rustc_ast as ast;
 use rustc_hir::diagnostic_items::DiagnosticItems;
+use rustc_hir::OwnerId;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
-use rustc_span::symbol::{kw::Empty, sym, Symbol};
+use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc_span::symbol::{sym, Symbol};
 
-use crate::errors::{DuplicateDiagnosticItem, DuplicateDiagnosticItemInCrate};
+use crate::errors::DuplicateDiagnosticItemInCrate;
 
-fn observe_item(tcx: TyCtxt<'_>, diagnostic_items: &mut DiagnosticItems, def_id: LocalDefId) {
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let attrs = tcx.hir().attrs(hir_id);
+fn observe_item<'tcx>(tcx: TyCtxt<'tcx>, diagnostic_items: &mut DiagnosticItems, owner: OwnerId) {
+    let attrs = tcx.hir().attrs(owner.into());
     if let Some(name) = extract(attrs) {
         // insert into our table
-        collect_item(tcx, diagnostic_items, name, def_id.to_def_id());
+        collect_item(tcx, diagnostic_items, name, owner.to_def_id());
     }
 }
 
@@ -31,23 +31,29 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item
     items.id_to_name.insert(item_def_id, name);
     if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
         if original_def_id != item_def_id {
-            let orig_span = tcx.hir().span_if_local(original_def_id);
-            let orig_crate_name =
-                orig_span.is_none().then(|| tcx.crate_name(original_def_id.krate));
-            match tcx.hir().span_if_local(item_def_id) {
-                Some(span) => tcx.sess.emit_err(DuplicateDiagnosticItem { span, name }),
-                None => tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
-                    span: orig_span,
-                    orig_crate_name: orig_crate_name.unwrap_or(Empty),
-                    have_orig_crate_name: orig_crate_name.map(|_| ()),
-                    crate_name: tcx.crate_name(item_def_id.krate),
-                    name,
-                }),
-            };
+            report_duplicate_item(tcx, name, original_def_id, item_def_id);
         }
     }
 }
 
+fn report_duplicate_item(
+    tcx: TyCtxt<'_>,
+    name: Symbol,
+    original_def_id: DefId,
+    item_def_id: DefId,
+) {
+    let orig_span = tcx.hir().span_if_local(original_def_id);
+    let duplicate_span = tcx.hir().span_if_local(item_def_id);
+    tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
+        duplicate_span,
+        orig_span,
+        crate_name: tcx.crate_name(item_def_id.krate),
+        orig_crate_name: tcx.crate_name(original_def_id.krate),
+        different_crates: (item_def_id.krate != original_def_id.krate).then_some(()),
+        name,
+    });
+}
+
 /// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.
 fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
     attrs.iter().find_map(|attr| {
@@ -64,21 +70,8 @@ fn diagnostic_items(tcx: TyCtxt<'_>, cnum: CrateNum) -> DiagnosticItems {
 
     // Collect diagnostic items in this crate.
     let crate_items = tcx.hir_crate_items(());
-
-    for id in crate_items.items() {
-        observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
-    }
-
-    for id in crate_items.trait_items() {
-        observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
-    }
-
-    for id in crate_items.impl_items() {
-        observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
-    }
-
-    for id in crate_items.foreign_items() {
-        observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
+    for id in crate_items.owners() {
+        observe_item(tcx, &mut diagnostic_items, id);
     }
 
     diagnostic_items
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 82fc3eeff94..9f1c0b5a0b7 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -641,8 +641,16 @@ pub struct MacroUse {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes_macro_export)]
-pub struct MacroExport;
+pub enum MacroExport {
+    #[diag(passes_macro_export)]
+    Normal,
+
+    #[diag(passes_invalid_macro_export_arguments)]
+    UnknownItem { name: Symbol },
+
+    #[diag(passes_invalid_macro_export_arguments_too_many_items)]
+    TooManyItems,
+}
 
 #[derive(LintDiagnostic)]
 #[diag(passes_plugin_registrar)]
@@ -802,22 +810,16 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_duplicate_diagnostic_item)]
-pub struct DuplicateDiagnosticItem {
-    #[primary_span]
-    pub span: Span,
-    pub name: Symbol,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_duplicate_diagnostic_item_in_crate)]
 pub struct DuplicateDiagnosticItemInCrate {
+    #[primary_span]
+    pub duplicate_span: Option<Span>,
     #[note(passes_diagnostic_item_first_defined)]
-    pub span: Option<Span>,
-    pub orig_crate_name: Symbol,
+    pub orig_span: Option<Span>,
     #[note]
-    pub have_orig_crate_name: Option<()>,
+    pub different_crates: Option<()>,
     pub crate_name: Symbol,
+    pub orig_crate_name: Symbol,
     pub name: Symbol,
 }
 
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 678f1815d01..df5c8f53ec1 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -475,7 +475,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
             | hir::ExprKind::InlineAsm(..)
             | hir::ExprKind::Box(..)
             | hir::ExprKind::Type(..)
-            | hir::ExprKind::Err
+            | hir::ExprKind::Err(_)
             | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
             | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {
                 intravisit::walk_expr(self, expr);
@@ -1129,7 +1129,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
             hir::ExprKind::Lit(..)
             | hir::ExprKind::ConstBlock(..)
-            | hir::ExprKind::Err
+            | hir::ExprKind::Err(_)
             | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
             | hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ,
 
@@ -1427,7 +1427,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
         | hir::ExprKind::Yield(..)
         | hir::ExprKind::Box(..)
         | hir::ExprKind::Type(..)
-        | hir::ExprKind::Err => {}
+        | hir::ExprKind::Err(_) => {}
     }
 }
 
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index acc54e7e110..c5b5cf7f5a9 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -219,7 +219,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
                 hir::intravisit::walk_expr(self, expr);
             }
 
-            ExprKind::Err => {
+            ExprKind::Err(_) => {
                 self.items.push((ItemKind::Err, span));
             }
         }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 88a55dc8319..16194a6f196 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -748,7 +748,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                         let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
                         c.visit_ty(self_ty);
                         c.visit_trait_ref(t);
-                        if c.fully_stable {
+
+                        // do not lint when the trait isn't resolved, since resolution error should
+                        // be fixed first
+                        if t.path.res != Res::Err && c.fully_stable {
                             self.tcx.struct_span_lint_hir(
                                 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
                                 item.hir_id(),
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index e2884f2026e..a8592bd7086 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -124,9 +124,7 @@ impl QueryContext for QueryCtxt<'_> {
             };
 
             // Use the `ImplicitCtxt` while we execute the query.
-            tls::enter_context(&new_icx, || {
-                rustc_data_structures::stack::ensure_sufficient_stack(compute)
-            })
+            tls::enter_context(&new_icx, compute)
         })
     }
 
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 9443ded704d..59e0c359745 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -6,6 +6,7 @@ use rustc_data_structures::sharded::{self, Sharded};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
+use rustc_data_structures::OnDrop;
 use rustc_index::vec::IndexVec;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use smallvec::{smallvec, SmallVec};
@@ -278,6 +279,7 @@ impl<K: DepKind> DepGraph<K> {
     ///   `arg` parameter.
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html
+    #[inline(always)]
     pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
         &self,
         key: DepNode<K>,
@@ -297,6 +299,7 @@ impl<K: DepKind> DepGraph<K> {
         }
     }
 
+    #[inline(always)]
     fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
         &self,
         key: DepNode<K>,
@@ -597,6 +600,7 @@ impl<K: DepKind> DepGraph<K> {
         self.data.is_some() && self.dep_node_index_of_opt(dep_node).is_some()
     }
 
+    #[inline]
     pub fn prev_fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
         self.data.as_ref().unwrap().previous.fingerprint_of(dep_node)
     }
@@ -671,17 +675,24 @@ impl<K: DepKind> DepGraph<K> {
         let prev_index = data.previous.node_to_index_opt(dep_node)?;
 
         match data.colors.get(prev_index) {
-            Some(DepNodeColor::Green(dep_node_index)) => Some((prev_index, dep_node_index)),
-            Some(DepNodeColor::Red) => None,
-            None => {
-                // This DepNode and the corresponding query invocation existed
-                // in the previous compilation session too, so we can try to
-                // mark it as green by recursively marking all of its
-                // dependencies green.
-                self.try_mark_previous_green(qcx, data, prev_index, &dep_node)
-                    .map(|dep_node_index| (prev_index, dep_node_index))
-            }
+            Some(DepNodeColor::Green(dep_node_index)) => return Some((prev_index, dep_node_index)),
+            Some(DepNodeColor::Red) => return None,
+            None => {}
         }
+
+        let backtrace = backtrace_printer(qcx.dep_context().sess(), data, prev_index);
+
+        // This DepNode and the corresponding query invocation existed
+        // in the previous compilation session too, so we can try to
+        // mark it as green by recursively marking all of its
+        // dependencies green.
+        let ret = self
+            .try_mark_previous_green(qcx, data, prev_index, &dep_node)
+            .map(|dep_node_index| (prev_index, dep_node_index));
+
+        // We succeeded, no backtrace.
+        backtrace.disable();
+        return ret;
     }
 
     #[instrument(skip(self, qcx, data, parent_dep_node_index), level = "debug")]
@@ -794,7 +805,10 @@ impl<K: DepKind> DepGraph<K> {
         let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
 
         for &dep_dep_node_index in prev_deps {
-            self.try_mark_parent_green(qcx, data, dep_dep_node_index, dep_node)?
+            let backtrace = backtrace_printer(qcx.dep_context().sess(), data, dep_dep_node_index);
+            let success = self.try_mark_parent_green(qcx, data, dep_dep_node_index, dep_node);
+            backtrace.disable();
+            success?;
         }
 
         // If we got here without hitting a `return` that means that all
@@ -1116,6 +1130,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
 
     /// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it.
     /// Assumes that this is a node that has no equivalent in the previous dep-graph.
+    #[inline(always)]
     fn intern_new_node(
         &self,
         profiler: &SelfProfilerRef,
@@ -1354,6 +1369,7 @@ impl DepNodeColorMap {
         }
     }
 
+    #[inline]
     fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) {
         self.values[index].store(
             match color {
@@ -1364,3 +1380,26 @@ impl DepNodeColorMap {
         )
     }
 }
+
+fn backtrace_printer<'a, K: DepKind>(
+    sess: &'a rustc_session::Session,
+    graph: &'a DepGraphData<K>,
+    node: SerializedDepNodeIndex,
+) -> OnDrop<impl Fn() + 'a> {
+    OnDrop(
+        #[inline(never)]
+        #[cold]
+        move || {
+            let node = graph.previous.index_to_node(node);
+            // Do not try to rely on DepNode's Debug implementation, since it may panic.
+            let diag = rustc_errors::Diagnostic::new(
+                rustc_errors::Level::FailureNote,
+                &format!(
+                    "encountered while trying to mark dependency green: {:?}({})",
+                    node.kind, node.hash
+                ),
+            );
+            sess.diagnostic().force_print_diagnostic(diag);
+        },
+    )
+}
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index e840108bdd8..4b3cd16c29f 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -21,7 +21,7 @@ pub trait QueryStorage {
 }
 
 pub trait QueryCache: QueryStorage + Sized {
-    type Key: Hash + Eq + Clone + Debug;
+    type Key: Hash + Eq + Copy + Debug;
 
     /// Checks if the query is already computed and in the cache.
     /// It returns the shard index and a lock guard to the shard,
@@ -61,7 +61,7 @@ impl<K: Eq + Hash, V: Copy + Debug> QueryStorage for DefaultCache<K, V> {
 
 impl<K, V> QueryCache for DefaultCache<K, V>
 where
-    K: Eq + Hash + Clone + Debug,
+    K: Eq + Hash + Copy + Debug,
     V: Copy + Debug,
 {
     type Key = K;
@@ -179,7 +179,7 @@ impl<K: Eq + Idx, V: Copy + Debug> QueryStorage for VecCache<K, V> {
 
 impl<K, V> QueryCache for VecCache<K, V>
 where
-    K: Eq + Idx + Clone + Debug,
+    K: Eq + Idx + Copy + Debug,
     V: Copy + Debug,
 {
     type Key = K;
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index 56247e827a2..d5637387346 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -19,7 +19,9 @@ pub type TryLoadFromDisk<Qcx, Q> =
 pub trait QueryConfig<Qcx: QueryContext> {
     const NAME: &'static str;
 
-    type Key: DepNodeParams<Qcx::DepContext> + Eq + Hash + Clone + Debug;
+    // `Key` and `Value` are `Copy` instead of `Clone` to ensure copying them stays cheap,
+    // but it isn't necessary.
+    type Key: DepNodeParams<Qcx::DepContext> + Eq + Hash + Copy + Debug;
     type Value: Debug + Copy;
 
     type Cache: QueryCache<Key = Self::Key, Value = Self::Value>;
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 21a0c73d720..586bd38fbb8 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::TimingGuard;
 #[cfg(parallel_compiler)]
 use rustc_data_structures::sharded::Sharded;
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lock;
 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError};
 use rustc_session::Session;
@@ -48,7 +49,7 @@ enum QueryResult<D: DepKind> {
 
 impl<K, D> QueryState<K, D>
 where
-    K: Eq + Hash + Clone + Debug,
+    K: Eq + Hash + Copy + Debug,
     D: DepKind,
 {
     pub fn all_inactive(&self) -> bool {
@@ -77,7 +78,7 @@ where
             for shard in shards.iter() {
                 for (k, v) in shard.iter() {
                     if let QueryResult::Started(ref job) = *v {
-                        let query = make_query(qcx, k.clone());
+                        let query = make_query(qcx, *k);
                         jobs.insert(job.id, QueryJobInfo { query, job: job.clone() });
                     }
                 }
@@ -91,7 +92,7 @@ where
             // really hurt much.)
             for (k, v) in self.active.try_lock()?.iter() {
                 if let QueryResult::Started(ref job) = *v {
-                    let query = make_query(qcx, k.clone());
+                    let query = make_query(qcx, *k);
                     jobs.insert(job.id, QueryJobInfo { query, job: job.clone() });
                 }
             }
@@ -111,7 +112,7 @@ impl<K, D: DepKind> Default for QueryState<K, D> {
 /// This will poison the relevant query if dropped.
 struct JobOwner<'tcx, K, D: DepKind>
 where
-    K: Eq + Hash + Clone,
+    K: Eq + Hash + Copy,
 {
     state: &'tcx QueryState<K, D>,
     key: K,
@@ -163,7 +164,7 @@ where
 
 impl<'tcx, K, D: DepKind> JobOwner<'tcx, K, D>
 where
-    K: Eq + Hash + Clone,
+    K: Eq + Hash + Copy,
 {
     /// Either gets a `JobOwner` corresponding the query, allowing us to
     /// start executing the query, or returns with the result of the query.
@@ -188,14 +189,14 @@ where
         #[cfg(not(parallel_compiler))]
         let mut state_lock = state.active.lock();
         let lock = &mut *state_lock;
+        let current_job_id = qcx.current_query_job();
 
         match lock.entry(key) {
             Entry::Vacant(entry) => {
                 let id = qcx.next_job_id();
-                let job = qcx.current_query_job();
-                let job = QueryJob::new(id, span, job);
+                let job = QueryJob::new(id, span, current_job_id);
 
-                let key = entry.key().clone();
+                let key = *entry.key();
                 entry.insert(QueryResult::Started(job));
 
                 let owner = JobOwner { state, id, key };
@@ -212,7 +213,7 @@ where
                         // so we just return the error.
                         return TryGetJob::Cycle(id.find_cycle_in_stack(
                             qcx.try_collect_active_jobs().unwrap(),
-                            &qcx.current_query_job(),
+                            &current_job_id,
                             span,
                         ));
                     }
@@ -230,7 +231,7 @@ where
 
                         // With parallel queries we might just have to wait on some other
                         // thread.
-                        let result = latch.wait_on(qcx.current_query_job(), span);
+                        let result = latch.wait_on(current_job_id, span);
 
                         match result {
                             Ok(()) => TryGetJob::JobCompleted(query_blocked_prof_timer),
@@ -274,7 +275,7 @@ where
 
 impl<'tcx, K, D> Drop for JobOwner<'tcx, K, D>
 where
-    K: Eq + Hash + Clone,
+    K: Eq + Hash + Copy,
     D: DepKind,
 {
     #[inline(never)]
@@ -291,7 +292,7 @@ where
                 QueryResult::Started(job) => job,
                 QueryResult::Poisoned => panic!(),
             };
-            shard.insert(self.key.clone(), QueryResult::Poisoned);
+            shard.insert(self.key, QueryResult::Poisoned);
             job
         };
         // Also signal the completion of the job, so waiters
@@ -310,7 +311,7 @@ pub(crate) struct CycleError<D: DepKind> {
 /// The result of `try_start`.
 enum TryGetJob<'tcx, K, D>
 where
-    K: Eq + Hash + Clone,
+    K: Eq + Hash + Copy,
     D: DepKind,
 {
     /// The query is not yet started. Contains a guard to the cache eventually used to start it.
@@ -346,10 +347,9 @@ where
     }
 }
 
+#[inline(never)]
 fn try_execute_query<Q, Qcx>(
     qcx: Qcx,
-    state: &QueryState<Q::Key, Qcx::DepKind>,
-    cache: &Q::Cache,
     span: Span,
     key: Q::Key,
     dep_node: Option<DepNode<Qcx::DepKind>>,
@@ -358,10 +358,11 @@ where
     Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
-    match JobOwner::<'_, Q::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
+    let state = Q::query_state(qcx);
+    match JobOwner::<'_, Q::Key, Qcx::DepKind>::try_start(&qcx, state, span, key) {
         TryGetJob::NotYetStarted(job) => {
-            let (result, dep_node_index) =
-                execute_job::<Q, Qcx>(qcx, key.clone(), dep_node, job.id);
+            let (result, dep_node_index) = execute_job::<Q, Qcx>(qcx, key, dep_node, job.id);
+            let cache = Q::query_cache(qcx);
             if Q::FEEDABLE {
                 // We should not compute queries that also got a value via feeding.
                 // This can't happen, as query feeding adds the very dependencies to the fed query
@@ -382,7 +383,7 @@ where
         }
         #[cfg(parallel_compiler)]
         TryGetJob::JobCompleted(query_blocked_prof_timer) => {
-            let Some((v, index)) = cache.lookup(&key) else {
+            let Some((v, index)) = Q::query_cache(qcx).lookup(&key) else {
                 panic!("value must be in cache after waiting")
             };
 
@@ -394,6 +395,7 @@ where
     }
 }
 
+#[inline(always)]
 fn execute_job<Q, Qcx>(
     qcx: Qcx,
     key: Q::Key,
@@ -479,6 +481,7 @@ where
     (result, dep_node_index)
 }
 
+#[inline(always)]
 fn try_load_from_disk_and_cache_in_memory<Q, Qcx>(
     qcx: Qcx,
     key: &Q::Key,
@@ -551,7 +554,7 @@ where
     let prof_timer = qcx.dep_context().profiler().query_provider();
 
     // The dep-graph for this computation is already in-place.
-    let result = dep_graph.with_ignore(|| Q::compute(qcx, key.clone()));
+    let result = dep_graph.with_ignore(|| Q::compute(qcx, *key));
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
@@ -569,6 +572,7 @@ where
     Some((result, dep_node_index))
 }
 
+#[inline]
 #[instrument(skip(tcx, result, hash_result), level = "debug")]
 pub(crate) fn incremental_verify_ich<Tcx, V: Debug>(
     tcx: Tcx,
@@ -723,6 +727,7 @@ pub enum QueryMode {
     Ensure,
 }
 
+#[inline(always)]
 pub fn get_query<Q, Qcx, D>(qcx: Qcx, span: Span, key: Q::Key, mode: QueryMode) -> Option<Q::Value>
 where
     D: DepKind,
@@ -740,14 +745,8 @@ where
         None
     };
 
-    let (result, dep_node_index) = try_execute_query::<Q, Qcx>(
-        qcx,
-        Q::query_state(qcx),
-        Q::query_cache(qcx),
-        span,
-        key,
-        dep_node,
-    );
+    let (result, dep_node_index) =
+        ensure_sufficient_stack(|| try_execute_query::<Q, Qcx>(qcx, span, key, dep_node));
     if let Some(dep_node_index) = dep_node_index {
         qcx.dep_context().dep_graph().read_index(dep_node_index)
     }
@@ -763,14 +762,12 @@ where
 {
     // We may be concurrently trying both execute and force a query.
     // Ensure that only one of them runs the query.
-    let cache = Q::query_cache(qcx);
-    if let Some((_, index)) = cache.lookup(&key) {
+    if let Some((_, index)) = Q::query_cache(qcx).lookup(&key) {
         qcx.dep_context().profiler().query_cache_hit(index.into());
         return;
     }
 
-    let state = Q::query_state(qcx);
     debug_assert!(!Q::ANON);
 
-    try_execute_query::<Q, _>(qcx, state, cache, DUMMY_SP, key, Some(dep_node));
+    ensure_sufficient_stack(|| try_execute_query::<Q, _>(qcx, DUMMY_SP, key, Some(dep_node)));
 }
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 0114e116386..b2578e4c4b4 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -29,11 +29,12 @@ use crate::Resolver;
 
 use rustc_ast as ast;
 use rustc_ast::visit::{self, Visitor};
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{pluralize, MultiSpan};
-use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
+use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS};
 use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
 struct UnusedImport<'a> {
@@ -53,11 +54,28 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     r: &'a mut Resolver<'b, 'tcx>,
     /// All the (so far) unused imports, grouped path list
     unused_imports: FxIndexMap<ast::NodeId, UnusedImport<'a>>,
+    extern_crate_items: Vec<ExternCrateToLint>,
     base_use_tree: Option<&'a ast::UseTree>,
     base_id: ast::NodeId,
     item_span: Span,
 }
 
+struct ExternCrateToLint {
+    id: ast::NodeId,
+    /// Span from the item
+    span: Span,
+    /// Span to use to suggest complete removal.
+    span_with_attributes: Span,
+    /// Span of the visibility, if any.
+    vis_span: Span,
+    /// Whether the item has attrs.
+    has_attrs: bool,
+    /// Name used to refer to the crate.
+    ident: Ident,
+    /// Whether the statement renames the crate `extern crate orig_name as new_name;`.
+    renames: bool,
+}
+
 impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     // We have information about whether `use` (import) items are actually
     // used now. If an import is not used at all, we signal a lint error.
@@ -96,18 +114,27 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
 
 impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     fn visit_item(&mut self, item: &'a ast::Item) {
-        self.item_span = item.span_with_attributes();
-
-        // Ignore is_public import statements because there's no way to be sure
-        // whether they're used or not. Also ignore imports with a dummy span
-        // because this means that they were generated in some fashion by the
-        // compiler and we don't need to consider them.
-        if let ast::ItemKind::Use(..) = item.kind {
-            if item.vis.kind.is_pub() || item.span.is_dummy() {
-                return;
+        match item.kind {
+            // Ignore is_public import statements because there's no way to be sure
+            // whether they're used or not. Also ignore imports with a dummy span
+            // because this means that they were generated in some fashion by the
+            // compiler and we don't need to consider them.
+            ast::ItemKind::Use(..) if item.vis.kind.is_pub() || item.span.is_dummy() => return,
+            ast::ItemKind::ExternCrate(orig_name) => {
+                self.extern_crate_items.push(ExternCrateToLint {
+                    id: item.id,
+                    span: item.span,
+                    vis_span: item.vis.span,
+                    span_with_attributes: item.span_with_attributes(),
+                    has_attrs: !item.attrs.is_empty(),
+                    ident: item.ident,
+                    renames: orig_name.is_some(),
+                });
             }
+            _ => {}
         }
 
+        self.item_span = item.span_with_attributes();
         visit::walk_item(self, item);
     }
 
@@ -224,6 +251,9 @@ fn calc_unused_spans(
 
 impl Resolver<'_, '_> {
     pub(crate) fn check_unused(&mut self, krate: &ast::Crate) {
+        let tcx = self.tcx;
+        let mut maybe_unused_extern_crates = FxHashMap::default();
+
         for import in self.potentially_unused_imports.iter() {
             match import.kind {
                 _ if import.used.get()
@@ -246,7 +276,14 @@ impl Resolver<'_, '_> {
                 }
                 ImportKind::ExternCrate { id, .. } => {
                     let def_id = self.local_def_id(id);
-                    self.maybe_unused_extern_crates.push((def_id, import.span));
+                    if self.extern_crate_map.get(&def_id).map_or(true, |&cnum| {
+                        !tcx.is_compiler_builtins(cnum)
+                            && !tcx.is_panic_runtime(cnum)
+                            && !tcx.has_global_allocator(cnum)
+                            && !tcx.has_panic_handler(cnum)
+                    }) {
+                        maybe_unused_extern_crates.insert(id, import.span);
+                    }
                 }
                 ImportKind::MacroUse => {
                     let msg = "unused `#[macro_use]` import";
@@ -259,6 +296,7 @@ impl Resolver<'_, '_> {
         let mut visitor = UnusedImportCheckVisitor {
             r: self,
             unused_imports: Default::default(),
+            extern_crate_items: Default::default(),
             base_use_tree: None,
             base_id: ast::DUMMY_NODE_ID,
             item_span: DUMMY_SP,
@@ -290,7 +328,7 @@ impl Resolver<'_, '_> {
             let ms = MultiSpan::from_spans(spans.clone());
             let mut span_snippets = spans
                 .iter()
-                .filter_map(|s| match visitor.r.tcx.sess.source_map().span_to_snippet(*s) {
+                .filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) {
                     Ok(s) => Some(format!("`{}`", s)),
                     _ => None,
                 })
@@ -317,7 +355,7 @@ impl Resolver<'_, '_> {
             // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]`
             // attribute; however, if not, suggest adding the attribute. There is no way to
             // retrieve attributes here because we do not have a `TyCtxt` yet.
-            let test_module_span = if visitor.r.tcx.sess.opts.test {
+            let test_module_span = if tcx.sess.opts.test {
                 None
             } else {
                 let parent_module = visitor.r.get_nearest_non_block_module(
@@ -346,5 +384,74 @@ impl Resolver<'_, '_> {
                 BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes, test_module_span),
             );
         }
+
+        for extern_crate in visitor.extern_crate_items {
+            let warn_if_unused = !extern_crate.ident.name.as_str().starts_with('_');
+
+            // If the crate is fully unused, we suggest removing it altogether.
+            // We do this in any edition.
+            if warn_if_unused {
+                if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) {
+                    visitor.r.lint_buffer.buffer_lint_with_diagnostic(
+                        UNUSED_EXTERN_CRATES,
+                        extern_crate.id,
+                        span,
+                        "unused extern crate",
+                        BuiltinLintDiagnostics::UnusedExternCrate {
+                            removal_span: extern_crate.span_with_attributes,
+                        },
+                    );
+                    continue;
+                }
+            }
+
+            // If we are not in Rust 2018 edition, then we don't make any further
+            // suggestions.
+            if !tcx.sess.rust_2018() {
+                continue;
+            }
+
+            // If the extern crate has any attributes, they may have funky
+            // semantics we can't faithfully represent using `use` (most
+            // notably `#[macro_use]`). Ignore it.
+            if extern_crate.has_attrs {
+                continue;
+            }
+
+            // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
+            // would not insert the new name into the prelude, where other imports in the crate may be
+            // expecting it.
+            if extern_crate.renames {
+                continue;
+            }
+
+            // If the extern crate isn't in the extern prelude,
+            // there is no way it can be written as a `use`.
+            if !visitor
+                .r
+                .extern_prelude
+                .get(&extern_crate.ident)
+                .map_or(false, |entry| !entry.introduced_by_item)
+            {
+                continue;
+            }
+
+            let vis_span = extern_crate
+                .vis_span
+                .find_ancestor_inside(extern_crate.span)
+                .unwrap_or(extern_crate.vis_span);
+            let ident_span = extern_crate
+                .ident
+                .span
+                .find_ancestor_inside(extern_crate.span)
+                .unwrap_or(extern_crate.ident.span);
+            visitor.r.lint_buffer.buffer_lint_with_diagnostic(
+                UNUSED_EXTERN_CRATES,
+                extern_crate.id,
+                extern_crate.span,
+                "`extern crate` is not idiomatic in the new edition",
+                BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span },
+            );
+        }
     }
 }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index ee2d2301399..7add59ac627 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -189,7 +189,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         let container = match parent.kind {
-            ModuleKind::Def(kind, _, _) => self.tcx.def_kind_descr(kind, parent.def_id()),
+            // Avoid using TyCtxt::def_kind_descr in the resolver, because it
+            // indirectly *calls* the resolver, and would cause a query cycle.
+            ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
             ModuleKind::Block => "block",
         };
 
@@ -1804,7 +1806,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         found("module")
                     } else {
                         match binding.res() {
-                            Res::Def(kind, id) => found(self.tcx.def_kind_descr(kind, id)),
+                            // Avoid using TyCtxt::def_kind_descr in the resolver, because it
+                            // indirectly *calls* the resolver, and would cause a query cycle.
+                            Res::Def(kind, id) => found(kind.descr(id)),
                             _ => found(ns_to_try.descr()),
                         }
                     }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 7a1f14f71f2..1fdfb1a53d4 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -946,7 +946,6 @@ pub struct Resolver<'a, 'tcx> {
     has_pub_restricted: bool,
     used_imports: FxHashSet<NodeId>,
     maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
-    maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
 
     /// Privacy errors are delayed until the end in order to deduplicate them.
     privacy_errors: Vec<PrivacyError<'a>>,
@@ -1284,7 +1283,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             has_pub_restricted: false,
             used_imports: FxHashSet::default(),
             maybe_unused_trait_imports: Default::default(),
-            maybe_unused_extern_crates: Vec::new(),
 
             privacy_errors: Vec::new(),
             ambiguity_errors: Vec::new(),
@@ -1400,7 +1398,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let extern_crate_map = self.extern_crate_map;
         let reexport_map = self.reexport_map;
         let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
-        let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
         let glob_map = self.glob_map;
         let main_def = self.main_def;
         let confused_type_with_std_module = self.confused_type_with_std_module;
@@ -1414,12 +1411,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             reexport_map,
             glob_map,
             maybe_unused_trait_imports,
-            maybe_unused_extern_crates,
-            extern_prelude: self
-                .extern_prelude
-                .iter()
-                .map(|(ident, entry)| (ident.name, entry.introduced_by_item))
-                .collect(),
             main_def,
             trait_impls: self.trait_impls,
             proc_macros,
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 377c364961b..567fe06109b 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -43,7 +43,6 @@ pub trait Encoder {
     fn emit_str(&mut self, v: &str);
     fn emit_raw_bytes(&mut self, s: &[u8]);
 
-    // Convenience for the derive macro:
     fn emit_enum_variant<F>(&mut self, v_id: usize, f: F)
     where
         F: FnOnce(&mut Self),
@@ -51,17 +50,6 @@ pub trait Encoder {
         self.emit_usize(v_id);
         f(self);
     }
-
-    // We put the field index in a const generic to allow the emit_usize to be
-    // compiled into a more efficient form. In practice, the variant index is
-    // known at compile-time, and that knowledge allows much more efficient
-    // codegen than we'd otherwise get. LLVM isn't always able to make the
-    // optimization that would otherwise be necessary here, likely due to the
-    // multiple levels of inlining and const-prop that are needed.
-    #[inline]
-    fn emit_fieldless_enum_variant<const ID: usize>(&mut self) {
-        self.emit_usize(ID)
-    }
 }
 
 // Note: all the methods in this trait are infallible, which may be surprising.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 1f3eb8d4832..4beac931632 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1489,6 +1489,8 @@ options! {
         "keep hygiene data after analysis (default: no)"),
     layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
         "seed layout randomization"),
+    link_directives: bool = (true, parse_bool, [TRACKED],
+        "honor #[link] directives in the compiled crate (default: yes)"),
     link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
         "link native libraries in the linker invocation (default: yes)"),
     link_only: bool = (false, parse_bool, [TRACKED],
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index e112100aa5f..873cd33f6a4 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -2149,3 +2149,17 @@ where
         Hash::hash(&len, hasher);
     }
 }
+
+/// Useful type to use with `Result<>` indicate that an error has already
+/// been reported to the user, so no need to continue checking.
+#[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(HashStable_Generic)]
+pub struct ErrorGuaranteed(());
+
+impl ErrorGuaranteed {
+    /// To be used only if you really know what you are doing... ideally, we would find a way to
+    /// eliminate all calls to this method.
+    pub fn unchecked_claim_error_was_emitted() -> Self {
+        ErrorGuaranteed(())
+    }
+}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 37d2aea42ad..fb579e4ff77 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -740,6 +740,7 @@ symbols! {
         frem_fast,
         from,
         from_desugaring,
+        from_fn,
         from_iter,
         from_method,
         from_output,
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 1d299e29256..1a679f32ca5 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -675,7 +675,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
         _ if ty.is_unit() => {}
 
         ty::Tuple(tys) => {
-            ty = tcx.mk_tup(tys.iter().map(|ty| transform_ty(tcx, ty, options)));
+            ty = tcx.mk_tup_from_iter(tys.iter().map(|ty| transform_ty(tcx, ty, options)));
         }
 
         ty::Array(ty0, len) => {
@@ -825,7 +825,7 @@ fn transform_substs<'tcx>(
             subst
         }
     });
-    tcx.mk_substs(substs)
+    tcx.mk_substs_from_iter(substs)
 }
 
 /// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 015029b7ac4..9b47c7299bb 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -42,7 +42,7 @@ pub trait InferCtxtExt<'tcx> {
     fn type_implements_trait(
         &self,
         trait_def_id: DefId,
-        params: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+        params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> traits::EvaluationResult;
 }
@@ -82,7 +82,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
     fn type_implements_trait(
         &self,
         trait_def_id: DefId,
-        params: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+        params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> traits::EvaluationResult {
         let trait_ref = self.tcx.mk_trait_ref(trait_def_id, params);
diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index 6172a9539f6..dec9f8016b0 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -99,6 +99,15 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
         requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
     ) -> QueryResult<'tcx>;
 
+    // Consider a clause specifically for a `dyn Trait` self type. This requires
+    // additionally checking all of the supertraits and object bounds to hold,
+    // since they're not implied by the well-formedness of the object type.
+    fn consider_object_bound_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+    ) -> QueryResult<'tcx>;
+
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -455,7 +464,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         for assumption in
             elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)))
         {
-            match G::consider_implied_clause(self, goal, assumption.predicate, []) {
+            match G::consider_object_bound_candidate(self, goal, assumption.predicate) {
                 Ok(result) => {
                     candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
                 }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index c080f7e59fa..71f536dd3cb 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -567,7 +567,7 @@ fn compute_external_query_constraints<'tcx>(
 ) -> Result<ExternalConstraints<'tcx>, NoSolution> {
     let region_obligations = infcx.take_registered_region_obligations();
     let opaque_types = infcx.take_opaque_types_for_query_response();
-    Ok(infcx.tcx.intern_external_constraints(ExternalConstraintsData {
+    Ok(infcx.tcx.mk_external_constraints(ExternalConstraintsData {
         // FIXME: Now that's definitely wrong :)
         //
         // Should also do the leak check here I think
@@ -616,8 +616,7 @@ pub(super) fn response_no_constraints<'tcx>(
             var_values: CanonicalVarValues::make_identity(tcx, goal.variables),
             // FIXME: maybe we should store the "no response" version in tcx, like
             // we do for tcx.types and stuff.
-            external_constraints: tcx
-                .intern_external_constraints(ExternalConstraintsData::default()),
+            external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()),
             certainty,
         },
     })
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 08c24ce13a5..88fd8bb8bd0 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -128,6 +128,51 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
         }
     }
 
+    fn consider_object_bound_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+    ) -> QueryResult<'tcx> {
+        if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
+            && poly_projection_pred.projection_def_id() == goal.predicate.def_id()
+        {
+            ecx.probe(|ecx| {
+                let assumption_projection_pred =
+                    ecx.instantiate_binder_with_infer(poly_projection_pred);
+                let mut nested_goals = ecx.eq(
+                    goal.param_env,
+                    goal.predicate.projection_ty,
+                    assumption_projection_pred.projection_ty,
+                )?;
+
+                let tcx = ecx.tcx();
+                let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
+                    bug!("expected object type in `consider_object_bound_candidate`");
+                };
+                nested_goals.extend(
+                    structural_traits::predicates_for_object_candidate(
+                        ecx,
+                        goal.param_env,
+                        goal.predicate.projection_ty.trait_ref(tcx),
+                        bounds,
+                    )
+                    .into_iter()
+                    .map(|pred| goal.with(tcx, pred)),
+                );
+
+                let subst_certainty = ecx.evaluate_all(nested_goals)?;
+
+                ecx.eq_term_and_make_canonical_response(
+                    goal,
+                    subst_certainty,
+                    assumption_projection_pred.term,
+                )
+            })
+        } else {
+            Err(NoSolution)
+        }
+    }
+
     fn consider_impl_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
@@ -316,7 +361,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 | ty::Never
                 | ty::Foreign(..) => tcx.types.unit,
 
-                ty::Error(e) => tcx.ty_error_with_guaranteed(*e),
+                ty::Error(e) => tcx.ty_error(*e),
 
                 ty::Str | ty::Slice(_) => tcx.types.usize,
 
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index aff79739d45..5c499c36e9b 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -86,6 +86,46 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         }
     }
 
+    fn consider_object_bound_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+        assumption: ty::Predicate<'tcx>,
+    ) -> QueryResult<'tcx> {
+        if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
+            && poly_trait_pred.def_id() == goal.predicate.def_id()
+        {
+            // FIXME: Constness and polarity
+            ecx.probe(|ecx| {
+                let assumption_trait_pred =
+                    ecx.instantiate_binder_with_infer(poly_trait_pred);
+                let mut nested_goals = ecx.eq(
+                    goal.param_env,
+                    goal.predicate.trait_ref,
+                    assumption_trait_pred.trait_ref,
+                )?;
+
+                let tcx = ecx.tcx();
+                let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
+                    bug!("expected object type in `consider_object_bound_candidate`");
+                };
+                nested_goals.extend(
+                    structural_traits::predicates_for_object_candidate(
+                        ecx,
+                        goal.param_env,
+                        goal.predicate.trait_ref,
+                        bounds,
+                    )
+                    .into_iter()
+                    .map(|pred| goal.with(tcx, pred)),
+                );
+
+                ecx.evaluate_all_and_make_canonical_response(nested_goals)
+            })
+        } else {
+            Err(NoSolution)
+        }
+    }
+
     fn consider_auto_trait_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -343,9 +383,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                     // Substitute just the unsizing params from B into A. The type after
                     // this substitution must be equal to B. This is so we don't unsize
                     // unrelated type parameters.
-                    let new_a_substs = tcx.mk_substs(a_substs.iter().enumerate().map(|(i, a)| {
-                        if unsizing_params.contains(i as u32) { b_substs[i] } else { a }
-                    }));
+                    let new_a_substs =
+                        tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| {
+                            if unsizing_params.contains(i as u32) { b_substs[i] } else { a }
+                        }));
                     let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs);
 
                     // Finally, we require that `TailA: Unsize<TailB>` for the tail field
@@ -368,7 +409,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                     let b_last_ty = b_tys.last().unwrap();
 
                     // Substitute just the tail field of B., and require that they're equal.
-                    let unsized_a_ty = tcx.mk_tup(a_rest_tys.iter().chain([b_last_ty]).copied());
+                    let unsized_a_ty =
+                        tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied());
                     let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
 
                     // Similar to ADTs, require that the rest of the fields are equal.
@@ -425,7 +467,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                             .map(ty::ExistentialPredicate::AutoTrait)
                             .map(ty::Binder::dummy),
                     );
-                let new_a_data = tcx.mk_poly_existential_predicates(new_a_data);
+                let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data);
                 let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn);
 
                 // We also require that A's lifetime outlives B's lifetime.
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
index 2c13465d347..d7d93377cf1 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
@@ -1,6 +1,7 @@
-use rustc_hir::{Movability, Mutability};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{def_id::DefId, Movability, Mutability};
 use rustc_infer::traits::query::NoSolution;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
 
 use crate::solve::EvalCtxt;
 
@@ -20,12 +21,14 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         | ty::Float(_)
         | ty::FnDef(..)
         | ty::FnPtr(_)
-        | ty::Str
         | ty::Error(_)
         | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
         | ty::Never
         | ty::Char => Ok(vec![]),
 
+        // Treat this like `struct str([u8]);`
+        ty::Str => Ok(vec![tcx.mk_slice(tcx.types.u8)]),
+
         ty::Dynamic(..)
         | ty::Param(..)
         | ty::Foreign(..)
@@ -189,11 +192,9 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         ty::FnDef(def_id, substs) => Ok(Some(
             tcx.fn_sig(def_id)
                 .subst(tcx, substs)
-                .map_bound(|sig| (tcx.intern_tup(sig.inputs()), sig.output())),
+                .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
         )),
-        ty::FnPtr(sig) => {
-            Ok(Some(sig.map_bound(|sig| (tcx.intern_tup(sig.inputs()), sig.output()))))
-        }
+        ty::FnPtr(sig) => Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))),
         ty::Closure(_, substs) => {
             let closure_substs = substs.as_closure();
             match closure_substs.kind_ty().to_opt_closure_kind() {
@@ -233,3 +234,112 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         }
     }
 }
+
+/// Assemble a list of predicates that would be present on a theoretical
+/// user impl for an object type. These predicates must be checked any time
+/// we assemble a built-in object candidate for an object type, since they
+/// are not implied by the well-formedness of the type.
+///
+/// For example, given the following traits:
+///
+/// ```rust,ignore (theoretical code)
+/// trait Foo: Baz {
+///     type Bar: Copy;
+/// }
+///
+/// trait Baz {}
+/// ```
+///
+/// For the dyn type `dyn Foo<Item = Ty>`, we can imagine there being a
+/// pair of theoretical impls:
+///
+/// ```rust,ignore (theoretical code)
+/// impl Foo for dyn Foo<Item = Ty>
+/// where
+///     Self: Baz,
+///     <Self as Foo>::Bar: Copy,
+/// {
+///     type Bar = Ty;
+/// }
+///
+/// impl Baz for dyn Foo<Item = Ty> {}
+/// ```
+///
+/// However, in order to make such impls well-formed, we need to do an
+/// additional step of eagerly folding the associated types in the where
+/// clauses of the impl. In this example, that means replacing
+/// `<Self as Foo>::Bar` with `Ty` in the first impl.
+pub(crate) fn predicates_for_object_candidate<'tcx>(
+    ecx: &EvalCtxt<'_, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    trait_ref: ty::TraitRef<'tcx>,
+    object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+) -> Vec<ty::Predicate<'tcx>> {
+    let tcx = ecx.tcx();
+    let mut requirements = vec![];
+    requirements.extend(
+        tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.substs).predicates,
+    );
+    for item in tcx.associated_items(trait_ref.def_id).in_definition_order() {
+        // FIXME(associated_const_equality): Also add associated consts to
+        // the requirements here.
+        if item.kind == ty::AssocKind::Type {
+            requirements.extend(tcx.item_bounds(item.def_id).subst(tcx, trait_ref.substs));
+        }
+    }
+
+    let mut replace_projection_with = FxHashMap::default();
+    for bound in object_bound {
+        if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() {
+            let proj = proj.with_self_ty(tcx, trait_ref.self_ty());
+            let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj));
+            assert_eq!(
+                old_ty,
+                None,
+                "{} has two substitutions: {} and {}",
+                proj.projection_ty,
+                proj.term,
+                old_ty.unwrap()
+            );
+        }
+    }
+
+    requirements.fold_with(&mut ReplaceProjectionWith {
+        ecx,
+        param_env,
+        mapping: replace_projection_with,
+    })
+}
+
+struct ReplaceProjectionWith<'a, 'tcx> {
+    ecx: &'a EvalCtxt<'a, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.ecx.tcx()
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
+            && let Some(replacement) = self.mapping.get(&alias_ty.def_id)
+        {
+            // We may have a case where our object type's projection bound is higher-ranked,
+            // but the where clauses we instantiated are not. We can solve this by instantiating
+            // the binder at the usage site.
+            let proj = self.ecx.instantiate_binder_with_infer(*replacement);
+            // FIXME: Technically this folder could be fallible?
+            let nested = self
+                .ecx
+                .eq(self.param_env, alias_ty, proj.projection_ty)
+                .expect("expected to be able to unify goal projection with dyn's projection");
+            // FIXME: Technically we could register these too..
+            assert!(nested.is_empty(), "did not expect unification to have any nested goals");
+            proj.term.ty().unwrap()
+        } else {
+            ty.super_fold_with(self)
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 6f2b0856d51..1fb8659bb27 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -350,14 +350,14 @@ impl<'tcx> AutoTraitFinder<'tcx> {
             )
             .map(|o| o.predicate);
             new_env = ty::ParamEnv::new(
-                tcx.mk_predicates(normalized_preds),
+                tcx.mk_predicates_from_iter(normalized_preds),
                 param_env.reveal(),
                 param_env.constness(),
             );
         }
 
         let final_user_env = ty::ParamEnv::new(
-            tcx.mk_predicates(user_computed_preds.into_iter()),
+            tcx.mk_predicates_from_iter(user_computed_preds.into_iter()),
             user_env.reveal(),
             user_env.constness(),
         );
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
index 9474c70cb53..1174efdbfa8 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
@@ -98,7 +98,7 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
 
     fn register_predicates(
         &mut self,
-        _obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
+        _obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>,
     ) {
         // FIXME(deferred_projection_equality)
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index f4bbe415677..66d74fd05a6 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3107,6 +3107,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 self.tcx.def_span(def_id),
                                 "required because it's used within this closure",
                             ),
+                            ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"),
                             _ => err.note(&msg),
                         };
                     }
@@ -3534,7 +3535,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         {
             if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr {
                 let expr = expr.peel_blocks();
-                let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error());
+                let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc());
                 let span = expr.span;
                 if Some(span) != err.span.primary_span() {
                     err.span_label(
@@ -3637,7 +3638,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         let mut assocs = vec![];
         let mut expr = expr;
         let mut prev_ty = self.resolve_vars_if_possible(
-            typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
+            typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()),
         );
         while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind {
             // Point at every method call in the chain with the resulting type.
@@ -3648,7 +3649,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
             assocs.push(assocs_in_this_method);
             prev_ty = self.resolve_vars_if_possible(
-                typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()),
+                typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()),
             );
 
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
@@ -3666,7 +3667,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 if let hir::Node::Param(param) = parent {
                     // ...and it is a an fn argument.
                     let prev_ty = self.resolve_vars_if_possible(
-                        typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error()),
+                        typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error_misc()),
                     );
                     let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env);
                     if assocs_in_this_method.iter().any(|a| a.is_some()) {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index c8b233bfe26..b2317f55d25 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -281,7 +281,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
 
     let elaborated_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
+        tcx.mk_predicates(&predicates),
         unnormalized_env.reveal(),
         unnormalized_env.constness(),
     );
@@ -333,10 +333,9 @@ pub fn normalize_param_env_or_error<'tcx>(
     // Not sure whether it is better to include the unnormalized TypeOutlives predicates
     // here. I believe they should not matter, because we are ignoring TypeOutlives param-env
     // predicates here anyway. Keeping them here anyway because it seems safer.
-    let outlives_env: Vec<_> =
-        non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
+    let outlives_env = non_outlives_predicates.iter().chain(&outlives_predicates).cloned();
     let outlives_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&outlives_env),
+        tcx.mk_predicates_from_iter(outlives_env),
         unnormalized_env.reveal(),
         unnormalized_env.constness(),
     );
@@ -356,7 +355,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     predicates.extend(outlives_predicates);
     debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
     ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
+        tcx.mk_predicates(&predicates),
         unnormalized_env.reveal(),
         unnormalized_env.constness(),
     )
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index b87f75422ef..4eacb5211f7 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -18,10 +18,10 @@ use rustc_errors::{DelayDm, FatalError, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
+use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{
     self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
-use rustc_middle::ty::{Predicate, ToPredicate};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -666,8 +666,9 @@ fn object_ty_for_trait<'tcx>(
     elaborated_predicates.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
     elaborated_predicates.dedup();
 
-    let existential_predicates = tcx
-        .mk_poly_existential_predicates(iter::once(trait_predicate).chain(elaborated_predicates));
+    let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(
+        iter::once(trait_predicate).chain(elaborated_predicates),
+    );
     debug!(?existential_predicates);
 
     tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn)
@@ -766,11 +767,11 @@ fn receiver_is_dispatchable<'tcx>(
             ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, substs)).to_predicate(tcx)
         };
 
-        let caller_bounds: Vec<Predicate<'tcx>> =
-            param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]).collect();
+        let caller_bounds =
+            param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]);
 
         ty::ParamEnv::new(
-            tcx.intern_predicates(&caller_bounds),
+            tcx.mk_predicates_from_iter(caller_bounds),
             param_env.reveal(),
             param_env.constness(),
         )
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 279725b16d8..d542240be9b 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1213,8 +1213,8 @@ struct Progress<'tcx> {
 }
 
 impl<'tcx> Progress<'tcx> {
-    fn error(tcx: TyCtxt<'tcx>) -> Self {
-        Progress { term: tcx.ty_error().into(), obligations: vec![] }
+    fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
+        Progress { term: tcx.ty_error(guar).into(), obligations: vec![] }
     }
 
     fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self {
@@ -1240,8 +1240,8 @@ fn project<'cx, 'tcx>(
         )));
     }
 
-    if obligation.predicate.references_error() {
-        return Ok(Projected::Progress(Progress::error(selcx.tcx())));
+    if let Err(guar) = obligation.predicate.error_reported() {
+        return Ok(Projected::Progress(Progress::error(selcx.tcx(), guar)));
     }
 
     let mut candidates = ProjectionCandidateSet::None;
@@ -1307,21 +1307,38 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
         let _ = selcx.infcx.commit_if_ok(|_| {
             match selcx.select(&obligation.with(tcx, trait_predicate)) {
                 Ok(Some(super::ImplSource::UserDefined(data))) => {
-                    candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
-                    Ok(())
+                    let Ok(leaf_def) = specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) else {
+                        return Err(());
+                    };
+                    // Only reveal a specializable default if we're past type-checking
+                    // and the obligation is monomorphic, otherwise passes such as
+                    // transmute checking and polymorphic MIR optimizations could
+                    // get a result which isn't correct for all monomorphizations.
+                    if leaf_def.is_final()
+                        || (obligation.param_env.reveal() == Reveal::All
+                            && !selcx
+                                .infcx
+                                .resolve_vars_if_possible(obligation.predicate.trait_ref(tcx))
+                                .still_further_specializable())
+                    {
+                        candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
+                        Ok(())
+                    } else {
+                        Err(())
+                    }
                 }
                 Ok(None) => {
                     candidate_set.mark_ambiguous();
-                    return Err(());
+                    Err(())
                 }
                 Ok(Some(_)) => {
                     // Don't know enough about the impl to provide a useful signature
-                    return Err(());
+                    Err(())
                 }
                 Err(e) => {
                     debug!(error = ?e, "selection error");
                     candidate_set.mark_error(e);
-                    return Err(());
+                    Err(())
                 }
             }
         });
@@ -1906,7 +1923,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
     let self_ty = obligation.predicate.self_ty();
-    let substs = tcx.intern_substs(&[self_ty.into()]);
+    let substs = tcx.mk_substs(&[self_ty.into()]);
     let lang_items = tcx.lang_items();
     let item_def_id = obligation.predicate.def_id;
     let trait_def_id = tcx.trait_of_item(item_def_id).unwrap();
@@ -2097,8 +2114,9 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
 
     let param_env = obligation.param_env;
-    let Ok(assoc_ty) = specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) else {
-        return Progress { term: tcx.ty_error().into(), obligations: nested };
+    let assoc_ty = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) {
+        Ok(assoc_ty) => assoc_ty,
+        Err(guar) => return Progress::error(tcx, guar),
     };
 
     if !assoc_ty.item.defaultness(tcx).has_value() {
@@ -2110,7 +2128,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
             "confirm_impl_candidate: no associated type {:?} for {:?}",
             assoc_ty.item.name, obligation.predicate
         );
-        return Progress { term: tcx.ty_error().into(), obligations: nested };
+        return Progress { term: tcx.ty_error_misc().into(), obligations: nested };
     }
     // If we're trying to normalize `<Vec<u32> as X>::A<S>` using
     //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
@@ -2194,11 +2212,12 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
     let mut obligations = data.nested;
 
     let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.def_id);
-    let Ok(leaf_def) = specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) else {
-        return Progress { term: tcx.ty_error().into(), obligations };
+    let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) {
+        Ok(assoc_ty) => assoc_ty,
+        Err(guar) => return Progress::error(tcx, guar),
     };
     if !leaf_def.item.defaultness(tcx).has_value() {
-        return Progress { term: tcx.ty_error().into(), obligations };
+        return Progress { term: tcx.ty_error_misc().into(), obligations };
     }
 
     // Use the default `impl Trait` for the trait, e.g., for a default trait body
@@ -2269,7 +2288,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
         obligation.recursion_depth + 1,
         tcx.bound_return_position_impl_trait_in_trait_tys(impl_fn_def_id)
             .map_bound(|tys| {
-                tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.def_id])
+                tys.map_or_else(|guar| tcx.ty_error(guar), |tys| tys[&obligation.predicate.def_id])
             })
             .subst(tcx, impl_fn_substs),
         &mut obligations,
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 270f513ce3c..21c158fd0fd 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -564,8 +564,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 .into()
                             }
                         });
-                        let bound_vars = tcx.intern_bound_variable_kinds(&bound_vars);
-                        let assoc_ty_substs = tcx.intern_substs(&substs);
+                        let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
+                        let assoc_ty_substs = tcx.mk_substs(&substs);
                         let bound =
                             bound.map_bound(|b| b.kind().skip_binder()).subst(tcx, assoc_ty_substs);
                         tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars))
@@ -880,7 +880,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             .map(ty::ExistentialPredicate::AutoTrait)
                             .map(ty::Binder::dummy),
                     );
-                let existential_predicates = tcx.mk_poly_existential_predicates(iter);
+                let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter);
                 let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_a);
 
                 // Require that the traits involved in this upcast are **equal**;
@@ -979,7 +979,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             .map(ty::ExistentialPredicate::AutoTrait)
                             .map(ty::Binder::dummy),
                     );
-                let existential_predicates = tcx.mk_poly_existential_predicates(iter);
+                let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter);
                 let source_trait = tcx.mk_dynamic(existential_predicates, r_b, dyn_a);
 
                 // Require that the traits involved in this upcast are **equal**;
@@ -1099,7 +1099,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // Check that the source struct with the target's
                 // unsizing parameters is equal to the target.
-                let substs = tcx.mk_substs(substs_a.iter().enumerate().map(|(i, k)| {
+                let substs = tcx.mk_substs_from_iter(substs_a.iter().enumerate().map(|(i, k)| {
                     if unsizing_params.contains(i as u32) { substs_b[i] } else { k }
                 }));
                 let new_struct = tcx.mk_adt(def, substs);
@@ -1131,7 +1131,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // Check that the source tuple with the target's
                 // last element is equal to the target.
-                let new_tuple = tcx.mk_tup(a_mid.iter().copied().chain(iter::once(b_last)));
+                let new_tuple =
+                    tcx.mk_tup_from_iter(a_mid.iter().copied().chain(iter::once(b_last)));
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index e7e0f8838a4..01c1ad3a4ce 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2230,7 +2230,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                 }
                 // (*) binder moved here
-                let all_vars = self.tcx().mk_bound_variable_kinds(
+                let all_vars = self.tcx().mk_bound_variable_kinds_from_iter(
                     obligation.predicate.bound_vars().iter().chain(binder.bound_vars().iter()),
                 );
                 Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars))
@@ -2300,12 +2300,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Float(_)
             | ty::FnDef(..)
             | ty::FnPtr(_)
-            | ty::Str
             | ty::Error(_)
             | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Never
             | ty::Char => ty::Binder::dummy(Vec::new()),
 
+            // Treat this like `struct str([u8]);`
+            ty::Str => ty::Binder::dummy(vec![self.tcx().mk_slice(self.tcx().types.u8)]),
+
             ty::Placeholder(..)
             | ty::Dynamic(..)
             | ty::Param(..)
@@ -2443,7 +2445,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // the placeholder trait ref may fail due the Generalizer relation
                 // raising a CyclicalTy error due to a sub_root_var relation
                 // for a variable being generalized...
-                self.infcx.tcx.sess.delay_span_bug(
+                let guar = self.infcx.tcx.sess.delay_span_bug(
                     obligation.cause.span,
                     &format!(
                         "Impl {:?} was matchable against {:?} but now is not",
@@ -2451,7 +2453,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     ),
                 );
                 let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
-                let err = self.tcx().ty_error();
+                let err = self.tcx().ty_error(guar);
                 let value = value.fold_with(&mut BottomUpFolder {
                     tcx: self.tcx(),
                     ty_op: |_| err,
@@ -3034,7 +3036,7 @@ fn bind_generator_hidden_types_above<'tcx>(
     if considering_regions {
         debug_assert!(!hidden_types.has_erased_regions());
     }
-    let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.iter().chain(
+    let bound_vars = tcx.mk_bound_variable_kinds_from_iter(bound_vars.iter().chain(
         (num_bound_variables..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
     ));
     ty::Binder::bind_with_vars(hidden_types, bound_vars)
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 0c55c35ffb4..bcf63d5a6f6 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -239,7 +239,7 @@ pub fn predicate_for_trait_def<'tcx>(
     cause: ObligationCause<'tcx>,
     trait_def_id: DefId,
     recursion_depth: usize,
-    params: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+    params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
 ) -> PredicateObligation<'tcx> {
     let trait_ref = tcx.mk_trait_ref(trait_def_id, params);
     predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth)
@@ -292,7 +292,7 @@ pub fn closure_trait_ref_and_return_type<'tcx>(
     assert!(!self_ty.has_escaping_bound_vars());
     let arguments_tuple = match tuple_arguments {
         TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
-        TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()),
+        TupleArgumentsFlag::Yes => tcx.mk_tup(sig.skip_binder().inputs()),
     };
     let trait_ref = tcx.mk_trait_ref(fn_trait_def_id, [self_ty, arguments_tuple]);
     sig.map_bound(|sig| (trait_ref, sig.output()))
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index fe80de5a069..60e22d1001c 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -62,7 +62,9 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution<RustInterner<'tcx>>> for Subst
 
 impl<'tcx> LowerInto<'tcx, SubstsRef<'tcx>> for &chalk_ir::Substitution<RustInterner<'tcx>> {
     fn lower_into(self, interner: RustInterner<'tcx>) -> SubstsRef<'tcx> {
-        interner.tcx.mk_substs(self.iter(interner).map(|subst| subst.lower_into(interner)))
+        interner
+            .tcx
+            .mk_substs_from_iter(self.iter(interner).map(|subst| subst.lower_into(interner)))
     }
 }
 
@@ -455,7 +457,7 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> {
                 interner.tcx.mk_alias_ty(assoc_ty.0, substitution.lower_into(interner)),
             ),
             TyKind::Foreign(def_id) => ty::Foreign(def_id.0),
-            TyKind::Error => return interner.tcx.ty_error(),
+            TyKind::Error => return interner.tcx.ty_error_misc(),
             TyKind::Alias(alias_ty) => match alias_ty {
                 chalk_ir::AliasTy::Projection(projection) => ty::Alias(
                     ty::Projection,
@@ -487,7 +489,7 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> {
             TyKind::InferenceVar(_, _) => unimplemented!(),
             TyKind::Dyn(_) => unimplemented!(),
         };
-        interner.tcx.mk_ty(kind)
+        interner.tcx.mk_ty_from_kind(kind)
     }
 }
 
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index 5855a8e28dd..a5ebc26a8bc 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -96,37 +96,34 @@ pub(crate) fn evaluate_goal<'tcx>(
         use rustc_middle::infer::canonical::CanonicalVarInfo;
 
         let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params);
-        let var_values = tcx.mk_substs(
+        let var_values = tcx.mk_substs_from_iter(
             subst
                 .as_slice(interner)
                 .iter()
                 .map(|p| p.lower_into(interner).fold_with(&mut reverse_param_substitutor)),
         );
-        let variables: Vec<_> = binders
-            .iter(interner)
-            .map(|var| {
-                let kind = match var.kind {
-                    chalk_ir::VariableKind::Ty(ty_kind) => CanonicalVarKind::Ty(match ty_kind {
-                        chalk_ir::TyVariableKind::General => CanonicalTyVarKind::General(
-                            ty::UniverseIndex::from_usize(var.skip_kind().counter),
-                        ),
-                        chalk_ir::TyVariableKind::Integer => CanonicalTyVarKind::Int,
-                        chalk_ir::TyVariableKind::Float => CanonicalTyVarKind::Float,
-                    }),
-                    chalk_ir::VariableKind::Lifetime => CanonicalVarKind::Region(
+        let variables = binders.iter(interner).map(|var| {
+            let kind = match var.kind {
+                chalk_ir::VariableKind::Ty(ty_kind) => CanonicalVarKind::Ty(match ty_kind {
+                    chalk_ir::TyVariableKind::General => CanonicalTyVarKind::General(
                         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 }
-            })
-            .collect();
+                    chalk_ir::TyVariableKind::Integer => CanonicalTyVarKind::Int,
+                    chalk_ir::TyVariableKind::Float => CanonicalTyVarKind::Float,
+                }),
+                chalk_ir::VariableKind::Lifetime => {
+                    CanonicalVarKind::Region(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 }
+        });
         let max_universe = binders.iter(interner).map(|v| v.skip_kind().counter).max().unwrap_or(0);
         let sol = Canonical {
             max_universe: ty::UniverseIndex::from_usize(max_universe),
-            variables: tcx.intern_canonical_var_infos(&variables),
+            variables: tcx.mk_canonical_var_infos_from_iter(variables),
             value: QueryResponse {
                 var_values: CanonicalVarValues { var_values },
                 region_constraints: QueryRegionConstraints::default(),
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 41924dc2a6d..35c9f95eb03 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -54,7 +54,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 sig = sig.map_bound(|mut sig| {
                     let mut inputs_and_output = sig.inputs_and_output.to_vec();
                     inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]);
-                    sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
+                    sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
                     sig
                 });
             }
@@ -63,7 +63,7 @@ fn fn_sig_for_fn_abi<'tcx>(
         ty::Closure(def_id, substs) => {
             let sig = substs.as_closure().sig();
 
-            let bound_vars = tcx.mk_bound_variable_kinds(
+            let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
                 sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
             );
             let br = ty::BoundRegion {
@@ -88,7 +88,7 @@ fn fn_sig_for_fn_abi<'tcx>(
         ty::Generator(did, substs, _) => {
             let sig = substs.as_generator().poly_sig();
 
-            let bound_vars = tcx.mk_bound_variable_kinds(
+            let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
                 sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
             );
             let br = ty::BoundRegion {
@@ -99,7 +99,7 @@ fn fn_sig_for_fn_abi<'tcx>(
 
             let pin_did = tcx.require_lang_item(LangItem::Pin, None);
             let pin_adt_ref = tcx.adt_def(pin_did);
-            let pin_substs = tcx.intern_substs(&[env_ty.into()]);
+            let pin_substs = tcx.mk_substs(&[env_ty.into()]);
             let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
 
             let sig = sig.skip_binder();
@@ -111,7 +111,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 // The signature should be `Future::poll(_, &mut Context<'_>) -> Poll<Output>`
                 let poll_did = tcx.require_lang_item(LangItem::Poll, None);
                 let poll_adt_ref = tcx.adt_def(poll_did);
-                let poll_substs = tcx.intern_substs(&[sig.return_ty.into()]);
+                let poll_substs = tcx.mk_substs(&[sig.return_ty.into()]);
                 let ret_ty = tcx.mk_adt(poll_adt_ref, poll_substs);
 
                 // We have to replace the `ResumeTy` that is used for type and borrow checking
@@ -133,7 +133,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 // The signature should be `Generator::resume(_, Resume) -> GeneratorState<Yield, Return>`
                 let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
                 let state_adt_ref = tcx.adt_def(state_did);
-                let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
+                let state_substs = tcx.mk_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
                 let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
 
                 (sig.resume_ty, ret_ty)
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index ae824a31f75..f2635271609 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -144,7 +144,7 @@ fn recurse_build<'tcx>(
             for &id in args.iter() {
                 new_args.push(recurse_build(tcx, body, id, root_span)?);
             }
-            let new_args = tcx.intern_const_list(&new_args);
+            let new_args = tcx.mk_const_list(&new_args);
             tcx.mk_const(Expr::FunctionCall(fun, new_args), node.ty)
         }
         &ExprKind::Binary { op, lhs, rhs } if check_binop(op) => {
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index eb307e66e34..7fecee2a38b 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -19,16 +19,16 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
             let mut assumed_wf_types: Vec<_> =
                 tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into();
             assumed_wf_types.extend(liberated_sig.inputs_and_output);
-            tcx.intern_type_list(&assumed_wf_types)
+            tcx.mk_type_list(&assumed_wf_types)
         }
         DefKind::Impl { .. } => {
             match tcx.impl_trait_ref(def_id) {
                 Some(trait_ref) => {
                     let types: Vec<_> = trait_ref.skip_binder().substs.types().collect();
-                    tcx.intern_type_list(&types)
+                    tcx.mk_type_list(&types)
                 }
                 // Only the impl self type
-                None => tcx.intern_type_list(&[tcx.type_of(def_id).subst_identity()]),
+                None => tcx.mk_type_list(&[tcx.type_of(def_id).subst_identity()]),
             }
         }
         DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index a400fbfe683..e3132fcc4c4 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -104,23 +104,23 @@ fn layout_of_uncached<'tcx>(
         assert!(size.bits() <= 128);
         Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
     };
-    let scalar = |value: Primitive| tcx.intern_layout(LayoutS::scalar(cx, scalar_unit(value)));
+    let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value)));
 
     let univariant = |fields: &[Layout<'_>], repr: &ReprOptions, kind| {
-        Ok(tcx.intern_layout(univariant_uninterned(cx, ty, fields, repr, kind)?))
+        Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?))
     };
     debug_assert!(!ty.has_non_region_infer());
 
     Ok(match *ty.kind() {
         // Basic scalars.
-        ty::Bool => tcx.intern_layout(LayoutS::scalar(
+        ty::Bool => tcx.mk_layout(LayoutS::scalar(
             cx,
             Scalar::Initialized {
                 value: Int(I8, false),
                 valid_range: WrappingRange { start: 0, end: 1 },
             },
         )),
-        ty::Char => tcx.intern_layout(LayoutS::scalar(
+        ty::Char => tcx.mk_layout(LayoutS::scalar(
             cx,
             Scalar::Initialized {
                 value: Int(I32, false),
@@ -136,11 +136,11 @@ fn layout_of_uncached<'tcx>(
         ty::FnPtr(_) => {
             let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
             ptr.valid_range_mut().start = 1;
-            tcx.intern_layout(LayoutS::scalar(cx, ptr))
+            tcx.mk_layout(LayoutS::scalar(cx, ptr))
         }
 
         // The never type.
-        ty::Never => tcx.intern_layout(cx.layout_of_never_type()),
+        ty::Never => tcx.mk_layout(cx.layout_of_never_type()),
 
         // Potentially-wide pointers.
         ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
@@ -151,7 +151,7 @@ fn layout_of_uncached<'tcx>(
 
             let pointee = tcx.normalize_erasing_regions(param_env, pointee);
             if pointee.is_sized(tcx, param_env) {
-                return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
+                return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
             }
 
             let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
@@ -164,7 +164,7 @@ fn layout_of_uncached<'tcx>(
                 let metadata_layout = cx.layout_of(metadata_ty)?;
                 // If the metadata is a 1-zst, then the pointer is thin.
                 if metadata_layout.is_zst() && metadata_layout.align.abi.bytes() == 1 {
-                    return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
+                    return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
                 }
 
                 let Abi::Scalar(metadata) = metadata_layout.abi else {
@@ -174,7 +174,7 @@ fn layout_of_uncached<'tcx>(
             } else {
                 match unsized_part.kind() {
                     ty::Foreign(..) => {
-                        return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
+                        return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
                     }
                     ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
                     ty::Dynamic(..) => {
@@ -189,7 +189,7 @@ fn layout_of_uncached<'tcx>(
             };
 
             // Effectively a (ptr, meta) tuple.
-            tcx.intern_layout(cx.scalar_pair(data_ptr, metadata))
+            tcx.mk_layout(cx.scalar_pair(data_ptr, metadata))
         }
 
         ty::Dynamic(_, _, ty::DynStar) => {
@@ -197,7 +197,7 @@ fn layout_of_uncached<'tcx>(
             data.valid_range_mut().start = 0;
             let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
             vtable.valid_range_mut().start = 1;
-            tcx.intern_layout(cx.scalar_pair(data, vtable))
+            tcx.mk_layout(cx.scalar_pair(data, vtable))
         }
 
         // Arrays and slices.
@@ -222,7 +222,7 @@ fn layout_of_uncached<'tcx>(
 
             let largest_niche = if count != 0 { element.largest_niche } else { None };
 
-            tcx.intern_layout(LayoutS {
+            tcx.mk_layout(LayoutS {
                 variants: Variants::Single { index: VariantIdx::new(0) },
                 fields: FieldsShape::Array { stride: element.size, count },
                 abi,
@@ -233,7 +233,7 @@ fn layout_of_uncached<'tcx>(
         }
         ty::Slice(element) => {
             let element = cx.layout_of(element)?;
-            tcx.intern_layout(LayoutS {
+            tcx.mk_layout(LayoutS {
                 variants: Variants::Single { index: VariantIdx::new(0) },
                 fields: FieldsShape::Array { stride: element.size, count: 0 },
                 abi: Abi::Aggregate { sized: false },
@@ -242,7 +242,7 @@ fn layout_of_uncached<'tcx>(
                 size: Size::ZERO,
             })
         }
-        ty::Str => tcx.intern_layout(LayoutS {
+        ty::Str => tcx.mk_layout(LayoutS {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
             abi: Abi::Aggregate { sized: false },
@@ -265,7 +265,7 @@ fn layout_of_uncached<'tcx>(
                 Abi::Aggregate { ref mut sized } => *sized = false,
                 _ => bug!(),
             }
-            tcx.intern_layout(unit)
+            tcx.mk_layout(unit)
         }
 
         ty::Generator(def_id, substs, _) => generator_layout(cx, ty, def_id, substs)?,
@@ -394,7 +394,7 @@ fn layout_of_uncached<'tcx>(
                 FieldsShape::Array { stride: e_ly.size, count: e_len }
             };
 
-            tcx.intern_layout(LayoutS {
+            tcx.mk_layout(LayoutS {
                 variants: Variants::Single { index: VariantIdx::new(0) },
                 fields,
                 abi: Abi::Vector { element: e_abi, count: e_len },
@@ -427,12 +427,12 @@ fn layout_of_uncached<'tcx>(
                     return Err(LayoutError::Unknown(ty));
                 }
 
-                return Ok(tcx.intern_layout(
+                return Ok(tcx.mk_layout(
                     cx.layout_of_union(&def.repr(), &variants).ok_or(LayoutError::Unknown(ty))?,
                 ));
             }
 
-            tcx.intern_layout(
+            tcx.mk_layout(
                 cx.layout_of_struct_or_enum(
                     &def.repr(),
                     &variants,
@@ -636,7 +636,7 @@ fn generator_layout<'tcx>(
         value: Primitive::Int(discr_int, false),
         valid_range: WrappingRange { start: 0, end: max_discr },
     };
-    let tag_layout = cx.tcx.intern_layout(LayoutS::scalar(cx, tag));
+    let tag_layout = cx.tcx.mk_layout(LayoutS::scalar(cx, tag));
 
     let promoted_layouts = ineligible_locals
         .iter()
@@ -784,7 +784,7 @@ fn generator_layout<'tcx>(
         Abi::Aggregate { sized: true }
     };
 
-    let layout = tcx.intern_layout(LayoutS {
+    let layout = tcx.mk_layout(LayoutS {
         variants: Variants::Multiple {
             tag,
             tag_encoding: TagEncoding::Direct,
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index c177d60bb59..de7fd003176 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -303,7 +303,7 @@ fn adt_drop_tys<'tcx>(
         false,
     )
     .collect::<Result<Vec<_>, _>>()
-    .map(|components| tcx.intern_type_list(&components))
+    .map(|components| tcx.mk_type_list(&components))
 }
 // If `def_id` refers to a generic ADT, the queries above and below act as if they had been handed
 // a `tcx.make_ty(def, identity_substs)` and as such it is legal to substitute the generic parameters
@@ -320,7 +320,7 @@ fn adt_significant_drop_tys(
         true,
     )
     .collect::<Result<Vec<_>, _>>()
-    .map(|components| tcx.intern_type_list(&components))
+    .map(|components| tcx.mk_type_list(&components))
 }
 
 pub(crate) fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index a47e7ce23e3..18159778a8e 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -98,12 +98,12 @@ fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
 fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
     if let Some(def_id) = def_id.as_local() {
         if matches!(tcx.representability(def_id), ty::Representability::Infinite) {
-            return tcx.intern_type_list(&[tcx.ty_error()]);
+            return tcx.mk_type_list(&[tcx.ty_error_misc()]);
         }
     }
     let def = tcx.adt_def(def_id);
 
-    let result = tcx.mk_type_list(
+    let result = tcx.mk_type_list_from_iter(
         def.variants()
             .iter()
             .flat_map(|v| v.fields.last())
@@ -226,11 +226,8 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
         None => hir::Constness::NotConst,
     };
 
-    let unnormalized_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
-        traits::Reveal::UserFacing,
-        constness,
-    );
+    let unnormalized_env =
+        ty::ParamEnv::new(tcx.mk_predicates(&predicates), traits::Reveal::UserFacing, constness);
 
     let body_id = local_did.unwrap_or(CRATE_DEF_ID);
     let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
@@ -386,7 +383,7 @@ fn well_formed_types_in_env(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Predica
         }
     });
 
-    tcx.mk_predicates(clauses.chain(input_clauses))
+    tcx.mk_predicates_from_iter(clauses.chain(input_clauses))
 }
 
 fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
diff --git a/config.toml.example b/config.toml.example
index df4478bb0cb..69eb228a2d5 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -666,6 +666,9 @@ changelog-seen = 2
 # LTO entirely.
 #lto = "thin-local"
 
+# Build compiler with the optimization enabled and -Zvalidate-mir, currently only for `std`
+#validate-mir-opts = 3
+
 # =============================================================================
 # Options for specific targets
 #
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index 0b73b1af4eb..f1d0a305d99 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -851,18 +851,30 @@ impl<T: Ord> BinaryHeap<T> {
     where
         F: FnMut(&T) -> bool,
     {
-        let mut first_removed = self.len();
+        struct RebuildOnDrop<'a, T: Ord> {
+            heap: &'a mut BinaryHeap<T>,
+            first_removed: usize,
+        }
+
+        let mut guard = RebuildOnDrop { first_removed: self.len(), heap: self };
+
         let mut i = 0;
-        self.data.retain(|e| {
+        guard.heap.data.retain(|e| {
             let keep = f(e);
-            if !keep && i < first_removed {
-                first_removed = i;
+            if !keep && i < guard.first_removed {
+                guard.first_removed = i;
             }
             i += 1;
             keep
         });
-        // data[0..first_removed] is untouched, so we only need to rebuild the tail:
-        self.rebuild_tail(first_removed);
+
+        impl<'a, T: Ord> Drop for RebuildOnDrop<'a, T> {
+            fn drop(&mut self) {
+                // data[..first_removed] is untouched, so we only need to
+                // rebuild the tail:
+                self.heap.rebuild_tail(self.first_removed);
+            }
+        }
     }
 }
 
diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/src/collections/binary_heap/tests.rs
index ffbb6c80ac0..500caa35678 100644
--- a/library/alloc/src/collections/binary_heap/tests.rs
+++ b/library/alloc/src/collections/binary_heap/tests.rs
@@ -474,6 +474,25 @@ fn test_retain() {
     assert!(a.is_empty());
 }
 
+#[test]
+fn test_retain_catch_unwind() {
+    let mut heap = BinaryHeap::from(vec![3, 1, 2]);
+
+    // Removes the 3, then unwinds out of retain.
+    let _ = catch_unwind(AssertUnwindSafe(|| {
+        heap.retain(|e| {
+            if *e == 1 {
+                panic!();
+            }
+            false
+        });
+    }));
+
+    // Naively this would be [1, 2] (an invalid heap) if BinaryHeap delegates to
+    // Vec's retain impl and then does not rebuild the heap after that unwinds.
+    assert_eq!(heap.into_vec(), [2, 1]);
+}
+
 // old binaryheap failed this test
 //
 // Integrity means that all elements are present after a comparison panics,
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 1573b3d77dc..d4a12509b1c 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -944,65 +944,72 @@ impl<T, A: Allocator> VecDeque<T, A> {
             return;
         }
 
-        if target_cap < self.capacity() {
-            // There are three cases of interest:
-            //   All elements are out of desired bounds
-            //   Elements are contiguous, and head is out of desired bounds
-            //   Elements are discontiguous, and tail is out of desired bounds
+        // There are three cases of interest:
+        //   All elements are out of desired bounds
+        //   Elements are contiguous, and tail is out of desired bounds
+        //   Elements are discontiguous
+        //
+        // At all other times, element positions are unaffected.
+
+        // `head` and `len` are at most `isize::MAX` and `target_cap < self.capacity()`, so nothing can
+        // overflow.
+        let tail_outside = (target_cap + 1..=self.capacity()).contains(&(self.head + self.len));
+
+        if self.len == 0 {
+            self.head = 0;
+        } else if self.head >= target_cap && tail_outside {
+            // Head and tail are both out of bounds, so copy all of them to the front.
             //
-            // At all other times, element positions are unaffected.
+            //  H := head
+            //  L := last element
+            //                    H           L
+            //   [. . . . . . . . o o o o o o o . ]
+            //    H           L
+            //   [o o o o o o o . ]
+            unsafe {
+                // nonoverlapping because `self.head >= target_cap >= self.len`.
+                self.copy_nonoverlapping(self.head, 0, self.len);
+            }
+            self.head = 0;
+        } else if self.head < target_cap && tail_outside {
+            // Head is in bounds, tail is out of bounds.
+            // Copy the overflowing part to the beginning of the
+            // buffer. This won't overlap because `target_cap >= self.len`.
             //
-            // Indicates that elements at the head should be moved.
-
-            let tail_outside = (target_cap + 1..=self.capacity()).contains(&(self.head + self.len));
-            // Move elements from out of desired bounds (positions after target_cap)
-            if self.len == 0 {
-                self.head = 0;
-            } else if self.head >= target_cap && tail_outside {
-                //  H := head
-                //  L := last element
-                //                    H           L
-                //   [. . . . . . . . o o o o o o o . ]
-                //    H           L
-                //   [o o o o o o o . ]
-                unsafe {
-                    // nonoverlapping because self.head >= target_cap >= self.len
-                    self.copy_nonoverlapping(self.head, 0, self.len);
-                }
-                self.head = 0;
-            } else if self.head < target_cap && tail_outside {
-                //  H := head
-                //  L := last element
-                //          H           L
-                //   [. . . o o o o o o o . . . . . . ]
-                //      L   H
-                //   [o o . o o o o o ]
-                let len = self.head + self.len - target_cap;
-                unsafe {
-                    self.copy_nonoverlapping(target_cap, 0, len);
-                }
-            } else if self.head >= target_cap {
-                //  H := head
-                //  L := last element
-                //            L                   H
-                //   [o o o o o . . . . . . . . . o o ]
-                //            L   H
-                //   [o o o o o . o o ]
-                let len = self.capacity() - self.head;
-                let new_head = target_cap - len;
-                unsafe {
-                    // can't use copy_nonoverlapping here for the same reason
-                    // as in `handle_capacity_increase()`
-                    self.copy(self.head, new_head, len);
-                }
-                self.head = new_head;
+            //  H := head
+            //  L := last element
+            //          H           L
+            //   [. . . o o o o o o o . . . . . . ]
+            //      L   H
+            //   [o o . o o o o o ]
+            let len = self.head + self.len - target_cap;
+            unsafe {
+                self.copy_nonoverlapping(target_cap, 0, len);
             }
-
-            self.buf.shrink_to_fit(target_cap);
-
-            debug_assert!(self.head < self.capacity() || self.capacity() == 0);
-            debug_assert!(self.len <= self.capacity());
+        } else if !self.is_contiguous() {
+            // The head slice is at least partially out of bounds, tail is in bounds.
+            // Copy the head backwards so it lines up with the target capacity.
+            // This won't overlap because `target_cap >= self.len`.
+            //
+            //  H := head
+            //  L := last element
+            //            L                   H
+            //   [o o o o o . . . . . . . . . o o ]
+            //            L   H
+            //   [o o o o o . o o ]
+            let head_len = self.capacity() - self.head;
+            let new_head = target_cap - head_len;
+            unsafe {
+                // can't use `copy_nonoverlapping()` here because the new and old
+                // regions for the head might overlap.
+                self.copy(self.head, new_head, head_len);
+            }
+            self.head = new_head;
         }
+        self.buf.shrink_to_fit(target_cap);
+
+        debug_assert!(self.head < self.capacity() || self.capacity() == 0);
+        debug_assert!(self.len <= self.capacity());
     }
 
     /// Shortens the deque, keeping the first `len` elements and dropping
diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs
index 220ad71beab..205a8ff3c19 100644
--- a/library/alloc/src/collections/vec_deque/tests.rs
+++ b/library/alloc/src/collections/vec_deque/tests.rs
@@ -749,6 +749,48 @@ fn test_drain() {
 }
 
 #[test]
+fn issue_108453() {
+    let mut deque = VecDeque::with_capacity(10);
+
+    deque.push_back(1u8);
+    deque.push_back(2);
+    deque.push_back(3);
+
+    deque.push_front(10);
+    deque.push_front(9);
+
+    deque.shrink_to(9);
+
+    assert_eq!(deque.into_iter().collect::<Vec<_>>(), vec![9, 10, 1, 2, 3]);
+}
+
+#[test]
+fn test_shrink_to() {
+    // test deques with capacity 16 with all possible head positions, lengths and target capacities.
+    let cap = 16;
+
+    for len in 0..cap {
+        for head in 0..cap {
+            let expected = (1..=len).collect::<VecDeque<_>>();
+
+            for target_cap in len..cap {
+                let mut deque = VecDeque::with_capacity(cap);
+                // currently, `with_capacity` always allocates the exact capacity if it's greater than 8.
+                assert_eq!(deque.capacity(), cap);
+
+                // we can let the head point anywhere in the buffer since the deque is empty.
+                deque.head = head;
+                deque.extend(1..=len);
+
+                deque.shrink_to(target_cap);
+
+                assert_eq!(deque, expected);
+            }
+        }
+    }
+}
+
+#[test]
 fn test_shrink_to_fit() {
     // This test checks that every single combination of head and tail position,
     // is tested. Capacity 15 should be large enough to cover every case.
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index a07f3da78d3..b279f21b524 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -378,8 +378,8 @@ mod spec_extend;
 /// Currently, `Vec` does not guarantee the order in which elements are dropped.
 /// The order has changed in the past and may change again.
 ///
-/// [`get`]: ../../std/vec/struct.Vec.html#method.get
-/// [`get_mut`]: ../../std/vec/struct.Vec.html#method.get_mut
+/// [`get`]: slice::get
+/// [`get_mut`]: slice::get_mut
 /// [`String`]: crate::string::String
 /// [`&str`]: type@str
 /// [`shrink_to_fit`]: Vec::shrink_to_fit
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index f95b880df34..805354be089 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -542,7 +542,7 @@ pub trait Into<T>: Sized {
 #[const_trait]
 pub trait From<T>: Sized {
     /// Converts to this type from the input type.
-    #[lang = "from"]
+    #[rustc_diagnostic_item = "from_fn"]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn from(value: T) -> Self;
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index 156b925de77..ae00232c12c 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -278,6 +278,7 @@
 //!
 //! ```
 //! # #![allow(unused_must_use)]
+//! # #![cfg_attr(not(bootstrap), allow(map_unit_fn))]
 //! let v = vec![1, 2, 3, 4, 5];
 //! v.iter().map(|x| println!("{x}"));
 //! ```
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 9e3e13e7004..b8e7d0a68da 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -69,6 +69,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
 #[doc(notable_trait)]
 #[rustc_diagnostic_item = "Iterator"]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
+#[cfg_attr(not(bootstrap), const_trait)]
 pub trait Iterator {
     /// The type of the elements being iterated over.
     #[rustc_diagnostic_item = "IteratorItem"]
@@ -141,6 +142,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[unstable(feature = "iter_next_chunk", reason = "recently added", issue = "98326")]
+    #[rustc_do_not_const_check]
     fn next_chunk<const N: usize>(
         &mut self,
     ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
@@ -218,6 +220,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn size_hint(&self) -> (usize, Option<usize>) {
         (0, None)
     }
@@ -255,6 +258,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn count(self) -> usize
     where
         Self: Sized,
@@ -285,6 +289,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn last(self) -> Option<Self::Item>
     where
         Self: Sized,
@@ -331,6 +336,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
+    #[rustc_do_not_const_check]
     fn advance_by(&mut self, n: usize) -> Result<(), usize> {
         for i in 0..n {
             self.next().ok_or(i)?;
@@ -379,6 +385,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
         self.advance_by(n).ok()?;
         self.next()
@@ -431,6 +438,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iterator_step_by", since = "1.28.0")]
+    #[rustc_do_not_const_check]
     fn step_by(self, step: usize) -> StepBy<Self>
     where
         Self: Sized,
@@ -502,6 +510,7 @@ pub trait Iterator {
     /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn chain<U>(self, other: U) -> Chain<Self, U::IntoIter>
     where
         Self: Sized,
@@ -620,6 +629,7 @@ pub trait Iterator {
     /// [`zip`]: crate::iter::zip
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>
     where
         Self: Sized,
@@ -662,6 +672,7 @@ pub trait Iterator {
     /// [`intersperse_with`]: Iterator::intersperse_with
     #[inline]
     #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+    #[rustc_do_not_const_check]
     fn intersperse(self, separator: Self::Item) -> Intersperse<Self>
     where
         Self: Sized,
@@ -720,6 +731,7 @@ pub trait Iterator {
     /// [`intersperse`]: Iterator::intersperse
     #[inline]
     #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+    #[rustc_do_not_const_check]
     fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G>
     where
         Self: Sized,
@@ -777,8 +789,10 @@ pub trait Iterator {
     ///     println!("{x}");
     /// }
     /// ```
+    #[rustc_diagnostic_item = "IteratorMap"]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn map<B, F>(self, f: F) -> Map<Self, F>
     where
         Self: Sized,
@@ -824,6 +838,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iterator_for_each", since = "1.21.0")]
+    #[rustc_do_not_const_check]
     fn for_each<F>(self, f: F)
     where
         Self: Sized,
@@ -899,6 +914,7 @@ pub trait Iterator {
     /// Note that `iter.filter(f).next()` is equivalent to `iter.find(f)`.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn filter<P>(self, predicate: P) -> Filter<Self, P>
     where
         Self: Sized,
@@ -944,6 +960,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
     where
         Self: Sized,
@@ -990,6 +1007,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn enumerate(self) -> Enumerate<Self>
     where
         Self: Sized,
@@ -1061,6 +1079,7 @@ pub trait Iterator {
     /// [`next`]: Iterator::next
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn peekable(self) -> Peekable<Self>
     where
         Self: Sized,
@@ -1126,6 +1145,7 @@ pub trait Iterator {
     #[inline]
     #[doc(alias = "drop_while")]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
     where
         Self: Sized,
@@ -1207,6 +1227,7 @@ pub trait Iterator {
     /// the iteration should stop, but wasn't placed back into the iterator.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
     where
         Self: Sized,
@@ -1295,6 +1316,7 @@ pub trait Iterator {
     /// [`fuse`]: Iterator::fuse
     #[inline]
     #[stable(feature = "iter_map_while", since = "1.57.0")]
+    #[rustc_do_not_const_check]
     fn map_while<B, P>(self, predicate: P) -> MapWhile<Self, P>
     where
         Self: Sized,
@@ -1326,6 +1348,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn skip(self, n: usize) -> Skip<Self>
     where
         Self: Sized,
@@ -1379,6 +1402,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn take(self, n: usize) -> Take<Self>
     where
         Self: Sized,
@@ -1428,6 +1452,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
     where
         Self: Sized,
@@ -1468,6 +1493,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
     where
         Self: Sized,
@@ -1552,6 +1578,7 @@ pub trait Iterator {
     /// [`flat_map()`]: Iterator::flat_map
     #[inline]
     #[stable(feature = "iterator_flatten", since = "1.29.0")]
+    #[rustc_do_not_const_check]
     fn flatten(self) -> Flatten<Self>
     where
         Self: Sized,
@@ -1620,6 +1647,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn fuse(self) -> Fuse<Self>
     where
         Self: Sized,
@@ -1704,6 +1732,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn inspect<F>(self, f: F) -> Inspect<Self, F>
     where
         Self: Sized,
@@ -1734,6 +1763,7 @@ pub trait Iterator {
     /// assert_eq!(of_rust, vec!["of", "Rust"]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn by_ref(&mut self) -> &mut Self
     where
         Self: Sized,
@@ -1853,6 +1883,7 @@ pub trait Iterator {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"]
     #[cfg_attr(not(test), rustc_diagnostic_item = "iterator_collect_fn")]
+    #[rustc_do_not_const_check]
     fn collect<B: FromIterator<Self::Item>>(self) -> B
     where
         Self: Sized,
@@ -1931,6 +1962,7 @@ pub trait Iterator {
     /// [`collect`]: Iterator::collect
     #[inline]
     #[unstable(feature = "iterator_try_collect", issue = "94047")]
+    #[rustc_do_not_const_check]
     fn try_collect<B>(&mut self) -> ChangeOutputType<Self::Item, B>
     where
         Self: Sized,
@@ -2004,6 +2036,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[unstable(feature = "iter_collect_into", reason = "new API", issue = "94780")]
+    #[rustc_do_not_const_check]
     fn collect_into<E: Extend<Self::Item>>(self, collection: &mut E) -> &mut E
     where
         Self: Sized,
@@ -2038,6 +2071,7 @@ pub trait Iterator {
     /// assert_eq!(odd, vec![1, 3]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn partition<B, F>(self, f: F) -> (B, B)
     where
         Self: Sized,
@@ -2100,6 +2134,7 @@ pub trait Iterator {
     /// assert!(a[i..].iter().all(|&n| n % 2 == 1)); // odds
     /// ```
     #[unstable(feature = "iter_partition_in_place", reason = "new API", issue = "62543")]
+    #[rustc_do_not_const_check]
     fn partition_in_place<'a, T: 'a, P>(mut self, ref mut predicate: P) -> usize
     where
         Self: Sized + DoubleEndedIterator<Item = &'a mut T>,
@@ -2157,6 +2192,7 @@ pub trait Iterator {
     /// assert!(!"IntoIterator".chars().is_partitioned(char::is_uppercase));
     /// ```
     #[unstable(feature = "iter_is_partitioned", reason = "new API", issue = "62544")]
+    #[rustc_do_not_const_check]
     fn is_partitioned<P>(mut self, mut predicate: P) -> bool
     where
         Self: Sized,
@@ -2251,6 +2287,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iterator_try_fold", since = "1.27.0")]
+    #[rustc_do_not_const_check]
     fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
     where
         Self: Sized,
@@ -2309,6 +2346,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iterator_try_fold", since = "1.27.0")]
+    #[rustc_do_not_const_check]
     fn try_for_each<F, R>(&mut self, f: F) -> R
     where
         Self: Sized,
@@ -2428,6 +2466,7 @@ pub trait Iterator {
     #[doc(alias = "inject", alias = "foldl")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn fold<B, F>(mut self, init: B, mut f: F) -> B
     where
         Self: Sized,
@@ -2465,6 +2504,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iterator_fold_self", since = "1.51.0")]
+    #[rustc_do_not_const_check]
     fn reduce<F>(mut self, f: F) -> Option<Self::Item>
     where
         Self: Sized,
@@ -2536,6 +2576,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[unstable(feature = "iterator_try_reduce", reason = "new API", issue = "87053")]
+    #[rustc_do_not_const_check]
     fn try_reduce<F, R>(&mut self, f: F) -> ChangeOutputType<R, Option<R::Output>>
     where
         Self: Sized,
@@ -2593,6 +2634,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn all<F>(&mut self, f: F) -> bool
     where
         Self: Sized,
@@ -2646,6 +2688,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn any<F>(&mut self, f: F) -> bool
     where
         Self: Sized,
@@ -2709,6 +2752,7 @@ pub trait Iterator {
     /// Note that `iter.find(f)` is equivalent to `iter.filter(f).next()`.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
     where
         Self: Sized,
@@ -2740,6 +2784,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iterator_find_map", since = "1.30.0")]
+    #[rustc_do_not_const_check]
     fn find_map<B, F>(&mut self, f: F) -> Option<B>
     where
         Self: Sized,
@@ -2796,6 +2841,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[unstable(feature = "try_find", reason = "new API", issue = "63178")]
+    #[rustc_do_not_const_check]
     fn try_find<F, R>(&mut self, f: F) -> ChangeOutputType<R, Option<Self::Item>>
     where
         Self: Sized,
@@ -2878,6 +2924,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn position<P>(&mut self, predicate: P) -> Option<usize>
     where
         Self: Sized,
@@ -2935,6 +2982,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn rposition<P>(&mut self, predicate: P) -> Option<usize>
     where
         P: FnMut(Self::Item) -> bool,
@@ -2986,6 +3034,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn max(self) -> Option<Self::Item>
     where
         Self: Sized,
@@ -3024,6 +3073,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn min(self) -> Option<Self::Item>
     where
         Self: Sized,
@@ -3046,6 +3096,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iter_cmp_by_key", since = "1.6.0")]
+    #[rustc_do_not_const_check]
     fn max_by_key<B: Ord, F>(self, f: F) -> Option<Self::Item>
     where
         Self: Sized,
@@ -3079,6 +3130,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iter_max_by", since = "1.15.0")]
+    #[rustc_do_not_const_check]
     fn max_by<F>(self, compare: F) -> Option<Self::Item>
     where
         Self: Sized,
@@ -3106,6 +3158,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iter_cmp_by_key", since = "1.6.0")]
+    #[rustc_do_not_const_check]
     fn min_by_key<B: Ord, F>(self, f: F) -> Option<Self::Item>
     where
         Self: Sized,
@@ -3139,6 +3192,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[stable(feature = "iter_min_by", since = "1.15.0")]
+    #[rustc_do_not_const_check]
     fn min_by<F>(self, compare: F) -> Option<Self::Item>
     where
         Self: Sized,
@@ -3176,6 +3230,7 @@ pub trait Iterator {
     #[inline]
     #[doc(alias = "reverse")]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn rev(self) -> Rev<Self>
     where
         Self: Sized + DoubleEndedIterator,
@@ -3214,6 +3269,7 @@ pub trait Iterator {
     /// assert_eq!(z, [3, 6]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB)
     where
         FromA: Default + Extend<A>,
@@ -3246,6 +3302,7 @@ pub trait Iterator {
     /// assert_eq!(v_map, vec![1, 2, 3]);
     /// ```
     #[stable(feature = "iter_copied", since = "1.36.0")]
+    #[rustc_do_not_const_check]
     fn copied<'a, T: 'a>(self) -> Copied<Self>
     where
         Self: Sized + Iterator<Item = &'a T>,
@@ -3293,6 +3350,7 @@ pub trait Iterator {
     /// assert_eq!(&[vec![23]], &faster[..]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_do_not_const_check]
     fn cloned<'a, T: 'a>(self) -> Cloned<Self>
     where
         Self: Sized + Iterator<Item = &'a T>,
@@ -3327,6 +3385,7 @@ pub trait Iterator {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[rustc_do_not_const_check]
     fn cycle(self) -> Cycle<Self>
     where
         Self: Sized + Clone,
@@ -3370,6 +3429,7 @@ pub trait Iterator {
     /// ```
     #[track_caller]
     #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+    #[rustc_do_not_const_check]
     fn array_chunks<const N: usize>(self) -> ArrayChunks<Self, N>
     where
         Self: Sized,
@@ -3400,6 +3460,7 @@ pub trait Iterator {
     /// assert_eq!(sum, 6);
     /// ```
     #[stable(feature = "iter_arith", since = "1.11.0")]
+    #[rustc_do_not_const_check]
     fn sum<S>(self) -> S
     where
         Self: Sized,
@@ -3429,6 +3490,7 @@ pub trait Iterator {
     /// assert_eq!(factorial(5), 120);
     /// ```
     #[stable(feature = "iter_arith", since = "1.11.0")]
+    #[rustc_do_not_const_check]
     fn product<P>(self) -> P
     where
         Self: Sized,
@@ -3450,6 +3512,7 @@ pub trait Iterator {
     /// assert_eq!([1, 2].iter().cmp([1].iter()), Ordering::Greater);
     /// ```
     #[stable(feature = "iter_order", since = "1.5.0")]
+    #[rustc_do_not_const_check]
     fn cmp<I>(self, other: I) -> Ordering
     where
         I: IntoIterator<Item = Self::Item>,
@@ -3479,6 +3542,7 @@ pub trait Iterator {
     /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater);
     /// ```
     #[unstable(feature = "iter_order_by", issue = "64295")]
+    #[rustc_do_not_const_check]
     fn cmp_by<I, F>(self, other: I, cmp: F) -> Ordering
     where
         Self: Sized,
@@ -3535,6 +3599,7 @@ pub trait Iterator {
     /// ```
     ///
     #[stable(feature = "iter_order", since = "1.5.0")]
+    #[rustc_do_not_const_check]
     fn partial_cmp<I>(self, other: I) -> Option<Ordering>
     where
         I: IntoIterator,
@@ -3573,6 +3638,7 @@ pub trait Iterator {
     /// );
     /// ```
     #[unstable(feature = "iter_order_by", issue = "64295")]
+    #[rustc_do_not_const_check]
     fn partial_cmp_by<I, F>(self, other: I, partial_cmp: F) -> Option<Ordering>
     where
         Self: Sized,
@@ -3606,6 +3672,7 @@ pub trait Iterator {
     /// assert_eq!([1].iter().eq([1, 2].iter()), false);
     /// ```
     #[stable(feature = "iter_order", since = "1.5.0")]
+    #[rustc_do_not_const_check]
     fn eq<I>(self, other: I) -> bool
     where
         I: IntoIterator,
@@ -3631,6 +3698,7 @@ pub trait Iterator {
     /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y));
     /// ```
     #[unstable(feature = "iter_order_by", issue = "64295")]
+    #[rustc_do_not_const_check]
     fn eq_by<I, F>(self, other: I, eq: F) -> bool
     where
         Self: Sized,
@@ -3663,6 +3731,7 @@ pub trait Iterator {
     /// assert_eq!([1].iter().ne([1, 2].iter()), true);
     /// ```
     #[stable(feature = "iter_order", since = "1.5.0")]
+    #[rustc_do_not_const_check]
     fn ne<I>(self, other: I) -> bool
     where
         I: IntoIterator,
@@ -3684,6 +3753,7 @@ pub trait Iterator {
     /// assert_eq!([1, 2].iter().lt([1, 2].iter()), false);
     /// ```
     #[stable(feature = "iter_order", since = "1.5.0")]
+    #[rustc_do_not_const_check]
     fn lt<I>(self, other: I) -> bool
     where
         I: IntoIterator,
@@ -3705,6 +3775,7 @@ pub trait Iterator {
     /// assert_eq!([1, 2].iter().le([1, 2].iter()), true);
     /// ```
     #[stable(feature = "iter_order", since = "1.5.0")]
+    #[rustc_do_not_const_check]
     fn le<I>(self, other: I) -> bool
     where
         I: IntoIterator,
@@ -3726,6 +3797,7 @@ pub trait Iterator {
     /// assert_eq!([1, 2].iter().gt([1, 2].iter()), false);
     /// ```
     #[stable(feature = "iter_order", since = "1.5.0")]
+    #[rustc_do_not_const_check]
     fn gt<I>(self, other: I) -> bool
     where
         I: IntoIterator,
@@ -3747,6 +3819,7 @@ pub trait Iterator {
     /// assert_eq!([1, 2].iter().ge([1, 2].iter()), true);
     /// ```
     #[stable(feature = "iter_order", since = "1.5.0")]
+    #[rustc_do_not_const_check]
     fn ge<I>(self, other: I) -> bool
     where
         I: IntoIterator,
@@ -3778,6 +3851,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
+    #[rustc_do_not_const_check]
     fn is_sorted(self) -> bool
     where
         Self: Sized,
@@ -3806,6 +3880,7 @@ pub trait Iterator {
     ///
     /// [`is_sorted`]: Iterator::is_sorted
     #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
+    #[rustc_do_not_const_check]
     fn is_sorted_by<F>(mut self, compare: F) -> bool
     where
         Self: Sized,
@@ -3852,6 +3927,7 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
+    #[rustc_do_not_const_check]
     fn is_sorted_by_key<F, K>(self, f: F) -> bool
     where
         Self: Sized,
@@ -3867,6 +3943,7 @@ pub trait Iterator {
     #[inline]
     #[doc(hidden)]
     #[unstable(feature = "trusted_random_access", issue = "none")]
+    #[rustc_do_not_const_check]
     unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item
     where
         Self: TrustedRandomAccessNoCoerce,
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index dc0702c467a..d17ff651f4f 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -124,6 +124,8 @@
 #![feature(const_inherent_unchecked_arith)]
 #![feature(const_int_unchecked_arith)]
 #![feature(const_intrinsic_forget)]
+#![feature(const_ipv4)]
+#![feature(const_ipv6)]
 #![feature(const_likely)]
 #![feature(const_maybe_uninit_uninit_array)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
@@ -179,6 +181,7 @@
 #![feature(const_slice_index)]
 #![feature(const_is_char_boundary)]
 #![feature(const_cstr_methods)]
+#![feature(ip)]
 #![feature(is_ascii_octdigit)]
 //
 // Language features:
@@ -194,6 +197,7 @@
 #![feature(cfg_target_has_atomic_equal_alignment)]
 #![feature(const_closures)]
 #![feature(const_fn_floating_point_arithmetic)]
+#![feature(const_for)]
 #![feature(const_mut_refs)]
 #![feature(const_precise_live_drops)]
 #![feature(const_refs_to_cell)]
@@ -228,7 +232,6 @@
 #![feature(simd_ffi)]
 #![feature(staged_api)]
 #![feature(stmt_expr_attributes)]
-#![feature(target_feature_11)]
 #![feature(trait_alias)]
 #![feature(transparent_unions)]
 #![feature(try_blocks)]
@@ -241,7 +244,6 @@
 // Target features:
 #![feature(arm_target_feature)]
 #![feature(avx512_target_feature)]
-#![feature(cmpxchg16b_target_feature)]
 #![feature(hexagon_target_feature)]
 #![feature(mips_target_feature)]
 #![feature(powerpc_target_feature)]
@@ -250,6 +252,7 @@
 #![feature(sse4a_target_feature)]
 #![feature(tbm_target_feature)]
 #![feature(wasm_target_feature)]
+#![cfg_attr(bootstrap, feature(cmpxchg16b_target_feature))]
 
 // allow using `core::` in intra-doc links
 #[allow(unused_extern_crates)]
@@ -348,6 +351,7 @@ pub mod cell;
 pub mod char;
 pub mod ffi;
 pub mod iter;
+pub mod net;
 pub mod option;
 pub mod panic;
 pub mod panicking;
diff --git a/library/std/src/net/display_buffer.rs b/library/core/src/net/display_buffer.rs
index 7aadf06e92f..7aadf06e92f 100644
--- a/library/std/src/net/display_buffer.rs
+++ b/library/core/src/net/display_buffer.rs
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
new file mode 100644
index 00000000000..954d88d548e
--- /dev/null
+++ b/library/core/src/net/ip_addr.rs
@@ -0,0 +1,2070 @@
+use crate::cmp::Ordering;
+use crate::fmt::{self, Write};
+use crate::mem::transmute;
+
+use super::display_buffer::DisplayBuffer;
+
+/// An IP address, either IPv4 or IPv6.
+///
+/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their
+/// respective documentation for more details.
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+///
+/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
+/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+///
+/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4));
+/// assert_eq!("::1".parse(), Ok(localhost_v6));
+///
+/// assert_eq!(localhost_v4.is_ipv6(), false);
+/// assert_eq!(localhost_v4.is_ipv4(), true);
+/// ```
+#[cfg_attr(not(test), rustc_diagnostic_item = "IpAddr")]
+#[stable(feature = "ip_addr", since = "1.7.0")]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
+pub enum IpAddr {
+    /// An IPv4 address.
+    #[stable(feature = "ip_addr", since = "1.7.0")]
+    V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr),
+    /// An IPv6 address.
+    #[stable(feature = "ip_addr", since = "1.7.0")]
+    V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr),
+}
+
+/// An IPv4 address.
+///
+/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791].
+/// They are usually represented as four octets.
+///
+/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
+///
+/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791
+///
+/// # Textual representation
+///
+/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal
+/// notation, divided by `.` (this is called "dot-decimal notation").
+/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which
+/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943].
+///
+/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1
+/// [`FromStr`]: crate::str::FromStr
+///
+/// # Examples
+///
+/// ```
+/// use std::net::Ipv4Addr;
+///
+/// let localhost = Ipv4Addr::new(127, 0, 0, 1);
+/// assert_eq!("127.0.0.1".parse(), Ok(localhost));
+/// assert_eq!(localhost.is_loopback(), true);
+/// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal
+/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
+/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Ipv4Addr {
+    octets: [u8; 4],
+}
+
+/// An IPv6 address.
+///
+/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
+/// They are usually represented as eight 16-bit segments.
+///
+/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+///
+/// # Embedding IPv4 Addresses
+///
+/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
+///
+/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined:
+/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated.
+///
+/// Both types of addresses are not assigned any special meaning by this implementation,
+/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`,
+/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is.
+/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address.
+///
+/// ### IPv4-Compatible IPv6 Addresses
+///
+/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated.
+/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows:
+///
+/// ```text
+/// |                80 bits               | 16 |      32 bits        |
+/// +--------------------------------------+--------------------------+
+/// |0000..............................0000|0000|    IPv4 address     |
+/// +--------------------------------------+----+---------------------+
+/// ```
+/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`.
+///
+/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`].
+/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address.
+///
+/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1
+///
+/// ### IPv4-Mapped IPv6 Addresses
+///
+/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2].
+/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows:
+///
+/// ```text
+/// |                80 bits               | 16 |      32 bits        |
+/// +--------------------------------------+--------------------------+
+/// |0000..............................0000|FFFF|    IPv4 address     |
+/// +--------------------------------------+----+---------------------+
+/// ```
+/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`.
+///
+/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`].
+/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address.
+/// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use
+/// [`Ipv6Addr::to_ipv4_mapped`] to avoid this.
+///
+/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2
+///
+/// # Textual representation
+///
+/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent
+/// an IPv6 address in text, but in general, each segments is written in hexadecimal
+/// notation, and segments are separated by `:`. For more information, see
+/// [IETF RFC 5952].
+///
+/// [`FromStr`]: crate::str::FromStr
+/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952
+///
+/// # Examples
+///
+/// ```
+/// use std::net::Ipv6Addr;
+///
+/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+/// assert_eq!("::1".parse(), Ok(localhost));
+/// assert_eq!(localhost.is_loopback(), true);
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Ipv6Addr {
+    octets: [u8; 16],
+}
+
+/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2].
+///
+/// # Stability Guarantees
+///
+/// Not all possible values for a multicast scope have been assigned.
+/// Future RFCs may introduce new scopes, which will be added as variants to this enum;
+/// because of this the enum is marked as `#[non_exhaustive]`.
+///
+/// # Examples
+/// ```
+/// #![feature(ip)]
+///
+/// use std::net::Ipv6Addr;
+/// use std::net::Ipv6MulticastScope::*;
+///
+/// // An IPv6 multicast address with global scope (`ff0e::`).
+/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0);
+///
+/// // Will print "Global scope".
+/// match address.multicast_scope() {
+///     Some(InterfaceLocal) => println!("Interface-Local scope"),
+///     Some(LinkLocal) => println!("Link-Local scope"),
+///     Some(RealmLocal) => println!("Realm-Local scope"),
+///     Some(AdminLocal) => println!("Admin-Local scope"),
+///     Some(SiteLocal) => println!("Site-Local scope"),
+///     Some(OrganizationLocal) => println!("Organization-Local scope"),
+///     Some(Global) => println!("Global scope"),
+///     Some(_) => println!("Unknown scope"),
+///     None => println!("Not a multicast address!")
+/// }
+///
+/// ```
+///
+/// [IPv6 multicast address]: Ipv6Addr
+/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2
+#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+#[unstable(feature = "ip", issue = "27709")]
+#[non_exhaustive]
+pub enum Ipv6MulticastScope {
+    /// Interface-Local scope.
+    InterfaceLocal,
+    /// Link-Local scope.
+    LinkLocal,
+    /// Realm-Local scope.
+    RealmLocal,
+    /// Admin-Local scope.
+    AdminLocal,
+    /// Site-Local scope.
+    SiteLocal,
+    /// Organization-Local scope.
+    OrganizationLocal,
+    /// Global scope.
+    Global,
+}
+
+impl IpAddr {
+    /// Returns [`true`] for the special 'unspecified' address.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_unspecified()`] and
+    /// [`Ipv6Addr::is_unspecified()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unspecified(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_unspecified(),
+            IpAddr::V6(ip) => ip.is_unspecified(),
+        }
+    }
+
+    /// Returns [`true`] if this is a loopback address.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_loopback()`] and
+    /// [`Ipv6Addr::is_loopback()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_loopback(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_loopback(),
+            IpAddr::V6(ip) => ip.is_loopback(),
+        }
+    }
+
+    /// Returns [`true`] if the address appears to be globally routable.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_global()`] and
+    /// [`Ipv6Addr::is_global()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_global(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_global(),
+            IpAddr::V6(ip) => ip.is_global(),
+        }
+    }
+
+    /// Returns [`true`] if this is a multicast address.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_multicast()`] and
+    /// [`Ipv6Addr::is_multicast()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_multicast(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_multicast(),
+            IpAddr::V6(ip) => ip.is_multicast(),
+        }
+    }
+
+    /// Returns [`true`] if this address is in a range designated for documentation.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_documentation()`] and
+    /// [`Ipv6Addr::is_documentation()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true);
+    /// assert_eq!(
+    ///     IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(),
+    ///     true
+    /// );
+    /// ```
+    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_documentation(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_documentation(),
+            IpAddr::V6(ip) => ip.is_documentation(),
+        }
+    }
+
+    /// Returns [`true`] if this address is in a range designated for benchmarking.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and
+    /// [`Ipv6Addr::is_benchmarking()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true);
+    /// ```
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_benchmarking(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_benchmarking(),
+            IpAddr::V6(ip) => ip.is_benchmarking(),
+        }
+    }
+
+    /// Returns [`true`] if this address is an [`IPv4` address], and [`false`]
+    /// otherwise.
+    ///
+    /// [`IPv4` address]: IpAddr::V4
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "ipaddr_checker", since = "1.16.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_ipv4(&self) -> bool {
+        matches!(self, IpAddr::V4(_))
+    }
+
+    /// Returns [`true`] if this address is an [`IPv6` address], and [`false`]
+    /// otherwise.
+    ///
+    /// [`IPv6` address]: IpAddr::V6
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "ipaddr_checker", since = "1.16.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_ipv6(&self) -> bool {
+        matches!(self, IpAddr::V6(_))
+    }
+
+    /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it
+    /// return `self` as-is.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true);
+    /// ```
+    #[inline]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    pub const fn to_canonical(&self) -> IpAddr {
+        match self {
+            &v4 @ IpAddr::V4(_) => v4,
+            IpAddr::V6(v6) => v6.to_canonical(),
+        }
+    }
+}
+
+impl Ipv4Addr {
+    /// Creates a new IPv4 address from four eight-bit octets.
+    ///
+    /// The result will represent the IP address `a`.`b`.`c`.`d`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[inline]
+    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+        Ipv4Addr { octets: [a, b, c, d] }
+    }
+
+    /// An IPv4 address with the address pointing to localhost: `127.0.0.1`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::LOCALHOST;
+    /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
+    /// ```
+    #[stable(feature = "ip_constructors", since = "1.30.0")]
+    pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
+
+    /// An IPv4 address representing an unspecified address: `0.0.0.0`
+    ///
+    /// This corresponds to the constant `INADDR_ANY` in other languages.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::UNSPECIFIED;
+    /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
+    /// ```
+    #[doc(alias = "INADDR_ANY")]
+    #[stable(feature = "ip_constructors", since = "1.30.0")]
+    pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
+
+    /// An IPv4 address representing the broadcast address: `255.255.255.255`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::BROADCAST;
+    /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255));
+    /// ```
+    #[stable(feature = "ip_constructors", since = "1.30.0")]
+    pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
+
+    /// Returns the four eight-bit integers that make up this address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
+    /// assert_eq!(addr.octets(), [127, 0, 0, 1]);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[inline]
+    pub const fn octets(&self) -> [u8; 4] {
+        self.octets
+    }
+
+    /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`).
+    ///
+    /// This property is defined in _UNIX Network Programming, Second Edition_,
+    /// W. Richard Stevens, p. 891; see also [ip7].
+    ///
+    /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true);
+    /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unspecified(&self) -> bool {
+        u32::from_be_bytes(self.octets) == 0
+    }
+
+    /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`).
+    ///
+    /// This property is defined by [IETF RFC 1122].
+    ///
+    /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true);
+    /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_loopback(&self) -> bool {
+        self.octets()[0] == 127
+    }
+
+    /// Returns [`true`] if this is a private address.
+    ///
+    /// The private address ranges are defined in [IETF RFC 1918] and include:
+    ///
+    ///  - `10.0.0.0/8`
+    ///  - `172.16.0.0/12`
+    ///  - `192.168.0.0/16`
+    ///
+    /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true);
+    /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true);
+    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true);
+    /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true);
+    /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false);
+    /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true);
+    /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_private(&self) -> bool {
+        match self.octets() {
+            [10, ..] => true,
+            [172, b, ..] if b >= 16 && b <= 31 => true,
+            [192, 168, ..] => true,
+            _ => false,
+        }
+    }
+
+    /// Returns [`true`] if the address is link-local (`169.254.0.0/16`).
+    ///
+    /// This property is defined by [IETF RFC 3927].
+    ///
+    /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true);
+    /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true);
+    /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_link_local(&self) -> bool {
+        matches!(self.octets(), [169, 254, ..])
+    }
+
+    /// Returns [`true`] if the address appears to be globally reachable
+    /// as specified by the [IANA IPv4 Special-Purpose Address Registry].
+    /// Whether or not an address is practically reachable will depend on your network configuration.
+    ///
+    /// Most IPv4 addresses are globally reachable;
+    /// unless they are specifically defined as *not* globally reachable.
+    ///
+    /// Non-exhaustive list of notable addresses that are not globally reachable:
+    ///
+    /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified))
+    /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private))
+    /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared))
+    /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback))
+    /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local))
+    /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation))
+    /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking))
+    /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved))
+    /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast))
+    ///
+    /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry].
+    ///
+    /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
+    /// [unspecified address]: Ipv4Addr::UNSPECIFIED
+    /// [broadcast address]: Ipv4Addr::BROADCAST
+
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv4Addr;
+    ///
+    /// // Most IPv4 addresses are globally reachable:
+    /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
+    ///
+    /// // However some addresses have been assigned a special meaning
+    /// // that makes them not globally reachable. Some examples are:
+    ///
+    /// // The unspecified address (`0.0.0.0`)
+    /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false);
+    ///
+    /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16)
+    /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
+    /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
+    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
+    ///
+    /// // Addresses in the shared address space (`100.64.0.0/10`)
+    /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
+    ///
+    /// // The loopback addresses (`127.0.0.0/8`)
+    /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false);
+    ///
+    /// // Link-local addresses (`169.254.0.0/16`)
+    /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false);
+    ///
+    /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`)
+    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false);
+    /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false);
+    /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false);
+    ///
+    /// // Addresses reserved for benchmarking (`198.18.0.0/15`)
+    /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
+    ///
+    /// // Reserved addresses (`240.0.0.0/4`)
+    /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
+    ///
+    /// // The broadcast address (`255.255.255.255`)
+    /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false);
+    ///
+    /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry.
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_global(&self) -> bool {
+        !(self.octets()[0] == 0 // "This network"
+            || self.is_private()
+            || self.is_shared()
+            || self.is_loopback()
+            || self.is_link_local()
+            // addresses reserved for future protocols (`192.0.0.0/24`)
+            ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
+            || self.is_documentation()
+            || self.is_benchmarking()
+            || self.is_reserved()
+            || self.is_broadcast())
+    }
+
+    /// Returns [`true`] if this address is part of the Shared Address Space defined in
+    /// [IETF RFC 6598] (`100.64.0.0/10`).
+    ///
+    /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true);
+    /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true);
+    /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_shared(&self) -> bool {
+        self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
+    }
+
+    /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for
+    /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0`
+    /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`.
+    ///
+    /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544
+    /// [errata 423]: https://www.rfc-editor.org/errata/eid423
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false);
+    /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true);
+    /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true);
+    /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_benchmarking(&self) -> bool {
+        self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
+    }
+
+    /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112]
+    /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the
+    /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since
+    /// it is obviously not reserved for future use.
+    ///
+    /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112
+    ///
+    /// # Warning
+    ///
+    /// As IANA assigns new addresses, this method will be
+    /// updated. This may result in non-reserved addresses being
+    /// treated as reserved in code that relies on an outdated version
+    /// of this method.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true);
+    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true);
+    ///
+    /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false);
+    /// // The broadcast address is not considered as reserved for future use by this implementation
+    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_reserved(&self) -> bool {
+        self.octets()[0] & 240 == 240 && !self.is_broadcast()
+    }
+
+    /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`).
+    ///
+    /// Multicast addresses have a most significant octet between `224` and `239`,
+    /// and is defined by [IETF RFC 5771].
+    ///
+    /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true);
+    /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true);
+    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_multicast(&self) -> bool {
+        self.octets()[0] >= 224 && self.octets()[0] <= 239
+    }
+
+    /// Returns [`true`] if this is a broadcast address (`255.255.255.255`).
+    ///
+    /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919].
+    ///
+    /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true);
+    /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_broadcast(&self) -> bool {
+        u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets())
+    }
+
+    /// Returns [`true`] if this address is in a range designated for documentation.
+    ///
+    /// This is defined in [IETF RFC 5737]:
+    ///
+    /// - `192.0.2.0/24` (TEST-NET-1)
+    /// - `198.51.100.0/24` (TEST-NET-2)
+    /// - `203.0.113.0/24` (TEST-NET-3)
+    ///
+    /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true);
+    /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true);
+    /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true);
+    /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_documentation(&self) -> bool {
+        matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _])
+    }
+
+    /// Converts this address to an [IPv4-compatible] [`IPv6` address].
+    ///
+    /// `a.b.c.d` becomes `::a.b.c.d`
+    ///
+    /// Note that IPv4-compatible addresses have been officially deprecated.
+    /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead.
+    ///
+    /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
+    /// [`IPv6` address]: Ipv6Addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(
+    ///     Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(),
+    ///     Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff)
+    /// );
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
+        let [a, b, c, d] = self.octets();
+        Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] }
+    }
+
+    /// Converts this address to an [IPv4-mapped] [`IPv6` address].
+    ///
+    /// `a.b.c.d` becomes `::ffff:a.b.c.d`
+    ///
+    /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
+    /// [`IPv6` address]: Ipv6Addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(),
+    ///            Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff));
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
+        let [a, b, c, d] = self.octets();
+        Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] }
+    }
+}
+
+#[stable(feature = "ip_addr", since = "1.7.0")]
+impl fmt::Display for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            IpAddr::V4(ip) => ip.fmt(fmt),
+            IpAddr::V6(ip) => ip.fmt(fmt),
+        }
+    }
+}
+
+#[stable(feature = "ip_addr", since = "1.7.0")]
+impl fmt::Debug for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<Ipv4Addr> for IpAddr {
+    /// Copies this address to a new `IpAddr::V4`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr};
+    ///
+    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
+    ///
+    /// assert_eq!(
+    ///     IpAddr::V4(addr),
+    ///     IpAddr::from(addr)
+    /// )
+    /// ```
+    #[inline]
+    fn from(ipv4: Ipv4Addr) -> IpAddr {
+        IpAddr::V4(ipv4)
+    }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<Ipv6Addr> for IpAddr {
+    /// Copies this address to a new `IpAddr::V6`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv6Addr};
+    ///
+    /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
+    ///
+    /// assert_eq!(
+    ///     IpAddr::V6(addr),
+    ///     IpAddr::from(addr)
+    /// );
+    /// ```
+    #[inline]
+    fn from(ipv6: Ipv6Addr) -> IpAddr {
+        IpAddr::V6(ipv6)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let octets = self.octets();
+
+        // If there are no alignment requirements, write the IP address directly to `f`.
+        // Otherwise, write it to a local buffer and then use `f.pad`.
+        if fmt.precision().is_none() && fmt.width().is_none() {
+            write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+        } else {
+            const LONGEST_IPV4_ADDR: &str = "255.255.255.255";
+
+            let mut buf = DisplayBuffer::<{ LONGEST_IPV4_ADDR.len() }>::new();
+            // Buffer is long enough for the longest possible IPv4 address, so this should never fail.
+            write!(buf, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
+
+            fmt.pad(buf.as_str())
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<Ipv4Addr> for IpAddr {
+    #[inline]
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        match self {
+            IpAddr::V4(v4) => v4 == other,
+            IpAddr::V6(_) => false,
+        }
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<IpAddr> for Ipv4Addr {
+    #[inline]
+    fn eq(&self, other: &IpAddr) -> bool {
+        match other {
+            IpAddr::V4(v4) => self == v4,
+            IpAddr::V6(_) => false,
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for Ipv4Addr {
+    #[inline]
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<Ipv4Addr> for IpAddr {
+    #[inline]
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        match self {
+            IpAddr::V4(v4) => v4.partial_cmp(other),
+            IpAddr::V6(_) => Some(Ordering::Greater),
+        }
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<IpAddr> for Ipv4Addr {
+    #[inline]
+    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+        match other {
+            IpAddr::V4(v4) => self.partial_cmp(v4),
+            IpAddr::V6(_) => Some(Ordering::Less),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for Ipv4Addr {
+    #[inline]
+    fn cmp(&self, other: &Ipv4Addr) -> Ordering {
+        self.octets.cmp(&other.octets)
+    }
+}
+
+#[stable(feature = "ip_u32", since = "1.1.0")]
+impl From<Ipv4Addr> for u32 {
+    /// Converts an `Ipv4Addr` into a host byte order `u32`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78);
+    /// assert_eq!(0x12345678, u32::from(addr));
+    /// ```
+    #[inline]
+    fn from(ip: Ipv4Addr) -> u32 {
+        u32::from_be_bytes(ip.octets)
+    }
+}
+
+#[stable(feature = "ip_u32", since = "1.1.0")]
+impl From<u32> for Ipv4Addr {
+    /// Converts a host byte order `u32` into an `Ipv4Addr`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::from(0x12345678);
+    /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr);
+    /// ```
+    #[inline]
+    fn from(ip: u32) -> Ipv4Addr {
+        Ipv4Addr { octets: ip.to_be_bytes() }
+    }
+}
+
+#[stable(feature = "from_slice_v4", since = "1.9.0")]
+impl From<[u8; 4]> for Ipv4Addr {
+    /// Creates an `Ipv4Addr` from a four element byte array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]);
+    /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
+    /// ```
+    #[inline]
+    fn from(octets: [u8; 4]) -> Ipv4Addr {
+        Ipv4Addr { octets }
+    }
+}
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u8; 4]> for IpAddr {
+    /// Creates an `IpAddr::V4` from a four element byte array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr};
+    ///
+    /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]);
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr);
+    /// ```
+    #[inline]
+    fn from(octets: [u8; 4]) -> IpAddr {
+        IpAddr::V4(Ipv4Addr::from(octets))
+    }
+}
+
+impl Ipv6Addr {
+    /// Creates a new IPv6 address from eight 16-bit segments.
+    ///
+    /// The result will represent the IP address `a:b:c:d:e:f:g:h`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[inline]
+    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
+        let addr16 = [
+            a.to_be(),
+            b.to_be(),
+            c.to_be(),
+            d.to_be(),
+            e.to_be(),
+            f.to_be(),
+            g.to_be(),
+            h.to_be(),
+        ];
+        Ipv6Addr {
+            // All elements in `addr16` are big endian.
+            // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
+            octets: unsafe { transmute::<_, [u8; 16]>(addr16) },
+        }
+    }
+
+    /// An IPv6 address representing localhost: `::1`.
+    ///
+    /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other
+    /// languages.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::LOCALHOST;
+    /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+    /// ```
+    #[doc(alias = "IN6ADDR_LOOPBACK_INIT")]
+    #[doc(alias = "in6addr_loopback")]
+    #[stable(feature = "ip_constructors", since = "1.30.0")]
+    pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+
+    /// An IPv6 address representing the unspecified address: `::`
+    ///
+    /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::UNSPECIFIED;
+    /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+    /// ```
+    #[doc(alias = "IN6ADDR_ANY_INIT")]
+    #[doc(alias = "in6addr_any")]
+    #[stable(feature = "ip_constructors", since = "1.30.0")]
+    pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+
+    /// Returns the eight 16-bit segments that make up this address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(),
+    ///            [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[inline]
+    pub const fn segments(&self) -> [u16; 8] {
+        // All elements in `self.octets` must be big endian.
+        // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
+        let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) };
+        // We want native endian u16
+        [
+            u16::from_be(a),
+            u16::from_be(b),
+            u16::from_be(c),
+            u16::from_be(d),
+            u16::from_be(e),
+            u16::from_be(f),
+            u16::from_be(g),
+            u16::from_be(h),
+        ]
+    }
+
+    /// Returns [`true`] for the special 'unspecified' address (`::`).
+    ///
+    /// This property is defined in [IETF RFC 4291].
+    ///
+    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unspecified(&self) -> bool {
+        u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
+    }
+
+    /// Returns [`true`] if this is the [loopback address] (`::1`),
+    /// as defined in [IETF RFC 4291 section 2.5.3].
+    ///
+    /// Contrary to IPv4, in IPv6 there is only one loopback address.
+    ///
+    /// [loopback address]: Ipv6Addr::LOCALHOST
+    /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_loopback(&self) -> bool {
+        u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
+    }
+
+    /// Returns [`true`] if the address appears to be globally reachable
+    /// as specified by the [IANA IPv6 Special-Purpose Address Registry].
+    /// Whether or not an address is practically reachable will depend on your network configuration.
+    ///
+    /// Most IPv6 addresses are globally reachable;
+    /// unless they are specifically defined as *not* globally reachable.
+    ///
+    /// Non-exhaustive list of notable addresses that are not globally reachable:
+    /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified))
+    /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback))
+    /// - IPv4-mapped addresses
+    /// - Addresses reserved for benchmarking
+    /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation))
+    /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local))
+    /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local))
+    ///
+    /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry].
+    ///
+    /// Note that an address having global scope is not the same as being globally reachable,
+    /// and there is no direct relation between the two concepts: There exist addresses with global scope
+    /// that are not globally reachable (for example unique local addresses),
+    /// and addresses that are globally reachable without having global scope
+    /// (multicast addresses with non-global scope).
+    ///
+    /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
+    /// [unspecified address]: Ipv6Addr::UNSPECIFIED
+    /// [loopback address]: Ipv6Addr::LOCALHOST
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// // Most IPv6 addresses are globally reachable:
+    /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true);
+    ///
+    /// // However some addresses have been assigned a special meaning
+    /// // that makes them not globally reachable. Some examples are:
+    ///
+    /// // The unspecified address (`::`)
+    /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false);
+    ///
+    /// // The loopback address (`::1`)
+    /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false);
+    ///
+    /// // IPv4-mapped addresses (`::ffff:0:0/96`)
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false);
+    ///
+    /// // Addresses reserved for benchmarking (`2001:2::/48`)
+    /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
+    ///
+    /// // Addresses reserved for documentation (`2001:db8::/32`)
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
+    ///
+    /// // Unique local addresses (`fc00::/7`)
+    /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
+    ///
+    /// // Unicast addresses with link-local scope (`fe80::/10`)
+    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
+    ///
+    /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry.
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_global(&self) -> bool {
+        !(self.is_unspecified()
+            || self.is_loopback()
+            // IPv4-mapped Address (`::ffff:0:0/96`)
+            || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
+            // IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
+            || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
+            // Discard-Only Address Block (`100::/64`)
+            || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
+            // IETF Protocol Assignments (`2001::/23`)
+            || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
+                && !(
+                    // Port Control Protocol Anycast (`2001:1::1`)
+                    u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
+                    // Traversal Using Relays around NAT Anycast (`2001:1::2`)
+                    || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
+                    // AMT (`2001:3::/32`)
+                    || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
+                    // AS112-v6 (`2001:4:112::/48`)
+                    || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
+                    // ORCHIDv2 (`2001:20::/28`)
+                    || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
+                ))
+            || self.is_documentation()
+            || self.is_unique_local()
+            || self.is_unicast_link_local())
+    }
+
+    /// Returns [`true`] if this is a unique local address (`fc00::/7`).
+    ///
+    /// This property is defined in [IETF RFC 4193].
+    ///
+    /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false);
+    /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unique_local(&self) -> bool {
+        (self.segments()[0] & 0xfe00) == 0xfc00
+    }
+
+    /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291].
+    /// Any address that is not a [multicast address] (`ff00::/8`) is unicast.
+    ///
+    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+    /// [multicast address]: Ipv6Addr::is_multicast
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// // The unspecified and loopback addresses are unicast.
+    /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true);
+    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true);
+    ///
+    /// // Any address that is not a multicast address (`ff00::/8`) is unicast.
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true);
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unicast(&self) -> bool {
+        !self.is_multicast()
+    }
+
+    /// Returns `true` if the address is a unicast address with link-local scope,
+    /// as defined in [RFC 4291].
+    ///
+    /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
+    /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
+    /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
+    ///
+    /// ```text
+    /// | 10 bits  |         54 bits         |          64 bits           |
+    /// +----------+-------------------------+----------------------------+
+    /// |1111111010|           0             |       interface ID         |
+    /// +----------+-------------------------+----------------------------+
+    /// ```
+    /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
+    /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
+    /// and those addresses will have link-local scope.
+    ///
+    /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope",
+    /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
+    ///
+    /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
+    /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
+    /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
+    /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
+    /// [loopback address]: Ipv6Addr::LOCALHOST
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// // The loopback address (`::1`) does not actually have link-local scope.
+    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
+    ///
+    /// // Only addresses in `fe80::/10` have link-local scope.
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
+    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
+    ///
+    /// // Addresses outside the stricter `fe80::/64` also have link-local scope.
+    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
+    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unicast_link_local(&self) -> bool {
+        (self.segments()[0] & 0xffc0) == 0xfe80
+    }
+
+    /// Returns [`true`] if this is an address reserved for documentation
+    /// (`2001:db8::/32`).
+    ///
+    /// This property is defined in [IETF RFC 3849].
+    ///
+    /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false);
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_documentation(&self) -> bool {
+        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
+    }
+
+    /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`).
+    ///
+    /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`.
+    /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`.
+    ///
+    /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180
+    /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false);
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true);
+    /// ```
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_benchmarking(&self) -> bool {
+        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0)
+    }
+
+    /// Returns [`true`] if the address is a globally routable unicast address.
+    ///
+    /// The following return false:
+    ///
+    /// - the loopback address
+    /// - the link-local addresses
+    /// - unique local addresses
+    /// - the unspecified address
+    /// - the address range reserved for documentation
+    ///
+    /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7]
+    ///
+    /// ```no_rust
+    /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer
+    /// be supported in new implementations (i.e., new implementations must treat this prefix as
+    /// Global Unicast).
+    /// ```
+    ///
+    /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unicast_global(&self) -> bool {
+        self.is_unicast()
+            && !self.is_loopback()
+            && !self.is_unicast_link_local()
+            && !self.is_unique_local()
+            && !self.is_unspecified()
+            && !self.is_documentation()
+            && !self.is_benchmarking()
+    }
+
+    /// Returns the address's multicast scope if the address is multicast.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::{Ipv6Addr, Ipv6MulticastScope};
+    ///
+    /// assert_eq!(
+    ///     Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(),
+    ///     Some(Ipv6MulticastScope::Global)
+    /// );
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
+        if self.is_multicast() {
+            match self.segments()[0] & 0x000f {
+                1 => Some(Ipv6MulticastScope::InterfaceLocal),
+                2 => Some(Ipv6MulticastScope::LinkLocal),
+                3 => Some(Ipv6MulticastScope::RealmLocal),
+                4 => Some(Ipv6MulticastScope::AdminLocal),
+                5 => Some(Ipv6MulticastScope::SiteLocal),
+                8 => Some(Ipv6MulticastScope::OrganizationLocal),
+                14 => Some(Ipv6MulticastScope::Global),
+                _ => None,
+            }
+        } else {
+            None
+        }
+    }
+
+    /// Returns [`true`] if this is a multicast address (`ff00::/8`).
+    ///
+    /// This property is defined by [IETF RFC 4291].
+    ///
+    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_multicast(&self) -> bool {
+        (self.segments()[0] & 0xff00) == 0xff00
+    }
+
+    /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address,
+    /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
+    ///
+    /// `::ffff:a.b.c.d` becomes `a.b.c.d`.
+    /// All addresses *not* starting with `::ffff` will return `None`.
+    ///
+    /// [`IPv4` address]: Ipv4Addr
+    /// [IPv4-mapped]: Ipv6Addr
+    /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(),
+    ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
+        match self.octets() {
+            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
+                Some(Ipv4Addr::new(a, b, c, d))
+            }
+            _ => None,
+        }
+    }
+
+    /// Converts this address to an [`IPv4` address] if it is either
+    /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1],
+    /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2],
+    /// otherwise returns [`None`].
+    ///
+    /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use
+    /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this.
+    ///
+    /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`.
+    /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`.
+    ///
+    /// [`IPv4` address]: Ipv4Addr
+    /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
+    /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
+    /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1
+    /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(),
+    ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(),
+    ///            Some(Ipv4Addr::new(0, 0, 0, 1)));
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
+        if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
+            let [a, b] = ab.to_be_bytes();
+            let [c, d] = cd.to_be_bytes();
+            Some(Ipv4Addr::new(a, b, c, d))
+        } else {
+            None
+        }
+    }
+
+    /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it
+    /// returns self wrapped in an `IpAddr::V6`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub const fn to_canonical(&self) -> IpAddr {
+        if let Some(mapped) = self.to_ipv4_mapped() {
+            return IpAddr::V4(mapped);
+        }
+        IpAddr::V6(*self)
+    }
+
+    /// Returns the sixteen eight-bit integers the IPv6 address consists of.
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(),
+    ///            [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
+    #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
+    #[must_use]
+    #[inline]
+    pub const fn octets(&self) -> [u8; 16] {
+        self.octets
+    }
+}
+
+/// Write an Ipv6Addr, conforming to the canonical style described by
+/// [RFC 5952](https://tools.ietf.org/html/rfc5952).
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Ipv6Addr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // If there are no alignment requirements, write the IP address directly to `f`.
+        // Otherwise, write it to a local buffer and then use `f.pad`.
+        if f.precision().is_none() && f.width().is_none() {
+            let segments = self.segments();
+
+            // Special case for :: and ::1; otherwise they get written with the
+            // IPv4 formatter
+            if self.is_unspecified() {
+                f.write_str("::")
+            } else if self.is_loopback() {
+                f.write_str("::1")
+            } else if let Some(ipv4) = self.to_ipv4() {
+                match segments[5] {
+                    // IPv4 Compatible address
+                    0 => write!(f, "::{}", ipv4),
+                    // IPv4 Mapped address
+                    0xffff => write!(f, "::ffff:{}", ipv4),
+                    _ => unreachable!(),
+                }
+            } else {
+                #[derive(Copy, Clone, Default)]
+                struct Span {
+                    start: usize,
+                    len: usize,
+                }
+
+                // Find the inner 0 span
+                let zeroes = {
+                    let mut longest = Span::default();
+                    let mut current = Span::default();
+
+                    for (i, &segment) in segments.iter().enumerate() {
+                        if segment == 0 {
+                            if current.len == 0 {
+                                current.start = i;
+                            }
+
+                            current.len += 1;
+
+                            if current.len > longest.len {
+                                longest = current;
+                            }
+                        } else {
+                            current = Span::default();
+                        }
+                    }
+
+                    longest
+                };
+
+                /// Write a colon-separated part of the address
+                #[inline]
+                fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
+                    if let Some((first, tail)) = chunk.split_first() {
+                        write!(f, "{:x}", first)?;
+                        for segment in tail {
+                            f.write_char(':')?;
+                            write!(f, "{:x}", segment)?;
+                        }
+                    }
+                    Ok(())
+                }
+
+                if zeroes.len > 1 {
+                    fmt_subslice(f, &segments[..zeroes.start])?;
+                    f.write_str("::")?;
+                    fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
+                } else {
+                    fmt_subslice(f, &segments)
+                }
+            }
+        } else {
+            const LONGEST_IPV6_ADDR: &str = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
+
+            let mut buf = DisplayBuffer::<{ LONGEST_IPV6_ADDR.len() }>::new();
+            // Buffer is long enough for the longest possible IPv6 address, so this should never fail.
+            write!(buf, "{}", self).unwrap();
+
+            f.pad(buf.as_str())
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Ipv6Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<IpAddr> for Ipv6Addr {
+    #[inline]
+    fn eq(&self, other: &IpAddr) -> bool {
+        match other {
+            IpAddr::V4(_) => false,
+            IpAddr::V6(v6) => self == v6,
+        }
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<Ipv6Addr> for IpAddr {
+    #[inline]
+    fn eq(&self, other: &Ipv6Addr) -> bool {
+        match self {
+            IpAddr::V4(_) => false,
+            IpAddr::V6(v6) => v6 == other,
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for Ipv6Addr {
+    #[inline]
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<Ipv6Addr> for IpAddr {
+    #[inline]
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        match self {
+            IpAddr::V4(_) => Some(Ordering::Less),
+            IpAddr::V6(v6) => v6.partial_cmp(other),
+        }
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<IpAddr> for Ipv6Addr {
+    #[inline]
+    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+        match other {
+            IpAddr::V4(_) => Some(Ordering::Greater),
+            IpAddr::V6(v6) => self.partial_cmp(v6),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for Ipv6Addr {
+    #[inline]
+    fn cmp(&self, other: &Ipv6Addr) -> Ordering {
+        self.segments().cmp(&other.segments())
+    }
+}
+
+#[stable(feature = "i128", since = "1.26.0")]
+impl From<Ipv6Addr> for u128 {
+    /// Convert an `Ipv6Addr` into a host byte order `u128`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(
+    ///     0x1020, 0x3040, 0x5060, 0x7080,
+    ///     0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
+    /// );
+    /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
+    /// ```
+    #[inline]
+    fn from(ip: Ipv6Addr) -> u128 {
+        u128::from_be_bytes(ip.octets)
+    }
+}
+#[stable(feature = "i128", since = "1.26.0")]
+impl From<u128> for Ipv6Addr {
+    /// Convert a host byte order `u128` into an `Ipv6Addr`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128);
+    /// assert_eq!(
+    ///     Ipv6Addr::new(
+    ///         0x1020, 0x3040, 0x5060, 0x7080,
+    ///         0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
+    ///     ),
+    ///     addr);
+    /// ```
+    #[inline]
+    fn from(ip: u128) -> Ipv6Addr {
+        Ipv6Addr::from(ip.to_be_bytes())
+    }
+}
+
+#[stable(feature = "ipv6_from_octets", since = "1.9.0")]
+impl From<[u8; 16]> for Ipv6Addr {
+    /// Creates an `Ipv6Addr` from a sixteen element byte array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::from([
+    ///     25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
+    ///     17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
+    /// ]);
+    /// assert_eq!(
+    ///     Ipv6Addr::new(
+    ///         0x1918, 0x1716,
+    ///         0x1514, 0x1312,
+    ///         0x1110, 0x0f0e,
+    ///         0x0d0c, 0x0b0a
+    ///     ),
+    ///     addr
+    /// );
+    /// ```
+    #[inline]
+    fn from(octets: [u8; 16]) -> Ipv6Addr {
+        Ipv6Addr { octets }
+    }
+}
+
+#[stable(feature = "ipv6_from_segments", since = "1.16.0")]
+impl From<[u16; 8]> for Ipv6Addr {
+    /// Creates an `Ipv6Addr` from an eight element 16-bit array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::from([
+    ///     525u16, 524u16, 523u16, 522u16,
+    ///     521u16, 520u16, 519u16, 518u16,
+    /// ]);
+    /// assert_eq!(
+    ///     Ipv6Addr::new(
+    ///         0x20d, 0x20c,
+    ///         0x20b, 0x20a,
+    ///         0x209, 0x208,
+    ///         0x207, 0x206
+    ///     ),
+    ///     addr
+    /// );
+    /// ```
+    #[inline]
+    fn from(segments: [u16; 8]) -> Ipv6Addr {
+        let [a, b, c, d, e, f, g, h] = segments;
+        Ipv6Addr::new(a, b, c, d, e, f, g, h)
+    }
+}
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u8; 16]> for IpAddr {
+    /// Creates an `IpAddr::V6` from a sixteen element byte array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv6Addr};
+    ///
+    /// let addr = IpAddr::from([
+    ///     25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
+    ///     17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
+    /// ]);
+    /// assert_eq!(
+    ///     IpAddr::V6(Ipv6Addr::new(
+    ///         0x1918, 0x1716,
+    ///         0x1514, 0x1312,
+    ///         0x1110, 0x0f0e,
+    ///         0x0d0c, 0x0b0a
+    ///     )),
+    ///     addr
+    /// );
+    /// ```
+    #[inline]
+    fn from(octets: [u8; 16]) -> IpAddr {
+        IpAddr::V6(Ipv6Addr::from(octets))
+    }
+}
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u16; 8]> for IpAddr {
+    /// Creates an `IpAddr::V6` from an eight element 16-bit array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv6Addr};
+    ///
+    /// let addr = IpAddr::from([
+    ///     525u16, 524u16, 523u16, 522u16,
+    ///     521u16, 520u16, 519u16, 518u16,
+    /// ]);
+    /// assert_eq!(
+    ///     IpAddr::V6(Ipv6Addr::new(
+    ///         0x20d, 0x20c,
+    ///         0x20b, 0x20a,
+    ///         0x209, 0x208,
+    ///         0x207, 0x206
+    ///     )),
+    ///     addr
+    /// );
+    /// ```
+    #[inline]
+    fn from(segments: [u16; 8]) -> IpAddr {
+        IpAddr::V6(Ipv6Addr::from(segments))
+    }
+}
diff --git a/library/core/src/net/mod.rs b/library/core/src/net/mod.rs
new file mode 100644
index 00000000000..31f5f5d3c22
--- /dev/null
+++ b/library/core/src/net/mod.rs
@@ -0,0 +1,24 @@
+//! Networking primitives for IP communication.
+//!
+//! This module provides types for IP and socket addresses.
+//!
+//! # Organization
+//!
+//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and
+//!   [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses
+//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`]
+//!   and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses
+
+#![unstable(feature = "ip_in_core", issue = "108443")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::parser::AddrParseError;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6};
+
+mod display_buffer;
+mod ip_addr;
+mod parser;
+mod socket_addr;
diff --git a/library/std/src/net/parser.rs b/library/core/src/net/parser.rs
index a38031c48c8..a08d2792d04 100644
--- a/library/std/src/net/parser.rs
+++ b/library/core/src/net/parser.rs
@@ -3,9 +3,7 @@
 //! This module is "publicly exported" through the `FromStr` implementations
 //! below.
 
-#[cfg(test)]
-mod tests;
-
+use crate::convert::TryInto;
 use crate::error::Error;
 use crate::fmt;
 use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
new file mode 100644
index 00000000000..0d25ab1d5e1
--- /dev/null
+++ b/library/core/src/net/socket_addr.rs
@@ -0,0 +1,664 @@
+use crate::cmp::Ordering;
+use crate::fmt::{self, Write};
+use crate::hash;
+use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+
+use super::display_buffer::DisplayBuffer;
+
+/// An internet socket address, either IPv4 or IPv6.
+///
+/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well
+/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and
+/// [`SocketAddrV6`]'s respective documentation for more details.
+///
+/// The size of a `SocketAddr` instance may vary depending on the target operating
+/// system.
+///
+/// [IP address]: IpAddr
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+///
+/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+///
+/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
+/// assert_eq!(socket.port(), 8080);
+/// assert_eq!(socket.is_ipv4(), true);
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum SocketAddr {
+    /// An IPv4 socket address.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4),
+    /// An IPv6 socket address.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6),
+}
+
+/// An IPv4 socket address.
+///
+/// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port number, as
+/// stated in [IETF RFC 793].
+///
+/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
+///
+/// The size of a `SocketAddrV4` struct may vary depending on the target operating
+/// system. Do not assume that this type has the same memory layout as the underlying
+/// system representation.
+///
+/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
+/// [`IPv4` address]: Ipv4Addr
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{Ipv4Addr, SocketAddrV4};
+///
+/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+///
+/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
+/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
+/// assert_eq!(socket.port(), 8080);
+/// ```
+#[derive(Copy, Clone, Eq, PartialEq)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SocketAddrV4 {
+    ip: Ipv4Addr,
+    port: u16,
+}
+
+/// An IPv6 socket address.
+///
+/// IPv6 socket addresses consist of an [`IPv6` address], a 16-bit port number, as well
+/// as fields containing the traffic class, the flow label, and a scope identifier
+/// (see [IETF RFC 2553, Section 3.3] for more details).
+///
+/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
+///
+/// The size of a `SocketAddrV6` struct may vary depending on the target operating
+/// system. Do not assume that this type has the same memory layout as the underlying
+/// system representation.
+///
+/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+/// [`IPv6` address]: Ipv6Addr
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{Ipv6Addr, SocketAddrV6};
+///
+/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+///
+/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket));
+/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
+/// assert_eq!(socket.port(), 8080);
+/// ```
+#[derive(Copy, Clone, Eq, PartialEq)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SocketAddrV6 {
+    ip: Ipv6Addr,
+    port: u16,
+    flowinfo: u32,
+    scope_id: u32,
+}
+
+impl SocketAddr {
+    /// Creates a new socket address from an [IP address] and a port number.
+    ///
+    /// [IP address]: IpAddr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+    /// assert_eq!(socket.port(), 8080);
+    /// ```
+    #[stable(feature = "ip_addr", since = "1.7.0")]
+    #[must_use]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
+        match ip {
+            IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
+            IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)),
+        }
+    }
+
+    /// Returns the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+    /// ```
+    #[must_use]
+    #[stable(feature = "ip_addr", since = "1.7.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn ip(&self) -> IpAddr {
+        match *self {
+            SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
+            SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()),
+        }
+    }
+
+    /// Changes the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
+    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_ip(&mut self, new_ip: IpAddr) {
+        // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
+        match (self, new_ip) {
+            (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip),
+            (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip),
+            (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()),
+        }
+    }
+
+    /// Returns the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// assert_eq!(socket.port(), 8080);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn port(&self) -> u16 {
+        match *self {
+            SocketAddr::V4(ref a) => a.port(),
+            SocketAddr::V6(ref a) => a.port(),
+        }
+    }
+
+    /// Changes the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// socket.set_port(1025);
+    /// assert_eq!(socket.port(), 1025);
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_port(&mut self, new_port: u16) {
+        match *self {
+            SocketAddr::V4(ref mut a) => a.set_port(new_port),
+            SocketAddr::V6(ref mut a) => a.set_port(new_port),
+        }
+    }
+
+    /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
+    /// [`IPv4` address], and [`false`] otherwise.
+    ///
+    /// [IP address]: IpAddr
+    /// [`IPv4` address]: IpAddr::V4
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// assert_eq!(socket.is_ipv4(), true);
+    /// assert_eq!(socket.is_ipv6(), false);
+    /// ```
+    #[must_use]
+    #[stable(feature = "sockaddr_checker", since = "1.16.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn is_ipv4(&self) -> bool {
+        matches!(*self, SocketAddr::V4(_))
+    }
+
+    /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
+    /// [`IPv6` address], and [`false`] otherwise.
+    ///
+    /// [IP address]: IpAddr
+    /// [`IPv6` address]: IpAddr::V6
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv6Addr, SocketAddr};
+    ///
+    /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080);
+    /// assert_eq!(socket.is_ipv4(), false);
+    /// assert_eq!(socket.is_ipv6(), true);
+    /// ```
+    #[must_use]
+    #[stable(feature = "sockaddr_checker", since = "1.16.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn is_ipv6(&self) -> bool {
+        matches!(*self, SocketAddr::V6(_))
+    }
+}
+
+impl SocketAddrV4 {
+    /// Creates a new socket address from an [`IPv4` address] and a port number.
+    ///
+    /// [`IPv4` address]: Ipv4Addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
+        SocketAddrV4 { ip, port }
+    }
+
+    /// Returns the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn ip(&self) -> &Ipv4Addr {
+        &self.ip
+    }
+
+    /// Changes the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
+    /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
+        self.ip = new_ip;
+    }
+
+    /// Returns the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// assert_eq!(socket.port(), 8080);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn port(&self) -> u16 {
+        self.port
+    }
+
+    /// Changes the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// socket.set_port(4242);
+    /// assert_eq!(socket.port(), 4242);
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_port(&mut self, new_port: u16) {
+        self.port = new_port;
+    }
+}
+
+impl SocketAddrV6 {
+    /// Creates a new socket address from an [`IPv6` address], a 16-bit port number,
+    /// and the `flowinfo` and `scope_id` fields.
+    ///
+    /// For more information on the meaning and layout of the `flowinfo` and `scope_id`
+    /// parameters, see [IETF RFC 2553, Section 3.3].
+    ///
+    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+    /// [`IPv6` address]: Ipv6Addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
+        SocketAddrV6 { ip, port, flowinfo, scope_id }
+    }
+
+    /// Returns the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn ip(&self) -> &Ipv6Addr {
+        &self.ip
+    }
+
+    /// Changes the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
+    /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
+        self.ip = new_ip;
+    }
+
+    /// Returns the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// assert_eq!(socket.port(), 8080);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn port(&self) -> u16 {
+        self.port
+    }
+
+    /// Changes the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// socket.set_port(4242);
+    /// assert_eq!(socket.port(), 4242);
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_port(&mut self, new_port: u16) {
+        self.port = new_port;
+    }
+
+    /// Returns the flow information associated with this address.
+    ///
+    /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`,
+    /// as specified in [IETF RFC 2553, Section 3.3].
+    /// It combines information about the flow label and the traffic class as specified
+    /// in [IETF RFC 2460], respectively [Section 6] and [Section 7].
+    ///
+    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+    /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460
+    /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6
+    /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
+    /// assert_eq!(socket.flowinfo(), 10);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn flowinfo(&self) -> u32 {
+        self.flowinfo
+    }
+
+    /// Changes the flow information associated with this socket address.
+    ///
+    /// See [`SocketAddrV6::flowinfo`]'s documentation for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
+    /// socket.set_flowinfo(56);
+    /// assert_eq!(socket.flowinfo(), 56);
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
+        self.flowinfo = new_flowinfo;
+    }
+
+    /// Returns the scope ID associated with this address.
+    ///
+    /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`,
+    /// as specified in [IETF RFC 2553, Section 3.3].
+    ///
+    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
+    /// assert_eq!(socket.scope_id(), 78);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn scope_id(&self) -> u32 {
+        self.scope_id
+    }
+
+    /// Changes the scope ID associated with this socket address.
+    ///
+    /// See [`SocketAddrV6::scope_id`]'s documentation for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
+    /// socket.set_scope_id(42);
+    /// assert_eq!(socket.scope_id(), 42);
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_scope_id(&mut self, new_scope_id: u32) {
+        self.scope_id = new_scope_id;
+    }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<SocketAddrV4> for SocketAddr {
+    /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
+    fn from(sock4: SocketAddrV4) -> SocketAddr {
+        SocketAddr::V4(sock4)
+    }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<SocketAddrV6> for SocketAddr {
+    /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
+    fn from(sock6: SocketAddrV6) -> SocketAddr {
+        SocketAddr::V6(sock6)
+    }
+}
+
+#[stable(feature = "addr_from_into_ip", since = "1.17.0")]
+impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr {
+    /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`].
+    ///
+    /// This conversion creates a [`SocketAddr::V4`] for an [`IpAddr::V4`]
+    /// and creates a [`SocketAddr::V6`] for an [`IpAddr::V6`].
+    ///
+    /// `u16` is treated as port of the newly created [`SocketAddr`].
+    fn from(pieces: (I, u16)) -> SocketAddr {
+        SocketAddr::new(pieces.0.into(), pieces.1)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            SocketAddr::V4(ref a) => a.fmt(f),
+            SocketAddr::V6(ref a) => a.fmt(f),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddrV4 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // If there are no alignment requirements, write the socket address directly to `f`.
+        // Otherwise, write it to a local buffer and then use `f.pad`.
+        if f.precision().is_none() && f.width().is_none() {
+            write!(f, "{}:{}", self.ip(), self.port())
+        } else {
+            const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65536";
+
+            let mut buf = DisplayBuffer::<{ LONGEST_IPV4_SOCKET_ADDR.len() }>::new();
+            // Buffer is long enough for the longest possible IPv4 socket address, so this should never fail.
+            write!(buf, "{}:{}", self.ip(), self.port()).unwrap();
+
+            f.pad(buf.as_str())
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddrV4 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddrV6 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // If there are no alignment requirements, write the socket address directly to `f`.
+        // Otherwise, write it to a local buffer and then use `f.pad`.
+        if f.precision().is_none() && f.width().is_none() {
+            match self.scope_id() {
+                0 => write!(f, "[{}]:{}", self.ip(), self.port()),
+                scope_id => write!(f, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
+            }
+        } else {
+            const LONGEST_IPV6_SOCKET_ADDR: &str =
+                "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967296]:65536";
+
+            let mut buf = DisplayBuffer::<{ LONGEST_IPV6_SOCKET_ADDR.len() }>::new();
+            match self.scope_id() {
+                0 => write!(buf, "[{}]:{}", self.ip(), self.port()),
+                scope_id => write!(buf, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
+            }
+            // Buffer is long enough for the longest possible IPv6 socket address, so this should never fail.
+            .unwrap();
+
+            f.pad(buf.as_str())
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddrV6 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl PartialOrd for SocketAddrV4 {
+    fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl PartialOrd for SocketAddrV6 {
+    fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl Ord for SocketAddrV4 {
+    fn cmp(&self, other: &SocketAddrV4) -> Ordering {
+        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl Ord for SocketAddrV6 {
+    fn cmp(&self, other: &SocketAddrV6) -> Ordering {
+        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for SocketAddrV4 {
+    fn hash<H: hash::Hasher>(&self, s: &mut H) {
+        (self.port, self.ip).hash(s)
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for SocketAddrV6 {
+    fn hash<H: hash::Hasher>(&self, s: &mut H) {
+        (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s)
+    }
+}
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 572191d0f9b..aec15212d7f 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -3,21 +3,26 @@ macro_rules! int_impl {
         Self = $SelfT:ty,
         ActualT = $ActualT:ident,
         UnsignedT = $UnsignedT:ty,
-        BITS = $BITS:expr,
-        BITS_MINUS_ONE = $BITS_MINUS_ONE:expr,
-        Min = $Min:expr,
-        Max = $Max:expr,
-        rot = $rot:expr,
-        rot_op = $rot_op:expr,
-        rot_result = $rot_result:expr,
-        swap_op = $swap_op:expr,
-        swapped = $swapped:expr,
-        reversed = $reversed:expr,
-        le_bytes = $le_bytes:expr,
-        be_bytes = $be_bytes:expr,
+
+        // There are all for use *only* in doc comments.
+        // As such, they're all passed as literals -- passing them as a string
+        // literal is fine if they need to be multiple code tokens.
+        // In non-comments, use the associated constants rather than these.
+        BITS = $BITS:literal,
+        BITS_MINUS_ONE = $BITS_MINUS_ONE:literal,
+        Min = $Min:literal,
+        Max = $Max:literal,
+        rot = $rot:literal,
+        rot_op = $rot_op:literal,
+        rot_result = $rot_result:literal,
+        swap_op = $swap_op:literal,
+        swapped = $swapped:literal,
+        reversed = $reversed:literal,
+        le_bytes = $le_bytes:literal,
+        be_bytes = $be_bytes:literal,
         to_xe_bytes_doc = $to_xe_bytes_doc:expr,
         from_xe_bytes_doc = $from_xe_bytes_doc:expr,
-        bound_condition = $bound_condition:expr,
+        bound_condition = $bound_condition:literal,
     ) => {
         /// The smallest value that can be represented by this integer type
         #[doc = concat!("(&minus;2<sup>", $BITS_MINUS_ONE, "</sup>", $bound_condition, ").")]
@@ -30,7 +35,7 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");")]
         /// ```
         #[stable(feature = "assoc_int_consts", since = "1.43.0")]
-        pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self;
+        pub const MIN: Self = !Self::MAX;
 
         /// The largest value that can be represented by this integer type
         #[doc = concat!("(2<sup>", $BITS_MINUS_ONE, "</sup> &minus; 1", $bound_condition, ").")]
@@ -43,7 +48,7 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");")]
         /// ```
         #[stable(feature = "assoc_int_consts", since = "1.43.0")]
-        pub const MAX: Self = !Self::MIN;
+        pub const MAX: Self = (<$UnsignedT>::MAX >> 1) as Self;
 
         /// The size of this integer type in bits.
         ///
@@ -53,7 +58,7 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")]
         /// ```
         #[stable(feature = "int_bits_const", since = "1.53.0")]
-        pub const BITS: u32 = $BITS;
+        pub const BITS: u32 = <$UnsignedT>::BITS;
 
         /// Converts a string slice in a given base to an integer.
         ///
@@ -1380,7 +1385,7 @@ macro_rules! int_impl {
             // SAFETY: the masking by the bitsize of the type ensures that we do not shift
             // out of bounds
             unsafe {
-                self.unchecked_shl(rhs & ($BITS - 1))
+                self.unchecked_shl(rhs & (Self::BITS - 1))
             }
         }
 
@@ -1410,7 +1415,7 @@ macro_rules! int_impl {
             // SAFETY: the masking by the bitsize of the type ensures that we do not shift
             // out of bounds
             unsafe {
-                self.unchecked_shr(rhs & ($BITS - 1))
+                self.unchecked_shr(rhs & (Self::BITS - 1))
             }
         }
 
@@ -1916,7 +1921,7 @@ macro_rules! int_impl {
                       without modifying the original"]
         #[inline]
         pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
-            (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
+            (self.wrapping_shl(rhs), rhs >= Self::BITS)
         }
 
         /// Shifts self right by `rhs` bits.
@@ -1939,7 +1944,7 @@ macro_rules! int_impl {
                       without modifying the original"]
         #[inline]
         pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
-            (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
+            (self.wrapping_shr(rhs), rhs >= Self::BITS)
         }
 
         /// Computes the absolute value of `self`.
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index c4fe8e966fd..932038a0b01 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -4,19 +4,24 @@ macro_rules! uint_impl {
         ActualT = $ActualT:ident,
         SignedT = $SignedT:ident,
         NonZeroT = $NonZeroT:ident,
-        BITS = $BITS:expr,
-        MAX = $MaxV:expr,
-        rot = $rot:expr,
-        rot_op = $rot_op:expr,
-        rot_result = $rot_result:expr,
-        swap_op = $swap_op:expr,
-        swapped = $swapped:expr,
-        reversed = $reversed:expr,
-        le_bytes = $le_bytes:expr,
-        be_bytes = $be_bytes:expr,
+
+        // There are all for use *only* in doc comments.
+        // As such, they're all passed as literals -- passing them as a string
+        // literal is fine if they need to be multiple code tokens.
+        // In non-comments, use the associated constants rather than these.
+        BITS = $BITS:literal,
+        MAX = $MaxV:literal,
+        rot = $rot:literal,
+        rot_op = $rot_op:literal,
+        rot_result = $rot_result:literal,
+        swap_op = $swap_op:literal,
+        swapped = $swapped:literal,
+        reversed = $reversed:literal,
+        le_bytes = $le_bytes:literal,
+        be_bytes = $be_bytes:literal,
         to_xe_bytes_doc = $to_xe_bytes_doc:expr,
         from_xe_bytes_doc = $from_xe_bytes_doc:expr,
-        bound_condition = $bound_condition:expr,
+        bound_condition = $bound_condition:literal,
     ) => {
         /// The smallest value that can be represented by this integer type.
         ///
@@ -51,7 +56,7 @@ macro_rules! uint_impl {
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")]
         /// ```
         #[stable(feature = "int_bits_const", since = "1.53.0")]
-        pub const BITS: u32 = $BITS;
+        pub const BITS: u32 = Self::MAX.count_ones();
 
         /// Converts a string slice in a given base to an integer.
         ///
@@ -1403,7 +1408,7 @@ macro_rules! uint_impl {
             // SAFETY: the masking by the bitsize of the type ensures that we do not shift
             // out of bounds
             unsafe {
-                self.unchecked_shl(rhs & ($BITS - 1))
+                self.unchecked_shl(rhs & (Self::BITS - 1))
             }
         }
 
@@ -1436,7 +1441,7 @@ macro_rules! uint_impl {
             // SAFETY: the masking by the bitsize of the type ensures that we do not shift
             // out of bounds
             unsafe {
-                self.unchecked_shr(rhs & ($BITS - 1))
+                self.unchecked_shr(rhs & (Self::BITS - 1))
             }
         }
 
@@ -1860,7 +1865,7 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline(always)]
         pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
-            (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
+            (self.wrapping_shl(rhs), rhs >= Self::BITS)
         }
 
         /// Shifts self right by `rhs` bits.
@@ -1885,7 +1890,7 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline(always)]
         pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
-            (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
+            (self.wrapping_shr(rhs), rhs >= Self::BITS)
         }
 
         /// Raises self to the power of `exp`, using exponentiation by squaring.
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 4ca4eb86bde..7b8062c431e 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -673,19 +673,23 @@ where
 fn break_patterns<T>(v: &mut [T]) {
     let len = v.len();
     if len >= 8 {
-        // Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia.
-        let mut random = len as u32;
-        let mut gen_u32 = || {
-            random ^= random << 13;
-            random ^= random >> 17;
-            random ^= random << 5;
-            random
-        };
+        let mut seed = len;
         let mut gen_usize = || {
+            // Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia.
             if usize::BITS <= 32 {
-                gen_u32() as usize
+                let mut r = seed as u32;
+                r ^= r << 13;
+                r ^= r >> 17;
+                r ^= r << 5;
+                seed = r as usize;
+                seed
             } else {
-                (((gen_u32() as u64) << 32) | (gen_u32() as u64)) as usize
+                let mut r = seed as u64;
+                r ^= r << 13;
+                r ^= r >> 7;
+                r ^= r << 17;
+                seed = r as usize;
+                seed
             }
         };
 
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 42a26ae1675..3947a64e5c6 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -66,6 +66,7 @@
 #![feature(try_trait_v2)]
 #![feature(slice_internals)]
 #![feature(slice_partition_dedup)]
+#![feature(ip)]
 #![feature(iter_advance_by)]
 #![feature(iter_array_chunks)]
 #![feature(iter_collect_into)]
@@ -77,6 +78,9 @@
 #![feature(iter_repeat_n)]
 #![feature(iterator_try_collect)]
 #![feature(iterator_try_reduce)]
+#![feature(const_ip)]
+#![feature(const_ipv4)]
+#![feature(const_ipv6)]
 #![feature(const_mut_refs)]
 #![feature(const_pin)]
 #![feature(const_waker)]
@@ -135,6 +139,7 @@ mod lazy;
 mod macros;
 mod manually_drop;
 mod mem;
+mod net;
 mod nonzero;
 mod num;
 mod ops;
diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs
new file mode 100644
index 00000000000..5a6ac08c088
--- /dev/null
+++ b/library/core/tests/net/ip_addr.rs
@@ -0,0 +1,1035 @@
+use super::{sa4, sa6};
+use core::net::{
+    IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope, SocketAddr, SocketAddrV4, SocketAddrV6,
+};
+use core::str::FromStr;
+
+#[test]
+fn test_from_str_ipv4() {
+    assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
+    assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
+    assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
+
+    // out of range
+    let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
+    assert_eq!(None, none);
+    // too short
+    let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
+    assert_eq!(None, none);
+    // too long
+    let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
+    assert_eq!(None, none);
+    // no number between dots
+    let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
+    assert_eq!(None, none);
+    // octal
+    let none: Option<Ipv4Addr> = "255.0.0.01".parse().ok();
+    assert_eq!(None, none);
+    // octal zero
+    let none: Option<Ipv4Addr> = "255.0.0.00".parse().ok();
+    assert_eq!(None, none);
+    let none: Option<Ipv4Addr> = "255.0.00.0".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn test_from_str_ipv6() {
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
+
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
+
+    assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse());
+
+    // too long group
+    let none: Option<Ipv6Addr> = "::00000".parse().ok();
+    assert_eq!(None, none);
+    // too short
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
+    assert_eq!(None, none);
+    // too long
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
+    assert_eq!(None, none);
+    // triple colon
+    let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
+    assert_eq!(None, none);
+    // two double colons
+    let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
+    assert_eq!(None, none);
+    // `::` indicating zero groups of zeros
+    let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn test_from_str_ipv4_in_ipv6() {
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse());
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse());
+    assert_eq!(
+        Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
+        "64:ff9b::192.0.2.33".parse()
+    );
+    assert_eq!(
+        Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
+        "2001:db8:122:c000:2:2100:192.0.2.33".parse()
+    );
+
+    // colon after v4
+    let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
+    assert_eq!(None, none);
+    // not enough groups
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:127.0.0.1".parse().ok();
+    assert_eq!(None, none);
+    // too many groups
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:127.0.0.1".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn test_from_str_socket_addr() {
+    assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
+    assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
+    assert_eq!(
+        Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
+        "[2a02:6b8:0:1::1]:53".parse()
+    );
+    assert_eq!(
+        Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)),
+        "[2a02:6b8:0:1::1]:53".parse()
+    );
+    assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse());
+    assert_eq!(
+        Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)),
+        "[::127.0.0.1]:22".parse()
+    );
+
+    // without port
+    let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
+    assert_eq!(None, none);
+    // without port
+    let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
+    assert_eq!(None, none);
+    // wrong brackets around v4
+    let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
+    assert_eq!(None, none);
+    // port out of range
+    let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn ipv4_addr_to_string() {
+    assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1");
+    // Short address
+    assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1");
+    // Long address
+    assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127");
+
+    // Test padding
+    assert_eq!(format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1         ");
+    assert_eq!(format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), "         1.1.1.1");
+}
+
+#[test]
+fn ipv6_addr_to_string() {
+    // ipv4-mapped address
+    let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
+    assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
+
+    // ipv4-compatible address
+    let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
+    assert_eq!(a1.to_string(), "::192.0.2.128");
+
+    // v6 address with no zero segments
+    assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f");
+
+    // longest possible IPv6 length
+    assert_eq!(
+        Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(),
+        "1111:2222:3333:4444:5555:6666:7777:8888"
+    );
+    // padding
+    assert_eq!(format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8     ");
+    assert_eq!(format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "     1:2:3:4:5:6:7:8");
+
+    // reduce a single run of zeros
+    assert_eq!(
+        "ae::ffff:102:304",
+        Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()
+    );
+
+    // don't reduce just a single zero segment
+    assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
+
+    // 'any' address
+    assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+    // loopback address
+    assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
+
+    // ends in zeros
+    assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+    // two runs of zeros, second one is longer
+    assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
+
+    // two runs of zeros, equal length
+    assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
+
+    // don't prefix `0x` to each segment in `dbg!`.
+    assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8)));
+}
+
+#[test]
+fn ipv4_to_ipv6() {
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
+        Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()
+    );
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
+        Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()
+    );
+}
+
+#[test]
+fn ipv6_to_ipv4_mapped() {
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(),
+        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
+    );
+    assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None);
+}
+
+#[test]
+fn ipv6_to_ipv4() {
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
+        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
+    );
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
+        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
+    );
+    assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None);
+}
+
+#[test]
+fn ip_properties() {
+    macro_rules! ip {
+        ($s:expr) => {
+            IpAddr::from_str($s).unwrap()
+        };
+    }
+
+    macro_rules! check {
+        ($s:expr) => {
+            check!($s, 0);
+        };
+
+        ($s:expr, $mask:expr) => {{
+            let unspec: u8 = 1 << 0;
+            let loopback: u8 = 1 << 1;
+            let global: u8 = 1 << 2;
+            let multicast: u8 = 1 << 3;
+            let doc: u8 = 1 << 4;
+            let benchmarking: u8 = 1 << 5;
+
+            if ($mask & unspec) == unspec {
+                assert!(ip!($s).is_unspecified());
+            } else {
+                assert!(!ip!($s).is_unspecified());
+            }
+
+            if ($mask & loopback) == loopback {
+                assert!(ip!($s).is_loopback());
+            } else {
+                assert!(!ip!($s).is_loopback());
+            }
+
+            if ($mask & global) == global {
+                assert!(ip!($s).is_global());
+            } else {
+                assert!(!ip!($s).is_global());
+            }
+
+            if ($mask & multicast) == multicast {
+                assert!(ip!($s).is_multicast());
+            } else {
+                assert!(!ip!($s).is_multicast());
+            }
+
+            if ($mask & doc) == doc {
+                assert!(ip!($s).is_documentation());
+            } else {
+                assert!(!ip!($s).is_documentation());
+            }
+
+            if ($mask & benchmarking) == benchmarking {
+                assert!(ip!($s).is_benchmarking());
+            } else {
+                assert!(!ip!($s).is_benchmarking());
+            }
+        }};
+    }
+
+    let unspec: u8 = 1 << 0;
+    let loopback: u8 = 1 << 1;
+    let global: u8 = 1 << 2;
+    let multicast: u8 = 1 << 3;
+    let doc: u8 = 1 << 4;
+    let benchmarking: u8 = 1 << 5;
+
+    check!("0.0.0.0", unspec);
+    check!("0.0.0.1");
+    check!("0.1.0.0");
+    check!("10.9.8.7");
+    check!("127.1.2.3", loopback);
+    check!("172.31.254.253");
+    check!("169.254.253.242");
+    check!("192.0.2.183", doc);
+    check!("192.1.2.183", global);
+    check!("192.168.254.253");
+    check!("198.51.100.0", doc);
+    check!("203.0.113.0", doc);
+    check!("203.2.113.0", global);
+    check!("224.0.0.0", global | multicast);
+    check!("239.255.255.255", global | multicast);
+    check!("255.255.255.255");
+    // make sure benchmarking addresses are not global
+    check!("198.18.0.0", benchmarking);
+    check!("198.18.54.2", benchmarking);
+    check!("198.19.255.255", benchmarking);
+    // make sure addresses reserved for protocol assignment are not global
+    check!("192.0.0.0");
+    check!("192.0.0.255");
+    check!("192.0.0.100");
+    // make sure reserved addresses are not global
+    check!("240.0.0.0");
+    check!("251.54.1.76");
+    check!("254.255.255.255");
+    // make sure shared addresses are not global
+    check!("100.64.0.0");
+    check!("100.127.255.255");
+    check!("100.100.100.0");
+
+    check!("::", unspec);
+    check!("::1", loopback);
+    check!("::0.0.0.2", global);
+    check!("1::", global);
+    check!("fc00::");
+    check!("fdff:ffff::");
+    check!("fe80:ffff::");
+    check!("febf:ffff::");
+    check!("fec0::", global);
+    check!("ff01::", global | multicast);
+    check!("ff02::", global | multicast);
+    check!("ff03::", global | multicast);
+    check!("ff04::", global | multicast);
+    check!("ff05::", global | multicast);
+    check!("ff08::", global | multicast);
+    check!("ff0e::", global | multicast);
+    check!("2001:db8:85a3::8a2e:370:7334", doc);
+    check!("2001:2::ac32:23ff:21", benchmarking);
+    check!("102:304:506:708:90a:b0c:d0e:f10", global);
+}
+
+#[test]
+fn ipv4_properties() {
+    macro_rules! ip {
+        ($s:expr) => {
+            Ipv4Addr::from_str($s).unwrap()
+        };
+    }
+
+    macro_rules! check {
+        ($s:expr) => {
+            check!($s, 0);
+        };
+
+        ($s:expr, $mask:expr) => {{
+            let unspec: u16 = 1 << 0;
+            let loopback: u16 = 1 << 1;
+            let private: u16 = 1 << 2;
+            let link_local: u16 = 1 << 3;
+            let global: u16 = 1 << 4;
+            let multicast: u16 = 1 << 5;
+            let broadcast: u16 = 1 << 6;
+            let documentation: u16 = 1 << 7;
+            let benchmarking: u16 = 1 << 8;
+            let reserved: u16 = 1 << 10;
+            let shared: u16 = 1 << 11;
+
+            if ($mask & unspec) == unspec {
+                assert!(ip!($s).is_unspecified());
+            } else {
+                assert!(!ip!($s).is_unspecified());
+            }
+
+            if ($mask & loopback) == loopback {
+                assert!(ip!($s).is_loopback());
+            } else {
+                assert!(!ip!($s).is_loopback());
+            }
+
+            if ($mask & private) == private {
+                assert!(ip!($s).is_private());
+            } else {
+                assert!(!ip!($s).is_private());
+            }
+
+            if ($mask & link_local) == link_local {
+                assert!(ip!($s).is_link_local());
+            } else {
+                assert!(!ip!($s).is_link_local());
+            }
+
+            if ($mask & global) == global {
+                assert!(ip!($s).is_global());
+            } else {
+                assert!(!ip!($s).is_global());
+            }
+
+            if ($mask & multicast) == multicast {
+                assert!(ip!($s).is_multicast());
+            } else {
+                assert!(!ip!($s).is_multicast());
+            }
+
+            if ($mask & broadcast) == broadcast {
+                assert!(ip!($s).is_broadcast());
+            } else {
+                assert!(!ip!($s).is_broadcast());
+            }
+
+            if ($mask & documentation) == documentation {
+                assert!(ip!($s).is_documentation());
+            } else {
+                assert!(!ip!($s).is_documentation());
+            }
+
+            if ($mask & benchmarking) == benchmarking {
+                assert!(ip!($s).is_benchmarking());
+            } else {
+                assert!(!ip!($s).is_benchmarking());
+            }
+
+            if ($mask & reserved) == reserved {
+                assert!(ip!($s).is_reserved());
+            } else {
+                assert!(!ip!($s).is_reserved());
+            }
+
+            if ($mask & shared) == shared {
+                assert!(ip!($s).is_shared());
+            } else {
+                assert!(!ip!($s).is_shared());
+            }
+        }};
+    }
+
+    let unspec: u16 = 1 << 0;
+    let loopback: u16 = 1 << 1;
+    let private: u16 = 1 << 2;
+    let link_local: u16 = 1 << 3;
+    let global: u16 = 1 << 4;
+    let multicast: u16 = 1 << 5;
+    let broadcast: u16 = 1 << 6;
+    let documentation: u16 = 1 << 7;
+    let benchmarking: u16 = 1 << 8;
+    let reserved: u16 = 1 << 10;
+    let shared: u16 = 1 << 11;
+
+    check!("0.0.0.0", unspec);
+    check!("0.0.0.1");
+    check!("0.1.0.0");
+    check!("10.9.8.7", private);
+    check!("127.1.2.3", loopback);
+    check!("172.31.254.253", private);
+    check!("169.254.253.242", link_local);
+    check!("192.0.2.183", documentation);
+    check!("192.1.2.183", global);
+    check!("192.168.254.253", private);
+    check!("198.51.100.0", documentation);
+    check!("203.0.113.0", documentation);
+    check!("203.2.113.0", global);
+    check!("224.0.0.0", global | multicast);
+    check!("239.255.255.255", global | multicast);
+    check!("255.255.255.255", broadcast);
+    check!("198.18.0.0", benchmarking);
+    check!("198.18.54.2", benchmarking);
+    check!("198.19.255.255", benchmarking);
+    check!("192.0.0.0");
+    check!("192.0.0.255");
+    check!("192.0.0.100");
+    check!("240.0.0.0", reserved);
+    check!("251.54.1.76", reserved);
+    check!("254.255.255.255", reserved);
+    check!("100.64.0.0", shared);
+    check!("100.127.255.255", shared);
+    check!("100.100.100.0", shared);
+}
+
+#[test]
+fn ipv6_properties() {
+    macro_rules! ip {
+        ($s:expr) => {
+            Ipv6Addr::from_str($s).unwrap()
+        };
+    }
+
+    macro_rules! check {
+        ($s:expr, &[$($octet:expr),*], $mask:expr) => {
+            assert_eq!($s, ip!($s).to_string());
+            let octets = &[$($octet),*];
+            assert_eq!(&ip!($s).octets(), octets);
+            assert_eq!(Ipv6Addr::from(*octets), ip!($s));
+
+            let unspecified: u32 = 1 << 0;
+            let loopback: u32 = 1 << 1;
+            let unique_local: u32 = 1 << 2;
+            let global: u32 = 1 << 3;
+            let unicast_link_local: u32 = 1 << 4;
+            let unicast_global: u32 = 1 << 7;
+            let documentation: u32 = 1 << 8;
+            let benchmarking: u32 = 1 << 16;
+            let multicast_interface_local: u32 = 1 << 9;
+            let multicast_link_local: u32 = 1 << 10;
+            let multicast_realm_local: u32 = 1 << 11;
+            let multicast_admin_local: u32 = 1 << 12;
+            let multicast_site_local: u32 = 1 << 13;
+            let multicast_organization_local: u32 = 1 << 14;
+            let multicast_global: u32 = 1 << 15;
+            let multicast: u32 = multicast_interface_local
+                | multicast_admin_local
+                | multicast_global
+                | multicast_link_local
+                | multicast_realm_local
+                | multicast_site_local
+                | multicast_organization_local;
+
+            if ($mask & unspecified) == unspecified {
+                assert!(ip!($s).is_unspecified());
+            } else {
+                assert!(!ip!($s).is_unspecified());
+            }
+            if ($mask & loopback) == loopback {
+                assert!(ip!($s).is_loopback());
+            } else {
+                assert!(!ip!($s).is_loopback());
+            }
+            if ($mask & unique_local) == unique_local {
+                assert!(ip!($s).is_unique_local());
+            } else {
+                assert!(!ip!($s).is_unique_local());
+            }
+            if ($mask & global) == global {
+                assert!(ip!($s).is_global());
+            } else {
+                assert!(!ip!($s).is_global());
+            }
+            if ($mask & unicast_link_local) == unicast_link_local {
+                assert!(ip!($s).is_unicast_link_local());
+            } else {
+                assert!(!ip!($s).is_unicast_link_local());
+            }
+            if ($mask & unicast_global) == unicast_global {
+                assert!(ip!($s).is_unicast_global());
+            } else {
+                assert!(!ip!($s).is_unicast_global());
+            }
+            if ($mask & documentation) == documentation {
+                assert!(ip!($s).is_documentation());
+            } else {
+                assert!(!ip!($s).is_documentation());
+            }
+            if ($mask & benchmarking) == benchmarking {
+                assert!(ip!($s).is_benchmarking());
+            } else {
+                assert!(!ip!($s).is_benchmarking());
+            }
+            if ($mask & multicast) != 0 {
+                assert!(ip!($s).multicast_scope().is_some());
+                assert!(ip!($s).is_multicast());
+            } else {
+                assert!(ip!($s).multicast_scope().is_none());
+                assert!(!ip!($s).is_multicast());
+            }
+            if ($mask & multicast_interface_local) == multicast_interface_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::InterfaceLocal);
+            }
+            if ($mask & multicast_link_local) == multicast_link_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::LinkLocal);
+            }
+            if ($mask & multicast_realm_local) == multicast_realm_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::RealmLocal);
+            }
+            if ($mask & multicast_admin_local) == multicast_admin_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::AdminLocal);
+            }
+            if ($mask & multicast_site_local) == multicast_site_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::SiteLocal);
+            }
+            if ($mask & multicast_organization_local) == multicast_organization_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::OrganizationLocal);
+            }
+            if ($mask & multicast_global) == multicast_global {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::Global);
+            }
+        }
+    }
+
+    let unspecified: u32 = 1 << 0;
+    let loopback: u32 = 1 << 1;
+    let unique_local: u32 = 1 << 2;
+    let global: u32 = 1 << 3;
+    let unicast_link_local: u32 = 1 << 4;
+    let unicast_global: u32 = 1 << 7;
+    let documentation: u32 = 1 << 8;
+    let benchmarking: u32 = 1 << 16;
+    let multicast_interface_local: u32 = 1 << 9;
+    let multicast_link_local: u32 = 1 << 10;
+    let multicast_realm_local: u32 = 1 << 11;
+    let multicast_admin_local: u32 = 1 << 12;
+    let multicast_site_local: u32 = 1 << 13;
+    let multicast_organization_local: u32 = 1 << 14;
+    let multicast_global: u32 = 1 << 15;
+
+    check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified);
+
+    check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback);
+
+    check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global);
+
+    check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
+
+    check!(
+        "::ffff:127.0.0.1",
+        &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1],
+        unicast_global
+    );
+
+    check!(
+        "64:ff9b:1::",
+        &[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_global
+    );
+
+    check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+
+    check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+
+    check!(
+        "2001:1::1",
+        &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:1::2",
+        &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:3::",
+        &[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:4:112::",
+        &[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:20::",
+        &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+
+    check!(
+        "2001:200::",
+        &[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
+
+    check!(
+        "fdff:ffff::",
+        &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unique_local
+    );
+
+    check!(
+        "fe80:ffff::",
+        &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_link_local
+    );
+
+    check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
+
+    check!(
+        "febf:ffff::",
+        &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_link_local
+    );
+
+    check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
+
+    check!(
+        "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+        &[
+            0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff
+        ],
+        unicast_link_local
+    );
+
+    check!(
+        "fe80::ffff:ffff:ffff:ffff",
+        &[
+            0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff
+        ],
+        unicast_link_local
+    );
+
+    check!(
+        "fe80:0:0:1::",
+        &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_link_local
+    );
+
+    check!(
+        "fec0::",
+        &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_global | global
+    );
+
+    check!(
+        "ff01::",
+        &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_interface_local | global
+    );
+
+    check!(
+        "ff02::",
+        &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_link_local | global
+    );
+
+    check!(
+        "ff03::",
+        &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_realm_local | global
+    );
+
+    check!(
+        "ff04::",
+        &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_admin_local | global
+    );
+
+    check!(
+        "ff05::",
+        &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_site_local | global
+    );
+
+    check!(
+        "ff08::",
+        &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_organization_local | global
+    );
+
+    check!(
+        "ff0e::",
+        &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_global | global
+    );
+
+    check!(
+        "2001:db8:85a3::8a2e:370:7334",
+        &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
+        documentation
+    );
+
+    check!(
+        "2001:2::ac32:23ff:21",
+        &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21],
+        benchmarking
+    );
+
+    check!(
+        "102:304:506:708:90a:b0c:d0e:f10",
+        &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
+        global | unicast_global
+    );
+}
+
+#[test]
+fn test_ipv4_to_int() {
+    let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
+    assert_eq!(u32::from(a), 0x11223344);
+}
+
+#[test]
+fn test_int_to_ipv4() {
+    let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
+    assert_eq!(Ipv4Addr::from(0x11223344), a);
+}
+
+#[test]
+fn test_ipv6_to_int() {
+    let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
+    assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128);
+}
+
+#[test]
+fn test_int_to_ipv6() {
+    let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
+    assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
+}
+
+#[test]
+fn ipv4_from_constructors() {
+    assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1));
+    assert!(Ipv4Addr::LOCALHOST.is_loopback());
+    assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0));
+    assert!(Ipv4Addr::UNSPECIFIED.is_unspecified());
+    assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255));
+    assert!(Ipv4Addr::BROADCAST.is_broadcast());
+}
+
+#[test]
+fn ipv6_from_constructors() {
+    assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+    assert!(Ipv6Addr::LOCALHOST.is_loopback());
+    assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+    assert!(Ipv6Addr::UNSPECIFIED.is_unspecified());
+}
+
+#[test]
+fn ipv4_from_octets() {
+    assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
+}
+
+#[test]
+fn ipv6_from_segments() {
+    let from_u16s =
+        Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
+    let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff);
+    assert_eq!(new, from_u16s);
+}
+
+#[test]
+fn ipv6_from_octets() {
+    let from_u16s =
+        Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
+    let from_u8s = Ipv6Addr::from([
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
+        0xff,
+    ]);
+    assert_eq!(from_u16s, from_u8s);
+}
+
+#[test]
+fn cmp() {
+    let v41 = Ipv4Addr::new(100, 64, 3, 3);
+    let v42 = Ipv4Addr::new(192, 0, 2, 2);
+    let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap();
+    let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap();
+    assert!(v41 < v42);
+    assert!(v61 < v62);
+
+    assert_eq!(v41, IpAddr::V4(v41));
+    assert_eq!(v61, IpAddr::V6(v61));
+    assert!(v41 != IpAddr::V4(v42));
+    assert!(v61 != IpAddr::V6(v62));
+
+    assert!(v41 < IpAddr::V4(v42));
+    assert!(v61 < IpAddr::V6(v62));
+    assert!(IpAddr::V4(v41) < v42);
+    assert!(IpAddr::V6(v61) < v62);
+
+    assert!(v41 < IpAddr::V6(v61));
+    assert!(IpAddr::V4(v41) < v61);
+}
+
+#[test]
+fn is_v4() {
+    let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3));
+    assert!(ip.is_ipv4());
+    assert!(!ip.is_ipv6());
+}
+
+#[test]
+fn is_v6() {
+    let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678));
+    assert!(!ip.is_ipv4());
+    assert!(ip.is_ipv6());
+}
+
+#[test]
+fn ipv4_const() {
+    // test that the methods of `Ipv4Addr` are usable in a const context
+
+    const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
+    assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST);
+
+    const OCTETS: [u8; 4] = IP_ADDRESS.octets();
+    assert_eq!(OCTETS, [127, 0, 0, 1]);
+
+    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
+    assert!(!IS_UNSPECIFIED);
+
+    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
+    assert!(IS_LOOPBACK);
+
+    const IS_PRIVATE: bool = IP_ADDRESS.is_private();
+    assert!(!IS_PRIVATE);
+
+    const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local();
+    assert!(!IS_LINK_LOCAL);
+
+    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
+    assert!(!IS_GLOBAL);
+
+    const IS_SHARED: bool = IP_ADDRESS.is_shared();
+    assert!(!IS_SHARED);
+
+    const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
+    assert!(!IS_BENCHMARKING);
+
+    const IS_RESERVED: bool = IP_ADDRESS.is_reserved();
+    assert!(!IS_RESERVED);
+
+    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
+    assert!(!IS_MULTICAST);
+
+    const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast();
+    assert!(!IS_BROADCAST);
+
+    const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
+    assert!(!IS_DOCUMENTATION);
+
+    const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible();
+    assert_eq!(
+        IP_V6_COMPATIBLE,
+        Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1])
+    );
+
+    const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped();
+    assert_eq!(
+        IP_V6_MAPPED,
+        Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1])
+    );
+}
+
+#[test]
+fn ipv6_const() {
+    // test that the methods of `Ipv6Addr` are usable in a const context
+
+    const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST);
+
+    const SEGMENTS: [u16; 8] = IP_ADDRESS.segments();
+    assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]);
+
+    const OCTETS: [u8; 16] = IP_ADDRESS.octets();
+    assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
+
+    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
+    assert!(!IS_UNSPECIFIED);
+
+    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
+    assert!(IS_LOOPBACK);
+
+    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
+    assert!(!IS_GLOBAL);
+
+    const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
+    assert!(!IS_UNIQUE_LOCAL);
+
+    const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
+    assert!(!IS_UNICAST_LINK_LOCAL);
+
+    const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
+    assert!(!IS_DOCUMENTATION);
+
+    const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
+    assert!(!IS_BENCHMARKING);
+
+    const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global();
+    assert!(!IS_UNICAST_GLOBAL);
+
+    const MULTICAST_SCOPE: Option<Ipv6MulticastScope> = IP_ADDRESS.multicast_scope();
+    assert_eq!(MULTICAST_SCOPE, None);
+
+    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
+    assert!(!IS_MULTICAST);
+
+    const IP_V4: Option<Ipv4Addr> = IP_ADDRESS.to_ipv4();
+    assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1));
+}
+
+#[test]
+fn ip_const() {
+    // test that the methods of `IpAddr` are usable in a const context
+
+    const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
+
+    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
+    assert!(!IS_UNSPECIFIED);
+
+    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
+    assert!(IS_LOOPBACK);
+
+    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
+    assert!(!IS_GLOBAL);
+
+    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
+    assert!(!IS_MULTICAST);
+
+    const IS_IP_V4: bool = IP_ADDRESS.is_ipv4();
+    assert!(IS_IP_V4);
+
+    const IS_IP_V6: bool = IP_ADDRESS.is_ipv6();
+    assert!(!IS_IP_V6);
+}
+
+#[test]
+fn structural_match() {
+    // test that all IP types can be structurally matched upon
+
+    const IPV4: Ipv4Addr = Ipv4Addr::LOCALHOST;
+    match IPV4 {
+        Ipv4Addr::LOCALHOST => {}
+        _ => unreachable!(),
+    }
+
+    const IPV6: Ipv6Addr = Ipv6Addr::LOCALHOST;
+    match IPV6 {
+        Ipv6Addr::LOCALHOST => {}
+        _ => unreachable!(),
+    }
+
+    const IP: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
+    match IP {
+        IpAddr::V4(Ipv4Addr::LOCALHOST) => {}
+        _ => unreachable!(),
+    }
+}
diff --git a/library/core/tests/net/mod.rs b/library/core/tests/net/mod.rs
new file mode 100644
index 00000000000..8f17bbe5548
--- /dev/null
+++ b/library/core/tests/net/mod.rs
@@ -0,0 +1,13 @@
+use core::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+
+mod ip_addr;
+mod parser;
+mod socket_addr;
+
+pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr {
+    SocketAddr::V4(SocketAddrV4::new(a, p))
+}
+
+pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr {
+    SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0))
+}
diff --git a/library/std/src/net/parser/tests.rs b/library/core/tests/net/parser.rs
index 6d2d48ecad0..36b87d7c1f5 100644
--- a/library/std/src/net/parser/tests.rs
+++ b/library/core/tests/net/parser.rs
@@ -1,6 +1,6 @@
 // FIXME: These tests are all excellent candidates for AFL fuzz testing
-use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
-use crate::str::FromStr;
+use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+use core::str::FromStr;
 
 const PORT: u16 = 8080;
 const SCOPE_ID: u32 = 1337;
diff --git a/library/core/tests/net/socket_addr.rs b/library/core/tests/net/socket_addr.rs
new file mode 100644
index 00000000000..68c7cd94d32
--- /dev/null
+++ b/library/core/tests/net/socket_addr.rs
@@ -0,0 +1,233 @@
+use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+
+#[test]
+fn ipv4_socket_addr_to_string() {
+    // Shortest possible IPv4 length.
+    assert_eq!(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0).to_string(), "0.0.0.0:0");
+
+    // Longest possible IPv4 length.
+    assert_eq!(
+        SocketAddrV4::new(Ipv4Addr::new(255, 255, 255, 255), u16::MAX).to_string(),
+        "255.255.255.255:65535"
+    );
+
+    // Test padding.
+    assert_eq!(
+        &format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
+        "1.1.1.1:53      "
+    );
+    assert_eq!(
+        &format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
+        "      1.1.1.1:53"
+    );
+}
+
+#[test]
+fn ipv6_socket_addr_to_string() {
+    // IPv4-mapped address.
+    assert_eq!(
+        SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280), 8080, 0, 0)
+            .to_string(),
+        "[::ffff:192.0.2.128]:8080"
+    );
+
+    // IPv4-compatible address.
+    assert_eq!(
+        SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(),
+        "[::192.0.2.128]:8080"
+    );
+
+    // IPv6 address with no zero segments.
+    assert_eq!(
+        SocketAddrV6::new(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15), 80, 0, 0).to_string(),
+        "[8:9:a:b:c:d:e:f]:80"
+    );
+
+    // Shortest possible IPv6 length.
+    assert_eq!(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0).to_string(), "[::]:0");
+
+    // Longest possible IPv6 length.
+    assert_eq!(
+        SocketAddrV6::new(
+            Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888),
+            u16::MAX,
+            u32::MAX,
+            u32::MAX,
+        )
+        .to_string(),
+        "[1111:2222:3333:4444:5555:6666:7777:8888%4294967295]:65535"
+    );
+
+    // Test padding.
+    assert_eq!(
+        &format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
+        "[1:2:3:4:5:6:7:8]:9   "
+    );
+    assert_eq!(
+        &format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
+        "   [1:2:3:4:5:6:7:8]:9"
+    );
+}
+
+#[test]
+fn set_ip() {
+    fn ip4(low: u8) -> Ipv4Addr {
+        Ipv4Addr::new(77, 88, 21, low)
+    }
+    fn ip6(low: u16) -> Ipv6Addr {
+        Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low)
+    }
+
+    let mut v4 = SocketAddrV4::new(ip4(11), 80);
+    assert_eq!(v4.ip(), &ip4(11));
+    v4.set_ip(ip4(12));
+    assert_eq!(v4.ip(), &ip4(12));
+
+    let mut addr = SocketAddr::V4(v4);
+    assert_eq!(addr.ip(), IpAddr::V4(ip4(12)));
+    addr.set_ip(IpAddr::V4(ip4(13)));
+    assert_eq!(addr.ip(), IpAddr::V4(ip4(13)));
+    addr.set_ip(IpAddr::V6(ip6(14)));
+    assert_eq!(addr.ip(), IpAddr::V6(ip6(14)));
+
+    let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0);
+    assert_eq!(v6.ip(), &ip6(1));
+    v6.set_ip(ip6(2));
+    assert_eq!(v6.ip(), &ip6(2));
+
+    let mut addr = SocketAddr::V6(v6);
+    assert_eq!(addr.ip(), IpAddr::V6(ip6(2)));
+    addr.set_ip(IpAddr::V6(ip6(3)));
+    assert_eq!(addr.ip(), IpAddr::V6(ip6(3)));
+    addr.set_ip(IpAddr::V4(ip4(4)));
+    assert_eq!(addr.ip(), IpAddr::V4(ip4(4)));
+}
+
+#[test]
+fn set_port() {
+    let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80);
+    assert_eq!(v4.port(), 80);
+    v4.set_port(443);
+    assert_eq!(v4.port(), 443);
+
+    let mut addr = SocketAddr::V4(v4);
+    assert_eq!(addr.port(), 443);
+    addr.set_port(8080);
+    assert_eq!(addr.port(), 8080);
+
+    let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0);
+    assert_eq!(v6.port(), 80);
+    v6.set_port(443);
+    assert_eq!(v6.port(), 443);
+
+    let mut addr = SocketAddr::V6(v6);
+    assert_eq!(addr.port(), 443);
+    addr.set_port(8080);
+    assert_eq!(addr.port(), 8080);
+}
+
+#[test]
+fn set_flowinfo() {
+    let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0);
+    assert_eq!(v6.flowinfo(), 10);
+    v6.set_flowinfo(20);
+    assert_eq!(v6.flowinfo(), 20);
+}
+
+#[test]
+fn set_scope_id() {
+    let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10);
+    assert_eq!(v6.scope_id(), 10);
+    v6.set_scope_id(20);
+    assert_eq!(v6.scope_id(), 20);
+}
+
+#[test]
+fn is_v4() {
+    let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80));
+    assert!(v4.is_ipv4());
+    assert!(!v4.is_ipv6());
+}
+
+#[test]
+fn is_v6() {
+    let v6 = SocketAddr::V6(SocketAddrV6::new(
+        Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1),
+        80,
+        10,
+        0,
+    ));
+    assert!(!v6.is_ipv4());
+    assert!(v6.is_ipv6());
+}
+
+#[test]
+fn socket_v4_to_str() {
+    let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080);
+
+    assert_eq!(format!("{socket}"), "192.168.0.1:8080");
+    assert_eq!(format!("{socket:<20}"), "192.168.0.1:8080    ");
+    assert_eq!(format!("{socket:>20}"), "    192.168.0.1:8080");
+    assert_eq!(format!("{socket:^20}"), "  192.168.0.1:8080  ");
+    assert_eq!(format!("{socket:.10}"), "192.168.0.");
+}
+
+#[test]
+fn socket_v6_to_str() {
+    let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0);
+
+    assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1]:53");
+    assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1]:53    ");
+    assert_eq!(format!("{socket:>24}"), "    [2a02:6b8:0:1::1]:53");
+    assert_eq!(format!("{socket:^24}"), "  [2a02:6b8:0:1::1]:53  ");
+    assert_eq!(format!("{socket:.15}"), "[2a02:6b8:0:1::");
+
+    socket.set_scope_id(5);
+
+    assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1%5]:53");
+    assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1%5]:53  ");
+    assert_eq!(format!("{socket:>24}"), "  [2a02:6b8:0:1::1%5]:53");
+    assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1%5]:53 ");
+    assert_eq!(format!("{socket:.18}"), "[2a02:6b8:0:1::1%5");
+}
+
+#[test]
+fn compare() {
+    let v4_1 = "224.120.45.1:23456".parse::<SocketAddrV4>().unwrap();
+    let v4_2 = "224.210.103.5:12345".parse::<SocketAddrV4>().unwrap();
+    let v4_3 = "224.210.103.5:23456".parse::<SocketAddrV4>().unwrap();
+    let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap();
+    let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap();
+    let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
+
+    // equality
+    assert_eq!(v4_1, v4_1);
+    assert_eq!(v6_1, v6_1);
+    assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1));
+    assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1));
+    assert!(v4_1 != v4_2);
+    assert!(v6_1 != v6_2);
+
+    // compare different addresses
+    assert!(v4_1 < v4_2);
+    assert!(v6_1 < v6_2);
+    assert!(v4_2 > v4_1);
+    assert!(v6_2 > v6_1);
+
+    // compare the same address with different ports
+    assert!(v4_2 < v4_3);
+    assert!(v6_2 < v6_3);
+    assert!(v4_3 > v4_2);
+    assert!(v6_3 > v6_2);
+
+    // compare different addresses with the same port
+    assert!(v4_1 < v4_3);
+    assert!(v6_1 < v6_3);
+    assert!(v4_3 > v4_1);
+    assert!(v6_3 > v6_1);
+
+    // compare with an inferred right-hand side
+    assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap());
+    assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap());
+    assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap());
+}
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 349cd91c89e..311b2e21c17 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -43,7 +43,7 @@ dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
 fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(target_os = "hermit")'.dependencies]
-hermit-abi = { version = "0.2.6", features = ['rustc-dep-of-std'] }
+hermit-abi = { version = "0.3.0", features = ['rustc-dep-of-std'] }
 
 [target.wasm32-wasi.dependencies]
 wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 839fdc96632..909d9bf4093 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1595,3 +1595,19 @@ fn test_read_dir_infinite_loop() {
     // Check for duplicate errors
     assert!(dir.filter(|e| e.is_err()).take(2).count() < 2);
 }
+
+#[test]
+fn rename_directory() {
+    let tmpdir = tmpdir();
+    let old_path = tmpdir.join("foo/bar/baz");
+    fs::create_dir_all(&old_path).unwrap();
+    let test_file = &old_path.join("temp.txt");
+
+    File::create(test_file).unwrap();
+
+    let new_path = tmpdir.join("quux/blat");
+    fs::create_dir_all(&new_path).unwrap();
+    fs::rename(&old_path, &new_path.join("newdir")).unwrap();
+    assert!(new_path.join("newdir").is_dir());
+    assert!(new_path.join("newdir/temp.txt").exists());
+}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 363a2667174..b62f3ad29d3 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -232,6 +232,7 @@
     all(target_vendor = "fortanix", target_env = "sgx"),
     feature(slice_index_methods, coerce_unsized, sgx_platform)
 )]
+#![cfg_attr(windows, feature(round_char_boundary))]
 //
 // Language features:
 #![feature(alloc_error_handler)]
@@ -287,6 +288,8 @@
 #![feature(float_next_up_down)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
+#![feature(ip)]
+#![feature(ip_in_core)]
 #![feature(is_some_and)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_write_slice)]
diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs
index 07f08c1b586..e167fbd1b9c 100644
--- a/library/std/src/net/ip_addr.rs
+++ b/library/std/src/net/ip_addr.rs
@@ -2,2101 +2,40 @@
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
 
-use crate::cmp::Ordering;
-use crate::fmt::{self, Write};
-use crate::mem::transmute;
 use crate::sys::net::netc as c;
 use crate::sys_common::{FromInner, IntoInner};
 
-use super::display_buffer::DisplayBuffer;
-
-/// An IP address, either IPv4 or IPv6.
-///
-/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their
-/// respective documentation for more details.
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-///
-/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
-/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-///
-/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4));
-/// assert_eq!("::1".parse(), Ok(localhost_v6));
-///
-/// assert_eq!(localhost_v4.is_ipv6(), false);
-/// assert_eq!(localhost_v4.is_ipv4(), true);
-/// ```
-#[cfg_attr(not(test), rustc_diagnostic_item = "IpAddr")]
 #[stable(feature = "ip_addr", since = "1.7.0")]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
-pub enum IpAddr {
-    /// An IPv4 address.
-    #[stable(feature = "ip_addr", since = "1.7.0")]
-    V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr),
-    /// An IPv6 address.
-    #[stable(feature = "ip_addr", since = "1.7.0")]
-    V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr),
-}
+pub use core::net::IpAddr;
 
-/// An IPv4 address.
-///
-/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791].
-/// They are usually represented as four octets.
-///
-/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
-///
-/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791
-///
-/// # Textual representation
-///
-/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal
-/// notation, divided by `.` (this is called "dot-decimal notation").
-/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which
-/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943].
-///
-/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1
-/// [`FromStr`]: crate::str::FromStr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::Ipv4Addr;
-///
-/// let localhost = Ipv4Addr::new(127, 0, 0, 1);
-/// assert_eq!("127.0.0.1".parse(), Ok(localhost));
-/// assert_eq!(localhost.is_loopback(), true);
-/// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal
-/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
-/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct Ipv4Addr {
-    octets: [u8; 4],
-}
+pub use core::net::{Ipv4Addr, Ipv6Addr};
 
-/// An IPv6 address.
-///
-/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
-/// They are usually represented as eight 16-bit segments.
-///
-/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-///
-/// # Embedding IPv4 Addresses
-///
-/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
-///
-/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined:
-/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated.
-///
-/// Both types of addresses are not assigned any special meaning by this implementation,
-/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`,
-/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is.
-/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address.
-///
-/// ### IPv4-Compatible IPv6 Addresses
-///
-/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated.
-/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows:
-///
-/// ```text
-/// |                80 bits               | 16 |      32 bits        |
-/// +--------------------------------------+--------------------------+
-/// |0000..............................0000|0000|    IPv4 address     |
-/// +--------------------------------------+----+---------------------+
-/// ```
-/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`.
-///
-/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`].
-/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address.
-///
-/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1
-///
-/// ### IPv4-Mapped IPv6 Addresses
-///
-/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2].
-/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows:
-///
-/// ```text
-/// |                80 bits               | 16 |      32 bits        |
-/// +--------------------------------------+--------------------------+
-/// |0000..............................0000|FFFF|    IPv4 address     |
-/// +--------------------------------------+----+---------------------+
-/// ```
-/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`.
-///
-/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`].
-/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address.
-/// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use
-/// [`Ipv6Addr::to_ipv4_mapped`] to avoid this.
-///
-/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2
-///
-/// # Textual representation
-///
-/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent
-/// an IPv6 address in text, but in general, each segments is written in hexadecimal
-/// notation, and segments are separated by `:`. For more information, see
-/// [IETF RFC 5952].
-///
-/// [`FromStr`]: crate::str::FromStr
-/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952
-///
-/// # Examples
-///
-/// ```
-/// use std::net::Ipv6Addr;
-///
-/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
-/// assert_eq!("::1".parse(), Ok(localhost));
-/// assert_eq!(localhost.is_loopback(), true);
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Ipv6Addr {
-    octets: [u8; 16],
-}
-
-/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2].
-///
-/// # Stability Guarantees
-///
-/// Not all possible values for a multicast scope have been assigned.
-/// Future RFCs may introduce new scopes, which will be added as variants to this enum;
-/// because of this the enum is marked as `#[non_exhaustive]`.
-///
-/// # Examples
-/// ```
-/// #![feature(ip)]
-///
-/// use std::net::Ipv6Addr;
-/// use std::net::Ipv6MulticastScope::*;
-///
-/// // An IPv6 multicast address with global scope (`ff0e::`).
-/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0);
-///
-/// // Will print "Global scope".
-/// match address.multicast_scope() {
-///     Some(InterfaceLocal) => println!("Interface-Local scope"),
-///     Some(LinkLocal) => println!("Link-Local scope"),
-///     Some(RealmLocal) => println!("Realm-Local scope"),
-///     Some(AdminLocal) => println!("Admin-Local scope"),
-///     Some(SiteLocal) => println!("Site-Local scope"),
-///     Some(OrganizationLocal) => println!("Organization-Local scope"),
-///     Some(Global) => println!("Global scope"),
-///     Some(_) => println!("Unknown scope"),
-///     None => println!("Not a multicast address!")
-/// }
-///
-/// ```
-///
-/// [IPv6 multicast address]: Ipv6Addr
-/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2
-#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
 #[unstable(feature = "ip", issue = "27709")]
-#[non_exhaustive]
-pub enum Ipv6MulticastScope {
-    /// Interface-Local scope.
-    InterfaceLocal,
-    /// Link-Local scope.
-    LinkLocal,
-    /// Realm-Local scope.
-    RealmLocal,
-    /// Admin-Local scope.
-    AdminLocal,
-    /// Site-Local scope.
-    SiteLocal,
-    /// Organization-Local scope.
-    OrganizationLocal,
-    /// Global scope.
-    Global,
-}
-
-impl IpAddr {
-    /// Returns [`true`] for the special 'unspecified' address.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_unspecified()`] and
-    /// [`Ipv6Addr::is_unspecified()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "ip_shared", since = "1.12.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unspecified(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_unspecified(),
-            IpAddr::V6(ip) => ip.is_unspecified(),
-        }
-    }
-
-    /// Returns [`true`] if this is a loopback address.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_loopback()`] and
-    /// [`Ipv6Addr::is_loopback()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "ip_shared", since = "1.12.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_loopback(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_loopback(),
-            IpAddr::V6(ip) => ip.is_loopback(),
-        }
-    }
-
-    /// Returns [`true`] if the address appears to be globally routable.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_global()`] and
-    /// [`Ipv6Addr::is_global()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_global(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_global(),
-            IpAddr::V6(ip) => ip.is_global(),
-        }
-    }
-
-    /// Returns [`true`] if this is a multicast address.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_multicast()`] and
-    /// [`Ipv6Addr::is_multicast()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "ip_shared", since = "1.12.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_multicast(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_multicast(),
-            IpAddr::V6(ip) => ip.is_multicast(),
-        }
-    }
-
-    /// Returns [`true`] if this address is in a range designated for documentation.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_documentation()`] and
-    /// [`Ipv6Addr::is_documentation()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true);
-    /// assert_eq!(
-    ///     IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(),
-    ///     true
-    /// );
-    /// ```
-    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_documentation(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_documentation(),
-            IpAddr::V6(ip) => ip.is_documentation(),
-        }
-    }
-
-    /// Returns [`true`] if this address is in a range designated for benchmarking.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and
-    /// [`Ipv6Addr::is_benchmarking()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true);
-    /// ```
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_benchmarking(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_benchmarking(),
-            IpAddr::V6(ip) => ip.is_benchmarking(),
-        }
-    }
-
-    /// Returns [`true`] if this address is an [`IPv4` address], and [`false`]
-    /// otherwise.
-    ///
-    /// [`IPv4` address]: IpAddr::V4
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "ipaddr_checker", since = "1.16.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_ipv4(&self) -> bool {
-        matches!(self, IpAddr::V4(_))
-    }
-
-    /// Returns [`true`] if this address is an [`IPv6` address], and [`false`]
-    /// otherwise.
-    ///
-    /// [`IPv6` address]: IpAddr::V6
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "ipaddr_checker", since = "1.16.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_ipv6(&self) -> bool {
-        matches!(self, IpAddr::V6(_))
-    }
-
-    /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it
-    /// return `self` as-is.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true);
-    /// ```
-    #[inline]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    pub const fn to_canonical(&self) -> IpAddr {
-        match self {
-            &v4 @ IpAddr::V4(_) => v4,
-            IpAddr::V6(v6) => v6.to_canonical(),
-        }
-    }
-}
-
-impl Ipv4Addr {
-    /// Creates a new IPv4 address from four eight-bit octets.
-    ///
-    /// The result will represent the IP address `a`.`b`.`c`.`d`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[inline]
-    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
-        Ipv4Addr { octets: [a, b, c, d] }
-    }
-
-    /// An IPv4 address with the address pointing to localhost: `127.0.0.1`
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::LOCALHOST;
-    /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
-    /// ```
-    #[stable(feature = "ip_constructors", since = "1.30.0")]
-    pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
-
-    /// An IPv4 address representing an unspecified address: `0.0.0.0`
-    ///
-    /// This corresponds to the constant `INADDR_ANY` in other languages.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::UNSPECIFIED;
-    /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
-    /// ```
-    #[doc(alias = "INADDR_ANY")]
-    #[stable(feature = "ip_constructors", since = "1.30.0")]
-    pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
-
-    /// An IPv4 address representing the broadcast address: `255.255.255.255`
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::BROADCAST;
-    /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255));
-    /// ```
-    #[stable(feature = "ip_constructors", since = "1.30.0")]
-    pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
-
-    /// Returns the four eight-bit integers that make up this address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
-    /// assert_eq!(addr.octets(), [127, 0, 0, 1]);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[inline]
-    pub const fn octets(&self) -> [u8; 4] {
-        self.octets
-    }
-
-    /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`).
-    ///
-    /// This property is defined in _UNIX Network Programming, Second Edition_,
-    /// W. Richard Stevens, p. 891; see also [ip7].
-    ///
-    /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true);
-    /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
-    #[stable(feature = "ip_shared", since = "1.12.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unspecified(&self) -> bool {
-        u32::from_be_bytes(self.octets) == 0
-    }
-
-    /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`).
-    ///
-    /// This property is defined by [IETF RFC 1122].
-    ///
-    /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true);
-    /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_loopback(&self) -> bool {
-        self.octets()[0] == 127
-    }
-
-    /// Returns [`true`] if this is a private address.
-    ///
-    /// The private address ranges are defined in [IETF RFC 1918] and include:
-    ///
-    ///  - `10.0.0.0/8`
-    ///  - `172.16.0.0/12`
-    ///  - `192.168.0.0/16`
-    ///
-    /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true);
-    /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true);
-    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true);
-    /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true);
-    /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false);
-    /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true);
-    /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_private(&self) -> bool {
-        match self.octets() {
-            [10, ..] => true,
-            [172, b, ..] if b >= 16 && b <= 31 => true,
-            [192, 168, ..] => true,
-            _ => false,
-        }
-    }
-
-    /// Returns [`true`] if the address is link-local (`169.254.0.0/16`).
-    ///
-    /// This property is defined by [IETF RFC 3927].
-    ///
-    /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true);
-    /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true);
-    /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_link_local(&self) -> bool {
-        matches!(self.octets(), [169, 254, ..])
-    }
-
-    /// Returns [`true`] if the address appears to be globally reachable
-    /// as specified by the [IANA IPv4 Special-Purpose Address Registry].
-    /// Whether or not an address is practically reachable will depend on your network configuration.
-    ///
-    /// Most IPv4 addresses are globally reachable;
-    /// unless they are specifically defined as *not* globally reachable.
-    ///
-    /// Non-exhaustive list of notable addresses that are not globally reachable:
-    ///
-    /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified))
-    /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private))
-    /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared))
-    /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback))
-    /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local))
-    /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation))
-    /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking))
-    /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved))
-    /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast))
-    ///
-    /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry].
-    ///
-    /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
-    /// [unspecified address]: Ipv4Addr::UNSPECIFIED
-    /// [broadcast address]: Ipv4Addr::BROADCAST
-
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv4Addr;
-    ///
-    /// // Most IPv4 addresses are globally reachable:
-    /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
-    ///
-    /// // However some addresses have been assigned a special meaning
-    /// // that makes them not globally reachable. Some examples are:
-    ///
-    /// // The unspecified address (`0.0.0.0`)
-    /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false);
-    ///
-    /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16)
-    /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
-    /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
-    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
-    ///
-    /// // Addresses in the shared address space (`100.64.0.0/10`)
-    /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
-    ///
-    /// // The loopback addresses (`127.0.0.0/8`)
-    /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false);
-    ///
-    /// // Link-local addresses (`169.254.0.0/16`)
-    /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false);
-    ///
-    /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`)
-    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false);
-    /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false);
-    /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false);
-    ///
-    /// // Addresses reserved for benchmarking (`198.18.0.0/15`)
-    /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
-    ///
-    /// // Reserved addresses (`240.0.0.0/4`)
-    /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
-    ///
-    /// // The broadcast address (`255.255.255.255`)
-    /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false);
-    ///
-    /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry.
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_global(&self) -> bool {
-        !(self.octets()[0] == 0 // "This network"
-            || self.is_private()
-            || self.is_shared()
-            || self.is_loopback()
-            || self.is_link_local()
-            // addresses reserved for future protocols (`192.0.0.0/24`)
-            ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
-            || self.is_documentation()
-            || self.is_benchmarking()
-            || self.is_reserved()
-            || self.is_broadcast())
-    }
-
-    /// Returns [`true`] if this address is part of the Shared Address Space defined in
-    /// [IETF RFC 6598] (`100.64.0.0/10`).
-    ///
-    /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true);
-    /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true);
-    /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_shared(&self) -> bool {
-        self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
-    }
-
-    /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for
-    /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0`
-    /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`.
-    ///
-    /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544
-    /// [errata 423]: https://www.rfc-editor.org/errata/eid423
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false);
-    /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true);
-    /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true);
-    /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_benchmarking(&self) -> bool {
-        self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
-    }
-
-    /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112]
-    /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the
-    /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since
-    /// it is obviously not reserved for future use.
-    ///
-    /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112
-    ///
-    /// # Warning
-    ///
-    /// As IANA assigns new addresses, this method will be
-    /// updated. This may result in non-reserved addresses being
-    /// treated as reserved in code that relies on an outdated version
-    /// of this method.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true);
-    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true);
-    ///
-    /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false);
-    /// // The broadcast address is not considered as reserved for future use by this implementation
-    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_reserved(&self) -> bool {
-        self.octets()[0] & 240 == 240 && !self.is_broadcast()
-    }
-
-    /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`).
-    ///
-    /// Multicast addresses have a most significant octet between `224` and `239`,
-    /// and is defined by [IETF RFC 5771].
-    ///
-    /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true);
-    /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true);
-    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_multicast(&self) -> bool {
-        self.octets()[0] >= 224 && self.octets()[0] <= 239
-    }
-
-    /// Returns [`true`] if this is a broadcast address (`255.255.255.255`).
-    ///
-    /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919].
-    ///
-    /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true);
-    /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_broadcast(&self) -> bool {
-        u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets())
-    }
-
-    /// Returns [`true`] if this address is in a range designated for documentation.
-    ///
-    /// This is defined in [IETF RFC 5737]:
-    ///
-    /// - `192.0.2.0/24` (TEST-NET-1)
-    /// - `198.51.100.0/24` (TEST-NET-2)
-    /// - `203.0.113.0/24` (TEST-NET-3)
-    ///
-    /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true);
-    /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true);
-    /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true);
-    /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_documentation(&self) -> bool {
-        matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _])
-    }
-
-    /// Converts this address to an [IPv4-compatible] [`IPv6` address].
-    ///
-    /// `a.b.c.d` becomes `::a.b.c.d`
-    ///
-    /// Note that IPv4-compatible addresses have been officially deprecated.
-    /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead.
-    ///
-    /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
-    /// [`IPv6` address]: Ipv6Addr
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(
-    ///     Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(),
-    ///     Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff)
-    /// );
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[inline]
-    pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
-        let [a, b, c, d] = self.octets();
-        Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] }
-    }
-
-    /// Converts this address to an [IPv4-mapped] [`IPv6` address].
-    ///
-    /// `a.b.c.d` becomes `::ffff:a.b.c.d`
-    ///
-    /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
-    /// [`IPv6` address]: Ipv6Addr
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(),
-    ///            Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff));
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[inline]
-    pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
-        let [a, b, c, d] = self.octets();
-        Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] }
-    }
-}
-
-#[stable(feature = "ip_addr", since = "1.7.0")]
-impl fmt::Display for IpAddr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            IpAddr::V4(ip) => ip.fmt(fmt),
-            IpAddr::V6(ip) => ip.fmt(fmt),
-        }
-    }
-}
-
-#[stable(feature = "ip_addr", since = "1.7.0")]
-impl fmt::Debug for IpAddr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<Ipv4Addr> for IpAddr {
-    /// Copies this address to a new `IpAddr::V4`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr};
-    ///
-    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
-    ///
-    /// assert_eq!(
-    ///     IpAddr::V4(addr),
-    ///     IpAddr::from(addr)
-    /// )
-    /// ```
-    #[inline]
-    fn from(ipv4: Ipv4Addr) -> IpAddr {
-        IpAddr::V4(ipv4)
-    }
-}
-
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<Ipv6Addr> for IpAddr {
-    /// Copies this address to a new `IpAddr::V6`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv6Addr};
-    ///
-    /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
-    ///
-    /// assert_eq!(
-    ///     IpAddr::V6(addr),
-    ///     IpAddr::from(addr)
-    /// );
-    /// ```
-    #[inline]
-    fn from(ipv6: Ipv6Addr) -> IpAddr {
-        IpAddr::V6(ipv6)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for Ipv4Addr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let octets = self.octets();
-
-        // If there are no alignment requirements, write the IP address directly to `f`.
-        // Otherwise, write it to a local buffer and then use `f.pad`.
-        if fmt.precision().is_none() && fmt.width().is_none() {
-            write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
-        } else {
-            const LONGEST_IPV4_ADDR: &str = "255.255.255.255";
-
-            let mut buf = DisplayBuffer::<{ LONGEST_IPV4_ADDR.len() }>::new();
-            // Buffer is long enough for the longest possible IPv4 address, so this should never fail.
-            write!(buf, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
-
-            fmt.pad(buf.as_str())
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Ipv4Addr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<Ipv4Addr> for IpAddr {
-    #[inline]
-    fn eq(&self, other: &Ipv4Addr) -> bool {
-        match self {
-            IpAddr::V4(v4) => v4 == other,
-            IpAddr::V6(_) => false,
-        }
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<IpAddr> for Ipv4Addr {
-    #[inline]
-    fn eq(&self, other: &IpAddr) -> bool {
-        match other {
-            IpAddr::V4(v4) => self == v4,
-            IpAddr::V6(_) => false,
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialOrd for Ipv4Addr {
-    #[inline]
-    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<Ipv4Addr> for IpAddr {
-    #[inline]
-    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
-        match self {
-            IpAddr::V4(v4) => v4.partial_cmp(other),
-            IpAddr::V6(_) => Some(Ordering::Greater),
-        }
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<IpAddr> for Ipv4Addr {
-    #[inline]
-    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
-        match other {
-            IpAddr::V4(v4) => self.partial_cmp(v4),
-            IpAddr::V6(_) => Some(Ordering::Less),
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Ord for Ipv4Addr {
-    #[inline]
-    fn cmp(&self, other: &Ipv4Addr) -> Ordering {
-        self.octets.cmp(&other.octets)
-    }
-}
+pub use core::net::Ipv6MulticastScope;
 
 impl IntoInner<c::in_addr> for Ipv4Addr {
     #[inline]
     fn into_inner(self) -> c::in_addr {
         // `s_addr` is stored as BE on all machines and the array is in BE order.
         // So the native endian conversion method is used so that it's never swapped.
-        c::in_addr { s_addr: u32::from_ne_bytes(self.octets) }
+        c::in_addr { s_addr: u32::from_ne_bytes(self.octets()) }
     }
 }
 impl FromInner<c::in_addr> for Ipv4Addr {
     fn from_inner(addr: c::in_addr) -> Ipv4Addr {
-        Ipv4Addr { octets: addr.s_addr.to_ne_bytes() }
-    }
-}
-
-#[stable(feature = "ip_u32", since = "1.1.0")]
-impl From<Ipv4Addr> for u32 {
-    /// Converts an `Ipv4Addr` into a host byte order `u32`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78);
-    /// assert_eq!(0x12345678, u32::from(addr));
-    /// ```
-    #[inline]
-    fn from(ip: Ipv4Addr) -> u32 {
-        u32::from_be_bytes(ip.octets)
-    }
-}
-
-#[stable(feature = "ip_u32", since = "1.1.0")]
-impl From<u32> for Ipv4Addr {
-    /// Converts a host byte order `u32` into an `Ipv4Addr`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::from(0x12345678);
-    /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr);
-    /// ```
-    #[inline]
-    fn from(ip: u32) -> Ipv4Addr {
-        Ipv4Addr { octets: ip.to_be_bytes() }
-    }
-}
-
-#[stable(feature = "from_slice_v4", since = "1.9.0")]
-impl From<[u8; 4]> for Ipv4Addr {
-    /// Creates an `Ipv4Addr` from a four element byte array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]);
-    /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
-    /// ```
-    #[inline]
-    fn from(octets: [u8; 4]) -> Ipv4Addr {
-        Ipv4Addr { octets }
-    }
-}
-
-#[stable(feature = "ip_from_slice", since = "1.17.0")]
-impl From<[u8; 4]> for IpAddr {
-    /// Creates an `IpAddr::V4` from a four element byte array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr};
-    ///
-    /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]);
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr);
-    /// ```
-    #[inline]
-    fn from(octets: [u8; 4]) -> IpAddr {
-        IpAddr::V4(Ipv4Addr::from(octets))
-    }
-}
-
-impl Ipv6Addr {
-    /// Creates a new IPv6 address from eight 16-bit segments.
-    ///
-    /// The result will represent the IP address `a:b:c:d:e:f:g:h`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[inline]
-    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
-        let addr16 = [
-            a.to_be(),
-            b.to_be(),
-            c.to_be(),
-            d.to_be(),
-            e.to_be(),
-            f.to_be(),
-            g.to_be(),
-            h.to_be(),
-        ];
-        Ipv6Addr {
-            // All elements in `addr16` are big endian.
-            // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
-            octets: unsafe { transmute::<_, [u8; 16]>(addr16) },
-        }
-    }
-
-    /// An IPv6 address representing localhost: `::1`.
-    ///
-    /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other
-    /// languages.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::LOCALHOST;
-    /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-    /// ```
-    #[doc(alias = "IN6ADDR_LOOPBACK_INIT")]
-    #[doc(alias = "in6addr_loopback")]
-    #[stable(feature = "ip_constructors", since = "1.30.0")]
-    pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
-
-    /// An IPv6 address representing the unspecified address: `::`
-    ///
-    /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::UNSPECIFIED;
-    /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
-    /// ```
-    #[doc(alias = "IN6ADDR_ANY_INIT")]
-    #[doc(alias = "in6addr_any")]
-    #[stable(feature = "ip_constructors", since = "1.30.0")]
-    pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
-
-    /// Returns the eight 16-bit segments that make up this address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(),
-    ///            [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[inline]
-    pub const fn segments(&self) -> [u16; 8] {
-        // All elements in `self.octets` must be big endian.
-        // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
-        let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) };
-        // We want native endian u16
-        [
-            u16::from_be(a),
-            u16::from_be(b),
-            u16::from_be(c),
-            u16::from_be(d),
-            u16::from_be(e),
-            u16::from_be(f),
-            u16::from_be(g),
-            u16::from_be(h),
-        ]
-    }
-
-    /// Returns [`true`] for the special 'unspecified' address (`::`).
-    ///
-    /// This property is defined in [IETF RFC 4291].
-    ///
-    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unspecified(&self) -> bool {
-        u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
-    }
-
-    /// Returns [`true`] if this is the [loopback address] (`::1`),
-    /// as defined in [IETF RFC 4291 section 2.5.3].
-    ///
-    /// Contrary to IPv4, in IPv6 there is only one loopback address.
-    ///
-    /// [loopback address]: Ipv6Addr::LOCALHOST
-    /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_loopback(&self) -> bool {
-        u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
-    }
-
-    /// Returns [`true`] if the address appears to be globally reachable
-    /// as specified by the [IANA IPv6 Special-Purpose Address Registry].
-    /// Whether or not an address is practically reachable will depend on your network configuration.
-    ///
-    /// Most IPv6 addresses are globally reachable;
-    /// unless they are specifically defined as *not* globally reachable.
-    ///
-    /// Non-exhaustive list of notable addresses that are not globally reachable:
-    /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified))
-    /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback))
-    /// - IPv4-mapped addresses
-    /// - Addresses reserved for benchmarking
-    /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation))
-    /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local))
-    /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local))
-    ///
-    /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry].
-    ///
-    /// Note that an address having global scope is not the same as being globally reachable,
-    /// and there is no direct relation between the two concepts: There exist addresses with global scope
-    /// that are not globally reachable (for example unique local addresses),
-    /// and addresses that are globally reachable without having global scope
-    /// (multicast addresses with non-global scope).
-    ///
-    /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
-    /// [unspecified address]: Ipv6Addr::UNSPECIFIED
-    /// [loopback address]: Ipv6Addr::LOCALHOST
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// // Most IPv6 addresses are globally reachable:
-    /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true);
-    ///
-    /// // However some addresses have been assigned a special meaning
-    /// // that makes them not globally reachable. Some examples are:
-    ///
-    /// // The unspecified address (`::`)
-    /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false);
-    ///
-    /// // The loopback address (`::1`)
-    /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false);
-    ///
-    /// // IPv4-mapped addresses (`::ffff:0:0/96`)
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false);
-    ///
-    /// // Addresses reserved for benchmarking (`2001:2::/48`)
-    /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
-    ///
-    /// // Addresses reserved for documentation (`2001:db8::/32`)
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
-    ///
-    /// // Unique local addresses (`fc00::/7`)
-    /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
-    ///
-    /// // Unicast addresses with link-local scope (`fe80::/10`)
-    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
-    ///
-    /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry.
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_global(&self) -> bool {
-        !(self.is_unspecified()
-            || self.is_loopback()
-            // IPv4-mapped Address (`::ffff:0:0/96`)
-            || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
-            // IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
-            || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
-            // Discard-Only Address Block (`100::/64`)
-            || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
-            // IETF Protocol Assignments (`2001::/23`)
-            || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
-                && !(
-                    // Port Control Protocol Anycast (`2001:1::1`)
-                    u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
-                    // Traversal Using Relays around NAT Anycast (`2001:1::2`)
-                    || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
-                    // AMT (`2001:3::/32`)
-                    || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
-                    // AS112-v6 (`2001:4:112::/48`)
-                    || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
-                    // ORCHIDv2 (`2001:20::/28`)
-                    || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
-                ))
-            || self.is_documentation()
-            || self.is_unique_local()
-            || self.is_unicast_link_local())
-    }
-
-    /// Returns [`true`] if this is a unique local address (`fc00::/7`).
-    ///
-    /// This property is defined in [IETF RFC 4193].
-    ///
-    /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false);
-    /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unique_local(&self) -> bool {
-        (self.segments()[0] & 0xfe00) == 0xfc00
-    }
-
-    /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291].
-    /// Any address that is not a [multicast address] (`ff00::/8`) is unicast.
-    ///
-    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-    /// [multicast address]: Ipv6Addr::is_multicast
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// // The unspecified and loopback addresses are unicast.
-    /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true);
-    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true);
-    ///
-    /// // Any address that is not a multicast address (`ff00::/8`) is unicast.
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true);
-    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unicast(&self) -> bool {
-        !self.is_multicast()
-    }
-
-    /// Returns `true` if the address is a unicast address with link-local scope,
-    /// as defined in [RFC 4291].
-    ///
-    /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
-    /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
-    /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
-    ///
-    /// ```text
-    /// | 10 bits  |         54 bits         |          64 bits           |
-    /// +----------+-------------------------+----------------------------+
-    /// |1111111010|           0             |       interface ID         |
-    /// +----------+-------------------------+----------------------------+
-    /// ```
-    /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
-    /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
-    /// and those addresses will have link-local scope.
-    ///
-    /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope",
-    /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
-    ///
-    /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
-    /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
-    /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
-    /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
-    /// [loopback address]: Ipv6Addr::LOCALHOST
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// // The loopback address (`::1`) does not actually have link-local scope.
-    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
-    ///
-    /// // Only addresses in `fe80::/10` have link-local scope.
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
-    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
-    ///
-    /// // Addresses outside the stricter `fe80::/64` also have link-local scope.
-    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
-    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unicast_link_local(&self) -> bool {
-        (self.segments()[0] & 0xffc0) == 0xfe80
-    }
-
-    /// Returns [`true`] if this is an address reserved for documentation
-    /// (`2001:db8::/32`).
-    ///
-    /// This property is defined in [IETF RFC 3849].
-    ///
-    /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false);
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_documentation(&self) -> bool {
-        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
-    }
-
-    /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`).
-    ///
-    /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`.
-    /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`.
-    ///
-    /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180
-    /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false);
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true);
-    /// ```
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_benchmarking(&self) -> bool {
-        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0)
-    }
-
-    /// Returns [`true`] if the address is a globally routable unicast address.
-    ///
-    /// The following return false:
-    ///
-    /// - the loopback address
-    /// - the link-local addresses
-    /// - unique local addresses
-    /// - the unspecified address
-    /// - the address range reserved for documentation
-    ///
-    /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7]
-    ///
-    /// ```no_rust
-    /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer
-    /// be supported in new implementations (i.e., new implementations must treat this prefix as
-    /// Global Unicast).
-    /// ```
-    ///
-    /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unicast_global(&self) -> bool {
-        self.is_unicast()
-            && !self.is_loopback()
-            && !self.is_unicast_link_local()
-            && !self.is_unique_local()
-            && !self.is_unspecified()
-            && !self.is_documentation()
-            && !self.is_benchmarking()
-    }
-
-    /// Returns the address's multicast scope if the address is multicast.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::{Ipv6Addr, Ipv6MulticastScope};
-    ///
-    /// assert_eq!(
-    ///     Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(),
-    ///     Some(Ipv6MulticastScope::Global)
-    /// );
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
-        if self.is_multicast() {
-            match self.segments()[0] & 0x000f {
-                1 => Some(Ipv6MulticastScope::InterfaceLocal),
-                2 => Some(Ipv6MulticastScope::LinkLocal),
-                3 => Some(Ipv6MulticastScope::RealmLocal),
-                4 => Some(Ipv6MulticastScope::AdminLocal),
-                5 => Some(Ipv6MulticastScope::SiteLocal),
-                8 => Some(Ipv6MulticastScope::OrganizationLocal),
-                14 => Some(Ipv6MulticastScope::Global),
-                _ => None,
-            }
-        } else {
-            None
-        }
-    }
-
-    /// Returns [`true`] if this is a multicast address (`ff00::/8`).
-    ///
-    /// This property is defined by [IETF RFC 4291].
-    ///
-    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_multicast(&self) -> bool {
-        (self.segments()[0] & 0xff00) == 0xff00
-    }
-
-    /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address,
-    /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
-    ///
-    /// `::ffff:a.b.c.d` becomes `a.b.c.d`.
-    /// All addresses *not* starting with `::ffff` will return `None`.
-    ///
-    /// [`IPv4` address]: Ipv4Addr
-    /// [IPv4-mapped]: Ipv6Addr
-    /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(),
-    ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[inline]
-    pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
-        match self.octets() {
-            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
-                Some(Ipv4Addr::new(a, b, c, d))
-            }
-            _ => None,
-        }
-    }
-
-    /// Converts this address to an [`IPv4` address] if it is either
-    /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1],
-    /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2],
-    /// otherwise returns [`None`].
-    ///
-    /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use
-    /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this.
-    ///
-    /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`.
-    /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`.
-    ///
-    /// [`IPv4` address]: Ipv4Addr
-    /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
-    /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
-    /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1
-    /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(),
-    ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(),
-    ///            Some(Ipv4Addr::new(0, 0, 0, 1)));
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[inline]
-    pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
-        if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
-            let [a, b] = ab.to_be_bytes();
-            let [c, d] = cd.to_be_bytes();
-            Some(Ipv4Addr::new(a, b, c, d))
-        } else {
-            None
-        }
-    }
-
-    /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it
-    /// returns self wrapped in an `IpAddr::V6`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[inline]
-    pub const fn to_canonical(&self) -> IpAddr {
-        if let Some(mapped) = self.to_ipv4_mapped() {
-            return IpAddr::V4(mapped);
-        }
-        IpAddr::V6(*self)
-    }
-
-    /// Returns the sixteen eight-bit integers the IPv6 address consists of.
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(),
-    ///            [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
-    #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
-    #[must_use]
-    #[inline]
-    pub const fn octets(&self) -> [u8; 16] {
-        self.octets
-    }
-}
-
-/// Write an Ipv6Addr, conforming to the canonical style described by
-/// [RFC 5952](https://tools.ietf.org/html/rfc5952).
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for Ipv6Addr {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // If there are no alignment requirements, write the IP address directly to `f`.
-        // Otherwise, write it to a local buffer and then use `f.pad`.
-        if f.precision().is_none() && f.width().is_none() {
-            let segments = self.segments();
-
-            // Special case for :: and ::1; otherwise they get written with the
-            // IPv4 formatter
-            if self.is_unspecified() {
-                f.write_str("::")
-            } else if self.is_loopback() {
-                f.write_str("::1")
-            } else if let Some(ipv4) = self.to_ipv4() {
-                match segments[5] {
-                    // IPv4 Compatible address
-                    0 => write!(f, "::{}", ipv4),
-                    // IPv4 Mapped address
-                    0xffff => write!(f, "::ffff:{}", ipv4),
-                    _ => unreachable!(),
-                }
-            } else {
-                #[derive(Copy, Clone, Default)]
-                struct Span {
-                    start: usize,
-                    len: usize,
-                }
-
-                // Find the inner 0 span
-                let zeroes = {
-                    let mut longest = Span::default();
-                    let mut current = Span::default();
-
-                    for (i, &segment) in segments.iter().enumerate() {
-                        if segment == 0 {
-                            if current.len == 0 {
-                                current.start = i;
-                            }
-
-                            current.len += 1;
-
-                            if current.len > longest.len {
-                                longest = current;
-                            }
-                        } else {
-                            current = Span::default();
-                        }
-                    }
-
-                    longest
-                };
-
-                /// Write a colon-separated part of the address
-                #[inline]
-                fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
-                    if let Some((first, tail)) = chunk.split_first() {
-                        write!(f, "{:x}", first)?;
-                        for segment in tail {
-                            f.write_char(':')?;
-                            write!(f, "{:x}", segment)?;
-                        }
-                    }
-                    Ok(())
-                }
-
-                if zeroes.len > 1 {
-                    fmt_subslice(f, &segments[..zeroes.start])?;
-                    f.write_str("::")?;
-                    fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
-                } else {
-                    fmt_subslice(f, &segments)
-                }
-            }
-        } else {
-            const LONGEST_IPV6_ADDR: &str = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
-
-            let mut buf = DisplayBuffer::<{ LONGEST_IPV6_ADDR.len() }>::new();
-            // Buffer is long enough for the longest possible IPv6 address, so this should never fail.
-            write!(buf, "{}", self).unwrap();
-
-            f.pad(buf.as_str())
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Ipv6Addr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<IpAddr> for Ipv6Addr {
-    #[inline]
-    fn eq(&self, other: &IpAddr) -> bool {
-        match other {
-            IpAddr::V4(_) => false,
-            IpAddr::V6(v6) => self == v6,
-        }
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<Ipv6Addr> for IpAddr {
-    #[inline]
-    fn eq(&self, other: &Ipv6Addr) -> bool {
-        match self {
-            IpAddr::V4(_) => false,
-            IpAddr::V6(v6) => v6 == other,
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialOrd for Ipv6Addr {
-    #[inline]
-    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<Ipv6Addr> for IpAddr {
-    #[inline]
-    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
-        match self {
-            IpAddr::V4(_) => Some(Ordering::Less),
-            IpAddr::V6(v6) => v6.partial_cmp(other),
-        }
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<IpAddr> for Ipv6Addr {
-    #[inline]
-    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
-        match other {
-            IpAddr::V4(_) => Some(Ordering::Greater),
-            IpAddr::V6(v6) => self.partial_cmp(v6),
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Ord for Ipv6Addr {
-    #[inline]
-    fn cmp(&self, other: &Ipv6Addr) -> Ordering {
-        self.segments().cmp(&other.segments())
+        Ipv4Addr::from(addr.s_addr.to_ne_bytes())
     }
 }
 
 impl IntoInner<c::in6_addr> for Ipv6Addr {
     fn into_inner(self) -> c::in6_addr {
-        c::in6_addr { s6_addr: self.octets }
+        c::in6_addr { s6_addr: self.octets() }
     }
 }
 impl FromInner<c::in6_addr> for Ipv6Addr {
     #[inline]
     fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
-        Ipv6Addr { octets: addr.s6_addr }
-    }
-}
-
-#[stable(feature = "i128", since = "1.26.0")]
-impl From<Ipv6Addr> for u128 {
-    /// Convert an `Ipv6Addr` into a host byte order `u128`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::new(
-    ///     0x1020, 0x3040, 0x5060, 0x7080,
-    ///     0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
-    /// );
-    /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
-    /// ```
-    #[inline]
-    fn from(ip: Ipv6Addr) -> u128 {
-        u128::from_be_bytes(ip.octets)
-    }
-}
-#[stable(feature = "i128", since = "1.26.0")]
-impl From<u128> for Ipv6Addr {
-    /// Convert a host byte order `u128` into an `Ipv6Addr`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128);
-    /// assert_eq!(
-    ///     Ipv6Addr::new(
-    ///         0x1020, 0x3040, 0x5060, 0x7080,
-    ///         0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
-    ///     ),
-    ///     addr);
-    /// ```
-    #[inline]
-    fn from(ip: u128) -> Ipv6Addr {
-        Ipv6Addr::from(ip.to_be_bytes())
-    }
-}
-
-#[stable(feature = "ipv6_from_octets", since = "1.9.0")]
-impl From<[u8; 16]> for Ipv6Addr {
-    /// Creates an `Ipv6Addr` from a sixteen element byte array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::from([
-    ///     25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
-    ///     17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
-    /// ]);
-    /// assert_eq!(
-    ///     Ipv6Addr::new(
-    ///         0x1918, 0x1716,
-    ///         0x1514, 0x1312,
-    ///         0x1110, 0x0f0e,
-    ///         0x0d0c, 0x0b0a
-    ///     ),
-    ///     addr
-    /// );
-    /// ```
-    #[inline]
-    fn from(octets: [u8; 16]) -> Ipv6Addr {
-        Ipv6Addr { octets }
-    }
-}
-
-#[stable(feature = "ipv6_from_segments", since = "1.16.0")]
-impl From<[u16; 8]> for Ipv6Addr {
-    /// Creates an `Ipv6Addr` from an eight element 16-bit array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::from([
-    ///     525u16, 524u16, 523u16, 522u16,
-    ///     521u16, 520u16, 519u16, 518u16,
-    /// ]);
-    /// assert_eq!(
-    ///     Ipv6Addr::new(
-    ///         0x20d, 0x20c,
-    ///         0x20b, 0x20a,
-    ///         0x209, 0x208,
-    ///         0x207, 0x206
-    ///     ),
-    ///     addr
-    /// );
-    /// ```
-    #[inline]
-    fn from(segments: [u16; 8]) -> Ipv6Addr {
-        let [a, b, c, d, e, f, g, h] = segments;
-        Ipv6Addr::new(a, b, c, d, e, f, g, h)
-    }
-}
-
-#[stable(feature = "ip_from_slice", since = "1.17.0")]
-impl From<[u8; 16]> for IpAddr {
-    /// Creates an `IpAddr::V6` from a sixteen element byte array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv6Addr};
-    ///
-    /// let addr = IpAddr::from([
-    ///     25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
-    ///     17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
-    /// ]);
-    /// assert_eq!(
-    ///     IpAddr::V6(Ipv6Addr::new(
-    ///         0x1918, 0x1716,
-    ///         0x1514, 0x1312,
-    ///         0x1110, 0x0f0e,
-    ///         0x0d0c, 0x0b0a
-    ///     )),
-    ///     addr
-    /// );
-    /// ```
-    #[inline]
-    fn from(octets: [u8; 16]) -> IpAddr {
-        IpAddr::V6(Ipv6Addr::from(octets))
-    }
-}
-
-#[stable(feature = "ip_from_slice", since = "1.17.0")]
-impl From<[u16; 8]> for IpAddr {
-    /// Creates an `IpAddr::V6` from an eight element 16-bit array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv6Addr};
-    ///
-    /// let addr = IpAddr::from([
-    ///     525u16, 524u16, 523u16, 522u16,
-    ///     521u16, 520u16, 519u16, 518u16,
-    /// ]);
-    /// assert_eq!(
-    ///     IpAddr::V6(Ipv6Addr::new(
-    ///         0x20d, 0x20c,
-    ///         0x20b, 0x20a,
-    ///         0x209, 0x208,
-    ///         0x207, 0x206
-    ///     )),
-    ///     addr
-    /// );
-    /// ```
-    #[inline]
-    fn from(segments: [u16; 8]) -> IpAddr {
-        IpAddr::V6(Ipv6Addr::from(segments))
+        Ipv6Addr::from(addr.s6_addr)
     }
 }
diff --git a/library/std/src/net/ip_addr/tests.rs b/library/std/src/net/ip_addr/tests.rs
index 0eb59d45de7..ab99c0c2fcc 100644
--- a/library/std/src/net/ip_addr/tests.rs
+++ b/library/std/src/net/ip_addr/tests.rs
@@ -1,1039 +1,8 @@
-use crate::net::test::{sa4, sa6, tsa};
-use crate::net::*;
-use crate::str::FromStr;
-
-#[test]
-fn test_from_str_ipv4() {
-    assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
-    assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
-    assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
-
-    // out of range
-    let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
-    assert_eq!(None, none);
-    // too short
-    let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
-    assert_eq!(None, none);
-    // too long
-    let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
-    assert_eq!(None, none);
-    // no number between dots
-    let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
-    assert_eq!(None, none);
-    // octal
-    let none: Option<Ipv4Addr> = "255.0.0.01".parse().ok();
-    assert_eq!(None, none);
-    // octal zero
-    let none: Option<Ipv4Addr> = "255.0.0.00".parse().ok();
-    assert_eq!(None, none);
-    let none: Option<Ipv4Addr> = "255.0.00.0".parse().ok();
-    assert_eq!(None, none);
-}
-
-#[test]
-fn test_from_str_ipv6() {
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
-
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
-
-    assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse());
-
-    // too long group
-    let none: Option<Ipv6Addr> = "::00000".parse().ok();
-    assert_eq!(None, none);
-    // too short
-    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
-    assert_eq!(None, none);
-    // too long
-    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
-    assert_eq!(None, none);
-    // triple colon
-    let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
-    assert_eq!(None, none);
-    // two double colons
-    let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
-    assert_eq!(None, none);
-    // `::` indicating zero groups of zeros
-    let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok();
-    assert_eq!(None, none);
-}
-
-#[test]
-fn test_from_str_ipv4_in_ipv6() {
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse());
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse());
-    assert_eq!(
-        Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
-        "64:ff9b::192.0.2.33".parse()
-    );
-    assert_eq!(
-        Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
-        "2001:db8:122:c000:2:2100:192.0.2.33".parse()
-    );
-
-    // colon after v4
-    let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
-    assert_eq!(None, none);
-    // not enough groups
-    let none: Option<Ipv6Addr> = "1:2:3:4:5:127.0.0.1".parse().ok();
-    assert_eq!(None, none);
-    // too many groups
-    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:127.0.0.1".parse().ok();
-    assert_eq!(None, none);
-}
-
-#[test]
-fn test_from_str_socket_addr() {
-    assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
-    assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
-    assert_eq!(
-        Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
-        "[2a02:6b8:0:1::1]:53".parse()
-    );
-    assert_eq!(
-        Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)),
-        "[2a02:6b8:0:1::1]:53".parse()
-    );
-    assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse());
-    assert_eq!(
-        Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)),
-        "[::127.0.0.1]:22".parse()
-    );
-
-    // without port
-    let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
-    assert_eq!(None, none);
-    // without port
-    let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
-    assert_eq!(None, none);
-    // wrong brackets around v4
-    let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
-    assert_eq!(None, none);
-    // port out of range
-    let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
-    assert_eq!(None, none);
-}
-
-#[test]
-fn ipv4_addr_to_string() {
-    assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1");
-    // Short address
-    assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1");
-    // Long address
-    assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127");
-
-    // Test padding
-    assert_eq!(format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1         ");
-    assert_eq!(format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), "         1.1.1.1");
-}
-
-#[test]
-fn ipv6_addr_to_string() {
-    // ipv4-mapped address
-    let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
-    assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
-
-    // ipv4-compatible address
-    let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
-    assert_eq!(a1.to_string(), "::192.0.2.128");
-
-    // v6 address with no zero segments
-    assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f");
-
-    // longest possible IPv6 length
-    assert_eq!(
-        Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(),
-        "1111:2222:3333:4444:5555:6666:7777:8888"
-    );
-    // padding
-    assert_eq!(format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8     ");
-    assert_eq!(format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "     1:2:3:4:5:6:7:8");
-
-    // reduce a single run of zeros
-    assert_eq!(
-        "ae::ffff:102:304",
-        Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()
-    );
-
-    // don't reduce just a single zero segment
-    assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
-
-    // 'any' address
-    assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
-
-    // loopback address
-    assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
-
-    // ends in zeros
-    assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
-
-    // two runs of zeros, second one is longer
-    assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
-
-    // two runs of zeros, equal length
-    assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
-
-    // don't prefix `0x` to each segment in `dbg!`.
-    assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8)));
-}
-
-#[test]
-fn ipv4_to_ipv6() {
-    assert_eq!(
-        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
-        Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()
-    );
-    assert_eq!(
-        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
-        Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()
-    );
-}
-
-#[test]
-fn ipv6_to_ipv4_mapped() {
-    assert_eq!(
-        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(),
-        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
-    );
-    assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None);
-}
-
-#[test]
-fn ipv6_to_ipv4() {
-    assert_eq!(
-        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
-        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
-    );
-    assert_eq!(
-        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
-        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
-    );
-    assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None);
-}
-
-#[test]
-fn ip_properties() {
-    macro_rules! ip {
-        ($s:expr) => {
-            IpAddr::from_str($s).unwrap()
-        };
-    }
-
-    macro_rules! check {
-        ($s:expr) => {
-            check!($s, 0);
-        };
-
-        ($s:expr, $mask:expr) => {{
-            let unspec: u8 = 1 << 0;
-            let loopback: u8 = 1 << 1;
-            let global: u8 = 1 << 2;
-            let multicast: u8 = 1 << 3;
-            let doc: u8 = 1 << 4;
-            let benchmarking: u8 = 1 << 5;
-
-            if ($mask & unspec) == unspec {
-                assert!(ip!($s).is_unspecified());
-            } else {
-                assert!(!ip!($s).is_unspecified());
-            }
-
-            if ($mask & loopback) == loopback {
-                assert!(ip!($s).is_loopback());
-            } else {
-                assert!(!ip!($s).is_loopback());
-            }
-
-            if ($mask & global) == global {
-                assert!(ip!($s).is_global());
-            } else {
-                assert!(!ip!($s).is_global());
-            }
-
-            if ($mask & multicast) == multicast {
-                assert!(ip!($s).is_multicast());
-            } else {
-                assert!(!ip!($s).is_multicast());
-            }
-
-            if ($mask & doc) == doc {
-                assert!(ip!($s).is_documentation());
-            } else {
-                assert!(!ip!($s).is_documentation());
-            }
-
-            if ($mask & benchmarking) == benchmarking {
-                assert!(ip!($s).is_benchmarking());
-            } else {
-                assert!(!ip!($s).is_benchmarking());
-            }
-        }};
-    }
-
-    let unspec: u8 = 1 << 0;
-    let loopback: u8 = 1 << 1;
-    let global: u8 = 1 << 2;
-    let multicast: u8 = 1 << 3;
-    let doc: u8 = 1 << 4;
-    let benchmarking: u8 = 1 << 5;
-
-    check!("0.0.0.0", unspec);
-    check!("0.0.0.1");
-    check!("0.1.0.0");
-    check!("10.9.8.7");
-    check!("127.1.2.3", loopback);
-    check!("172.31.254.253");
-    check!("169.254.253.242");
-    check!("192.0.2.183", doc);
-    check!("192.1.2.183", global);
-    check!("192.168.254.253");
-    check!("198.51.100.0", doc);
-    check!("203.0.113.0", doc);
-    check!("203.2.113.0", global);
-    check!("224.0.0.0", global | multicast);
-    check!("239.255.255.255", global | multicast);
-    check!("255.255.255.255");
-    // make sure benchmarking addresses are not global
-    check!("198.18.0.0", benchmarking);
-    check!("198.18.54.2", benchmarking);
-    check!("198.19.255.255", benchmarking);
-    // make sure addresses reserved for protocol assignment are not global
-    check!("192.0.0.0");
-    check!("192.0.0.255");
-    check!("192.0.0.100");
-    // make sure reserved addresses are not global
-    check!("240.0.0.0");
-    check!("251.54.1.76");
-    check!("254.255.255.255");
-    // make sure shared addresses are not global
-    check!("100.64.0.0");
-    check!("100.127.255.255");
-    check!("100.100.100.0");
-
-    check!("::", unspec);
-    check!("::1", loopback);
-    check!("::0.0.0.2", global);
-    check!("1::", global);
-    check!("fc00::");
-    check!("fdff:ffff::");
-    check!("fe80:ffff::");
-    check!("febf:ffff::");
-    check!("fec0::", global);
-    check!("ff01::", global | multicast);
-    check!("ff02::", global | multicast);
-    check!("ff03::", global | multicast);
-    check!("ff04::", global | multicast);
-    check!("ff05::", global | multicast);
-    check!("ff08::", global | multicast);
-    check!("ff0e::", global | multicast);
-    check!("2001:db8:85a3::8a2e:370:7334", doc);
-    check!("2001:2::ac32:23ff:21", benchmarking);
-    check!("102:304:506:708:90a:b0c:d0e:f10", global);
-}
-
-#[test]
-fn ipv4_properties() {
-    macro_rules! ip {
-        ($s:expr) => {
-            Ipv4Addr::from_str($s).unwrap()
-        };
-    }
-
-    macro_rules! check {
-        ($s:expr) => {
-            check!($s, 0);
-        };
-
-        ($s:expr, $mask:expr) => {{
-            let unspec: u16 = 1 << 0;
-            let loopback: u16 = 1 << 1;
-            let private: u16 = 1 << 2;
-            let link_local: u16 = 1 << 3;
-            let global: u16 = 1 << 4;
-            let multicast: u16 = 1 << 5;
-            let broadcast: u16 = 1 << 6;
-            let documentation: u16 = 1 << 7;
-            let benchmarking: u16 = 1 << 8;
-            let reserved: u16 = 1 << 10;
-            let shared: u16 = 1 << 11;
-
-            if ($mask & unspec) == unspec {
-                assert!(ip!($s).is_unspecified());
-            } else {
-                assert!(!ip!($s).is_unspecified());
-            }
-
-            if ($mask & loopback) == loopback {
-                assert!(ip!($s).is_loopback());
-            } else {
-                assert!(!ip!($s).is_loopback());
-            }
-
-            if ($mask & private) == private {
-                assert!(ip!($s).is_private());
-            } else {
-                assert!(!ip!($s).is_private());
-            }
-
-            if ($mask & link_local) == link_local {
-                assert!(ip!($s).is_link_local());
-            } else {
-                assert!(!ip!($s).is_link_local());
-            }
-
-            if ($mask & global) == global {
-                assert!(ip!($s).is_global());
-            } else {
-                assert!(!ip!($s).is_global());
-            }
-
-            if ($mask & multicast) == multicast {
-                assert!(ip!($s).is_multicast());
-            } else {
-                assert!(!ip!($s).is_multicast());
-            }
-
-            if ($mask & broadcast) == broadcast {
-                assert!(ip!($s).is_broadcast());
-            } else {
-                assert!(!ip!($s).is_broadcast());
-            }
-
-            if ($mask & documentation) == documentation {
-                assert!(ip!($s).is_documentation());
-            } else {
-                assert!(!ip!($s).is_documentation());
-            }
-
-            if ($mask & benchmarking) == benchmarking {
-                assert!(ip!($s).is_benchmarking());
-            } else {
-                assert!(!ip!($s).is_benchmarking());
-            }
-
-            if ($mask & reserved) == reserved {
-                assert!(ip!($s).is_reserved());
-            } else {
-                assert!(!ip!($s).is_reserved());
-            }
-
-            if ($mask & shared) == shared {
-                assert!(ip!($s).is_shared());
-            } else {
-                assert!(!ip!($s).is_shared());
-            }
-        }};
-    }
-
-    let unspec: u16 = 1 << 0;
-    let loopback: u16 = 1 << 1;
-    let private: u16 = 1 << 2;
-    let link_local: u16 = 1 << 3;
-    let global: u16 = 1 << 4;
-    let multicast: u16 = 1 << 5;
-    let broadcast: u16 = 1 << 6;
-    let documentation: u16 = 1 << 7;
-    let benchmarking: u16 = 1 << 8;
-    let reserved: u16 = 1 << 10;
-    let shared: u16 = 1 << 11;
-
-    check!("0.0.0.0", unspec);
-    check!("0.0.0.1");
-    check!("0.1.0.0");
-    check!("10.9.8.7", private);
-    check!("127.1.2.3", loopback);
-    check!("172.31.254.253", private);
-    check!("169.254.253.242", link_local);
-    check!("192.0.2.183", documentation);
-    check!("192.1.2.183", global);
-    check!("192.168.254.253", private);
-    check!("198.51.100.0", documentation);
-    check!("203.0.113.0", documentation);
-    check!("203.2.113.0", global);
-    check!("224.0.0.0", global | multicast);
-    check!("239.255.255.255", global | multicast);
-    check!("255.255.255.255", broadcast);
-    check!("198.18.0.0", benchmarking);
-    check!("198.18.54.2", benchmarking);
-    check!("198.19.255.255", benchmarking);
-    check!("192.0.0.0");
-    check!("192.0.0.255");
-    check!("192.0.0.100");
-    check!("240.0.0.0", reserved);
-    check!("251.54.1.76", reserved);
-    check!("254.255.255.255", reserved);
-    check!("100.64.0.0", shared);
-    check!("100.127.255.255", shared);
-    check!("100.100.100.0", shared);
-}
-
-#[test]
-fn ipv6_properties() {
-    macro_rules! ip {
-        ($s:expr) => {
-            Ipv6Addr::from_str($s).unwrap()
-        };
-    }
-
-    macro_rules! check {
-        ($s:expr, &[$($octet:expr),*], $mask:expr) => {
-            assert_eq!($s, ip!($s).to_string());
-            let octets = &[$($octet),*];
-            assert_eq!(&ip!($s).octets(), octets);
-            assert_eq!(Ipv6Addr::from(*octets), ip!($s));
-
-            let unspecified: u32 = 1 << 0;
-            let loopback: u32 = 1 << 1;
-            let unique_local: u32 = 1 << 2;
-            let global: u32 = 1 << 3;
-            let unicast_link_local: u32 = 1 << 4;
-            let unicast_global: u32 = 1 << 7;
-            let documentation: u32 = 1 << 8;
-            let benchmarking: u32 = 1 << 16;
-            let multicast_interface_local: u32 = 1 << 9;
-            let multicast_link_local: u32 = 1 << 10;
-            let multicast_realm_local: u32 = 1 << 11;
-            let multicast_admin_local: u32 = 1 << 12;
-            let multicast_site_local: u32 = 1 << 13;
-            let multicast_organization_local: u32 = 1 << 14;
-            let multicast_global: u32 = 1 << 15;
-            let multicast: u32 = multicast_interface_local
-                | multicast_admin_local
-                | multicast_global
-                | multicast_link_local
-                | multicast_realm_local
-                | multicast_site_local
-                | multicast_organization_local;
-
-            if ($mask & unspecified) == unspecified {
-                assert!(ip!($s).is_unspecified());
-            } else {
-                assert!(!ip!($s).is_unspecified());
-            }
-            if ($mask & loopback) == loopback {
-                assert!(ip!($s).is_loopback());
-            } else {
-                assert!(!ip!($s).is_loopback());
-            }
-            if ($mask & unique_local) == unique_local {
-                assert!(ip!($s).is_unique_local());
-            } else {
-                assert!(!ip!($s).is_unique_local());
-            }
-            if ($mask & global) == global {
-                assert!(ip!($s).is_global());
-            } else {
-                assert!(!ip!($s).is_global());
-            }
-            if ($mask & unicast_link_local) == unicast_link_local {
-                assert!(ip!($s).is_unicast_link_local());
-            } else {
-                assert!(!ip!($s).is_unicast_link_local());
-            }
-            if ($mask & unicast_global) == unicast_global {
-                assert!(ip!($s).is_unicast_global());
-            } else {
-                assert!(!ip!($s).is_unicast_global());
-            }
-            if ($mask & documentation) == documentation {
-                assert!(ip!($s).is_documentation());
-            } else {
-                assert!(!ip!($s).is_documentation());
-            }
-            if ($mask & benchmarking) == benchmarking {
-                assert!(ip!($s).is_benchmarking());
-            } else {
-                assert!(!ip!($s).is_benchmarking());
-            }
-            if ($mask & multicast) != 0 {
-                assert!(ip!($s).multicast_scope().is_some());
-                assert!(ip!($s).is_multicast());
-            } else {
-                assert!(ip!($s).multicast_scope().is_none());
-                assert!(!ip!($s).is_multicast());
-            }
-            if ($mask & multicast_interface_local) == multicast_interface_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::InterfaceLocal);
-            }
-            if ($mask & multicast_link_local) == multicast_link_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::LinkLocal);
-            }
-            if ($mask & multicast_realm_local) == multicast_realm_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::RealmLocal);
-            }
-            if ($mask & multicast_admin_local) == multicast_admin_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::AdminLocal);
-            }
-            if ($mask & multicast_site_local) == multicast_site_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::SiteLocal);
-            }
-            if ($mask & multicast_organization_local) == multicast_organization_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::OrganizationLocal);
-            }
-            if ($mask & multicast_global) == multicast_global {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::Global);
-            }
-        }
-    }
-
-    let unspecified: u32 = 1 << 0;
-    let loopback: u32 = 1 << 1;
-    let unique_local: u32 = 1 << 2;
-    let global: u32 = 1 << 3;
-    let unicast_link_local: u32 = 1 << 4;
-    let unicast_global: u32 = 1 << 7;
-    let documentation: u32 = 1 << 8;
-    let benchmarking: u32 = 1 << 16;
-    let multicast_interface_local: u32 = 1 << 9;
-    let multicast_link_local: u32 = 1 << 10;
-    let multicast_realm_local: u32 = 1 << 11;
-    let multicast_admin_local: u32 = 1 << 12;
-    let multicast_site_local: u32 = 1 << 13;
-    let multicast_organization_local: u32 = 1 << 14;
-    let multicast_global: u32 = 1 << 15;
-
-    check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified);
-
-    check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback);
-
-    check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global);
-
-    check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
-
-    check!(
-        "::ffff:127.0.0.1",
-        &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1],
-        unicast_global
-    );
-
-    check!(
-        "64:ff9b:1::",
-        &[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_global
-    );
-
-    check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
-
-    check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
-
-    check!(
-        "2001:1::1",
-        &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
-        global | unicast_global
-    );
-
-    check!(
-        "2001:1::2",
-        &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
-        global | unicast_global
-    );
-
-    check!(
-        "2001:3::",
-        &[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        global | unicast_global
-    );
-
-    check!(
-        "2001:4:112::",
-        &[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        global | unicast_global
-    );
-
-    check!(
-        "2001:20::",
-        &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        global | unicast_global
-    );
-
-    check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
-
-    check!(
-        "2001:200::",
-        &[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        global | unicast_global
-    );
-
-    check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
-
-    check!(
-        "fdff:ffff::",
-        &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unique_local
-    );
-
-    check!(
-        "fe80:ffff::",
-        &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_link_local
-    );
-
-    check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
-
-    check!(
-        "febf:ffff::",
-        &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_link_local
-    );
-
-    check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
-
-    check!(
-        "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-        &[
-            0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-            0xff, 0xff
-        ],
-        unicast_link_local
-    );
-
-    check!(
-        "fe80::ffff:ffff:ffff:ffff",
-        &[
-            0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-            0xff, 0xff
-        ],
-        unicast_link_local
-    );
-
-    check!(
-        "fe80:0:0:1::",
-        &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_link_local
-    );
-
-    check!(
-        "fec0::",
-        &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_global | global
-    );
-
-    check!(
-        "ff01::",
-        &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_interface_local | global
-    );
-
-    check!(
-        "ff02::",
-        &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_link_local | global
-    );
-
-    check!(
-        "ff03::",
-        &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_realm_local | global
-    );
-
-    check!(
-        "ff04::",
-        &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_admin_local | global
-    );
-
-    check!(
-        "ff05::",
-        &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_site_local | global
-    );
-
-    check!(
-        "ff08::",
-        &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_organization_local | global
-    );
-
-    check!(
-        "ff0e::",
-        &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_global | global
-    );
-
-    check!(
-        "2001:db8:85a3::8a2e:370:7334",
-        &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
-        documentation
-    );
-
-    check!(
-        "2001:2::ac32:23ff:21",
-        &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21],
-        benchmarking
-    );
-
-    check!(
-        "102:304:506:708:90a:b0c:d0e:f10",
-        &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
-        global | unicast_global
-    );
-}
+use crate::net::test::{sa4, tsa};
+use crate::net::Ipv4Addr;
 
 #[test]
 fn to_socket_addr_socketaddr() {
     let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345);
     assert_eq!(Ok(vec![a]), tsa(a));
 }
-
-#[test]
-fn test_ipv4_to_int() {
-    let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
-    assert_eq!(u32::from(a), 0x11223344);
-}
-
-#[test]
-fn test_int_to_ipv4() {
-    let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
-    assert_eq!(Ipv4Addr::from(0x11223344), a);
-}
-
-#[test]
-fn test_ipv6_to_int() {
-    let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
-    assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128);
-}
-
-#[test]
-fn test_int_to_ipv6() {
-    let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
-    assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
-}
-
-#[test]
-fn ipv4_from_constructors() {
-    assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1));
-    assert!(Ipv4Addr::LOCALHOST.is_loopback());
-    assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0));
-    assert!(Ipv4Addr::UNSPECIFIED.is_unspecified());
-    assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255));
-    assert!(Ipv4Addr::BROADCAST.is_broadcast());
-}
-
-#[test]
-fn ipv6_from_constructors() {
-    assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-    assert!(Ipv6Addr::LOCALHOST.is_loopback());
-    assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
-    assert!(Ipv6Addr::UNSPECIFIED.is_unspecified());
-}
-
-#[test]
-fn ipv4_from_octets() {
-    assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
-}
-
-#[test]
-fn ipv6_from_segments() {
-    let from_u16s =
-        Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
-    let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff);
-    assert_eq!(new, from_u16s);
-}
-
-#[test]
-fn ipv6_from_octets() {
-    let from_u16s =
-        Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
-    let from_u8s = Ipv6Addr::from([
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ]);
-    assert_eq!(from_u16s, from_u8s);
-}
-
-#[test]
-fn cmp() {
-    let v41 = Ipv4Addr::new(100, 64, 3, 3);
-    let v42 = Ipv4Addr::new(192, 0, 2, 2);
-    let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap();
-    let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap();
-    assert!(v41 < v42);
-    assert!(v61 < v62);
-
-    assert_eq!(v41, IpAddr::V4(v41));
-    assert_eq!(v61, IpAddr::V6(v61));
-    assert!(v41 != IpAddr::V4(v42));
-    assert!(v61 != IpAddr::V6(v62));
-
-    assert!(v41 < IpAddr::V4(v42));
-    assert!(v61 < IpAddr::V6(v62));
-    assert!(IpAddr::V4(v41) < v42);
-    assert!(IpAddr::V6(v61) < v62);
-
-    assert!(v41 < IpAddr::V6(v61));
-    assert!(IpAddr::V4(v41) < v61);
-}
-
-#[test]
-fn is_v4() {
-    let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3));
-    assert!(ip.is_ipv4());
-    assert!(!ip.is_ipv6());
-}
-
-#[test]
-fn is_v6() {
-    let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678));
-    assert!(!ip.is_ipv4());
-    assert!(ip.is_ipv6());
-}
-
-#[test]
-fn ipv4_const() {
-    // test that the methods of `Ipv4Addr` are usable in a const context
-
-    const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
-    assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST);
-
-    const OCTETS: [u8; 4] = IP_ADDRESS.octets();
-    assert_eq!(OCTETS, [127, 0, 0, 1]);
-
-    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
-    assert!(!IS_UNSPECIFIED);
-
-    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
-    assert!(IS_LOOPBACK);
-
-    const IS_PRIVATE: bool = IP_ADDRESS.is_private();
-    assert!(!IS_PRIVATE);
-
-    const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local();
-    assert!(!IS_LINK_LOCAL);
-
-    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
-    assert!(!IS_GLOBAL);
-
-    const IS_SHARED: bool = IP_ADDRESS.is_shared();
-    assert!(!IS_SHARED);
-
-    const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
-    assert!(!IS_BENCHMARKING);
-
-    const IS_RESERVED: bool = IP_ADDRESS.is_reserved();
-    assert!(!IS_RESERVED);
-
-    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
-    assert!(!IS_MULTICAST);
-
-    const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast();
-    assert!(!IS_BROADCAST);
-
-    const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
-    assert!(!IS_DOCUMENTATION);
-
-    const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible();
-    assert_eq!(
-        IP_V6_COMPATIBLE,
-        Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1])
-    );
-
-    const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped();
-    assert_eq!(
-        IP_V6_MAPPED,
-        Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1])
-    );
-}
-
-#[test]
-fn ipv6_const() {
-    // test that the methods of `Ipv6Addr` are usable in a const context
-
-    const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
-    assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST);
-
-    const SEGMENTS: [u16; 8] = IP_ADDRESS.segments();
-    assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]);
-
-    const OCTETS: [u8; 16] = IP_ADDRESS.octets();
-    assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
-
-    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
-    assert!(!IS_UNSPECIFIED);
-
-    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
-    assert!(IS_LOOPBACK);
-
-    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
-    assert!(!IS_GLOBAL);
-
-    const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
-    assert!(!IS_UNIQUE_LOCAL);
-
-    const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
-    assert!(!IS_UNICAST_LINK_LOCAL);
-
-    const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
-    assert!(!IS_DOCUMENTATION);
-
-    const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
-    assert!(!IS_BENCHMARKING);
-
-    const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global();
-    assert!(!IS_UNICAST_GLOBAL);
-
-    const MULTICAST_SCOPE: Option<Ipv6MulticastScope> = IP_ADDRESS.multicast_scope();
-    assert_eq!(MULTICAST_SCOPE, None);
-
-    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
-    assert!(!IS_MULTICAST);
-
-    const IP_V4: Option<Ipv4Addr> = IP_ADDRESS.to_ipv4();
-    assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1));
-}
-
-#[test]
-fn ip_const() {
-    // test that the methods of `IpAddr` are usable in a const context
-
-    const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
-
-    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
-    assert!(!IS_UNSPECIFIED);
-
-    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
-    assert!(IS_LOOPBACK);
-
-    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
-    assert!(!IS_GLOBAL);
-
-    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
-    assert!(!IS_MULTICAST);
-
-    const IS_IP_V4: bool = IP_ADDRESS.is_ipv4();
-    assert!(IS_IP_V4);
-
-    const IS_IP_V6: bool = IP_ADDRESS.is_ipv6();
-    assert!(!IS_IP_V6);
-}
-
-#[test]
-fn structural_match() {
-    // test that all IP types can be structurally matched upon
-
-    const IPV4: Ipv4Addr = Ipv4Addr::LOCALHOST;
-    match IPV4 {
-        Ipv4Addr::LOCALHOST => {}
-        _ => unreachable!(),
-    }
-
-    const IPV6: Ipv6Addr = Ipv6Addr::LOCALHOST;
-    match IPV6 {
-        Ipv6Addr::LOCALHOST => {}
-        _ => unreachable!(),
-    }
-
-    const IP: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
-    match IP {
-        IpAddr::V4(Ipv4Addr::LOCALHOST) => {}
-        _ => unreachable!(),
-    }
-}
diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs
index 19d90e7ec38..bcab15db35b 100644
--- a/library/std/src/net/mod.rs
+++ b/library/std/src/net/mod.rs
@@ -26,8 +26,6 @@ use crate::io::{self, ErrorKind};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use self::parser::AddrParseError;
-#[stable(feature = "rust1", since = "1.0.0")]
 pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
 #[unstable(feature = "tcplistener_into_incoming", issue = "88339")]
 pub use self::tcp::IntoIncoming;
@@ -35,10 +33,10 @@ pub use self::tcp::IntoIncoming;
 pub use self::tcp::{Incoming, TcpListener, TcpStream};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::udp::UdpSocket;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::net::AddrParseError;
 
-mod display_buffer;
 mod ip_addr;
-mod parser;
 mod socket_addr;
 mod tcp;
 #[cfg(test)]
diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs
index 1264bae809b..421fed9077c 100644
--- a/library/std/src/net/socket_addr.rs
+++ b/library/std/src/net/socket_addr.rs
@@ -1,9 +1,7 @@
+// Tests for this module
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
 
-use crate::cmp::Ordering;
-use crate::fmt::{self, Write};
-use crate::hash;
 use crate::io;
 use crate::iter;
 use crate::mem;
@@ -15,533 +13,23 @@ use crate::sys_common::net::LookupHost;
 use crate::sys_common::{FromInner, IntoInner};
 use crate::vec;
 
-use super::display_buffer::DisplayBuffer;
-
-/// An internet socket address, either IPv4 or IPv6.
-///
-/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well
-/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and
-/// [`SocketAddrV6`]'s respective documentation for more details.
-///
-/// The size of a `SocketAddr` instance may vary depending on the target operating
-/// system.
-///
-/// [IP address]: IpAddr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-///
-/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-///
-/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
-/// assert_eq!(socket.port(), 8080);
-/// assert_eq!(socket.is_ipv4(), true);
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub enum SocketAddr {
-    /// An IPv4 socket address.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4),
-    /// An IPv6 socket address.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6),
-}
-
-/// An IPv4 socket address.
-///
-/// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port number, as
-/// stated in [IETF RFC 793].
-///
-/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
-///
-/// The size of a `SocketAddrV4` struct may vary depending on the target operating
-/// system. Do not assume that this type has the same memory layout as the underlying
-/// system representation.
-///
-/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
-/// [`IPv4` address]: Ipv4Addr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{Ipv4Addr, SocketAddrV4};
-///
-/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-///
-/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
-/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
-/// assert_eq!(socket.port(), 8080);
-/// ```
-#[derive(Copy, Clone, Eq, PartialEq)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SocketAddrV4 {
-    ip: Ipv4Addr,
-    port: u16,
-}
-
-/// An IPv6 socket address.
-///
-/// IPv6 socket addresses consist of an [`IPv6` address], a 16-bit port number, as well
-/// as fields containing the traffic class, the flow label, and a scope identifier
-/// (see [IETF RFC 2553, Section 3.3] for more details).
-///
-/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
-///
-/// The size of a `SocketAddrV6` struct may vary depending on the target operating
-/// system. Do not assume that this type has the same memory layout as the underlying
-/// system representation.
-///
-/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
-/// [`IPv6` address]: Ipv6Addr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{Ipv6Addr, SocketAddrV6};
-///
-/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-///
-/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket));
-/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
-/// assert_eq!(socket.port(), 8080);
-/// ```
-#[derive(Copy, Clone, Eq, PartialEq)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct SocketAddrV6 {
-    ip: Ipv6Addr,
-    port: u16,
-    flowinfo: u32,
-    scope_id: u32,
-}
-
-impl SocketAddr {
-    /// Creates a new socket address from an [IP address] and a port number.
-    ///
-    /// [IP address]: IpAddr
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
-    /// assert_eq!(socket.port(), 8080);
-    /// ```
-    #[stable(feature = "ip_addr", since = "1.7.0")]
-    #[must_use]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
-        match ip {
-            IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
-            IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)),
-        }
-    }
-
-    /// Returns the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
-    /// ```
-    #[must_use]
-    #[stable(feature = "ip_addr", since = "1.7.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn ip(&self) -> IpAddr {
-        match *self {
-            SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
-            SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()),
-        }
-    }
-
-    /// Changes the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
-    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_ip(&mut self, new_ip: IpAddr) {
-        // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
-        match (self, new_ip) {
-            (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip),
-            (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip),
-            (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()),
-        }
-    }
-
-    /// Returns the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// assert_eq!(socket.port(), 8080);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn port(&self) -> u16 {
-        match *self {
-            SocketAddr::V4(ref a) => a.port(),
-            SocketAddr::V6(ref a) => a.port(),
-        }
-    }
-
-    /// Changes the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// socket.set_port(1025);
-    /// assert_eq!(socket.port(), 1025);
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_port(&mut self, new_port: u16) {
-        match *self {
-            SocketAddr::V4(ref mut a) => a.set_port(new_port),
-            SocketAddr::V6(ref mut a) => a.set_port(new_port),
-        }
-    }
-
-    /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
-    /// [`IPv4` address], and [`false`] otherwise.
-    ///
-    /// [IP address]: IpAddr
-    /// [`IPv4` address]: IpAddr::V4
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// assert_eq!(socket.is_ipv4(), true);
-    /// assert_eq!(socket.is_ipv6(), false);
-    /// ```
-    #[must_use]
-    #[stable(feature = "sockaddr_checker", since = "1.16.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn is_ipv4(&self) -> bool {
-        matches!(*self, SocketAddr::V4(_))
-    }
-
-    /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
-    /// [`IPv6` address], and [`false`] otherwise.
-    ///
-    /// [IP address]: IpAddr
-    /// [`IPv6` address]: IpAddr::V6
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv6Addr, SocketAddr};
-    ///
-    /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080);
-    /// assert_eq!(socket.is_ipv4(), false);
-    /// assert_eq!(socket.is_ipv6(), true);
-    /// ```
-    #[must_use]
-    #[stable(feature = "sockaddr_checker", since = "1.16.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn is_ipv6(&self) -> bool {
-        matches!(*self, SocketAddr::V6(_))
-    }
-}
-
-impl SocketAddrV4 {
-    /// Creates a new socket address from an [`IPv4` address] and a port number.
-    ///
-    /// [`IPv4` address]: Ipv4Addr
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV4, Ipv4Addr};
-    ///
-    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
-        SocketAddrV4 { ip, port }
-    }
-
-    /// Returns the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV4, Ipv4Addr};
-    ///
-    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-    /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn ip(&self) -> &Ipv4Addr {
-        &self.ip
-    }
-
-    /// Changes the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV4, Ipv4Addr};
-    ///
-    /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-    /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
-    /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
-        self.ip = new_ip;
-    }
-
-    /// Returns the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV4, Ipv4Addr};
-    ///
-    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-    /// assert_eq!(socket.port(), 8080);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn port(&self) -> u16 {
-        self.port
-    }
-
-    /// Changes the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV4, Ipv4Addr};
-    ///
-    /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-    /// socket.set_port(4242);
-    /// assert_eq!(socket.port(), 4242);
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_port(&mut self, new_port: u16) {
-        self.port = new_port;
-    }
-}
-
-impl SocketAddrV6 {
-    /// Creates a new socket address from an [`IPv6` address], a 16-bit port number,
-    /// and the `flowinfo` and `scope_id` fields.
-    ///
-    /// For more information on the meaning and layout of the `flowinfo` and `scope_id`
-    /// parameters, see [IETF RFC 2553, Section 3.3].
-    ///
-    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
-    /// [`IPv6` address]: Ipv6Addr
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
-        SocketAddrV6 { ip, port, flowinfo, scope_id }
-    }
-
-    /// Returns the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-    /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn ip(&self) -> &Ipv6Addr {
-        &self.ip
-    }
-
-    /// Changes the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-    /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
-    /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
-        self.ip = new_ip;
-    }
-
-    /// Returns the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-    /// assert_eq!(socket.port(), 8080);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn port(&self) -> u16 {
-        self.port
-    }
-
-    /// Changes the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-    /// socket.set_port(4242);
-    /// assert_eq!(socket.port(), 4242);
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_port(&mut self, new_port: u16) {
-        self.port = new_port;
-    }
-
-    /// Returns the flow information associated with this address.
-    ///
-    /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`,
-    /// as specified in [IETF RFC 2553, Section 3.3].
-    /// It combines information about the flow label and the traffic class as specified
-    /// in [IETF RFC 2460], respectively [Section 6] and [Section 7].
-    ///
-    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
-    /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460
-    /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6
-    /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
-    /// assert_eq!(socket.flowinfo(), 10);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn flowinfo(&self) -> u32 {
-        self.flowinfo
-    }
-
-    /// Changes the flow information associated with this socket address.
-    ///
-    /// See [`SocketAddrV6::flowinfo`]'s documentation for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
-    /// socket.set_flowinfo(56);
-    /// assert_eq!(socket.flowinfo(), 56);
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
-        self.flowinfo = new_flowinfo;
-    }
-
-    /// Returns the scope ID associated with this address.
-    ///
-    /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`,
-    /// as specified in [IETF RFC 2553, Section 3.3].
-    ///
-    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
-    /// assert_eq!(socket.scope_id(), 78);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn scope_id(&self) -> u32 {
-        self.scope_id
-    }
-
-    /// Changes the scope ID associated with this socket address.
-    ///
-    /// See [`SocketAddrV6::scope_id`]'s documentation for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
-    /// socket.set_scope_id(42);
-    /// assert_eq!(socket.scope_id(), 42);
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_scope_id(&mut self, new_scope_id: u32) {
-        self.scope_id = new_scope_id;
-    }
-}
+pub use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
 
 impl FromInner<c::sockaddr_in> for SocketAddrV4 {
     fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 {
-        SocketAddrV4 { ip: Ipv4Addr::from_inner(addr.sin_addr), port: u16::from_be(addr.sin_port) }
+        SocketAddrV4::new(Ipv4Addr::from_inner(addr.sin_addr), u16::from_be(addr.sin_port))
     }
 }
 
 impl FromInner<c::sockaddr_in6> for SocketAddrV6 {
     fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 {
-        SocketAddrV6 {
-            ip: Ipv6Addr::from_inner(addr.sin6_addr),
-            port: u16::from_be(addr.sin6_port),
-            flowinfo: addr.sin6_flowinfo,
-            scope_id: addr.sin6_scope_id,
-        }
+        SocketAddrV6::new(
+            Ipv6Addr::from_inner(addr.sin6_addr),
+            u16::from_be(addr.sin6_port),
+            addr.sin6_flowinfo,
+            addr.sin6_scope_id,
+        )
     }
 }
 
@@ -549,8 +37,8 @@ impl IntoInner<c::sockaddr_in> for SocketAddrV4 {
     fn into_inner(self) -> c::sockaddr_in {
         c::sockaddr_in {
             sin_family: c::AF_INET as c::sa_family_t,
-            sin_port: self.port.to_be(),
-            sin_addr: self.ip.into_inner(),
+            sin_port: self.port().to_be(),
+            sin_addr: self.ip().into_inner(),
             ..unsafe { mem::zeroed() }
         }
     }
@@ -560,162 +48,15 @@ impl IntoInner<c::sockaddr_in6> for SocketAddrV6 {
     fn into_inner(self) -> c::sockaddr_in6 {
         c::sockaddr_in6 {
             sin6_family: c::AF_INET6 as c::sa_family_t,
-            sin6_port: self.port.to_be(),
-            sin6_addr: self.ip.into_inner(),
-            sin6_flowinfo: self.flowinfo,
-            sin6_scope_id: self.scope_id,
+            sin6_port: self.port().to_be(),
+            sin6_addr: self.ip().into_inner(),
+            sin6_flowinfo: self.flowinfo(),
+            sin6_scope_id: self.scope_id(),
             ..unsafe { mem::zeroed() }
         }
     }
 }
 
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<SocketAddrV4> for SocketAddr {
-    /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
-    fn from(sock4: SocketAddrV4) -> SocketAddr {
-        SocketAddr::V4(sock4)
-    }
-}
-
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<SocketAddrV6> for SocketAddr {
-    /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
-    fn from(sock6: SocketAddrV6) -> SocketAddr {
-        SocketAddr::V6(sock6)
-    }
-}
-
-#[stable(feature = "addr_from_into_ip", since = "1.17.0")]
-impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr {
-    /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`].
-    ///
-    /// This conversion creates a [`SocketAddr::V4`] for an [`IpAddr::V4`]
-    /// and creates a [`SocketAddr::V6`] for an [`IpAddr::V6`].
-    ///
-    /// `u16` is treated as port of the newly created [`SocketAddr`].
-    fn from(pieces: (I, u16)) -> SocketAddr {
-        SocketAddr::new(pieces.0.into(), pieces.1)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for SocketAddr {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            SocketAddr::V4(ref a) => a.fmt(f),
-            SocketAddr::V6(ref a) => a.fmt(f),
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for SocketAddr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for SocketAddrV4 {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // If there are no alignment requirements, write the socket address directly to `f`.
-        // Otherwise, write it to a local buffer and then use `f.pad`.
-        if f.precision().is_none() && f.width().is_none() {
-            write!(f, "{}:{}", self.ip(), self.port())
-        } else {
-            const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65536";
-
-            let mut buf = DisplayBuffer::<{ LONGEST_IPV4_SOCKET_ADDR.len() }>::new();
-            // Buffer is long enough for the longest possible IPv4 socket address, so this should never fail.
-            write!(buf, "{}:{}", self.ip(), self.port()).unwrap();
-
-            f.pad(buf.as_str())
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for SocketAddrV4 {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for SocketAddrV6 {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // If there are no alignment requirements, write the socket address directly to `f`.
-        // Otherwise, write it to a local buffer and then use `f.pad`.
-        if f.precision().is_none() && f.width().is_none() {
-            match self.scope_id() {
-                0 => write!(f, "[{}]:{}", self.ip(), self.port()),
-                scope_id => write!(f, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
-            }
-        } else {
-            const LONGEST_IPV6_SOCKET_ADDR: &str =
-                "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967296]:65536";
-
-            let mut buf = DisplayBuffer::<{ LONGEST_IPV6_SOCKET_ADDR.len() }>::new();
-            match self.scope_id() {
-                0 => write!(buf, "[{}]:{}", self.ip(), self.port()),
-                scope_id => write!(buf, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
-            }
-            // Buffer is long enough for the longest possible IPv6 socket address, so this should never fail.
-            .unwrap();
-
-            f.pad(buf.as_str())
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for SocketAddrV6 {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl PartialOrd for SocketAddrV4 {
-    fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl PartialOrd for SocketAddrV6 {
-    fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl Ord for SocketAddrV4 {
-    fn cmp(&self, other: &SocketAddrV4) -> Ordering {
-        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl Ord for SocketAddrV6 {
-    fn cmp(&self, other: &SocketAddrV6) -> Ordering {
-        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl hash::Hash for SocketAddrV4 {
-    fn hash<H: hash::Hasher>(&self, s: &mut H) {
-        (self.port, self.ip).hash(s)
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl hash::Hash for SocketAddrV6 {
-    fn hash<H: hash::Hasher>(&self, s: &mut H) {
-        (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s)
-    }
-}
-
 /// A trait for objects which can be converted or resolved to one or more
 /// [`SocketAddr`] values.
 ///
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 439b8d52a2d..258919d53a4 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -9,7 +9,7 @@ use crate::fs;
 use crate::io;
 use crate::marker::PhantomData;
 use crate::mem::forget;
-#[cfg(not(any(target_arch = "wasm32", target_env = "sgx")))]
+#[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))]
 use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
@@ -89,7 +89,7 @@ impl OwnedFd {
 impl BorrowedFd<'_> {
     /// Creates a new `OwnedFd` instance that shares the same underlying file
     /// description as the existing `BorrowedFd` instance.
-    #[cfg(not(target_arch = "wasm32"))]
+    #[cfg(not(any(target_arch = "wasm32", target_os = "hermit")))]
     #[stable(feature = "io_safety", since = "1.63.0")]
     pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
         // We want to atomically duplicate this file descriptor and set the
@@ -112,7 +112,7 @@ impl BorrowedFd<'_> {
 
     /// Creates a new `OwnedFd` instance that shares the same underlying file
     /// description as the existing `BorrowedFd` instance.
-    #[cfg(target_arch = "wasm32")]
+    #[cfg(any(target_arch = "wasm32", target_os = "hermit"))]
     #[stable(feature = "io_safety", since = "1.63.0")]
     pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
         Err(crate::io::const_io_error!(
@@ -174,7 +174,10 @@ impl Drop for OwnedFd {
             // the file descriptor was closed or not, and if we retried (for
             // something like EINTR), we might close another valid file descriptor
             // opened after we closed ours.
+            #[cfg(not(target_os = "hermit"))]
             let _ = libc::close(self.fd);
+            #[cfg(target_os = "hermit")]
+            let _ = hermit_abi::close(self.fd);
         }
     }
 }
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index c138162f1ab..0a4cefd2095 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -4,6 +4,9 @@
 
 use crate::fs;
 use crate::io;
+#[cfg(target_os = "hermit")]
+use crate::os::hermit::io::OwnedFd;
+#[cfg(not(target_os = "hermit"))]
 use crate::os::raw;
 #[cfg(all(doc, not(target_arch = "wasm32")))]
 use crate::os::unix::io::AsFd;
@@ -12,11 +15,18 @@ use crate::os::unix::io::OwnedFd;
 #[cfg(target_os = "wasi")]
 use crate::os::wasi::io::OwnedFd;
 use crate::sys_common::{AsInner, IntoInner};
+#[cfg(target_os = "hermit")]
+use hermit_abi as libc;
 
 /// Raw file descriptors.
 #[rustc_allowed_through_unstable_modules]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(target_os = "hermit"))]
 pub type RawFd = raw::c_int;
+#[rustc_allowed_through_unstable_modules]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(target_os = "hermit")]
+pub type RawFd = i32;
 
 /// A trait to extract the raw file descriptor from an underlying object.
 ///
diff --git a/library/std/src/os/hermit/io/mod.rs b/library/std/src/os/hermit/io/mod.rs
new file mode 100644
index 00000000000..524dfae0d63
--- /dev/null
+++ b/library/std/src/os/hermit/io/mod.rs
@@ -0,0 +1,13 @@
+#![stable(feature = "os_fd", since = "1.66.0")]
+
+mod net;
+#[path = "../../fd/owned.rs"]
+mod owned;
+#[path = "../../fd/raw.rs"]
+mod raw;
+
+// Export the types and traits for the public API.
+#[stable(feature = "os_fd", since = "1.66.0")]
+pub use owned::*;
+#[stable(feature = "os_fd", since = "1.66.0")]
+pub use raw::*;
diff --git a/library/std/src/os/hermit/io/net.rs b/library/std/src/os/hermit/io/net.rs
new file mode 100644
index 00000000000..8f3802d7873
--- /dev/null
+++ b/library/std/src/os/hermit/io/net.rs
@@ -0,0 +1,46 @@
+use crate::os::hermit::io::OwnedFd;
+use crate::os::hermit::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+use crate::{net, sys};
+
+macro_rules! impl_as_raw_fd {
+    ($($t:ident)*) => {$(
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl AsRawFd for net::$t {
+            #[inline]
+            fn as_raw_fd(&self) -> RawFd {
+                self.as_inner().socket().as_raw_fd()
+            }
+        }
+    )*};
+}
+impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_from_raw_fd {
+    ($($t:ident)*) => {$(
+        #[stable(feature = "from_raw_os", since = "1.1.0")]
+        impl FromRawFd for net::$t {
+            #[inline]
+            unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
+                unsafe {
+                    let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)));
+                    net::$t::from_inner(sys_common::net::$t::from_inner(socket))
+                }
+            }
+        }
+    )*};
+}
+impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_into_raw_fd {
+    ($($t:ident)*) => {$(
+        #[stable(feature = "into_raw_os", since = "1.4.0")]
+        impl IntoRawFd for net::$t {
+            #[inline]
+            fn into_raw_fd(self) -> RawFd {
+                self.into_inner().into_socket().into_inner().into_inner().into_raw_fd()
+            }
+        }
+    )*};
+}
+impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
diff --git a/library/std/src/os/hermit/mod.rs b/library/std/src/os/hermit/mod.rs
index 4657b545a1b..89b1b831912 100644
--- a/library/std/src/os/hermit/mod.rs
+++ b/library/std/src/os/hermit/mod.rs
@@ -1,6 +1,11 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[allow(unused_extern_crates)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub extern crate hermit_abi as abi;
+
 pub mod ffi;
+pub mod io;
 
 /// A prelude for conveniently writing platform-specific code.
 ///
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 42773805cdb..af137c9bd85 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -60,16 +60,6 @@ pub mod windows {}
         all(target_vendor = "fortanix", target_env = "sgx")
     )
 )))]
-#[cfg(target_os = "hermit")]
-#[path = "hermit/mod.rs"]
-pub mod unix;
-#[cfg(not(all(
-    doc,
-    any(
-        all(target_arch = "wasm32", not(target_os = "wasi")),
-        all(target_vendor = "fortanix", target_env = "sgx")
-    )
-)))]
 #[cfg(all(not(target_os = "hermit"), any(unix, doc)))]
 pub mod unix;
 
@@ -123,6 +113,8 @@ pub mod freebsd;
 pub mod fuchsia;
 #[cfg(target_os = "haiku")]
 pub mod haiku;
+#[cfg(target_os = "hermit")]
+pub mod hermit;
 #[cfg(target_os = "horizon")]
 pub mod horizon;
 #[cfg(target_os = "illumos")]
diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs
index afcae6c90ee..220a76e4b12 100644
--- a/library/std/src/sys/hermit/args.rs
+++ b/library/std/src/sys/hermit/args.rs
@@ -1,6 +1,6 @@
 use crate::ffi::{c_char, CStr, OsString};
 use crate::fmt;
-use crate::os::unix::ffi::OsStringExt;
+use crate::os::hermit::ffi::OsStringExt;
 use crate::ptr;
 use crate::sync::atomic::{
     AtomicIsize, AtomicPtr,
diff --git a/library/std/src/sys/hermit/fd.rs b/library/std/src/sys/hermit/fd.rs
index c400f5f2c2e..3a2cdd301ea 100644
--- a/library/std/src/sys/hermit/fd.rs
+++ b/library/std/src/sys/hermit/fd.rs
@@ -1,36 +1,23 @@
 #![unstable(reason = "not public", issue = "none", feature = "fd")]
 
 use crate::io::{self, Read};
-use crate::mem;
+use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd};
 use crate::sys::cvt;
 use crate::sys::hermit::abi;
 use crate::sys::unsupported;
-use crate::sys_common::AsInner;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+use crate::os::hermit::io::*;
 
 #[derive(Debug)]
 pub struct FileDesc {
-    fd: i32,
+    fd: OwnedFd,
 }
 
 impl FileDesc {
-    pub fn new(fd: i32) -> FileDesc {
-        FileDesc { fd }
-    }
-
-    pub fn raw(&self) -> i32 {
-        self.fd
-    }
-
-    /// Extracts the actual file descriptor without closing it.
-    pub fn into_raw(self) -> i32 {
-        let fd = self.fd;
-        mem::forget(self);
-        fd
-    }
-
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        let result = unsafe { abi::read(self.fd, buf.as_mut_ptr(), buf.len()) };
-        cvt(result as i32)
+        let result = cvt(unsafe { abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?;
+        Ok(result as usize)
     }
 
     pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
@@ -39,8 +26,8 @@ impl FileDesc {
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        let result = unsafe { abi::write(self.fd, buf.as_ptr(), buf.len()) };
-        cvt(result as i32)
+        let result = cvt(unsafe { abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
+        Ok(result as usize)
     }
 
     pub fn duplicate(&self) -> io::Result<FileDesc> {
@@ -69,19 +56,45 @@ impl<'a> Read for &'a FileDesc {
     }
 }
 
-impl AsInner<i32> for FileDesc {
-    fn as_inner(&self) -> &i32 {
+impl IntoInner<OwnedFd> for FileDesc {
+    fn into_inner(self) -> OwnedFd {
+        self.fd
+    }
+}
+
+impl FromInner<OwnedFd> for FileDesc {
+    fn from_inner(owned_fd: OwnedFd) -> Self {
+        Self { fd: owned_fd }
+    }
+}
+
+impl FromRawFd for FileDesc {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        Self { fd: FromRawFd::from_raw_fd(raw_fd) }
+    }
+}
+
+impl AsInner<OwnedFd> for FileDesc {
+    fn as_inner(&self) -> &OwnedFd {
         &self.fd
     }
 }
 
-impl Drop for FileDesc {
-    fn drop(&mut self) {
-        // Note that errors are ignored when closing a file descriptor. The
-        // reason for this is that if an error occurs we don't actually know if
-        // the file descriptor was closed or not, and if we retried (for
-        // something like EINTR), we might close another valid file descriptor
-        // (opened after we closed ours.
-        let _ = unsafe { abi::close(self.fd) };
+impl AsFd for FileDesc {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.fd.as_fd()
+    }
+}
+
+impl AsRawFd for FileDesc {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for FileDesc {
+    fn into_raw_fd(self) -> RawFd {
+        self.fd.into_raw_fd()
     }
 }
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index 6fb92c037ee..c966f217757 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -3,14 +3,17 @@ use crate::fmt;
 use crate::hash::{Hash, Hasher};
 use crate::io::{self, Error, ErrorKind};
 use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
+use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::path::{Path, PathBuf};
 use crate::sys::common::small_c_string::run_path_with_cstr;
 use crate::sys::cvt;
-use crate::sys::hermit::abi;
-use crate::sys::hermit::abi::{O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY};
+use crate::sys::hermit::abi::{
+    self, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY,
+};
 use crate::sys::hermit::fd::FileDesc;
 use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
 pub use crate::sys_common::fs::{copy, try_exists};
 //pub use crate::sys_common::fs::remove_dir_all;
@@ -283,7 +286,7 @@ impl File {
         }
 
         let fd = unsafe { cvt(abi::open(path.as_ptr(), flags, mode))? };
-        Ok(File(FileDesc::new(fd as i32)))
+        Ok(File(unsafe { FileDesc::from_raw_fd(fd as i32) }))
     }
 
     pub fn file_attr(&self) -> io::Result<FileAttr> {
@@ -363,6 +366,54 @@ impl DirBuilder {
     }
 }
 
+impl AsInner<FileDesc> for File {
+    fn as_inner(&self) -> &FileDesc {
+        &self.0
+    }
+}
+
+impl AsInnerMut<FileDesc> for File {
+    fn as_inner_mut(&mut self) -> &mut FileDesc {
+        &mut self.0
+    }
+}
+
+impl IntoInner<FileDesc> for File {
+    fn into_inner(self) -> FileDesc {
+        self.0
+    }
+}
+
+impl FromInner<FileDesc> for File {
+    fn from_inner(file_desc: FileDesc) -> Self {
+        Self(file_desc)
+    }
+}
+
+impl AsFd for File {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for File {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for File {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for File {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        Self(FromRawFd::from_raw_fd(raw_fd))
+    }
+}
+
 pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
     unsupported()
 }
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 20fd3dd8f09..d34a4cfedea 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -13,7 +13,7 @@
 //! compiling for wasm. That way it's a compile time error for something that's
 //! guaranteed to be a runtime error!
 
-#![allow(unsafe_op_in_unsafe_fn)]
+#![allow(missing_docs, nonstandard_style, unsafe_op_in_unsafe_fn)]
 
 use crate::intrinsics;
 use crate::os::raw::c_char;
@@ -57,9 +57,7 @@ pub mod locks {
 }
 
 use crate::io::ErrorKind;
-
-#[allow(unused_extern_crates)]
-pub extern crate hermit_abi as abi;
+use crate::os::hermit::abi;
 
 pub fn unsupported<T>() -> crate::io::Result<T> {
     Err(unsupported_err())
@@ -126,25 +124,72 @@ pub unsafe extern "C" fn runtime_entry(
 
 pub fn decode_error_kind(errno: i32) -> ErrorKind {
     match errno {
-        x if x == 13 as i32 => ErrorKind::PermissionDenied,
-        x if x == 98 as i32 => ErrorKind::AddrInUse,
-        x if x == 99 as i32 => ErrorKind::AddrNotAvailable,
-        x if x == 11 as i32 => ErrorKind::WouldBlock,
-        x if x == 103 as i32 => ErrorKind::ConnectionAborted,
-        x if x == 111 as i32 => ErrorKind::ConnectionRefused,
-        x if x == 104 as i32 => ErrorKind::ConnectionReset,
-        x if x == 17 as i32 => ErrorKind::AlreadyExists,
-        x if x == 4 as i32 => ErrorKind::Interrupted,
-        x if x == 22 as i32 => ErrorKind::InvalidInput,
-        x if x == 2 as i32 => ErrorKind::NotFound,
-        x if x == 107 as i32 => ErrorKind::NotConnected,
-        x if x == 1 as i32 => ErrorKind::PermissionDenied,
-        x if x == 32 as i32 => ErrorKind::BrokenPipe,
-        x if x == 110 as i32 => ErrorKind::TimedOut,
+        abi::errno::EACCES => ErrorKind::PermissionDenied,
+        abi::errno::EADDRINUSE => ErrorKind::AddrInUse,
+        abi::errno::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+        abi::errno::EAGAIN => ErrorKind::WouldBlock,
+        abi::errno::ECONNABORTED => ErrorKind::ConnectionAborted,
+        abi::errno::ECONNREFUSED => ErrorKind::ConnectionRefused,
+        abi::errno::ECONNRESET => ErrorKind::ConnectionReset,
+        abi::errno::EEXIST => ErrorKind::AlreadyExists,
+        abi::errno::EINTR => ErrorKind::Interrupted,
+        abi::errno::EINVAL => ErrorKind::InvalidInput,
+        abi::errno::ENOENT => ErrorKind::NotFound,
+        abi::errno::ENOTCONN => ErrorKind::NotConnected,
+        abi::errno::EPERM => ErrorKind::PermissionDenied,
+        abi::errno::EPIPE => ErrorKind::BrokenPipe,
+        abi::errno::ETIMEDOUT => ErrorKind::TimedOut,
         _ => ErrorKind::Uncategorized,
     }
 }
 
-pub fn cvt(result: i32) -> crate::io::Result<usize> {
-    if result < 0 { Err(crate::io::Error::from_raw_os_error(-result)) } else { Ok(result as usize) }
+#[doc(hidden)]
+pub trait IsNegative {
+    fn is_negative(&self) -> bool;
+    fn negate(&self) -> i32;
+}
+
+macro_rules! impl_is_negative {
+    ($($t:ident)*) => ($(impl IsNegative for $t {
+        fn is_negative(&self) -> bool {
+            *self < 0
+        }
+
+        fn negate(&self) -> i32 {
+            i32::try_from(-(*self)).unwrap()
+        }
+    })*)
+}
+
+impl IsNegative for i32 {
+    fn is_negative(&self) -> bool {
+        *self < 0
+    }
+
+    fn negate(&self) -> i32 {
+        -(*self)
+    }
+}
+impl_is_negative! { i8 i16 i64 isize }
+
+pub fn cvt<T: IsNegative>(t: T) -> crate::io::Result<T> {
+    if t.is_negative() {
+        let e = decode_error_kind(t.negate());
+        Err(crate::io::Error::from(e))
+    } else {
+        Ok(t)
+    }
+}
+
+pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
+where
+    T: IsNegative,
+    F: FnMut() -> T,
+{
+    loop {
+        match cvt(f()) {
+            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+            other => return other,
+        }
+    }
 }
diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs
index 8a13879d8cc..5fb6281aa1e 100644
--- a/library/std/src/sys/hermit/net.rs
+++ b/library/std/src/sys/hermit/net.rs
@@ -1,490 +1,353 @@
-use crate::fmt;
-use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
-use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
-use crate::str;
-use crate::sync::Arc;
-use crate::sys::hermit::abi;
-use crate::sys::hermit::abi::IpAddress::{Ipv4, Ipv6};
-use crate::sys::unsupported;
-use crate::sys_common::AsInner;
+#![allow(dead_code)]
+
+use crate::cmp;
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::mem;
+use crate::net::{Shutdown, SocketAddr};
+use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
+use crate::sys::hermit::fd::FileDesc;
+use crate::sys::time::Instant;
+use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
+use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 
-/// Checks whether the HermitCore's socket interface has been started already, and
-/// if not, starts it.
-pub fn init() -> io::Result<()> {
-    if abi::network_init() < 0 {
-        return Err(io::const_io_error!(
-            ErrorKind::Uncategorized,
-            "Unable to initialize network interface",
-        ));
-    }
-
-    Ok(())
-}
-
-#[derive(Debug, Clone)]
-pub struct Socket(abi::Handle);
-
-impl AsInner<abi::Handle> for Socket {
-    fn as_inner(&self) -> &abi::Handle {
-        &self.0
-    }
-}
+use core::ffi::c_int;
 
-impl Drop for Socket {
-    fn drop(&mut self) {
-        let _ = abi::tcpstream::close(self.0);
-    }
-}
+#[allow(unused_extern_crates)]
+pub extern crate hermit_abi as netc;
 
-// Arc is used to count the number of used sockets.
-// Only if all sockets are released, the drop
-// method will close the socket.
-#[derive(Clone)]
-pub struct TcpStream(Arc<Socket>);
-
-impl TcpStream {
-    pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-        let addr = addr?;
-
-        match abi::tcpstream::connect(addr.ip().to_string().as_bytes(), addr.port(), None) {
-            Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
-            _ => Err(io::const_io_error!(
-                ErrorKind::Uncategorized,
-                "Unable to initiate a connection on a socket",
-            )),
-        }
-    }
+pub use crate::sys::{cvt, cvt_r};
 
-    pub fn connect_timeout(saddr: &SocketAddr, duration: Duration) -> io::Result<TcpStream> {
-        match abi::tcpstream::connect(
-            saddr.ip().to_string().as_bytes(),
-            saddr.port(),
-            Some(duration.as_millis() as u64),
-        ) {
-            Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
-            _ => Err(io::const_io_error!(
-                ErrorKind::Uncategorized,
-                "Unable to initiate a connection on a socket",
-            )),
-        }
-    }
+pub type wrlen_t = usize;
 
-    pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
-        abi::tcpstream::set_read_timeout(*self.0.as_inner(), duration.map(|d| d.as_millis() as u64))
-            .map_err(|_| {
-                io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value")
-            })
+pub fn cvt_gai(err: i32) -> io::Result<()> {
+    if err == 0 {
+        return Ok(());
     }
 
-    pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
-        abi::tcpstream::set_write_timeout(
-            *self.0.as_inner(),
-            duration.map(|d| d.as_millis() as u64),
-        )
-        .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value"))
-    }
+    let detail = "";
 
-    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner()).map_err(|_| {
-            io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
-        })?;
+    Err(io::Error::new(
+        io::ErrorKind::Uncategorized,
+        &format!("failed to lookup address information: {detail}")[..],
+    ))
+}
 
-        Ok(duration.map(|d| Duration::from_millis(d)))
+/// Checks whether the HermitCore's socket interface has been started already, and
+/// if not, starts it.
+pub fn init() {
+    if unsafe { netc::network_init() } < 0 {
+        panic!("Unable to initialize network interface");
     }
+}
 
-    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner()).map_err(|_| {
-            io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
-        })?;
+#[derive(Debug)]
+pub struct Socket(FileDesc);
 
-        Ok(duration.map(|d| Duration::from_millis(d)))
+impl Socket {
+    pub fn new(addr: &SocketAddr, ty: i32) -> io::Result<Socket> {
+        let fam = match *addr {
+            SocketAddr::V4(..) => netc::AF_INET,
+            SocketAddr::V6(..) => netc::AF_INET6,
+        };
+        Socket::new_raw(fam, ty)
     }
 
-    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
-        abi::tcpstream::peek(*self.0.as_inner(), buf)
-            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peek failed"))
+    pub fn new_raw(fam: i32, ty: i32) -> io::Result<Socket> {
+        let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?;
+        Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
     }
 
-    pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
-        self.read_vectored(&mut [IoSliceMut::new(buffer)])
+    pub fn new_pair(_fam: i32, _ty: i32) -> io::Result<(Socket, Socket)> {
+        unimplemented!()
     }
 
-    pub fn read_vectored(&self, ioslice: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        let mut size: usize = 0;
-
-        for i in ioslice.iter_mut() {
-            let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..]).map_err(|_| {
-                io::const_io_error!(ErrorKind::Uncategorized, "Unable to read on socket")
-            })?;
+    pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+        self.set_nonblocking(true)?;
+        let r = unsafe {
+            let (addr, len) = addr.into_inner();
+            cvt(netc::connect(self.as_raw_fd(), addr.as_ptr(), len))
+        };
+        self.set_nonblocking(false)?;
 
-            if ret != 0 {
-                size += ret;
-            }
+        match r {
+            Ok(_) => return Ok(()),
+            // there's no ErrorKind for EINPROGRESS :(
+            Err(ref e) if e.raw_os_error() == Some(netc::errno::EINPROGRESS) => {}
+            Err(e) => return Err(e),
         }
 
-        Ok(size)
-    }
-
-    #[inline]
-    pub fn is_read_vectored(&self) -> bool {
-        true
-    }
-
-    pub fn write(&self, buffer: &[u8]) -> io::Result<usize> {
-        self.write_vectored(&[IoSlice::new(buffer)])
-    }
+        let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
 
-    pub fn write_vectored(&self, ioslice: &[IoSlice<'_>]) -> io::Result<usize> {
-        let mut size: usize = 0;
-
-        for i in ioslice.iter() {
-            size += abi::tcpstream::write(*self.0.as_inner(), i).map_err(|_| {
-                io::const_io_error!(ErrorKind::Uncategorized, "Unable to write on socket")
-            })?;
+        if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+            return Err(io::const_io_error!(
+                io::ErrorKind::InvalidInput,
+                "cannot set a 0 duration timeout",
+            ));
         }
 
-        Ok(size)
-    }
-
-    #[inline]
-    pub fn is_write_vectored(&self) -> bool {
-        true
-    }
-
-    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner())
-            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"))?;
+        let start = Instant::now();
 
-        let saddr = match ipaddr {
-            Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
-            Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
-            _ => {
-                return Err(io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"));
+        loop {
+            let elapsed = start.elapsed();
+            if elapsed >= timeout {
+                return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
             }
-        };
-
-        Ok(saddr)
-    }
-
-    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        unsupported()
-    }
-
-    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
-        abi::tcpstream::shutdown(*self.0.as_inner(), how as i32)
-            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to shutdown socket"))
-    }
-
-    pub fn duplicate(&self) -> io::Result<TcpStream> {
-        Ok(self.clone())
-    }
-
-    pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
-        unsupported()
-    }
-
-    pub fn linger(&self) -> io::Result<Option<Duration>> {
-        unsupported()
-    }
-
-    pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
-        abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
-            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "set_nodelay failed"))
-    }
-
-    pub fn nodelay(&self) -> io::Result<bool> {
-        abi::tcpstream::nodelay(*self.0.as_inner())
-            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "nodelay failed"))
-    }
-
-    pub fn set_ttl(&self, tll: u32) -> io::Result<()> {
-        abi::tcpstream::set_tll(*self.0.as_inner(), tll)
-            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to set TTL"))
-    }
-
-    pub fn ttl(&self) -> io::Result<u32> {
-        abi::tcpstream::get_tll(*self.0.as_inner())
-            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to get TTL"))
-    }
 
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        unsupported()
-    }
-
-    pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> {
-        abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode).map_err(|_| {
-            io::const_io_error!(ErrorKind::Uncategorized, "unable to set blocking mode")
-        })
-    }
-}
-
-impl fmt::Debug for TcpStream {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Ok(())
-    }
-}
-
-#[derive(Clone)]
-pub struct TcpListener(SocketAddr);
-
-impl TcpListener {
-    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
-        let addr = addr?;
-
-        Ok(TcpListener(*addr))
-    }
-
-    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        Ok(self.0)
-    }
-
-    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
-        let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port())
-            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "accept failed"))?;
-        let saddr = match ipaddr {
-            Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
-            Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
-            _ => {
-                return Err(io::const_io_error!(ErrorKind::Uncategorized, "accept failed"));
+            let timeout = timeout - elapsed;
+            let mut timeout = timeout
+                .as_secs()
+                .saturating_mul(1_000)
+                .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
+            if timeout == 0 {
+                timeout = 1;
             }
-        };
-
-        Ok((TcpStream(Arc::new(Socket(handle))), saddr))
-    }
 
-    pub fn duplicate(&self) -> io::Result<TcpListener> {
-        Ok(self.clone())
-    }
-
-    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        unsupported()
-    }
-
-    pub fn ttl(&self) -> io::Result<u32> {
-        unsupported()
-    }
-
-    pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
-        unsupported()
+            let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
+
+            match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
+                -1 => {
+                    let err = io::Error::last_os_error();
+                    if err.kind() != io::ErrorKind::Interrupted {
+                        return Err(err);
+                    }
+                }
+                0 => {}
+                _ => {
+                    // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+                    // for POLLHUP rather than read readiness
+                    if pollfd.revents & netc::POLLHUP != 0 {
+                        let e = self.take_error()?.unwrap_or_else(|| {
+                            io::const_io_error!(
+                                io::ErrorKind::Uncategorized,
+                                "no error set after POLLHUP",
+                            )
+                        });
+                        return Err(e);
+                    }
+
+                    return Ok(());
+                }
+            }
+        }
     }
 
-    pub fn only_v6(&self) -> io::Result<bool> {
-        unsupported()
+    pub fn accept(
+        &self,
+        storage: *mut netc::sockaddr,
+        len: *mut netc::socklen_t,
+    ) -> io::Result<Socket> {
+        let fd = cvt(unsafe { netc::accept(self.0.as_raw_fd(), storage, len) })?;
+        Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
     }
 
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        unsupported()
+    pub fn duplicate(&self) -> io::Result<Socket> {
+        let fd = cvt(unsafe { netc::dup(self.0.as_raw_fd()) })?;
+        Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
     }
 
-    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        unsupported()
+    fn recv_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<usize> {
+        let ret =
+            cvt(unsafe { netc::recv(self.0.as_raw_fd(), buf.as_mut_ptr(), buf.len(), flags) })?;
+        Ok(ret as usize)
     }
-}
 
-impl fmt::Debug for TcpListener {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Ok(())
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.recv_with_flags(buf, 0)
     }
-}
-
-pub struct UdpSocket(abi::Handle);
 
-impl UdpSocket {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
-        unsupported()
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.recv_with_flags(buf, netc::MSG_PEEK)
     }
 
-    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        unsupported()
-    }
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        let mut size: isize = 0;
 
-    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        unsupported()
-    }
+        for i in bufs.iter_mut() {
+            let ret: isize =
+                cvt(unsafe { netc::read(self.0.as_raw_fd(), i.as_mut_ptr(), i.len()) })?;
 
-    pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-        unsupported()
-    }
+            if ret != 0 {
+                size += ret;
+            }
+        }
 
-    pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-        unsupported()
+        Ok(size.try_into().unwrap())
     }
 
-    pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
-        unsupported()
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        true
     }
 
-    pub fn duplicate(&self) -> io::Result<UdpSocket> {
-        unsupported()
-    }
+    fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> {
+        let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
+        let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
 
-    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        unsupported()
+        let n = cvt(unsafe {
+            netc::recvfrom(
+                self.as_raw_fd(),
+                buf.as_mut_ptr(),
+                buf.len(),
+                flags,
+                &mut storage as *mut _ as *mut _,
+                &mut addrlen,
+            )
+        })?;
+        Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
     }
 
-    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        unsupported()
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, 0)
     }
 
-    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        unsupported()
+    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, netc::MSG_PEEK)
     }
 
-    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        unsupported()
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let sz = cvt(unsafe { netc::write(self.0.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
+        Ok(sz.try_into().unwrap())
     }
 
-    pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
-        unsupported()
-    }
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let mut size: isize = 0;
 
-    pub fn broadcast(&self) -> io::Result<bool> {
-        unsupported()
-    }
+        for i in bufs.iter() {
+            size += cvt(unsafe { netc::write(self.0.as_raw_fd(), i.as_ptr(), i.len()) })?;
+        }
 
-    pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
-        unsupported()
+        Ok(size.try_into().unwrap())
     }
 
-    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
-        unsupported()
+    pub fn is_write_vectored(&self) -> bool {
+        true
     }
 
-    pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
-        unsupported()
-    }
+    pub fn set_timeout(&self, dur: Option<Duration>, kind: i32) -> io::Result<()> {
+        let timeout = match dur {
+            Some(dur) => {
+                if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+                    return Err(io::const_io_error!(
+                        io::ErrorKind::InvalidInput,
+                        "cannot set a 0 duration timeout",
+                    ));
+                }
+
+                let secs = if dur.as_secs() > netc::time_t::MAX as u64 {
+                    netc::time_t::MAX
+                } else {
+                    dur.as_secs() as netc::time_t
+                };
+                let mut timeout = netc::timeval {
+                    tv_sec: secs,
+                    tv_usec: dur.subsec_micros() as netc::suseconds_t,
+                };
+                if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+                    timeout.tv_usec = 1;
+                }
+                timeout
+            }
+            None => netc::timeval { tv_sec: 0, tv_usec: 0 },
+        };
 
-    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
-        unsupported()
+        setsockopt(self, netc::SOL_SOCKET, kind, timeout)
     }
 
-    pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
-        unsupported()
+    pub fn timeout(&self, kind: i32) -> io::Result<Option<Duration>> {
+        let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
+        if raw.tv_sec == 0 && raw.tv_usec == 0 {
+            Ok(None)
+        } else {
+            let sec = raw.tv_sec as u64;
+            let nsec = (raw.tv_usec as u32) * 1000;
+            Ok(Some(Duration::new(sec, nsec)))
+        }
     }
 
-    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
-        unsupported()
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        let how = match how {
+            Shutdown::Write => netc::SHUT_WR,
+            Shutdown::Read => netc::SHUT_RD,
+            Shutdown::Both => netc::SHUT_RDWR,
+        };
+        cvt(unsafe { netc::shutdown_socket(self.as_raw_fd(), how) })?;
+        Ok(())
     }
 
-    pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
-        unsupported()
-    }
+    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+        let linger = netc::linger {
+            l_onoff: linger.is_some() as i32,
+            l_linger: linger.unwrap_or_default().as_secs() as libc::c_int,
+        };
 
-    pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
-        unsupported()
+        setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger)
     }
 
-    pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
-        unsupported()
-    }
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?;
 
-    pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
-        unsupported()
+        Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
     }
 
-    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        unsupported()
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        let value: i32 = if nodelay { 1 } else { 0 };
+        setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, value)
     }
 
-    pub fn ttl(&self) -> io::Result<u32> {
-        unsupported()
+    pub fn nodelay(&self) -> io::Result<bool> {
+        let raw: i32 = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
+        Ok(raw != 0)
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        let mut nonblocking: i32 = if nonblocking { 1 } else { 0 };
+        cvt(unsafe {
+            netc::ioctl(
+                self.as_raw_fd(),
+                netc::FIONBIO,
+                &mut nonblocking as *mut _ as *mut core::ffi::c_void,
+            )
+        })
+        .map(drop)
     }
 
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        unsupported()
-    }
-
-    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        unsupported()
-    }
-
-    pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
-        unsupported()
-    }
-
-    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
-        unsupported()
+        unimplemented!()
     }
 
-    pub fn send(&self, _: &[u8]) -> io::Result<usize> {
-        unsupported()
-    }
-
-    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
-        unsupported()
+    // This is used by sys_common code to abstract over Windows and Unix.
+    pub fn as_raw(&self) -> RawFd {
+        self.0.as_raw_fd()
     }
 }
 
-impl fmt::Debug for UdpSocket {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Ok(())
+impl AsInner<FileDesc> for Socket {
+    fn as_inner(&self) -> &FileDesc {
+        &self.0
     }
 }
 
-pub struct LookupHost(!);
-
-impl LookupHost {
-    pub fn port(&self) -> u16 {
+impl IntoInner<FileDesc> for Socket {
+    fn into_inner(self) -> FileDesc {
         self.0
     }
 }
 
-impl Iterator for LookupHost {
-    type Item = SocketAddr;
-    fn next(&mut self) -> Option<SocketAddr> {
-        self.0
+impl FromInner<FileDesc> for Socket {
+    fn from_inner(file_desc: FileDesc) -> Self {
+        Self(file_desc)
     }
 }
 
-impl TryFrom<&str> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: &str) -> io::Result<LookupHost> {
-        unsupported()
+impl AsFd for Socket {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
     }
 }
 
-impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
-        unsupported()
+impl AsRawFd for Socket {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
     }
 }
-
-#[allow(nonstandard_style)]
-pub mod netc {
-    pub const AF_INET: u8 = 0;
-    pub const AF_INET6: u8 = 1;
-    pub type sa_family_t = u8;
-
-    #[derive(Copy, Clone)]
-    pub struct in_addr {
-        pub s_addr: u32,
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr_in {
-        pub sin_family: sa_family_t,
-        pub sin_port: u16,
-        pub sin_addr: in_addr,
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct in6_addr {
-        pub s6_addr: [u8; 16],
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr_in6 {
-        pub sin6_family: sa_family_t,
-        pub sin6_port: u16,
-        pub sin6_addr: in6_addr,
-        pub sin6_flowinfo: u32,
-        pub sin6_scope_id: u32,
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr {}
-}
diff --git a/library/std/src/sys/hermit/os.rs b/library/std/src/sys/hermit/os.rs
index 8f927df85be..e53dbae6119 100644
--- a/library/std/src/sys/hermit/os.rs
+++ b/library/std/src/sys/hermit/os.rs
@@ -4,7 +4,7 @@ use crate::ffi::{CStr, OsStr, OsString};
 use crate::fmt;
 use crate::io;
 use crate::marker::PhantomData;
-use crate::os::unix::ffi::OsStringExt;
+use crate::os::hermit::ffi::OsStringExt;
 use crate::path::{self, PathBuf};
 use crate::str;
 use crate::sync::Mutex;
diff --git a/library/std/src/sys/hermit/time.rs b/library/std/src/sys/hermit/time.rs
index c17e6c8af62..32ddc4346ee 100644
--- a/library/std/src/sys/hermit/time.rs
+++ b/library/std/src/sys/hermit/time.rs
@@ -1,6 +1,7 @@
 #![allow(dead_code)]
 
 use crate::cmp::Ordering;
+use crate::ops::{Add, AddAssign, Sub, SubAssign};
 use crate::sys::hermit::abi;
 use crate::sys::hermit::abi::timespec;
 use crate::sys::hermit::abi::{CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
@@ -102,55 +103,122 @@ impl Hash for Timespec {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct Instant {
-    t: Timespec,
-}
+pub struct Instant(Timespec);
 
 impl Instant {
     pub fn now() -> Instant {
         let mut time: Timespec = Timespec::zero();
         let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, &mut time.t as *mut timespec) };
 
-        Instant { t: time }
+        Instant(time)
+    }
+
+    #[stable(feature = "time2", since = "1.8.0")]
+    pub fn elapsed(&self) -> Duration {
+        Instant::now() - *self
+    }
+
+    pub fn duration_since(&self, earlier: Instant) -> Duration {
+        self.checked_duration_since(earlier).unwrap_or_default()
+    }
+
+    pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
+        self.checked_sub_instant(&earlier)
     }
 
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
-        self.t.sub_timespec(&other.t).ok()
+        self.0.sub_timespec(&other.0).ok()
     }
 
     pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
-        Some(Instant { t: self.t.checked_add_duration(other)? })
+        Some(Instant(self.0.checked_add_duration(other)?))
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
-        Some(Instant { t: self.t.checked_sub_duration(other)? })
+        Some(Instant(self.0.checked_sub_duration(other)?))
+    }
+
+    pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
+        self.0.checked_add_duration(&duration).map(Instant)
+    }
+
+    pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
+        self.0.checked_sub_duration(&duration).map(Instant)
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-pub struct SystemTime {
-    t: Timespec,
+impl Add<Duration> for Instant {
+    type Output = Instant;
+
+    /// # Panics
+    ///
+    /// This function may panic if the resulting point in time cannot be represented by the
+    /// underlying data structure. See [`Instant::checked_add`] for a version without panic.
+    fn add(self, other: Duration) -> Instant {
+        self.checked_add(other).expect("overflow when adding duration to instant")
+    }
 }
 
-pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
+impl AddAssign<Duration> for Instant {
+    fn add_assign(&mut self, other: Duration) {
+        *self = *self + other;
+    }
+}
+
+impl Sub<Duration> for Instant {
+    type Output = Instant;
+
+    fn sub(self, other: Duration) -> Instant {
+        self.checked_sub(other).expect("overflow when subtracting duration from instant")
+    }
+}
+
+impl SubAssign<Duration> for Instant {
+    fn sub_assign(&mut self, other: Duration) {
+        *self = *self - other;
+    }
+}
+
+impl Sub<Instant> for Instant {
+    type Output = Duration;
+
+    /// Returns the amount of time elapsed from another instant to this one,
+    /// or zero duration if that instant is later than this one.
+    ///
+    /// # Panics
+    ///
+    /// Previous rust versions panicked when `other` was later than `self`. Currently this
+    /// method saturates. Future versions may reintroduce the panic in some circumstances.
+    /// See [Monotonicity].
+    ///
+    /// [Monotonicity]: Instant#monotonicity
+    fn sub(self, other: Instant) -> Duration {
+        self.duration_since(other)
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct SystemTime(Timespec);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
 
 impl SystemTime {
     pub fn now() -> SystemTime {
         let mut time: Timespec = Timespec::zero();
         let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, &mut time.t as *mut timespec) };
 
-        SystemTime { t: time }
+        SystemTime(time)
     }
 
     pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        self.t.sub_timespec(&other.t)
+        self.0.sub_timespec(&other.0)
     }
 
     pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime { t: self.t.checked_add_duration(other)? })
+        Some(SystemTime(self.0.checked_add_duration(other)?))
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+        Some(SystemTime(self.0.checked_sub_duration(other)?))
     }
 }
diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs
index 6741ae46d32..30356fa8519 100644
--- a/library/std/src/sys/windows/args.rs
+++ b/library/std/src/sys/windows/args.rs
@@ -270,7 +270,7 @@ pub(crate) fn make_bat_command_line(
     // It is necessary to surround the command in an extra pair of quotes,
     // hence the trailing quote here. It will be closed after all arguments
     // have been added.
-    let mut cmd: Vec<u16> = "cmd.exe /c \"".encode_utf16().collect();
+    let mut cmd: Vec<u16> = "cmd.exe /d /c \"".encode_utf16().collect();
 
     // Push the script name surrounded by its quote pair.
     cmd.push(b'"' as u16);
@@ -290,6 +290,15 @@ pub(crate) fn make_bat_command_line(
     // reconstructed by the batch script by default.
     for arg in args {
         cmd.push(' ' as u16);
+        // Make sure to always quote special command prompt characters, including:
+        // * Characters `cmd /?` says require quotes.
+        // * `%` for environment variables, as in `%TMP%`.
+        // * `|<>` pipe/redirect characters.
+        const SPECIAL: &[u8] = b"\t &()[]{}^=;!'+,`~%|<>";
+        let force_quotes = match arg {
+            Arg::Regular(arg) if !force_quotes => arg.bytes().iter().any(|c| SPECIAL.contains(c)),
+            _ => force_quotes,
+        };
         append_arg(&mut cmd, arg, force_quotes)?;
     }
 
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index f58dcf1287b..5d150eca00e 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -6,13 +6,15 @@
 
 use crate::ffi::CStr;
 use crate::mem;
-use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort};
+use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort};
 use crate::os::windows::io::{BorrowedHandle, HandleOrInvalid, HandleOrNull};
 use crate::ptr;
 use core::ffi::NonZero_c_ulong;
 
 use libc::{c_void, size_t, wchar_t};
 
+pub use crate::os::raw::c_int;
+
 #[path = "c/errors.rs"] // c.rs is included from two places so we need to specify this
 mod errors;
 pub use errors::*;
@@ -47,16 +49,19 @@ pub type ACCESS_MASK = DWORD;
 
 pub type LPBOOL = *mut BOOL;
 pub type LPBYTE = *mut BYTE;
+pub type LPCCH = *const CHAR;
 pub type LPCSTR = *const CHAR;
+pub type LPCWCH = *const WCHAR;
 pub type LPCWSTR = *const WCHAR;
+pub type LPCVOID = *const c_void;
 pub type LPDWORD = *mut DWORD;
 pub type LPHANDLE = *mut HANDLE;
 pub type LPOVERLAPPED = *mut OVERLAPPED;
 pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
 pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
 pub type LPSTARTUPINFO = *mut STARTUPINFO;
+pub type LPSTR = *mut CHAR;
 pub type LPVOID = *mut c_void;
-pub type LPCVOID = *const c_void;
 pub type LPWCH = *mut WCHAR;
 pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
 pub type LPWSADATA = *mut WSADATA;
@@ -132,6 +137,10 @@ pub const MAX_PATH: usize = 260;
 
 pub const FILE_TYPE_PIPE: u32 = 3;
 
+pub const CP_UTF8: DWORD = 65001;
+pub const MB_ERR_INVALID_CHARS: DWORD = 0x08;
+pub const WC_ERR_INVALID_CHARS: DWORD = 0x80;
+
 #[repr(C)]
 #[derive(Copy)]
 pub struct WIN32_FIND_DATAW {
@@ -539,14 +548,6 @@ pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
     pub PathBuffer: WCHAR,
 }
 
-/// NB: Use carefully! In general using this as a reference is likely to get the
-/// provenance wrong for the `PathBuffer` field!
-#[repr(C)]
-pub struct FILE_NAME_INFO {
-    pub FileNameLength: DWORD,
-    pub FileName: [WCHAR; 1],
-}
-
 #[repr(C)]
 pub struct MOUNT_POINT_REPARSE_BUFFER {
     pub SubstituteNameOffset: c_ushort,
@@ -1155,6 +1156,25 @@ extern "system" {
         lpFilePart: *mut LPWSTR,
     ) -> DWORD;
     pub fn GetFileAttributesW(lpFileName: LPCWSTR) -> DWORD;
+
+    pub fn MultiByteToWideChar(
+        CodePage: UINT,
+        dwFlags: DWORD,
+        lpMultiByteStr: LPCCH,
+        cbMultiByte: c_int,
+        lpWideCharStr: LPWSTR,
+        cchWideChar: c_int,
+    ) -> c_int;
+    pub fn WideCharToMultiByte(
+        CodePage: UINT,
+        dwFlags: DWORD,
+        lpWideCharStr: LPCWCH,
+        cchWideChar: c_int,
+        lpMultiByteStr: LPSTR,
+        cbMultiByte: c_int,
+        lpDefaultChar: LPCCH,
+        lpUsedDefaultChar: LPBOOL,
+    ) -> c_int;
 }
 
 #[link(name = "ws2_32")]
diff --git a/library/std/src/sys/windows/io.rs b/library/std/src/sys/windows/io.rs
index 2cc34c986b9..7fdd1f702e2 100644
--- a/library/std/src/sys/windows/io.rs
+++ b/library/std/src/sys/windows/io.rs
@@ -2,8 +2,7 @@ use crate::marker::PhantomData;
 use crate::mem::size_of;
 use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle};
 use crate::slice;
-use crate::sys::{c, Align8};
-use core;
+use crate::sys::c;
 use libc;
 
 #[derive(Copy, Clone)]
@@ -125,22 +124,33 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool {
         return false;
     }
 
-    const SIZE: usize = size_of::<c::FILE_NAME_INFO>() + c::MAX_PATH * size_of::<c::WCHAR>();
-    let mut name_info_bytes = Align8([0u8; SIZE]);
+    /// Mirrors [`FILE_NAME_INFO`], giving it a fixed length that we can stack
+    /// allocate
+    ///
+    /// [`FILE_NAME_INFO`]: https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_name_info
+    #[repr(C)]
+    #[allow(non_snake_case)]
+    struct FILE_NAME_INFO {
+        FileNameLength: u32,
+        FileName: [u16; c::MAX_PATH as usize],
+    }
+    let mut name_info = FILE_NAME_INFO { FileNameLength: 0, FileName: [0; c::MAX_PATH as usize] };
+    // Safety: buffer length is fixed.
     let res = c::GetFileInformationByHandleEx(
         handle,
         c::FileNameInfo,
-        name_info_bytes.0.as_mut_ptr() as *mut libc::c_void,
-        SIZE as u32,
+        &mut name_info as *mut _ as *mut libc::c_void,
+        size_of::<FILE_NAME_INFO>() as u32,
     );
     if res == 0 {
         return false;
     }
-    let name_info: &c::FILE_NAME_INFO = &*(name_info_bytes.0.as_ptr() as *const c::FILE_NAME_INFO);
-    let name_len = name_info.FileNameLength as usize / 2;
-    // Offset to get the `FileName` field.
-    let name_ptr = name_info_bytes.0.as_ptr().offset(size_of::<c::DWORD>() as isize).cast::<u16>();
-    let s = core::slice::from_raw_parts(name_ptr, name_len);
+
+    // Use `get` because `FileNameLength` can be out of range.
+    let s = match name_info.FileName.get(..name_info.FileNameLength as usize / 2) {
+        None => return false,
+        Some(s) => s,
+    };
     let name = String::from_utf16_lossy(s);
     // Get the file name only.
     let name = name.rsplit('\\').next().unwrap_or(&name);
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index c2cd48470bd..32c6ccffb7a 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -169,14 +169,27 @@ fn write(
 }
 
 fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usize> {
+    debug_assert!(!utf8.is_empty());
+
     let mut utf16 = [MaybeUninit::<u16>::uninit(); MAX_BUFFER_SIZE / 2];
-    let mut len_utf16 = 0;
-    for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) {
-        *dest = MaybeUninit::new(chr);
-        len_utf16 += 1;
-    }
-    // Safety: We've initialized `len_utf16` values.
-    let utf16: &[u16] = unsafe { MaybeUninit::slice_assume_init_ref(&utf16[..len_utf16]) };
+    let utf8 = &utf8[..utf8.floor_char_boundary(utf16.len())];
+
+    let utf16: &[u16] = unsafe {
+        // Note that this theoretically checks validity twice in the (most common) case
+        // where the underlying byte sequence is valid utf-8 (given the check in `write()`).
+        let result = c::MultiByteToWideChar(
+            c::CP_UTF8,                      // CodePage
+            c::MB_ERR_INVALID_CHARS,         // dwFlags
+            utf8.as_ptr() as c::LPCCH,       // lpMultiByteStr
+            utf8.len() as c::c_int,          // cbMultiByte
+            utf16.as_mut_ptr() as c::LPWSTR, // lpWideCharStr
+            utf16.len() as c::c_int,         // cchWideChar
+        );
+        assert!(result != 0, "Unexpected error in MultiByteToWideChar");
+
+        // Safety: MultiByteToWideChar initializes `result` values.
+        MaybeUninit::slice_assume_init_ref(&utf16[..result as usize])
+    };
 
     let mut written = write_u16s(handle, &utf16)?;
 
@@ -189,8 +202,8 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
         // a missing surrogate can be produced (and also because of the UTF-8 validation above),
         // write the missing surrogate out now.
         // Buffering it would mean we have to lie about the number of bytes written.
-        let first_char_remaining = utf16[written];
-        if first_char_remaining >= 0xDCEE && first_char_remaining <= 0xDFFF {
+        let first_code_unit_remaining = utf16[written];
+        if first_code_unit_remaining >= 0xDCEE && first_code_unit_remaining <= 0xDFFF {
             // low surrogate
             // We just hope this works, and give up otherwise
             let _ = write_u16s(handle, &utf16[written..written + 1]);
@@ -212,6 +225,7 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
 }
 
 fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
+    debug_assert!(data.len() < u32::MAX as usize);
     let mut written = 0;
     cvt(unsafe {
         c::WriteConsoleW(
@@ -365,26 +379,32 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz
     Ok(amount as usize)
 }
 
-#[allow(unused)]
 fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> {
-    let mut written = 0;
-    for chr in char::decode_utf16(utf16.iter().cloned()) {
-        match chr {
-            Ok(chr) => {
-                chr.encode_utf8(&mut utf8[written..]);
-                written += chr.len_utf8();
-            }
-            Err(_) => {
-                // We can't really do any better than forget all data and return an error.
-                return Err(io::const_io_error!(
-                    io::ErrorKind::InvalidData,
-                    "Windows stdin in console mode does not support non-UTF-16 input; \
-                     encountered unpaired surrogate",
-                ));
-            }
-        }
+    debug_assert!(utf16.len() <= c::c_int::MAX as usize);
+    debug_assert!(utf8.len() <= c::c_int::MAX as usize);
+
+    let result = unsafe {
+        c::WideCharToMultiByte(
+            c::CP_UTF8,                    // CodePage
+            c::WC_ERR_INVALID_CHARS,       // dwFlags
+            utf16.as_ptr(),                // lpWideCharStr
+            utf16.len() as c::c_int,       // cchWideChar
+            utf8.as_mut_ptr() as c::LPSTR, // lpMultiByteStr
+            utf8.len() as c::c_int,        // cbMultiByte
+            ptr::null(),                   // lpDefaultChar
+            ptr::null_mut(),               // lpUsedDefaultChar
+        )
+    };
+    if result == 0 {
+        // We can't really do any better than forget all data and return an error.
+        Err(io::const_io_error!(
+            io::ErrorKind::InvalidData,
+            "Windows stdin in console mode does not support non-UTF-16 input; \
+            encountered unpaired surrogate",
+        ))
+    } else {
+        Ok(result as usize)
     }
-    Ok(written)
 }
 
 impl IncompleteUtf8 {
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 6b24b0e9aa8..e9c727cbbd1 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -44,7 +44,6 @@ cfg_if::cfg_if! {
 
 cfg_if::cfg_if! {
     if #[cfg(any(target_os = "l4re",
-                 target_os = "hermit",
                  feature = "restricted-std",
                  all(target_family = "wasm", not(target_os = "emscripten")),
                  all(target_vendor = "fortanix", target_env = "sgx")))] {
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index acf9c29083f..5c2e9da70fb 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -352,7 +352,7 @@ impl Instant {
         self.checked_duration_since(earlier).unwrap_or_default()
     }
 
-    /// Returns the amount of time elapsed since this instant was created.
+    /// Returns the amount of time elapsed since this instant.
     ///
     /// # Panics
     ///
@@ -525,8 +525,8 @@ impl SystemTime {
         self.0.sub_time(&earlier.0).map_err(SystemTimeError)
     }
 
-    /// Returns the difference between the clock time when this
-    /// system time was created, and the current clock time.
+    /// Returns the difference from this system time to the
+    /// current clock time.
     ///
     /// This function may fail as the underlying system clock is susceptible to
     /// drift and updates (e.g., the system clock could go backwards), so this
diff --git a/library/std/tests/common/mod.rs b/library/std/tests/common/mod.rs
new file mode 100644
index 00000000000..fce220223a0
--- /dev/null
+++ b/library/std/tests/common/mod.rs
@@ -0,0 +1,58 @@
+#![allow(unused)]
+
+use std::env;
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::thread;
+use rand::RngCore;
+
+/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
+/// seed not being the same for every RNG invocation too.
+#[track_caller]
+pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
+    use core::hash::{BuildHasher, Hash, Hasher};
+    let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
+    core::panic::Location::caller().hash(&mut hasher);
+    let hc64 = hasher.finish();
+    let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
+    let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
+    rand::SeedableRng::from_seed(seed)
+}
+
+// Copied from std::sys_common::io
+pub struct TempDir(PathBuf);
+
+impl TempDir {
+    pub fn join(&self, path: &str) -> PathBuf {
+        let TempDir(ref p) = *self;
+        p.join(path)
+    }
+
+    pub fn path(&self) -> &Path {
+        let TempDir(ref p) = *self;
+        p
+    }
+}
+
+impl Drop for TempDir {
+    fn drop(&mut self) {
+        // Gee, seeing how we're testing the fs module I sure hope that we
+        // at least implement this correctly!
+        let TempDir(ref p) = *self;
+        let result = fs::remove_dir_all(p);
+        // Avoid panicking while panicking as this causes the process to
+        // immediately abort, without displaying test results.
+        if !thread::panicking() {
+            result.unwrap();
+        }
+    }
+}
+
+#[track_caller] // for `test_rng`
+pub fn tmpdir() -> TempDir {
+    let p = env::temp_dir();
+    let mut r = test_rng();
+    let ret = p.join(&format!("rust-{}", r.next_u32()));
+    fs::create_dir(&ret).unwrap();
+    TempDir(ret)
+}
diff --git a/library/std/tests/create_dir_all_bare.rs b/library/std/tests/create_dir_all_bare.rs
new file mode 100644
index 00000000000..fe789323f97
--- /dev/null
+++ b/library/std/tests/create_dir_all_bare.rs
@@ -0,0 +1,39 @@
+#![cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))]
+
+//! Note that this test changes the current directory so
+//! should not be in the same process as other tests.
+use std::env;
+use std::fs;
+use std::path::{Path, PathBuf};
+
+mod common;
+
+// On some platforms, setting the current directory will prevent deleting it.
+// So this helper ensures the current directory is reset.
+struct CurrentDir(PathBuf);
+impl CurrentDir {
+    fn new() -> Self {
+        Self(env::current_dir().unwrap())
+    }
+    fn set(&self, path: &Path) {
+        env::set_current_dir(path).unwrap();
+    }
+    fn with(path: &Path, f: impl FnOnce()) {
+        let current_dir = Self::new();
+        current_dir.set(path);
+        f();
+    }
+}
+impl Drop for CurrentDir {
+    fn drop(&mut self) {
+        env::set_current_dir(&self.0).unwrap();
+    }
+}
+
+#[test]
+fn create_dir_all_bare() {
+    let tmpdir = common::tmpdir();
+    CurrentDir::with(tmpdir.path(), || {
+        fs::create_dir_all("create-dir-all-bare").unwrap();
+    });
+}
diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs
index aae2c49d898..96b4f372b8b 100644
--- a/library/std/tests/env.rs
+++ b/library/std/tests/env.rs
@@ -3,18 +3,8 @@ use std::ffi::{OsStr, OsString};
 
 use rand::distributions::{Alphanumeric, DistString};
 
-/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
-/// seed not being the same for every RNG invocation too.
-#[track_caller]
-pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
-    use core::hash::{BuildHasher, Hash, Hasher};
-    let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
-    core::panic::Location::caller().hash(&mut hasher);
-    let hc64 = hasher.finish();
-    let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
-    let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
-    rand::SeedableRng::from_seed(seed)
-}
+mod common;
+use common::test_rng;
 
 #[track_caller]
 fn make_rand_name() -> OsString {
diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml
index 61b6f33bce0..18cb023d274 100644
--- a/library/test/Cargo.toml
+++ b/library/test/Cargo.toml
@@ -7,11 +7,9 @@ edition = "2021"
 crate-type = ["dylib", "rlib"]
 
 [dependencies]
-cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
 getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] }
 std = { path = "../std" }
 core = { path = "../core" }
-libc = { version = "0.2", default-features = false }
 panic_unwind = { path = "../panic_unwind" }
 panic_abort = { path = "../panic_abort" }
 
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 4a0ba592577..e861d520c53 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -50,6 +50,7 @@ dependencies = [
  "opener",
  "pretty_assertions",
  "serde",
+ "serde_derive",
  "serde_json",
  "sha2",
  "sysinfo",
@@ -564,9 +565,6 @@ name = "serde"
 version = "1.0.137"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
-dependencies = [
- "serde_derive",
-]
 
 [[package]]
 name = "serde_derive"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 22ceeca941e..663987f113c 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -39,7 +39,10 @@ cc = "1.0.69"
 libc = "0.2"
 hex = "0.4"
 object = { version = "0.29.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }
-serde = { version = "1.0.8", features = ["derive"] }
+serde = "1.0.137"
+# Directly use serde_derive rather than through the derive feature of serde to allow building both
+# in parallel and to allow serde_json and toml to start building as soon as serde has been built.
+serde_derive = "1.0.137"
 serde_json = "1.0.2"
 sha2 = "0.10"
 tar = "0.4"
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 952c70cec1c..b33fc02f49c 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -792,7 +792,7 @@ impl<'a> Builder<'a> {
                 run::CollectLicenseMetadata,
                 run::GenerateCopyright,
             ),
-            Kind::Setup => describe!(setup::Profile),
+            Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode),
             Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std),
             // special-cased in Build::build()
             Kind::Format => vec![],
@@ -1915,6 +1915,13 @@ impl<'a> Builder<'a> {
             }
         }
 
+        if matches!(mode, Mode::Std) {
+            if let Some(mir_opt_level) = self.config.rust_validate_mir_opts {
+                rustflags.arg("-Zvalidate-mir");
+                rustflags.arg(&format!("-Zmir-opt-level={}", mir_opt_level));
+            }
+        }
+
         Cargo { command: cargo, rustflags, rustdocflags, allow_features }
     }
 
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index ff7821fb9ff..cd19667139a 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -105,10 +105,15 @@ impl Step for Std {
             cargo.arg("--lib");
         }
 
-        builder.info(&format!(
-            "Checking stage{} library artifacts ({} -> {})",
-            builder.top_stage, &compiler.host, target
-        ));
+        let msg = if compiler.host == target {
+            format!("Checking stage{} library artifacts ({target})", builder.top_stage)
+        } else {
+            format!(
+                "Checking stage{} library artifacts ({} -> {})",
+                builder.top_stage, &compiler.host, target
+            )
+        };
+        builder.info(&msg);
         run_cargo(
             builder,
             cargo,
@@ -162,10 +167,18 @@ impl Step for Std {
             cargo.arg("-p").arg(krate.name);
         }
 
-        builder.info(&format!(
-            "Checking stage{} library test/bench/example targets ({} -> {})",
-            builder.top_stage, &compiler.host, target
-        ));
+        let msg = if compiler.host == target {
+            format!(
+                "Checking stage{} library test/bench/example targets ({target})",
+                builder.top_stage
+            )
+        } else {
+            format!(
+                "Checking stage{} library test/bench/example targets ({} -> {})",
+                builder.top_stage, &compiler.host, target
+            )
+        };
+        builder.info(&msg);
         run_cargo(
             builder,
             cargo,
@@ -239,10 +252,15 @@ impl Step for Rustc {
             cargo.arg("-p").arg(krate.name);
         }
 
-        builder.info(&format!(
-            "Checking stage{} compiler artifacts ({} -> {})",
-            builder.top_stage, &compiler.host, target
-        ));
+        let msg = if compiler.host == target {
+            format!("Checking stage{} compiler artifacts ({target})", builder.top_stage)
+        } else {
+            format!(
+                "Checking stage{} compiler artifacts ({} -> {})",
+                builder.top_stage, &compiler.host, target
+            )
+        };
+        builder.info(&msg);
         run_cargo(
             builder,
             cargo,
@@ -299,10 +317,15 @@ impl Step for CodegenBackend {
             .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
         rustc_cargo_env(builder, &mut cargo, target);
 
-        builder.info(&format!(
-            "Checking stage{} {} artifacts ({} -> {})",
-            builder.top_stage, backend, &compiler.host.triple, target.triple
-        ));
+        let msg = if compiler.host == target {
+            format!("Checking stage{} {} artifacts ({target})", builder.top_stage, backend)
+        } else {
+            format!(
+                "Checking stage{} {} library ({} -> {})",
+                builder.top_stage, backend, &compiler.host.triple, target.triple
+            )
+        };
+        builder.info(&msg);
 
         run_cargo(
             builder,
@@ -362,10 +385,15 @@ impl Step for RustAnalyzer {
             cargo.arg("--benches");
         }
 
-        builder.info(&format!(
-            "Checking stage{} {} artifacts ({} -> {})",
-            compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
-        ));
+        let msg = if compiler.host == target {
+            format!("Checking stage{} {} artifacts ({target})", compiler.stage, "rust-analyzer")
+        } else {
+            format!(
+                "Checking stage{} {} artifacts ({} -> {})",
+                compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
+            )
+        };
+        builder.info(&msg);
         run_cargo(
             builder,
             cargo,
@@ -432,14 +460,18 @@ macro_rules! tool_check_step {
                 // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
                 // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
                 cargo.rustflag("-Zunstable-options");
-
-                builder.info(&format!(
-                    "Checking stage{} {} artifacts ({} -> {})",
-                    builder.top_stage,
-                    stringify!($name).to_lowercase(),
-                    &compiler.host.triple,
-                    target.triple
-                ));
+                let msg = if compiler.host == target {
+                    format!("Checking stage{} {} artifacts ({target})", builder.top_stage, stringify!($name).to_lowercase())
+                } else {
+                    format!(
+                        "Checking stage{} {} artifacts ({} -> {})",
+                        builder.top_stage,
+                        stringify!($name).to_lowercase(),
+                        &compiler.host.triple,
+                        target.triple
+                    )
+                };
+                builder.info(&msg);
                 run_cargo(
                     builder,
                     cargo,
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 348d22a9ce6..8b80dfc0f9b 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -16,7 +16,7 @@ use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 use std::str;
 
-use serde::Deserialize;
+use serde_derive::Deserialize;
 
 use crate::builder::crate_description;
 use crate::builder::Cargo;
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 56f96734bbb..05e74254949 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -25,6 +25,7 @@ use crate::flags::{Color, Flags};
 use crate::util::{exe, output, t};
 use once_cell::sync::OnceCell;
 use serde::{Deserialize, Deserializer};
+use serde_derive::Deserialize;
 
 macro_rules! check_ci_llvm {
     ($name:expr) => {
@@ -173,6 +174,7 @@ pub struct Config {
     pub rust_profile_use: Option<String>,
     pub rust_profile_generate: Option<String>,
     pub rust_lto: RustcLto,
+    pub rust_validate_mir_opts: Option<u32>,
     pub llvm_profile_use: Option<String>,
     pub llvm_profile_generate: bool,
     pub llvm_libunwind_default: Option<LlvmLibunwind>,
@@ -770,6 +772,7 @@ define_config! {
         // ignored; this is set from an env var set by bootstrap.py
         download_rustc: Option<StringOrBool> = "download-rustc",
         lto: Option<String> = "lto",
+        validate_mir_opts: Option<u32> = "validate-mir-opts",
     }
 }
 
@@ -1149,6 +1152,7 @@ impl Config {
                 .as_deref()
                 .map(|value| RustcLto::from_str(value).unwrap())
                 .unwrap_or_default();
+            config.rust_validate_mir_opts = rust.validate_mir_opts;
         } else {
             config.rust_profile_use = flags.rust_profile_use;
             config.rust_profile_generate = flags.rust_profile_generate;
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 0af329e7007..04e798e3949 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -379,8 +379,14 @@ cur_section = None
 sections[None] = []
 section_order = [None]
 targets = {}
+top_level_keys = []
 
 for line in open(rust_dir + '/config.toml.example').read().split("\n"):
+    if cur_section == None:
+        if line.count('=') == 1:
+            top_level_key = line.split('=')[0]
+            top_level_key = top_level_key.strip(' #')
+            top_level_keys.append(top_level_key)
     if line.startswith('['):
         cur_section = line[1:-1]
         if cur_section.startswith('target'):
@@ -459,12 +465,22 @@ def configure_section(lines, config):
                 raise RuntimeError("failed to find config line for {}".format(key))
 
 
-for section_key in config:
-    section_config = config[section_key]
-    if section_key not in sections:
-        raise RuntimeError("config key {} not in sections".format(section_key))
+def configure_top_level_key(lines, top_level_key, value):
+    for i, line in enumerate(lines):
+        if line.startswith('#' + top_level_key + ' = ') or line.startswith(top_level_key + ' = '):
+            lines[i] = "{} = {}".format(top_level_key, value)
+            return
 
-    if section_key == 'target':
+    raise RuntimeError("failed to find config line for {}".format(top_level_key))
+
+
+for section_key, section_config in config.items():
+    if section_key not in sections and section_key not in top_level_keys:
+        raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key))
+    if section_key in top_level_keys:
+        configure_top_level_key(sections[None], section_key, section_config)
+
+    elif  section_key == 'target':
         for target in section_config:
             configure_section(targets[target], section_config[target])
     else:
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index f07e710a9e6..9d1504c34e8 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -554,7 +554,8 @@ Arguments:
             Kind::Setup => {
                 subcommand_help.push_str(&format!(
                     "\n
-x.py setup creates a `config.toml` which changes the defaults for x.py itself.
+x.py setup creates a `config.toml` which changes the defaults for x.py itself,
+as well as setting up a git pre-push hook, VS code config and toolchain link.
 
 Arguments:
     This subcommand accepts a 'profile' to use for builds. For example:
@@ -564,7 +565,13 @@ Arguments:
     The profile is optional and you will be prompted interactively if it is not given.
     The following profiles are available:
 
-{}",
+{}
+
+    To only set up the git hook, VS code or toolchain link, you may use
+        ./x.py setup hook
+        ./x.py setup vscode
+        ./x.py setup link
+",
                     Profile::all_for_help("        ").trim_end()
                 ));
             }
@@ -638,7 +645,7 @@ Arguments:
             }
             Kind::Setup => {
                 let profile = if paths.len() > 1 {
-                    eprintln!("\nerror: At most one profile can be passed to setup\n");
+                    eprintln!("\nerror: At most one option can be passed to setup\n");
                     usage(1, &opts, verbose, &subcommand_help)
                 } else if let Some(path) = paths.pop() {
                     let profile_string = t!(path.into_os_string().into_string().map_err(
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index 615794958d0..6d5753e8a6d 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -87,7 +87,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, Str
     get_git_modified_files(Some(&build.config.src), &vec!["rs"])
 }
 
-#[derive(serde::Deserialize)]
+#[derive(serde_derive::Deserialize)]
 struct RustfmtConfig {
     ignore: Vec<String>,
 }
@@ -218,7 +218,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                     WalkBuilder::new(first)
                 }
             } else {
-                WalkBuilder::new(first)
+                WalkBuilder::new(src.join(first))
             };
 
             for path in &paths[1..] {
@@ -229,7 +229,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                         walker.add(path);
                     }
                 } else {
-                    walker.add(path);
+                    walker.add(src.join(path));
                 }
             }
 
diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs
index e193e70a0c4..bba4d65e8c3 100644
--- a/src/bootstrap/metadata.rs
+++ b/src/bootstrap/metadata.rs
@@ -1,7 +1,7 @@
 use std::path::PathBuf;
 use std::process::Command;
 
-use serde::Deserialize;
+use serde_derive::Deserialize;
 
 use crate::cache::INTERNER;
 use crate::util::output;
diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs
index c823dc79684..2e62c950709 100644
--- a/src/bootstrap/metrics.rs
+++ b/src/bootstrap/metrics.rs
@@ -7,7 +7,7 @@
 use crate::builder::Step;
 use crate::util::t;
 use crate::Build;
-use serde::{Deserialize, Serialize};
+use serde_derive::{Deserialize, Serialize};
 use std::cell::RefCell;
 use std::fs::File;
 use std::io::BufWriter;
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index a027139df23..4480bce99d7 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -21,6 +21,7 @@ pub enum Profile {
     Library,
     Tools,
     User,
+    None,
 }
 
 /// A list of historical hashes of `src/etc/vscode_settings.json`.
@@ -41,7 +42,7 @@ impl Profile {
     pub fn all() -> impl Iterator<Item = Self> {
         use Profile::*;
         // N.B. these are ordered by how they are displayed, not alphabetically
-        [Library, Compiler, Codegen, Tools, User].iter().copied()
+        [Library, Compiler, Codegen, Tools, User, None].iter().copied()
     }
 
     pub fn purpose(&self) -> String {
@@ -52,6 +53,7 @@ impl Profile {
             Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
             Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)",
             User => "Install Rust from source",
+            None => "Do not modify `config.toml`"
         }
         .to_string()
     }
@@ -71,6 +73,7 @@ impl Profile {
             Profile::Library => "library",
             Profile::Tools => "tools",
             Profile::User => "user",
+            Profile::None => "none",
         }
     }
 }
@@ -87,6 +90,7 @@ impl FromStr for Profile {
             "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => {
                 Ok(Profile::Tools)
             }
+            "none" => Ok(Profile::None),
             _ => Err(format!("unknown profile: '{}'", s)),
         }
     }
@@ -144,17 +148,8 @@ impl Step for Profile {
 }
 
 pub fn setup(config: &Config, profile: Profile) {
-    let stage_path =
-        ["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
-
-    if !rustup_installed() && profile != Profile::User {
-        eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
-    } else if stage_dir_exists(&stage_path[..]) && !config.dry_run() {
-        attempt_toolchain_link(&stage_path[..]);
-    }
-
-    let suggestions = match profile {
-        Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
+    let suggestions: &[&str] = match profile {
+        Profile::Codegen | Profile::Compiler | Profile::None => &["check", "build", "test"],
         Profile::Tools => &[
             "check",
             "build",
@@ -167,11 +162,6 @@ pub fn setup(config: &Config, profile: Profile) {
         Profile::User => &["dist", "build"],
     };
 
-    if !config.dry_run() {
-        t!(install_git_hook_maybe(&config));
-        t!(create_vscode_settings_maybe(&config));
-    }
-
     println!();
 
     println!("To get started, try one of the following commands:");
@@ -190,6 +180,9 @@ pub fn setup(config: &Config, profile: Profile) {
 }
 
 fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
+    if profile == Profile::None {
+        return;
+    }
     if path.exists() {
         eprintln!();
         eprintln!(
@@ -217,6 +210,41 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
     println!("`x.py` will now use the configuration at {}", include_path.display());
 }
 
+/// Creates a toolchain link for stage1 using `rustup`
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub struct Link;
+impl Step for Link {
+    type Output = ();
+    const DEFAULT: bool = true;
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.alias("link")
+    }
+    fn make_run(run: RunConfig<'_>) {
+        if run.builder.config.dry_run() {
+            return;
+        }
+        if let [cmd] = &run.paths[..] {
+            if cmd.assert_single_path().path.as_path().as_os_str() == "link" {
+                run.builder.ensure(Link);
+            }
+        }
+    }
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let config = &builder.config;
+        if config.dry_run() {
+            return;
+        }
+        let stage_path =
+            ["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
+
+        if !rustup_installed() {
+            eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
+        } else if stage_dir_exists(&stage_path[..]) && !config.dry_run() {
+            attempt_toolchain_link(&stage_path[..]);
+        }
+    }
+}
+
 fn rustup_installed() -> bool {
     Command::new("rustup")
         .arg("--version")
@@ -394,6 +422,35 @@ fn prompt_user(prompt: &str) -> io::Result<Option<PromptResult>> {
     }
 }
 
+/// Installs `src/etc/pre-push.sh` as a Git hook
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub struct Hook;
+
+impl Step for Hook {
+    type Output = ();
+    const DEFAULT: bool = true;
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.alias("hook")
+    }
+    fn make_run(run: RunConfig<'_>) {
+        if run.builder.config.dry_run() {
+            return;
+        }
+        if let [cmd] = &run.paths[..] {
+            if cmd.assert_single_path().path.as_path().as_os_str() == "hook" {
+                run.builder.ensure(Hook);
+            }
+        }
+    }
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let config = &builder.config;
+        if config.dry_run() {
+            return;
+        }
+        t!(install_git_hook_maybe(&config));
+    }
+}
+
 // install a git hook to automatically run tidy, if they want
 fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
     let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
@@ -432,6 +489,35 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
     Ok(())
 }
 
+/// Sets up or displays `src/etc/vscode_settings.json`
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub struct Vscode;
+
+impl Step for Vscode {
+    type Output = ();
+    const DEFAULT: bool = true;
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.alias("vscode")
+    }
+    fn make_run(run: RunConfig<'_>) {
+        if run.builder.config.dry_run() {
+            return;
+        }
+        if let [cmd] = &run.paths[..] {
+            if cmd.assert_single_path().path.as_path().as_os_str() == "vscode" {
+                run.builder.ensure(Vscode);
+            }
+        }
+    }
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let config = &builder.config;
+        if config.dry_run() {
+            return;
+        }
+        t!(create_vscode_settings_maybe(&config));
+    }
+}
+
 /// Create a `.vscode/settings.json` file for rustc development, or just print it
 fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> {
     let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap();
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index 1969e0b6f87..7aab88a1a73 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -1,6 +1,6 @@
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::util::t;
-use serde::{Deserialize, Serialize};
+use serde_derive::{Deserialize, Serialize};
 use std::collections::HashMap;
 use std::env;
 use std::fmt;
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index 4cc5d9f8a0d..98bd90210d6 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -23,6 +23,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 
 RUN curl -sL https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz | tar -xJ
 ENV PATH="/node-v16.9.0-linux-x64/bin:${PATH}"
+ENV RUST_CONFIGURE_ARGS="--set rust.validate-mir-opts=3"
+
 # Install es-check
 # Pin its version to prevent unrelated CI failures due to future es-check versions.
 RUN npm install es-check@6.1.1 eslint@8.6.0 -g
@@ -38,7 +40,7 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 
 ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
-           python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu --all-targets && \
+           python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
            python3 ../x.py build --stage 0 src/tools/build-manifest && \
            python3 ../x.py test --stage 0 src/tools/compiletest && \
            python3 ../x.py test --stage 0 core alloc std test proc_macro && \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index 94ec2401292..9c550b2d728 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.14.3
\ No newline at end of file
+0.14.4
\ No newline at end of file
diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py
index a6d84a3c18a..c3d532c4b27 100755
--- a/src/ci/docker/scripts/fuchsia-test-runner.py
+++ b/src/ci/docker/scripts/fuchsia-test-runner.py
@@ -507,9 +507,8 @@ class TestEnvironment:
     bin/{exe_name}={bin_path}
     lib/{libstd_name}={rust_dir}/lib/rustlib/{rustlib_dir}/lib/{libstd_name}
     lib/{libtest_name}={rust_dir}/lib/rustlib/{rustlib_dir}/lib/{libtest_name}
-    lib/ld.so.1={sdk_dir}/arch/{target_arch}/sysroot/lib/libc.so
-    lib/libzircon.so={sdk_dir}/arch/{target_arch}/sysroot/lib/libzircon.so
-    lib/libfdio.so={sdk_dir}/arch/{target_arch}/lib/libfdio.so
+    lib/ld.so.1={sdk_dir}/arch/{target_arch}/sysroot/dist/lib/ld.so.1
+    lib/libfdio.so={sdk_dir}/arch/{target_arch}/dist/libfdio.so
     """
 
     TEST_ENV_VARS: ClassVar[List[str]] = [
@@ -844,23 +843,34 @@ class TestEnvironment:
             "--",
             "--build-id-dir",
             os.path.join(self.sdk_dir, ".build-id"),
-            "--build-id-dir",
-            os.path.join(self.libs_dir(), ".build-id"),
         ]
 
-        # Add rust source if it's available
-        if args.rust_src is not None:
+        libs_build_id_path = os.path.join(self.libs_dir(), ".build-id")
+        if os.path.exists(libs_build_id_path):
+            # Add .build-id symbols if installed libs have been stripped into a
+            # .build-id directory
             command += [
-                "--build-dir",
-                args.rust_src,
+                "--build-id-dir",
+                libs_build_id_path,
+            ]
+        else:
+            # If no .build-id directory is detected, then assume that the shared
+            # libs contain their debug symbols
+            command += [
+                f"--symbol-path={self.rust_dir}/lib/rustlib/{self.target}/lib",
             ]
 
+        # Add rust source if it's available
+        rust_src_map = None
+        if args.rust_src is not None:
+            # This matches the remapped prefix used by compiletest. There's no
+            # clear way that we can determine this, so it's hard coded.
+            rust_src_map = f"/rustc/FAKE_PREFIX={args.rust_src}"
+
         # Add fuchsia source if it's available
+        fuchsia_src_map = None
         if args.fuchsia_src is not None:
-            command += [
-                "--build-dir",
-                os.path.join(args.fuchsia_src, "out", "default"),
-            ]
+            fuchsia_src_map = f"./../..={args.fuchsia_src}"
 
         # Load debug symbols for the test binary and automatically attach
         if args.test is not None:
@@ -883,7 +893,28 @@ class TestEnvironment:
                 test_name,
             )
 
+            # The fake-test-src-base directory maps to the suite directory
+            # e.g. tests/ui/foo.rs has a path of rust/fake-test-src-base/foo.rs
+            fake_test_src_base = os.path.join(
+                args.rust_src,
+                "fake-test-src-base",
+            )
+            real_test_src_base = os.path.join(
+                args.rust_src,
+                "tests",
+                args.test.split(os.path.sep)[0],
+            )
+            test_src_map = f"{fake_test_src_base}={real_test_src_base}"
+
             with open(self.zxdb_script_path(), mode="w", encoding="utf-8") as f:
+                print(f"set source-map += {test_src_map}", file=f)
+
+                if rust_src_map is not None:
+                    print(f"set source-map += {rust_src_map}", file=f)
+
+                if fuchsia_src_map is not None:
+                    print(f"set source-map += {fuchsia_src_map}", file=f)
+
                 print(f"attach {test_name[:31]}", file=f)
 
             command += [
@@ -900,6 +931,20 @@ class TestEnvironment:
         # Connect to the running emulator with zxdb
         subprocess.run(command, env=self.ffx_cmd_env(), check=False)
 
+    def syslog(self, args):
+        subprocess.run(
+            [
+                self.tool_path("ffx"),
+                "--config",
+                self.ffx_user_config_path(),
+                "log",
+                "--since",
+                "now",
+            ],
+            env=self.ffx_cmd_env(),
+            check=False,
+        )
+
 
 def start(args):
     test_env = TestEnvironment.from_args(args)
@@ -933,6 +978,12 @@ def debug(args):
     return 0
 
 
+def syslog(args):
+    test_env = TestEnvironment.read_from_file()
+    test_env.syslog(args)
+    return 0
+
+
 def main():
     parser = argparse.ArgumentParser()
 
@@ -1028,6 +1079,11 @@ def main():
     )
     debug_parser.set_defaults(func=debug)
 
+    syslog_parser = subparsers.add_parser(
+        "syslog", help="prints the device syslog"
+    )
+    syslog_parser.set_defaults(func=syslog)
+
     args = parser.parse_args()
     return args.func(args)
 
diff --git a/src/doc/index.md b/src/doc/index.md
index bf08960f338..7c97c16c20b 100644
--- a/src/doc/index.md
+++ b/src/doc/index.md
@@ -4,6 +4,20 @@
 nav {
     display: none;
 }
+body {
+    font-family: serif;
+}
+h1, h2, h3, h4, h5, h6 {
+    font-family: sans-serif;
+}
+h3 {
+    font-size: 1.35rem;
+}
+h4 {
+    font-size: 1.1rem;
+}
+
+/* Formatting for docs search bar */
 #search-input {
     width: calc(100% - 58px);
 }
@@ -21,53 +35,74 @@ nav {
 #search-but:hover, #search-input:focus {
     border-color: #55a9ff;
 }
-h2 {
-    font-size: 18px;
+
+/* Formatting for external link icon */
+svg.external-link {
+  display: inline-block;
+  position: relative;
+  vertical-align: super;
+  width: 0.7rem;
+  height: 0.7rem;
+  padding-left: 2px;
+  top: 3px;
 }
 </style>
 
-Welcome to an overview of the documentation provided by the [Rust project].
-All of these projects are managed by the Docs Team; there are other
-unofficial documentation resources as well!
+Welcome to an overview of the documentation provided by the [Rust
+project]. This page contains links to various helpful references,
+most of which are available offline (if opened with `rustup doc`). Many of these
+resources take the form of "books"; we collectively call these "The Rust
+Bookshelf." Some are large, some are small.
 
-Many of these resources take the form of "books"; we collectively call these
-"The Rust Bookshelf." Some are large, some are small.
+All of these books are managed by the Rust Organization, but other unofficial
+documentation resources are included here as well!
 
-# Learn Rust
+If you're just looking for the standard library reference, here it is:
+[Rust API documentation](std/index.html)
 
-If you'd like to learn Rust, this is the spot for you! All of these resources
+
+## Learning Rust
+
+If you'd like to learn Rust, this is the section for you! All of these resources
 assume that you have programmed before, but not in any specific language:
 
-## The Rust Programming Language
+### The Rust Programming Language
 
-Affectionately nicknamed "the book," [The Rust Programming
-Language](book/index.html) will give you an overview of the language from
-first principles. You'll build a few projects along the way, and by the end,
-you'll have a solid grasp of the language.
+Affectionately nicknamed "the book," [The Rust Programming Language](book/index.html)
+will give you an overview of the language from first principles. You'll build a
+few projects along the way, and by the end, you'll have a solid grasp of how to
+use the language.
 
-## Rust By Example
+### Rust By Example
 
 If reading multiple hundreds of pages about a language isn't your style, then
-[Rust By Example](rust-by-example/index.html) has you covered. While the book talks about code with
-a lot of words, RBE shows off a bunch of code, and keeps the talking to a
-minimum. It also includes exercises!
+[Rust By Example](rust-by-example/index.html) has you covered. RBE shows off a
+bunch of code without using a lot of words. It also includes exercises!
+
+### Rustlings
+
+[Rustlings](https://github.com/rust-lang/rustlings) guides you
+through downloading and setting up the Rust toolchain, then provides an
+interactive tool that teaches you how to solve coding challenges in Rust.
+
+### Rust Playground
 
-## Rustlings
+The [Rust Playground](https://play.rust-lang.org) is a great place
+to try out and share small bits of code, or experiment with some of the most
+popular crates.
 
-[Rustlings](https://github.com/rust-lang/rustlings) guides you through downloading and setting up the Rust toolchain,
-and teaches you the basics of reading and writing Rust syntax. It's an
-alternative to Rust by Example that works with your own environment.
 
-# Use Rust
+## Using Rust
 
-Once you've gotten familiar with the language, these resources can help you
-when you're actually using it day-to-day.
+Once you've gotten familiar with the language, these resources can help you put
+it to work.
 
-## The Standard Library
+### The Standard Library
 
-Rust's standard library has [extensive API documentation](std/index.html),
-with explanations of how to use various things, as well as example code for
-accomplishing various tasks.
+Rust's standard library has [extensive API documentation](std/index.html), with
+explanations of how to use various things, as well as example code for
+accomplishing various tasks. Code examples have a "Run" button on hover that
+opens the sample in the playground.
 
 <div>
   <form action="std/index.html" method="get">
@@ -77,76 +112,143 @@ accomplishing various tasks.
   </form>
 </div>
 
-## The Edition Guide
+### Your Personal Documentation
 
-[The Edition Guide](edition-guide/index.html) describes the Rust editions.
+Whenever you are working in a crate, `cargo doc --open` will generate
+documentation for your project _and_ all its dependencies in their correct
+version, and open it in your browser. Add the flag `--document-private-items` to
+also show items not marked `pub`.
 
-## The Rustc Book
+### The Edition Guide
 
-[The Rustc Book](rustc/index.html) describes the Rust compiler, `rustc`.
+[The Edition Guide](edition-guide/index.html) describes the Rust editions and
+their differences.
 
-## The Cargo Book
+### The `rustc` Book
 
-[The Cargo Book](cargo/index.html) is a guide to Cargo, Rust's build tool and dependency manager.
+[The `rustc` Book](rustc/index.html) describes the Rust compiler, `rustc`.
 
-## The Rustdoc Book
+### The Cargo Book
+
+[The Cargo Book](cargo/index.html) is a guide to Cargo, Rust's build tool and
+dependency manager.
+
+### The Rustdoc Book
 
 [The Rustdoc Book](rustdoc/index.html) describes our documentation tool, `rustdoc`.
 
-## The Clippy Book
+### The Clippy Book
 
 [The Clippy Book](clippy/index.html) describes our static analyzer, Clippy.
 
-## Extended Error Listing
+### Extended Error Listing
 
 Many of Rust's errors come with error codes, and you can request extended
-diagnostics from the compiler on those errors. You can also [read them
-here](error_codes/index.html), if you prefer to read them that way.
+diagnostics from the compiler on those errors (with `rustc --explain`). You can
+also read them here if you prefer: [rustc error codes](error_codes/index.html)
+
 
-# Master Rust
+## Mastering Rust
 
 Once you're quite familiar with the language, you may find these advanced
 resources useful.
 
-## The Reference
+### The Reference
 
-[The Reference](reference/index.html) is not a formal spec, but is more detailed and
-comprehensive than the book.
+[The Reference](reference/index.html) is not a formal spec, but is more detailed
+and comprehensive than the book.
 
-## The Style Guide
+### The Style Guide
 
-[The Rust Style Guide](style-guide/index.html) describes the standard formatting of Rust
-code. Most developers use rustfmt to format their code, and rustfmt's default
-formatting matches this style guide.
+[The Rust Style Guide](style-guide/index.html) describes the standard formatting
+of Rust code. Most developers use `cargo fmt` to invoke `rustfmt` and format the
+code automatically (the result matches this style guide).
 
-## The Rustonomicon
+### The Rustonomicon
 
-[The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of unsafe
-Rust. It's also sometimes called "the 'nomicon."
+[The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of
+unsafe Rust. It's also sometimes called "the 'nomicon."
 
-## The Unstable Book
+### The Unstable Book
 
-[The Unstable Book](unstable-book/index.html) has documentation for unstable features.
+[The Unstable Book](unstable-book/index.html) has documentation for unstable
+features.
 
-## The `rustc` Contribution Guide
+### The `rustc` Contribution Guide
 
-[The `rustc` Guide](https://rustc-dev-guide.rust-lang.org/) documents how
-the compiler works and how to contribute to it. This is useful if you want to build
-or modify the Rust compiler from source (e.g. to target something non-standard).
+[The `rustc` Guide](https://rustc-dev-guide.rust-lang.org/)
+documents how the compiler works and how to contribute to it. This is useful if
+you want to build or modify the Rust compiler from source (e.g. to target
+something non-standard).
 
-# Specialize Rust
 
-When using Rust in specific domain areas, consider using the following resources tailored to each domain.
+## Specialized Rust
 
-## Embedded Systems
+When using Rust in specific domains, consider using the following resources
+tailored to each area.
 
-When developing for Bare Metal or Embedded Linux systems, you may find these resources maintained by the [Embedded Working Group] useful.
+### Embedded Systems
+
+When developing for Bare Metal or Embedded Linux systems, you may find these
+resources maintained by the [Embedded Working Group] useful.
 
 [Embedded Working Group]: https://github.com/rust-embedded
 
-### The Embedded Rust Book
+#### The Embedded Rust Book
 
-[The Embedded Rust Book] is targeted at developers familiar with embedded development and familiar with Rust, but have not used Rust for embedded development.
+[The Embedded Rust Book] is targeted at developers familiar with embedded
+development and familiar with Rust, but have not used Rust for embedded
+development.
 
 [The Embedded Rust Book]: embedded-book/index.html
 [Rust project]: https://www.rust-lang.org
+
+<script>
+// check if a given link is external
+function isExternalLink(url) {
+  const tmp = document.createElement('a');
+  tmp.href = url;
+  return tmp.host !== window.location.host;
+}
+
+// Add the `external` class to all <a> tags with external links and append the external link SVG
+function updateExternalAnchors() {
+  /*
+    External link SVG from Font-Awesome
+    CC BY-SA 3.0 https://creativecommons.org/licenses/by-sa/3.0
+    via Wikimedia Commons
+  */
+  const svgText = `<svg
+     class='external-link'
+     xmlns='http://www.w3.org/2000/svg'
+     viewBox='0 -256 1850 1850'
+     width='100%'
+     height='100%'>
+       <g transform='matrix(1,0,0,-1,30,1427)'>
+         <path d='M 1408,608 V 288 Q 1408,169 1323.5,84.5 1239,0 1120,
+           0 H 288 Q 169,0 84.5,84.5 0,169 0,288 v 832 Q 0,1239 84.5,1323.5 169,
+           1408 288,1408 h 704 q 14,0 23,-9 9,-9 9,-23 v -64 q 0,-14 -9,-23 -9,
+           -9 -23,-9 H 288 q -66,0 -113,-47 -47,-47 -47,-113 V 288 q 0,-66 47,
+           -113 47,-47 113,-47 h 832 q 66,0 113,47 47,47 47,113 v 320 q 0,14 9,
+           23 9,9 23,9 h 64 q 14,0 23,-9 9,-9 9,-23 z m 384,864 V 960 q 0,
+           -26 -19,-45 -19,-19 -45,-19 -26,0 -45,19 L 1507,1091 855,439 q -10,
+           -10 -23,-10 -13,0 -23,10 L 695,553 q -10,10 -10,23 0,13 10,23 l 652,
+           652 -176,176 q -19,19 -19,45 0,26 19,45 19,19 45,19 h 512 q 26,0 45,
+           -19 19,-19 19,-45 z' style='fill:currentColor' />
+         </g>
+     </svg>`;
+  let allAnchors = document.getElementsByTagName("a");
+
+  for (var i = 0; i < allAnchors.length; ++i) {
+    let anchor = allAnchors[i];
+    if (isExternalLink(anchor.href)) {
+      anchor.classList.add("external");
+      anchor.innerHTML += svgText;
+    }
+  }
+}
+
+// on page load, update external anchors
+document.addEventListener("DOMContentLoaded", updateExternalAnchors);
+
+</script>
diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md
index 0f165b268ba..63dde2aaedd 100644
--- a/src/doc/rustc/src/platform-support/fuchsia.md
+++ b/src/doc/rustc/src/platform-support/fuchsia.md
@@ -687,7 +687,9 @@ Rust compiler locally. See "[Targeting Fuchsia with a compiler built from source
 for the steps to build locally.
 
 You'll also need to download a copy of the Fuchsia SDK. The current minimum
-supported SDK version is [9.20220726.1.1](https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core/linux-amd64/+/version:9.20220726.1.1).
+supported SDK version is [10.20221207.2.89][minimum_supported_sdk_version].
+
+[minimum_supported_sdk_version]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core/linux-amd64/+/version:10.20221207.2.89
 
 Fuchsia's test runner interacts with the Fuchsia emulator and is located at
 `src/ci/docker/scripts/fuchsia-test-runner.py`. We can use it to start our
@@ -697,7 +699,7 @@ test environment with:
 src/ci/docker/scripts/fuchsia-test-runner.py start
     --rust ${RUST_SRC_PATH}/install
     --sdk ${SDK_PATH}
-    --target-triple {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia}
+    --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia}
 ```
 
 Where `${RUST_SRC_PATH}/install` is the `prefix` set in `config.toml` and
@@ -717,17 +719,11 @@ run the full `tests/ui` test suite:
     --target x86_64-unknown-fuchsia                                           \
     --run=always --jobs 1                                                     \
     --test-args --target-rustcflags                                           \
-    --test-args -L                                                            \
-    --test-args --target-rustcflags                                           \
-    --test-args ${SDK_PATH}/arch/{x64|arm64}/sysroot/lib                      \
-    --test-args --target-rustcflags                                           \
-    --test-args -L                                                            \
+    --test-args -Lnative=${SDK_PATH}/arch/{x64|arm64}/sysroot/lib             \
     --test-args --target-rustcflags                                           \
-    --test-args ${SDK_PATH}/arch/{x64|arm64}/lib                              \
+    --test-args -Lnative=${SDK_PATH}/arch/{x64|arm64}/lib                     \
     --test-args --target-rustcflags                                           \
-    --test-args -Cpanic=abort                                                 \
-    --test-args --target-rustcflags                                           \
-    --test-args -Zpanic_abort_tests                                           \
+    --test-args -Clink-arg=--undefined-version                                \
     --test-args --remote-test-client                                          \
     --test-args src/ci/docker/scripts/fuchsia-test-runner.py                  \
 )
@@ -736,7 +732,18 @@ run the full `tests/ui` test suite:
 *Note: The test suite cannot be run in parallel at the moment, so `x.py`
 must be run with `--jobs 1` to ensure only one test runs at a time.*
 
-When finished, the test runner can be used to stop the test environment:
+By default, `x.py` compiles test binaries with `panic=unwind`. If you built your
+Rust toolchain with `-Cpanic=abort`, you need to tell `x.py` to compile test
+binaries with `panic=abort` as well:
+
+```sh
+    --test-args --target-rustcflags                                           \
+    --test-args -Cpanic=abort                                                 \
+    --test-args --target-rustcflags                                           \
+    --test-args -Zpanic_abort_tests                                           \
+```
+
+When finished testing, the test runner can be used to stop the test environment:
 
 ```sh
 src/ci/docker/scripts/fuchsia-test-runner.py stop
@@ -764,8 +771,9 @@ ${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \
 * `--symbol-path` gets required symbol paths, which are
 necessary for stepping through your program.
 
-The "[displaying source code in `zxdb`](#displaying-source-code-in-zxdb)" section describes how you can
-display Rust and/or Fuchsia source code in your debugging session.
+The "[displaying source code in `zxdb`](#displaying-source-code-in-zxdb)"
+section describes how you can display Rust and/or Fuchsia source code in your
+debugging session.
 
 ### Using `zxdb`
 
@@ -866,6 +874,64 @@ ${SDK_PATH}/tools/${ARCH}/ffx debug connect -- \
  Linking to a Fuchsia checkout can help with debugging Fuchsia libraries,
  such as [fdio].
 
+### Debugging the compiler test suite
+
+Debugging the compiler test suite requires some special configuration:
+
+First, we have to properly configure zxdb so it will be able to find debug
+symbols and source information for our test. The test runner can do this for us
+with:
+
+```sh
+src/ci/docker/scripts/fuchsia-test-runner.py debug                            \
+    --rust-src ${RUST_SRC_PATH}                                               \
+    --fuchsia-src ${FUCHSIA_SRC_PATH}                                         \
+    --test ${TEST}
+```
+
+where `${TEST}` is relative to Rust's `tests` directory (e.g. `ui/abi/...`).
+
+This will start a zxdb session that is properly configured for the specific test
+being run. All three arguments are optional, so you can omit `--fuchsia-src` if
+you don't have it downloaded. Now is a good time to set any desired breakpoints,
+like `b main`.
+
+Next, we have to tell `x.py` not to optimize or strip debug symbols from our
+test suite binaries. We can do this by passing some new arguments to `rustc`
+through our `x.py` invocation. The full invocation is:
+
+```sh
+( \
+    source config-env.sh &&                                                   \
+    ./x.py                                                                    \
+    --config config.toml                                                      \
+    --stage=2                                                                 \
+    test tests/${TEST}                                                        \
+    --target x86_64-unknown-fuchsia                                           \
+    --run=always --jobs 1                                                     \
+    --test-args --target-rustcflags                                           \
+    --test-args -Lnative=${SDK_PATH}/arch/{x64|arm64}/sysroot/lib             \
+    --test-args --target-rustcflags                                           \
+    --test-args -Lnative=${SDK_PATH}/arch/{x64|arm64}/lib                     \
+    --test-args --target-rustcflags                                           \
+    --test-args -Clink-arg=--undefined-version                                \
+    --test-args --target-rustcflags                                           \
+    --test-args -Cdebuginfo=2                                                 \
+    --test-args --target-rustcflags                                           \
+    --test-args -Copt-level=0                                                 \
+    --test-args --target-rustcflags                                           \
+    --test-args -Cstrip=none                                                  \
+    --test-args --remote-test-client                                          \
+    --test-args src/ci/docker/scripts/fuchsia-test-runner.py                  \
+)
+```
+
+*If you built your Rust toolchain with `panic=abort`, make sure to include the
+previous flags so your test binaries are also compiled with `panic=abort`.*
+
+Upon running this command, the test suite binary will be run and zxdb will
+attach and load any relevant debug symbols.
+
 [Fuchsia team]: https://team-api.infra.rust-lang.org/v1/teams/fuchsia.json
 [Fuchsia]: https://fuchsia.dev/
 [source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 58223f322b2..0e8f0cfc518 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -77,7 +77,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
     // This covers the case where somebody does an import which should pull in an item,
     // but there's already an item with the same namespace and same name. Rust gives
     // priority to the not-imported one, so we should, too.
-    items.extend(doc.items.iter().flat_map(|(item, renamed, import_id)| {
+    items.extend(doc.items.values().flat_map(|(item, renamed, import_id)| {
         // First, lower everything other than imports.
         if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
             return Vec::new();
@@ -90,7 +90,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
         }
         v
     }));
-    items.extend(doc.items.iter().flat_map(|(item, renamed, _)| {
+    items.extend(doc.items.values().flat_map(|(item, renamed, _)| {
         // Now we actually lower the imports, skipping everything else.
         if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
             let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
@@ -1661,7 +1661,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
         }
         TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
         // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
-        TyKind::Infer | TyKind::Err | TyKind::Typeof(..) => Infer,
+        TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) => Infer,
     }
 }
 
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index b5a34814382..fe446ae3c16 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -552,10 +552,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> {
 }
 
 fn check_if_allowed_tag(t: &Tag<'_>) -> bool {
-    matches!(
-        t,
-        Tag::Paragraph | Tag::Item | Tag::Emphasis | Tag::Strong | Tag::Link(..) | Tag::BlockQuote
-    )
+    matches!(t, Tag::Paragraph | Tag::Emphasis | Tag::Strong | Tag::Link(..) | Tag::BlockQuote)
 }
 
 fn is_forbidden_tag(t: &Tag<'_>) -> bool {
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 1e6c94d29ba..b3fc889431b 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -463,11 +463,10 @@ function initSearch(rawSearchIndex) {
      * @param {ParserState} parserState
      */
     function parseInput(query, parserState) {
-        let c, before;
         let foundStopChar = true;
 
         while (parserState.pos < parserState.length) {
-            c = parserState.userQuery[parserState.pos];
+            const c = parserState.userQuery[parserState.pos];
             if (isStopCharacter(c)) {
                 foundStopChar = true;
                 if (isSeparatorCharacter(c)) {
@@ -506,7 +505,7 @@ function initSearch(rawSearchIndex) {
                 }
                 throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
             }
-            before = query.elems.length;
+            const before = query.elems.length;
             getNextElem(query, parserState, query.elems, false);
             if (query.elems.length === before) {
                 // Nothing was added, weird... Let's increase the position to not remain stuck.
@@ -515,7 +514,6 @@ function initSearch(rawSearchIndex) {
             foundStopChar = false;
         }
         while (parserState.pos < parserState.length) {
-            c = parserState.userQuery[parserState.pos];
             if (isReturnArrow(parserState)) {
                 parserState.pos += 2;
                 // Get returned elements.
@@ -1940,7 +1938,6 @@ function initSearch(rawSearchIndex) {
          */
         const searchWords = [];
         const charA = "A".charCodeAt(0);
-        let i, word;
         let currentIndex = 0;
         let id = 0;
 
@@ -2035,7 +2032,7 @@ function initSearch(rawSearchIndex) {
             // convert `rawPaths` entries into object form
             // generate normalizedPaths for function search mode
             let len = paths.length;
-            for (i = 0; i < len; ++i) {
+            for (let i = 0; i < len; ++i) {
                 lowercasePaths.push({ty: paths[i][0], name: paths[i][1].toLowerCase()});
                 paths[i] = {ty: paths[i][0], name: paths[i][1]};
             }
@@ -2049,16 +2046,14 @@ function initSearch(rawSearchIndex) {
             // faster analysis operations
             len = itemTypes.length;
             let lastPath = "";
-            for (i = 0; i < len; ++i) {
+            for (let i = 0; i < len; ++i) {
+                let word = "";
                 // This object should have exactly the same set of fields as the "crateRow"
                 // object defined above.
                 if (typeof itemNames[i] === "string") {
                     word = itemNames[i].toLowerCase();
-                    searchWords.push(word);
-                } else {
-                    word = "";
-                    searchWords.push("");
                 }
+                searchWords.push(word);
                 const row = {
                     crate: crate,
                     ty: itemTypes.charCodeAt(i) - charA,
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index 0e1c864e62d..6c0f03b5bb0 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -117,8 +117,7 @@ function createSourceSidebar() {
     sidebar.appendChild(title);
     Object.keys(sourcesIndex).forEach(key => {
         sourcesIndex[key][NAME_OFFSET] = key;
-        hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "",
-            hasFoundFile);
+        hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "", hasFoundFile);
     });
 
     container.appendChild(sidebar);
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 9c1e5f4a3cd..277201e4de9 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -1,7 +1,7 @@
 //! The Rust AST Visitor. Extracts useful information and massages it into a form
 //! usable for `clean`.
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
@@ -26,8 +26,12 @@ pub(crate) struct Module<'hir> {
     pub(crate) where_inner: Span,
     pub(crate) mods: Vec<Module<'hir>>,
     pub(crate) def_id: LocalDefId,
-    // (item, renamed, import_id)
-    pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>, Option<LocalDefId>)>,
+    /// The key is the item `ItemId` and the value is: (item, renamed, import_id).
+    /// We use `FxIndexMap` to keep the insert order.
+    pub(crate) items: FxIndexMap<
+        (LocalDefId, Option<Symbol>),
+        (&'hir hir::Item<'hir>, Option<Symbol>, Option<LocalDefId>),
+    >,
     pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
 }
 
@@ -38,7 +42,7 @@ impl Module<'_> {
             def_id,
             where_inner,
             mods: Vec::new(),
-            items: Vec::new(),
+            items: FxIndexMap::default(),
             foreigns: Vec::new(),
         }
     }
@@ -136,7 +140,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 inserted.insert(def_id)
             {
                     let item = self.cx.tcx.hir().expect_item(local_def_id);
-                    top_level_module.items.push((item, None, None));
+                    top_level_module.items.insert((local_def_id, Some(item.ident.name)), (item, None, None));
             }
         }
 
@@ -294,7 +298,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         renamed: Option<Symbol>,
         parent_id: Option<LocalDefId>,
     ) {
-        self.modules.last_mut().unwrap().items.push((item, renamed, parent_id))
+        self.modules
+            .last_mut()
+            .unwrap()
+            .items
+            .insert((item.owner_id.def_id, renamed), (item, renamed, parent_id));
     }
 
     fn visit_item_inner(
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 17b3d0de0897e1c6b8ca347bd39f850bb0a5b9f
+Subproject 9d5b32f503fc099c4064298465add14d4bce11e
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 659e8aebcd5..765826ed867 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -4430,6 +4430,7 @@ Released 2018-09-13
 [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
 [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
+[`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params
 [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
 [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
 [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
@@ -4494,6 +4495,7 @@ Released 2018-09-13
 [`let_underscore_future`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_future
 [`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
 [`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
+[`let_underscore_untyped`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_untyped
 [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
 [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
 [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
@@ -4620,6 +4622,7 @@ Released 2018-09-13
 [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
 [`no_effect_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_replace
 [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
+[`no_mangle_with_rust_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_mangle_with_rust_abi
 [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
 [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
 [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
@@ -4675,6 +4678,7 @@ Released 2018-09-13
 [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
 [`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use
 [`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
+[`question_mark_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark_used
 [`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one
 [`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
 [`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
@@ -4734,6 +4738,7 @@ Released 2018-09-13
 [`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
 [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
 [`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
+[`significant_drop_tightening`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_tightening
 [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
 [`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
 [`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
@@ -4764,6 +4769,7 @@ Released 2018-09-13
 [`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
 [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
 [`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
+[`suspicious_command_arg_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_command_arg_space
 [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting
 [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
 [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
@@ -4790,6 +4796,7 @@ Released 2018-09-13
 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
 [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
 [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_int_to_non_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_non_zero
 [`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn
 [`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
 [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 95f6d2cc45c..3e7379ace7e 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -19,21 +19,35 @@ You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the
 | `clippy::complexity`  | code that does something simple but in a complex way                                | **warn**      |
 | `clippy::perf`        | code that can be written to run faster                                              | **warn**      |
 | `clippy::pedantic`    | lints which are rather strict or have occasional false positives                    | allow         |
+| `clippy::restriction` | lints which prevent the use of language and library features[^restrict]             | allow         |
 | `clippy::nursery`     | new lints that are still under development                                          | allow         |
 | `clippy::cargo`       | lints for the cargo manifest                                                        | allow         |
 
 More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
 
-The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also contains "restriction lints", which are
-for things which are usually not considered "bad", but may be useful to turn on in specific cases. These should be used
-very selectively, if at all.
+The `restriction` category should, *emphatically*, not be enabled as a whole. The contained
+lints may lint against perfectly reasonable code, may not have an alternative suggestion,
+and may contradict any other lints (including other categories). Lints should be considered
+on a case-by-case basis before enabling.
+
+[^restrict]: Some use cases for `restriction` lints include:
+    - Strict coding styles (e.g. [`clippy::else_if_without_else`]).
+    - Additional restrictions on CI (e.g. [`clippy::todo`]).
+    - Preventing panicking in certain functions (e.g. [`clippy::unwrap_used`]).
+    - Running a lint only on a subset of code (e.g. `#[forbid(clippy::float_arithmetic)]` on a module).
+
+[`clippy::else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
+[`clippy::todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
+[`clippy::unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
+
+---
 
 Table of contents:
 
-*   [Usage instructions](#usage)
-*   [Configuration](#configuration)
-*   [Contributing](#contributing)
-*   [License](#license)
+* [Usage instructions](#usage)
+* [Configuration](#configuration)
+* [Contributing](#contributing)
+* [License](#license)
 
 ## Usage
 
@@ -64,6 +78,7 @@ Once you have rustup and the latest stable release (at least Rust 1.29) installe
 ```terminal
 rustup component add clippy
 ```
+
 If it says that it can't find the `clippy` component, please run `rustup self update`.
 
 #### Step 3: Run Clippy
@@ -143,16 +158,16 @@ line. (You can swap `clippy::all` with the specific lint category you are target
 
 You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
 
-*   the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`).
+* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`).
     Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html).
 
-*   all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
+* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
     `#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive
     lints prone to false positives.
 
-*   only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.)
+* only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.)
 
-*   `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc.
+* `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc.
 
 Note: `allow` means to suppress the lint for your code. With `warn` the lint
 will only emit a warning, while with `deny` the lint will emit an error, when
@@ -176,12 +191,14 @@ cargo clippy -- -W clippy::lint_name
 
 This also works with lint groups. For example, you
 can run Clippy with warnings for all lints enabled:
+
 ```terminal
 cargo clippy -- -W clippy::pedantic
 ```
 
 If you care only about a single lint, you can allow all others and then explicitly warn on
 the lint(s) you are interested in:
+
 ```terminal
 cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
 ```
diff --git a/src/tools/clippy/book/src/development/infrastructure/backport.md b/src/tools/clippy/book/src/development/infrastructure/backport.md
index 15f3d1f0806..6920c4e4656 100644
--- a/src/tools/clippy/book/src/development/infrastructure/backport.md
+++ b/src/tools/clippy/book/src/development/infrastructure/backport.md
@@ -28,6 +28,7 @@ repository. You can do this with:
 ```bash
 # Assuming the current directory corresponds to the Rust repository
 $ git checkout beta
+# Make sure to change `your-github-name` to your github name in the following command
 $ git subtree pull -p src/tools/clippy https://github.com/<your-github-name>/rust-clippy backport
 $ ./x.py test src/tools/clippy
 ```
diff --git a/src/tools/clippy/book/src/development/infrastructure/sync.md b/src/tools/clippy/book/src/development/infrastructure/sync.md
index 5a0f7409a2e..02cfc11b55a 100644
--- a/src/tools/clippy/book/src/development/infrastructure/sync.md
+++ b/src/tools/clippy/book/src/development/infrastructure/sync.md
@@ -79,8 +79,7 @@ to be run inside the `rust` directory):
    `rustup check`.
 3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
     ```bash
-    # Make sure to change `your-github-name` to your github name in the following command. Also be
-    # sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
+    # Be sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
     # because changes cannot be fast forwarded and you have to run this command again.
     git subtree push -P src/tools/clippy clippy-local sync-from-rust
     ```
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 32e8e218c40..33f2b5c1de9 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -53,6 +53,7 @@ Please use that command to update the file and do not edit it by hand.
 | [ignore-interior-mutability](#ignore-interior-mutability) | `["bytes::Bytes"]` |
 | [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` |
 | [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` |
+| [missing-docs-in-crate-items](#missing-docs-in-crate-items) | `false` |
 
 ### arithmetic-side-effects-allowed
 Suppress checking of the passed type names in all types of operations.
@@ -471,7 +472,7 @@ The maximum size of a file included via `include_bytes!()` or `include_str!()`,
 
 
 ### allow-expect-in-tests
-Whether `expect` should be allowed within `#[cfg(test)]`
+Whether `expect` should be allowed in test functions or `#[cfg(test)]`
 
 **Default Value:** `false` (`bool`)
 
@@ -479,7 +480,7 @@ Whether `expect` should be allowed within `#[cfg(test)]`
 
 
 ### allow-unwrap-in-tests
-Whether `unwrap` should be allowed in test cfg
+Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
 
 **Default Value:** `false` (`bool`)
 
@@ -487,7 +488,7 @@ Whether `unwrap` should be allowed in test cfg
 
 
 ### allow-dbg-in-tests
-Whether `dbg!` should be allowed in test functions
+Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
 
 **Default Value:** `false` (`bool`)
 
@@ -495,7 +496,7 @@ Whether `dbg!` should be allowed in test functions
 
 
 ### allow-print-in-tests
-Whether print macros (ex. `println!`) should be allowed in test functions
+Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
 
 **Default Value:** `false` (`bool`)
 
@@ -540,4 +541,13 @@ if no suggestion can be made.
 * [indexing_slicing](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing)
 
 
+### missing-docs-in-crate-items
+Whether to **only** check for missing documentation in items visible within the current
+crate. For example, `pub(crate)` items.
+
+**Default Value:** `false` (`bool`)
+
+* [missing_docs_in_private_items](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items)
+
+
 
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index ec7f1dd0d84..420214d9256 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -1,5 +1,6 @@
 use crate::clippy_project_root;
 use indoc::{formatdoc, writedoc};
+use std::fmt;
 use std::fmt::Write as _;
 use std::fs::{self, OpenOptions};
 use std::io::prelude::*;
@@ -256,7 +257,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
         )
     });
 
-    let _ = write!(result, "{}", get_lint_declaration(&name_upper, category));
+    let _: fmt::Result = write!(result, "{}", get_lint_declaration(&name_upper, category));
 
     result.push_str(&if enable_msrv {
         formatdoc!(
@@ -353,7 +354,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
     let mut lint_file_contents = String::new();
 
     if enable_msrv {
-        let _ = writedoc!(
+        let _: fmt::Result = writedoc!(
             lint_file_contents,
             r#"
                 use clippy_utils::msrvs::{{self, Msrv}};
@@ -373,7 +374,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
             name_upper = name_upper,
         );
     } else {
-        let _ = writedoc!(
+        let _: fmt::Result = writedoc!(
             lint_file_contents,
             r#"
                 use rustc_lint::{{{context_import}, LintContext}};
@@ -521,7 +522,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
         .chain(std::iter::once(&*lint_name_upper))
         .filter(|s| !s.is_empty())
     {
-        let _ = write!(new_arr_content, "\n    {ident},");
+        let _: fmt::Result = write!(new_arr_content, "\n    {ident},");
     }
     new_arr_content.push('\n');
 
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 837618c9294..779e4d0e1e3 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -5,7 +5,7 @@ use itertools::Itertools;
 use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
 use std::collections::{HashMap, HashSet};
 use std::ffi::OsStr;
-use std::fmt::Write;
+use std::fmt::{self, Write};
 use std::fs::{self, OpenOptions};
 use std::io::{self, Read, Seek, SeekFrom, Write as _};
 use std::ops::Range;
@@ -691,7 +691,7 @@ fn gen_deprecated(lints: &[DeprecatedLint]) -> String {
     let mut output = GENERATED_FILE_COMMENT.to_string();
     output.push_str("{\n");
     for lint in lints {
-        let _ = write!(
+        let _: fmt::Result = write!(
             output,
             concat!(
                 "    store.register_removed(\n",
@@ -726,7 +726,7 @@ fn gen_declared_lints<'a>(
         if !is_public {
             output.push_str("    #[cfg(feature = \"internal\")]\n");
         }
-        let _ = writeln!(output, "    crate::{module_name}::{lint_name}_INFO,");
+        let _: fmt::Result = writeln!(output, "    crate::{module_name}::{lint_name}_INFO,");
     }
     output.push_str("];\n");
 
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 9d98a6bab71..dfa949d1af2 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -117,7 +117,8 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         ) => {
             if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) &&
                 let Some(sig) = expr_sig(cx, path) &&
-                let Some(input) = sig.input(index)
+                let Some(input) = sig.input(index) &&
+                !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait()
             {
                 input.no_bound_vars().is_some()
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index f3f8b8d8798..823970e35ab 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -168,7 +168,7 @@ pub(super) fn check(
     let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})");
 
     span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| {
-        diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...");
+        diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...");
         diag.span_suggestion_with_style(
             expr.span,
             "... or use `try_from` and handle the error accordingly",
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 457a25826e7..cd5dd7a5706 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -179,6 +179,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
     crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
     crate::functions::DOUBLE_MUST_USE_INFO,
+    crate::functions::IMPL_TRAIT_IN_PARAMS_INFO,
     crate::functions::MISNAMED_GETTERS_INFO,
     crate::functions::MUST_USE_CANDIDATE_INFO,
     crate::functions::MUST_USE_UNIT_INFO,
@@ -224,6 +225,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO,
     crate::let_underscore::LET_UNDERSCORE_LOCK_INFO,
     crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO,
+    crate::let_underscore::LET_UNDERSCORE_UNTYPED_INFO,
     crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO,
     crate::lifetimes::NEEDLESS_LIFETIMES_INFO,
     crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO,
@@ -378,6 +380,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::SKIP_WHILE_NEXT_INFO,
     crate::methods::STABLE_SORT_PRIMITIVE_INFO,
     crate::methods::STRING_EXTEND_CHARS_INFO,
+    crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO,
     crate::methods::SUSPICIOUS_MAP_INFO,
     crate::methods::SUSPICIOUS_SPLITN_INFO,
     crate::methods::SUSPICIOUS_TO_OWNED_INFO,
@@ -447,6 +450,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::no_effect::NO_EFFECT_INFO,
     crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO,
     crate::no_effect::UNNECESSARY_OPERATION_INFO,
+    crate::no_mangle_with_rust_abi::NO_MANGLE_WITH_RUST_ABI_INFO,
     crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO,
     crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO,
     crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO,
@@ -506,6 +510,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
     crate::pub_use::PUB_USE_INFO,
     crate::question_mark::QUESTION_MARK_INFO,
+    crate::question_mark_used::QUESTION_MARK_USED_INFO,
     crate::ranges::MANUAL_RANGE_CONTAINS_INFO,
     crate::ranges::RANGE_MINUS_ONE_INFO,
     crate::ranges::RANGE_PLUS_ONE_INFO,
@@ -536,6 +541,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::shadow::SHADOW_REUSE_INFO,
     crate::shadow::SHADOW_SAME_INFO,
     crate::shadow::SHADOW_UNRELATED_INFO,
+    crate::significant_drop_tightening::SIGNIFICANT_DROP_TIGHTENING_INFO,
     crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
     crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
     crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
@@ -573,6 +579,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
     crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
     crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
+    crate::transmute::TRANSMUTE_INT_TO_NON_ZERO_INFO,
     crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
     crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index ef46e23123b..47501980e66 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -3,7 +3,7 @@ use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exact
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res};
+use clippy_utils::ty::{adt_and_variant_of_res, expr_sig, is_copy, peel_mid_ty_refs, ty_sig};
 use clippy_utils::{
     fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
 };
@@ -26,8 +26,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{
-    self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
-    ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
+    self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy,
+    PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::sym, Span, Symbol};
@@ -736,7 +736,7 @@ fn walk_parents<'tcx>(
                 ..
             }) if span.ctxt() == ctxt => {
                 let ty = cx.tcx.type_of(owner_id.def_id).subst_identity();
-                Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
+                Some(ty_auto_deref_stability(cx.tcx, cx.param_env, ty, precedence).position_for_result(cx))
             },
 
             Node::Item(&Item {
@@ -760,7 +760,7 @@ fn walk_parents<'tcx>(
                 let output = cx
                     .tcx
                     .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
-                Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
+                Some(ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx))
             },
 
             Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
@@ -768,10 +768,23 @@ fn walk_parents<'tcx>(
                     hir_id,
                     kind: ExprKind::Struct(path, ..),
                     ..
-                }) => variant_of_res(cx, cx.qpath_res(path, *hir_id))
-                    .and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name))
-                    .map(|field_def| {
-                        ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did).subst_identity(), precedence).position_for_arg()
+                }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
+                    .and_then(|(adt, variant)| {
+                        variant
+                            .fields
+                            .iter()
+                            .find(|f| f.name == field.ident.name)
+                            .map(|f| (adt, f))
+                    })
+                    .map(|(adt, field_def)| {
+                        ty_auto_deref_stability(
+                            cx.tcx,
+                            // Use the param_env of the target type.
+                            cx.tcx.param_env(adt.did()),
+                            cx.tcx.type_of(field_def.did).subst_identity(),
+                            precedence,
+                        )
+                        .position_for_arg()
                     }),
                 _ => None,
             },
@@ -792,7 +805,7 @@ fn walk_parents<'tcx>(
                             let output = cx
                                 .tcx
                                 .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
-                            ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
+                            ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx)
                         },
                     )
                 },
@@ -835,15 +848,20 @@ fn walk_parents<'tcx>(
                                             msrv,
                                         )
                                     } else {
-                                        ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
-                                            .position_for_arg()
+                                        ty_auto_deref_stability(
+                                            cx.tcx,
+                                            // Use the param_env of the target function.
+                                            sig.predicates_id().map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)),
+                                            cx.tcx.erase_late_bound_regions(ty),
+                                            precedence
+                                        ).position_for_arg()
                                     }
                                 },
                             }
                         })
                     }),
                 ExprKind::MethodCall(method, receiver, args, _) => {
-                    let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
+                    let fn_id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
                     if receiver.hir_id == child_id {
                         // Check for calls to trait methods where the trait is implemented on a reference.
                         // Two cases need to be handled:
@@ -852,13 +870,17 @@ fn walk_parents<'tcx>(
                         //   priority.
                         if e.hir_id != child_id {
                             return Some(Position::ReborrowStable(precedence))
-                        } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
+                        } else if let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
                             && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
                             && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
                             && let subs = cx
                                 .typeck_results()
                                 .node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
-                            && let impl_ty = if cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[0].is_ref() {
+                            && let impl_ty = if cx.tcx.fn_sig(fn_id)
+                                .subst_identity()
+                                .skip_binder()
+                                .inputs()[0].is_ref()
+                            {
                                 // Trait methods taking `&self`
                                 sub_ty
                             } else {
@@ -879,10 +901,13 @@ fn walk_parents<'tcx>(
                         return Some(Position::MethodReceiver);
                     }
                     args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
-                        let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i + 1];
+                        let ty = cx.tcx.fn_sig(fn_id).subst_identity().input(i + 1);
                         // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
                         // `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
-                        if e.hir_id == child_id && method.args.is_none() && let ty::Param(param_ty) = ty.kind() {
+                        if e.hir_id == child_id
+                            && method.args.is_none()
+                            && let ty::Param(param_ty) = ty.skip_binder().kind()
+                        {
                             needless_borrow_impl_arg_position(
                                 cx,
                                 possible_borrowers,
@@ -895,8 +920,10 @@ fn walk_parents<'tcx>(
                             )
                         } else {
                             ty_auto_deref_stability(
-                                cx,
-                                cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().input(i + 1)),
+                                cx.tcx,
+                                // Use the param_env of the target function.
+                                cx.tcx.param_env(fn_id),
+                                cx.tcx.erase_late_bound_regions(ty),
                                 precedence,
                             )
                             .position_for_arg()
@@ -1022,7 +1049,7 @@ fn binding_ty_auto_deref_stability<'tcx>(
                     ))
                     .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
             ),
-            TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
+            TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err(_) => {
                 Position::ReborrowStable(precedence)
             },
         };
@@ -1038,7 +1065,7 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
             if self.0
                 || matches!(
                     ty.kind,
-                    TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(_) | TyKind::Err
+                    TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(_) | TyKind::Err(_)
                 )
             {
                 self.0 = true;
@@ -1378,11 +1405,18 @@ impl<'tcx> TyPosition<'tcx> {
 }
 
 // Checks whether a type is stable when switching to auto dereferencing,
-fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> {
+fn ty_auto_deref_stability<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    precedence: i8,
+) -> TyPosition<'tcx> {
     let ty::Ref(_, mut ty, _) = *ty.kind() else {
         return Position::Other(precedence).into();
     };
 
+    ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
+
     loop {
         break match *ty.kind() {
             ty::Ref(_, ref_ty, _) => {
@@ -1423,9 +1457,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
             | ty::Closure(..)
             | ty::Never
             | ty::Tuple(_)
-            | ty::Alias(ty::Projection, _) => {
-                Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into()
-            },
+            | ty::Alias(ty::Projection, _) => Position::DerefStable(precedence, ty.is_sized(tcx, param_env)).into(),
         };
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 1cdcccd5f14..b8428d66a5d 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -514,7 +514,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
     }
 
     ParamEnv::new(
-        tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
+        tcx.mk_predicates_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
                 tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate {
                     trait_ref: tcx.mk_trait_ref(eq_trait_id, [tcx.mk_param_from_def(param)]),
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 6fdb7de25cc..384aca7fead 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -6,6 +6,11 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
 use if_chain::if_chain;
 use itertools::Itertools;
+use pulldown_cmark::Event::{
+    Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
+};
+use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph};
+use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
 use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
 use rustc_ast::token::CommentKind;
 use rustc_data_structures::fx::FxHashSet;
@@ -497,7 +502,6 @@ struct DocHeaders {
 }
 
 fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> {
-    use pulldown_cmark::{BrokenLink, CowStr, Options};
     /// We don't want the parser to choke on intra doc links. Since we don't
     /// actually care about rendering them, just pretend that all broken links are
     /// point to a fake address.
@@ -538,8 +542,6 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
         pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).into_offset_iter();
     // Iterate over all `Events` and combine consecutive events into one
     let events = parser.coalesce(|previous, current| {
-        use pulldown_cmark::Event::Text;
-
         let previous_range = previous.1;
         let current_range = current.1;
 
@@ -564,12 +566,6 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     spans: &[(usize, Span)],
 ) -> DocHeaders {
     // true if a safety header was found
-    use pulldown_cmark::Event::{
-        Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
-    };
-    use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph};
-    use pulldown_cmark::{CodeBlockKind, CowStr};
-
     let mut headers = DocHeaders::default();
     let mut in_code = false;
     let mut in_link = None;
@@ -660,6 +656,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     check_link_quotes(cx, in_link.is_some(), trimmed_text, span, &range, begin, text.len());
                     // Adjust for the beginning of the current `Event`
                     let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
+                    if let Some(link) = in_link.as_ref()
+                      && let Ok(url) = Url::parse(link)
+                      && (url.scheme() == "https" || url.scheme() == "http") {
+                        // Don't check the text associated with external URLs
+                        continue;
+                    }
                     text_to_check.push((text, span));
                 }
             },
@@ -704,10 +706,8 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
                 let filename = FileName::anon_source_code(&code);
 
                 let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-                let fallback_bundle = rustc_errors::fallback_fluent_bundle(
-                    rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
-                    false
-                );
+                let fallback_bundle =
+                    rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
                 let emitter = EmitterWriter::new(
                     Box::new(io::sink()),
                     None,
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index b44e6243588..48a54f60253 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -6,7 +6,7 @@ use clippy_utils::{
     source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context},
     SpanlessEq,
 };
-use core::fmt::Write;
+use core::fmt::{self, Write};
 use rustc_errors::Applicability;
 use rustc_hir::{
     hir_id::HirIdSet,
@@ -65,6 +65,10 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
 impl<'tcx> LateLintPass<'tcx> for HashMapPass {
     #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
         let Some(higher::If { cond: cond_expr, then: then_expr, r#else: else_expr }) = higher::If::hir(expr) else {
             return
         };
@@ -532,7 +536,7 @@ impl<'tcx> InsertSearchResults<'tcx> {
             if is_expr_used_or_unified(cx.tcx, insertion.call) {
                 write_wrapped(&mut res, insertion, ctxt, app);
             } else {
-                let _ = write!(
+                let _: fmt::Result = write!(
                     res,
                     "e.insert({})",
                     snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
@@ -548,7 +552,7 @@ impl<'tcx> InsertSearchResults<'tcx> {
         (
             self.snippet(cx, span, app, |res, insertion, ctxt, app| {
                 // Insertion into a map would return `Some(&mut value)`, but the entry returns `&mut value`
-                let _ = write!(
+                let _: fmt::Result = write!(
                     res,
                     "Some(e.insert({}))",
                     snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
@@ -562,7 +566,7 @@ impl<'tcx> InsertSearchResults<'tcx> {
         (
             self.snippet(cx, span, app, |res, insertion, ctxt, app| {
                 // Insertion into a map would return `None`, but the entry returns a mutable reference.
-                let _ = if is_expr_final_block_expr(cx.tcx, insertion.call) {
+                let _: fmt::Result = if is_expr_final_block_expr(cx.tcx, insertion.call) {
                     write!(
                         res,
                         "e.insert({});\n{}None",
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
index 2fdd8a71466..20565e1d232 100644
--- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -4,12 +4,17 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::MultiSpan;
 use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
 use rustc_hir::{
-    GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate,
+    BodyId, ExprKind, GenericBound, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
+    PredicateOrigin, Ty, TyKind, WherePredicate,
 };
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{def_id::DefId, Span};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{
+    def_id::{DefId, LocalDefId},
+    Span,
+};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -21,7 +26,6 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```rust
-    /// // unused type parameters
     /// fn unused_ty<T>(x: u8) {
     ///     // ..
     /// }
@@ -37,13 +41,35 @@ declare_clippy_lint! {
     complexity,
     "unused type parameters in function definitions"
 }
-declare_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
+
+pub struct ExtraUnusedTypeParameters {
+    avoid_breaking_exported_api: bool,
+}
+
+impl ExtraUnusedTypeParameters {
+    pub fn new(avoid_breaking_exported_api: bool) -> Self {
+        Self {
+            avoid_breaking_exported_api,
+        }
+    }
+
+    /// Don't lint external macros or functions with empty bodies. Also, don't lint public items if
+    /// the `avoid_breaking_exported_api` config option is set.
+    fn check_false_positive(&self, cx: &LateContext<'_>, span: Span, def_id: LocalDefId, body_id: BodyId) -> bool {
+        let body = cx.tcx.hir().body(body_id).value;
+        let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none());
+        let is_exported = cx.effective_visibilities.is_exported(def_id);
+        in_external_macro(cx.sess(), span) || (self.avoid_breaking_exported_api && is_exported) || fn_empty
+    }
+}
+
+impl_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
 
 /// A visitor struct that walks a given function and gathers generic type parameters, plus any
 /// trait bounds those parameters have.
 struct TypeWalker<'cx, 'tcx> {
     cx: &'cx LateContext<'tcx>,
-    /// Collection of all the type parameters and their spans.
+    /// Collection of all the function's type parameters.
     ty_params: FxHashMap<DefId, Span>,
     /// Collection of any (inline) trait bounds corresponding to each type parameter.
     bounds: FxHashMap<DefId, Span>,
@@ -64,8 +90,8 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
             .params
             .iter()
             .filter_map(|param| {
-                if let GenericParamKind::Type { .. } = param.kind {
-                    Some((param.def_id.into(), param.span))
+                if let GenericParamKind::Type { synthetic, .. } = param.kind {
+                    (!synthetic).then_some((param.def_id.into(), param.span))
                 } else {
                     if !param.is_elided_lifetime() {
                         all_params_unused = false;
@@ -74,6 +100,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
                 }
             })
             .collect();
+
         Self {
             cx,
             ty_params,
@@ -83,6 +110,12 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
         }
     }
 
+    fn mark_param_used(&mut self, def_id: DefId) {
+        if self.ty_params.remove(&def_id).is_some() {
+            self.all_params_unused = false;
+        }
+    }
+
     fn emit_lint(&self) {
         let (msg, help) = match self.ty_params.len() {
             0 => return,
@@ -96,7 +129,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
             ),
         };
 
-        let source_map = self.cx.tcx.sess.source_map();
+        let source_map = self.cx.sess().source_map();
         let span = if self.all_params_unused {
             self.generics.span.into() // Remove the entire list of generics
         } else {
@@ -118,14 +151,18 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
     }
 }
 
+/// Given a generic bound, if the bound is for a trait that's not a `LangItem`, return the
+/// `LocalDefId` for that trait.
+fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option<LocalDefId> {
+    bound.trait_ref()?.trait_def_id()?.as_local()
+}
+
 impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
         if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
-            if self.ty_params.remove(&def_id).is_some() {
-                self.all_params_unused = false;
-            }
+            self.mark_param_used(def_id);
         } else if let TyKind::OpaqueDef(id, _, _) = t.kind {
             // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
             // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're
@@ -139,12 +176,21 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
 
     fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
         if let WherePredicate::BoundPredicate(predicate) = predicate {
-            // Collect spans for bounds that appear in the list of generics (not in a where-clause)
-            // for use in forming the help message
-            if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param()
-                && let PredicateOrigin::GenericParam = predicate.origin
-            {
-                self.bounds.insert(def_id, predicate.span);
+            // Collect spans for any bounds on type parameters. We only keep bounds that appear in
+            // the list of generics (not in a where-clause).
+            if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() {
+                // If the bound contains non-public traits, err on the safe side and don't lint the
+                // corresponding parameter.
+                if !predicate
+                    .bounds
+                    .iter()
+                    .filter_map(bound_to_trait_def_id)
+                    .all(|id| self.cx.effective_visibilities.is_exported(id))
+                {
+                    self.mark_param_used(def_id);
+                } else if let PredicateOrigin::GenericParam = predicate.origin {
+                    self.bounds.insert(def_id, predicate.span);
+                }
             }
             // Only walk the right-hand side of where-bounds
             for bound in predicate.bounds {
@@ -160,7 +206,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
 
 impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if let ItemKind::Fn(_, generics, _) = item.kind {
+        if let ItemKind::Fn(_, generics, body_id) = item.kind
+            && !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id)
+        {
             let mut walker = TypeWalker::new(cx, generics);
             walk_item(&mut walker, item);
             walker.emit_lint();
@@ -169,7 +217,10 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
         // Only lint on inherent methods, not trait methods.
-        if let ImplItemKind::Fn(..) = item.kind && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
+        if let ImplItemKind::Fn(.., body_id) = item.kind
+            && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+            && !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id)
+        {
             let mut walker = TypeWalker::new(cx, item.generics);
             walk_impl_item(&mut walker, item);
             walker.emit_lint();
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index ea26b96ee07..c511d85e9cf 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -340,6 +340,7 @@ fn check_one_arg(
     if matches!(param.kind, Implicit | Starred | Named(_) | Numbered)
         && let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind
         && let [segment] = path.segments
+        && segment.args.is_none()
         && let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id)
     {
         let replacement = match param.usage {
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
new file mode 100644
index 00000000000..2811a73f6c1
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -0,0 +1,50 @@
+use clippy_utils::{diagnostics::span_lint_and_then, is_in_test_function};
+
+use rustc_hir::{intravisit::FnKind, Body, HirId};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+use super::IMPL_TRAIT_IN_PARAMS;
+
+pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
+    if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id)
+    {
+        if let FnKind::ItemFn(ident, generics, _) = kind {
+            for param in generics.params {
+                if param.is_impl_trait() {
+                    // No generics with nested generics, and no generics like FnMut(x)
+                    span_lint_and_then(
+                        cx,
+                        IMPL_TRAIT_IN_PARAMS,
+                        param.span,
+                        "'`impl Trait` used as a function parameter'",
+                        |diag| {
+                            if let Some(gen_span) = generics.span_for_param_suggestion() {
+                                diag.span_suggestion_with_style(
+                                    gen_span,
+                                    "add a type paremeter",
+                                    format!(", {{ /* Generic name */ }}: {}", &param.name.ident().as_str()[5..]),
+                                    rustc_errors::Applicability::HasPlaceholders,
+                                    rustc_errors::SuggestionStyle::ShowAlways,
+                                );
+                            } else {
+                                diag.span_suggestion_with_style(
+                                    Span::new(
+                                        body.params[0].span.lo() - rustc_span::BytePos(1),
+                                        ident.span.hi(),
+                                        ident.span.ctxt(),
+                                        ident.span.parent(),
+                                    ),
+                                    "add a type paremeter",
+                                    format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
+                                    rustc_errors::Applicability::HasPlaceholders,
+                                    rustc_errors::SuggestionStyle::ShowAlways,
+                                );
+                            }
+                        },
+                    );
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 4399c68e130..d2852b4acad 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -1,3 +1,4 @@
+mod impl_trait_in_params;
 mod misnamed_getters;
 mod must_use;
 mod not_unsafe_ptr_arg_deref;
@@ -327,6 +328,32 @@ declare_clippy_lint! {
     "getter method returning the wrong field"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lints when `impl Trait` is being used in a function's paremeters.
+    /// ### Why is this bad?
+    /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
+    ///
+    /// ### Example
+    /// ```rust
+    /// trait MyTrait {}
+    /// fn foo(a: impl MyTrait) {
+    /// 	// [...]
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// trait MyTrait {}
+    /// fn foo<T: MyTrait>(a: T) {
+    /// 	// [...]
+    /// }
+    /// ```
+    #[clippy::version = "1.68.0"]
+    pub IMPL_TRAIT_IN_PARAMS,
+    restriction,
+    "`impl Trait` is used in the function's parameters"
+}
+
 #[derive(Copy, Clone)]
 pub struct Functions {
     too_many_arguments_threshold: u64,
@@ -354,6 +381,7 @@ impl_lint_pass!(Functions => [
     RESULT_UNIT_ERR,
     RESULT_LARGE_ERR,
     MISNAMED_GETTERS,
+    IMPL_TRAIT_IN_PARAMS,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Functions {
@@ -371,6 +399,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
         too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
         not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
         misnamed_getters::check_fn(cx, kind, decl, body, span);
+        impl_trait_in_params::check_fn(cx, &kind, body, hir_id);
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index e2f2d3d42e6..1ad886f2cf3 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -7,7 +7,7 @@ use rustc_hir::{self as hir, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Symbol;
-use std::fmt::Write as _;
+use std::fmt::{self, Write as _};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
                 let mut fields_snippet = String::new();
                 let (last_ident, idents) = ordered_fields.split_last().unwrap();
                 for ident in idents {
-                    let _ = write!(fields_snippet, "{ident}, ");
+                    let _: fmt::Result = write!(fields_snippet, "{ident}, ");
                 }
                 fields_snippet.push_str(&last_ident.to_string());
 
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index f8e35950980..7600777fab9 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -90,7 +90,45 @@ declare_clippy_lint! {
     "non-binding `let` on a future"
 }
 
-declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE]);
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `let _ = <expr>` without a type annotation, and suggests to either provide one,
+    /// or remove the `let` keyword altogether.
+    ///
+    /// ### Why is this bad?
+    /// The `let _ = <expr>` expression ignores the value of `<expr>` but will remain doing so even
+    /// if the type were to change, thus potentially introducing subtle bugs. By supplying a type
+    /// annotation, one will be forced to re-visit the decision to ignore the value in such cases.
+    ///
+    /// ### Known problems
+    /// The `_ = <expr>` is not properly supported by some tools (e.g. IntelliJ) and may seem odd
+    /// to many developers. This lint also partially overlaps with the other `let_underscore_*`
+    /// lints.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn foo() -> Result<u32, ()> {
+    ///     Ok(123)
+    /// }
+    /// let _ = foo();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn foo() -> Result<u32, ()> {
+    ///     Ok(123)
+    /// }
+    /// // Either provide a type annotation:
+    /// let _: Result<u32, ()> = foo();
+    /// // …or drop the let keyword:
+    /// _ = foo();
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub LET_UNDERSCORE_UNTYPED,
+    pedantic,
+    "non-binding `let` without a type annotation"
+}
+
+declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE, LET_UNDERSCORE_UNTYPED]);
 
 const SYNC_GUARD_PATHS: [&[&str]; 3] = [
     &paths::PARKING_LOT_MUTEX_GUARD,
@@ -148,6 +186,18 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                     "consider explicitly using function result",
                 );
             }
+
+            if local.pat.default_binding_modes && local.ty.is_none() {
+                // When `default_binding_modes` is true, the `let` keyword is present.
+                span_lint_and_help(
+                    cx,
+                    LET_UNDERSCORE_UNTYPED,
+                    local.span,
+                    "non-binding `let` without a type annotation",
+                    None,
+                    "consider adding a type annotation or removing the `let` keyword",
+                );
+            }
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 9011f0896a0..145cf524652 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -2,6 +2,7 @@
 #![feature(binary_heap_into_iter_sorted)]
 #![feature(box_patterns)]
 #![feature(drain_filter)]
+#![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(lint_reasons)]
@@ -219,6 +220,7 @@ mod neg_cmp_op_on_partial_ord;
 mod neg_multiply;
 mod new_without_default;
 mod no_effect;
+mod no_mangle_with_rust_abi;
 mod non_copy_const;
 mod non_expressive_names;
 mod non_octal_unix_permissions;
@@ -243,6 +245,7 @@ mod ptr;
 mod ptr_offset_with_cast;
 mod pub_use;
 mod question_mark;
+mod question_mark_used;
 mod ranges;
 mod rc_clone_in_vec_init;
 mod read_zero_byte_vec;
@@ -264,6 +267,7 @@ mod semicolon_block;
 mod semicolon_if_nothing_returned;
 mod serde_api;
 mod shadow;
+mod significant_drop_tightening;
 mod single_char_lifetime_names;
 mod single_component_path_imports;
 mod size_of_in_element_count;
@@ -559,6 +563,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
     store.register_late_pass(|_| Box::new(mut_mut::MutMut));
     store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
+    store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default());
     store.register_late_pass(|_| Box::new(len_zero::LenZero));
     store.register_late_pass(|_| Box::new(attrs::Attributes));
     store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
@@ -665,12 +670,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         ))
     });
     let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
+    let missing_docs_in_crate_items = conf.missing_docs_in_crate_items;
     store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
     store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
     store.register_late_pass(|_| Box::new(mem_forget::MemForget));
     store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
     store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
-    store.register_late_pass(|_| Box::new(missing_doc::MissingDoc::new()));
+    store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(missing_docs_in_crate_items)));
     store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
     store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
     store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
@@ -694,6 +700,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
     store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
     store.register_late_pass(|_| Box::new(question_mark::QuestionMark));
+    store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed));
     store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
     store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
     store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit));
@@ -911,7 +918,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
     store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
     store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
-    store.register_late_pass(|_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters));
+    store.register_late_pass(move |_| {
+        Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters::new(
+            avoid_breaking_exported_api,
+        ))
+    });
+    store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 43a1a65a43a..986ffcad883 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -144,6 +144,10 @@ fn check_fn_inner<'tcx>(
         .filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
 
     for typ in types {
+        if !typ.span.eq_ctxt(span) {
+            return;
+        }
+
         for pred in generics.bounds_for_param(typ.def_id) {
             if pred.origin == PredicateOrigin::WhereClause {
                 // has_where_lifetimes checked that this predicate contains no lifetime.
@@ -181,6 +185,10 @@ fn check_fn_inner<'tcx>(
     }
 
     if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params) {
+        if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) {
+            return;
+        }
+
         let lts = elidable_lts
             .iter()
             // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 3a7b7835c99..dadcd9c5135 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -210,7 +210,7 @@ impl WarningType {
                 cx,
                 UNUSUAL_BYTE_GROUPINGS,
                 span,
-                "digits of hex or binary literal not grouped by four",
+                "digits of hex, binary or octal literal not in groups of equal size",
                 "consider",
                 suggested_format,
                 Applicability::MachineApplicable,
@@ -427,8 +427,12 @@ impl LiteralDigitGrouping {
 
         let first = groups.next().expect("At least one group");
 
-        if (radix == Radix::Binary || radix == Radix::Hexadecimal) && groups.any(|i| i != 4 && i != 2) {
-            return Err(WarningType::UnusualByteGroupings);
+        if radix == Radix::Binary || radix == Radix::Octal || radix == Radix::Hexadecimal {
+            if let Some(second_size) = groups.next() {
+                if !groups.all(|i| i == second_size) || first > second_size {
+                    return Err(WarningType::UnusualByteGroupings);
+                }
+            }
         }
 
         if let Some(second) = groups.next() {
@@ -484,7 +488,7 @@ impl DecimalLiteralRepresentation {
             then {
                 let hex = format!("{val:#X}");
                 let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
-                let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
+                let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| {
                     warning_type.display(num_lit.format(), cx, span);
                 });
             }
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 14f161f5102..b1bc10802e1 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -39,6 +39,7 @@ pub(super) fn check(
             });
         },
         NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
+        NeverLoopResult::IgnoreUntilEnd(_) => unreachable!(),
     }
 }
 
@@ -48,6 +49,8 @@ enum NeverLoopResult {
     AlwaysBreak,
     // A continue may occur for the main loop.
     MayContinueMainLoop,
+    // Ignore everything until the end of the block with this id
+    IgnoreUntilEnd(HirId),
     Otherwise,
 }
 
@@ -56,6 +59,7 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
     match arg {
         NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
         NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
+        NeverLoopResult::IgnoreUntilEnd(id) => NeverLoopResult::IgnoreUntilEnd(id),
     }
 }
 
@@ -63,27 +67,26 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
 #[must_use]
 fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult {
     match first {
-        NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop => first,
-        NeverLoopResult::Otherwise => second,
-    }
-}
-
-// Combine two results where both parts are called but not necessarily in order.
-#[must_use]
-fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult {
-    match (left, right) {
-        (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
-            NeverLoopResult::MayContinueMainLoop
+        NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop | NeverLoopResult::IgnoreUntilEnd(_) => {
+            first
         },
-        (NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
-        (NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
+        NeverLoopResult::Otherwise => second,
     }
 }
 
 // Combine two results where only one of the part may have been executed.
 #[must_use]
-fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
+fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirId]) -> NeverLoopResult {
     match (b1, b2) {
+        (NeverLoopResult::IgnoreUntilEnd(a), NeverLoopResult::IgnoreUntilEnd(b)) => {
+            if ignore_ids.iter().find(|&e| e == &a || e == &b).unwrap() == &a {
+                NeverLoopResult::IgnoreUntilEnd(b)
+            } else {
+                NeverLoopResult::IgnoreUntilEnd(a)
+            }
+        },
+        (i @ NeverLoopResult::IgnoreUntilEnd(_), NeverLoopResult::AlwaysBreak)
+        | (NeverLoopResult::AlwaysBreak, i @ NeverLoopResult::IgnoreUntilEnd(_)) => i,
         (NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
         (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
             NeverLoopResult::MayContinueMainLoop
@@ -103,7 +106,7 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id
         let e = never_loop_expr(e, ignore_ids, main_loop_id);
         // els is an else block in a let...else binding
         els.map_or(e, |els| {
-            combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id))
+            combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id), ignore_ids)
         })
     })
     .fold(NeverLoopResult::Otherwise, combine_seq)
@@ -139,7 +142,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
         ExprKind::Struct(_, fields, base) => {
             let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
             if let Some(base) = base {
-                combine_both(fields, never_loop_expr(base, ignore_ids, main_loop_id))
+                combine_seq(fields, never_loop_expr(base, ignore_ids, main_loop_id))
             } else {
                 fields
             }
@@ -159,7 +162,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
             let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| {
                 never_loop_expr(e, ignore_ids, main_loop_id)
             });
-            combine_seq(e1, combine_branches(e2, e3))
+            combine_seq(e1, combine_branches(e2, e3, ignore_ids))
         },
         ExprKind::Match(e, arms, _) => {
             let e = never_loop_expr(e, ignore_ids, main_loop_id);
@@ -175,8 +178,13 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
                 ignore_ids.push(b.hir_id);
             }
             let ret = never_loop_block(b, ignore_ids, main_loop_id);
-            ignore_ids.pop();
-            ret
+            if l.is_some() {
+                ignore_ids.pop();
+            }
+            match ret {
+                NeverLoopResult::IgnoreUntilEnd(a) if a == b.hir_id => NeverLoopResult::Otherwise,
+                _ => ret,
+            }
         },
         ExprKind::Continue(d) => {
             let id = d
@@ -190,8 +198,8 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
         },
         // checks if break targets a block instead of a loop
         ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e
-            .map_or(NeverLoopResult::Otherwise, |e| {
-                combine_seq(never_loop_expr(e, ignore_ids, main_loop_id), NeverLoopResult::Otherwise)
+            .map_or(NeverLoopResult::IgnoreUntilEnd(t), |e| {
+                never_loop_expr(e, ignore_ids, main_loop_id)
             }),
         ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
             combine_seq(
@@ -218,13 +226,13 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
                 | InlineAsmOperand::SymFn { .. }
                 | InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
             })
-            .fold(NeverLoopResult::Otherwise, combine_both),
+            .fold(NeverLoopResult::Otherwise, combine_seq),
         ExprKind::Yield(_, _)
         | ExprKind::Closure { .. }
         | ExprKind::Path(_)
         | ExprKind::ConstBlock(_)
         | ExprKind::Lit(_)
-        | ExprKind::Err => NeverLoopResult::Otherwise,
+        | ExprKind::Err(_) => NeverLoopResult::Otherwise,
     }
 }
 
@@ -234,7 +242,7 @@ fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(
     main_loop_id: HirId,
 ) -> NeverLoopResult {
     es.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
-        .fold(NeverLoopResult::Otherwise, combine_both)
+        .fold(NeverLoopResult::Otherwise, combine_seq)
 }
 
 fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
@@ -242,8 +250,9 @@ fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
     ignore_ids: &mut Vec<HirId>,
     main_loop_id: HirId,
 ) -> NeverLoopResult {
-    e.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
-        .fold(NeverLoopResult::AlwaysBreak, combine_branches)
+    e.fold(NeverLoopResult::AlwaysBreak, |a, b| {
+        combine_branches(a, never_loop_expr(b, ignore_ids, main_loop_id), ignore_ids)
+    })
 }
 
 fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 9c6f8b43c07..98e698c6c2a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -4,11 +4,12 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::peel_blocks;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::visitors::{for_each_expr, Descend};
+use clippy_utils::visitors::{Descend, Visitable};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir::{Expr, ExprKind, HirId, ItemId, Local, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind, Ty};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -115,6 +116,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
                     .enumerate()
                     .find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
                 let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
+                // If the non-diverging arm is the first one, its pattern can be reused in a let/else statement.
+                // However, if it arrives in second position, its pattern may cover some cases already covered
+                // by the diverging one.
+                // TODO: accept the non-diverging arm as a second position if patterns are disjointed.
+                if idx == 0 {
+                    return;
+                }
                 let pat_arm = &arms[1 - idx];
                 if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
                     return;
@@ -162,61 +170,102 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat:
     );
 }
 
-fn expr_diverges(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
-    fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
-        if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
-            return ty.is_never();
-        }
-        false
+/// Check whether an expression is divergent. May give false negatives.
+fn expr_diverges(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    struct V<'cx, 'tcx> {
+        cx: &'cx LateContext<'tcx>,
+        res: ControlFlow<(), Descend>,
     }
-    // We can't just call is_never on expr and be done, because the type system
-    // sometimes coerces the ! type to something different before we can get
-    // our hands on it. So instead, we do a manual search. We do fall back to
-    // is_never in some places when there is no better alternative.
-    for_each_expr(expr, |ex| {
-        match ex.kind {
-            ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
-            ExprKind::Call(call, _) => {
-                if is_never(cx, ex) || is_never(cx, call) {
-                    return ControlFlow::Break(());
-                }
-                ControlFlow::Continue(Descend::Yes)
-            },
-            ExprKind::MethodCall(..) => {
-                if is_never(cx, ex) {
-                    return ControlFlow::Break(());
-                }
-                ControlFlow::Continue(Descend::Yes)
-            },
-            ExprKind::If(if_expr, if_then, if_else) => {
-                let else_diverges = if_else.map_or(false, |ex| expr_diverges(cx, ex));
-                let diverges = expr_diverges(cx, if_expr) || (else_diverges && expr_diverges(cx, if_then));
-                if diverges {
-                    return ControlFlow::Break(());
+    impl<'tcx> Visitor<'tcx> for V<'_, '_> {
+        fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
+            fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
+                if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
+                    return ty.is_never();
                 }
-                ControlFlow::Continue(Descend::No)
-            },
-            ExprKind::Match(match_expr, match_arms, _) => {
-                let diverges = expr_diverges(cx, match_expr)
-                    || match_arms.iter().all(|arm| {
-                        let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(cx, g.body()));
-                        guard_diverges || expr_diverges(cx, arm.body)
-                    });
-                if diverges {
-                    return ControlFlow::Break(());
-                }
-                ControlFlow::Continue(Descend::No)
-            },
+                false
+            }
 
-            // Don't continue into loops or labeled blocks, as they are breakable,
-            // and we'd have to start checking labels.
-            ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
+            if self.res.is_break() {
+                return;
+            }
 
-            // Default: descend
-            _ => ControlFlow::Continue(Descend::Yes),
+            // We can't just call is_never on expr and be done, because the type system
+            // sometimes coerces the ! type to something different before we can get
+            // our hands on it. So instead, we do a manual search. We do fall back to
+            // is_never in some places when there is no better alternative.
+            self.res = match e.kind {
+                ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
+                ExprKind::Call(call, _) => {
+                    if is_never(self.cx, e) || is_never(self.cx, call) {
+                        ControlFlow::Break(())
+                    } else {
+                        ControlFlow::Continue(Descend::Yes)
+                    }
+                },
+                ExprKind::MethodCall(..) => {
+                    if is_never(self.cx, e) {
+                        ControlFlow::Break(())
+                    } else {
+                        ControlFlow::Continue(Descend::Yes)
+                    }
+                },
+                ExprKind::If(if_expr, if_then, if_else) => {
+                    let else_diverges = if_else.map_or(false, |ex| expr_diverges(self.cx, ex));
+                    let diverges =
+                        expr_diverges(self.cx, if_expr) || (else_diverges && expr_diverges(self.cx, if_then));
+                    if diverges {
+                        ControlFlow::Break(())
+                    } else {
+                        ControlFlow::Continue(Descend::No)
+                    }
+                },
+                ExprKind::Match(match_expr, match_arms, _) => {
+                    let diverges = expr_diverges(self.cx, match_expr)
+                        || match_arms.iter().all(|arm| {
+                            let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(self.cx, g.body()));
+                            guard_diverges || expr_diverges(self.cx, arm.body)
+                        });
+                    if diverges {
+                        ControlFlow::Break(())
+                    } else {
+                        ControlFlow::Continue(Descend::No)
+                    }
+                },
+
+                // Don't continue into loops or labeled blocks, as they are breakable,
+                // and we'd have to start checking labels.
+                ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
+
+                // Default: descend
+                _ => ControlFlow::Continue(Descend::Yes),
+            };
+            if let ControlFlow::Continue(Descend::Yes) = self.res {
+                walk_expr(self, e);
+            }
+        }
+
+        fn visit_local(&mut self, local: &'tcx Local<'_>) {
+            // Don't visit the else block of a let/else statement as it will not make
+            // the statement divergent even though the else block is divergent.
+            if let Some(init) = local.init {
+                self.visit_expr(init);
+            }
         }
-    })
-    .is_some()
+
+        // Avoid unnecessary `walk_*` calls.
+        fn visit_ty(&mut self, _: &'tcx Ty<'tcx>) {}
+        fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {}
+        fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {}
+        // Avoid monomorphising all `visit_*` functions.
+        fn visit_nested_item(&mut self, _: ItemId) {}
+    }
+
+    let mut v = V {
+        cx,
+        res: ControlFlow::Continue(Descend::Yes),
+    };
+    expr.visit(&mut v);
+    v.res.is_break()
 }
 
 fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index f587c69f730..b33a2478172 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -341,7 +341,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
             ExprKind::ConstBlock(_) |
             ExprKind::Continue(_) |
             ExprKind::DropTemps(_) |
-            ExprKind::Err |
+            ExprKind::Err(_) |
             ExprKind::InlineAsm(_) |
             ExprKind::Let(_) |
             ExprKind::Lit(_) |
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
index d512cc4eeae..c5fc145b289 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
@@ -5,6 +5,8 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, LangItem};
 use rustc_lint::LateContext;
 
+use crate::methods::method_call;
+
 use super::BYTES_NTH;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) {
@@ -16,18 +18,32 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
     } else {
         return;
     };
+
     let mut applicability = Applicability::MachineApplicable;
-    span_lint_and_sugg(
-        cx,
-        BYTES_NTH,
-        expr.span,
-        &format!("called `.bytes().nth()` on a `{caller_type}`"),
-        "try",
-        format!(
-            "{}.as_bytes().get({})",
-            snippet_with_applicability(cx, recv.span, "..", &mut applicability),
-            snippet_with_applicability(cx, n_arg.span, "..", &mut applicability)
-        ),
-        applicability,
-    );
+    let receiver = snippet_with_applicability(cx, recv.span, "..", &mut applicability);
+    let n = snippet_with_applicability(cx, n_arg.span, "..", &mut applicability);
+
+    if let Some(parent) = clippy_utils::get_parent_expr(cx, expr)
+      && let Some((name, _, _, _, _)) = method_call(parent)
+      && name == "unwrap" {
+        span_lint_and_sugg(
+            cx,
+            BYTES_NTH,
+            parent.span,
+            &format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"),
+            "try",
+            format!("{receiver}.as_bytes()[{n}]",),
+            applicability
+        );
+    } else {
+        span_lint_and_sugg(
+            cx,
+            BYTES_NTH,
+            expr.span,
+            &format!("called `.bytes().nth()` on a `{caller_type}`"),
+            "try",
+            format!("{receiver}.as_bytes().get({n}).copied()"), 
+            applicability
+        );
+    };
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
index cce8f797e98..614610335a1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_in_cfg_test;
 use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::sym;
@@ -27,7 +27,7 @@ pub(super) fn check(
 
     let method = if is_err { "expect_err" } else { "expect" };
 
-    if allow_expect_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
+    if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
         return;
     }
 
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 374eb29fc52..5a78a416877 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -53,7 +53,9 @@ pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir
         "to_vec" => cx
             .tcx
             .impl_of_method(method_def_id)
-            .filter(|&impl_did| cx.tcx.type_of(impl_did).subst_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none())
+            .filter(|&impl_did| {
+                cx.tcx.type_of(impl_did).subst_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()
+            })
             .is_some(),
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 6301b3ded20..702df4b282b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -80,6 +80,7 @@ mod skip_while_next;
 mod stable_sort_primitive;
 mod str_splitn;
 mod string_extend_chars;
+mod suspicious_command_arg_space;
 mod suspicious_map;
 mod suspicious_splitn;
 mod suspicious_to_owned;
@@ -3162,6 +3163,32 @@ declare_clippy_lint! {
     "collecting an iterator when collect is not needed"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for `Command::arg()` invocations that look like they
+    /// should be multiple arguments instead, such as `arg("-t ext2")`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// `Command::arg()` does not split arguments by space. An argument like `arg("-t ext2")`
+    /// will be passed as a single argument to the command,
+    /// which is likely not what was intended.
+    ///
+    /// ### Example
+    /// ```rust
+    /// std::process::Command::new("echo").arg("-n hello").spawn().unwrap();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap();
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub SUSPICIOUS_COMMAND_ARG_SPACE,
+    suspicious,
+    "single command line argument that looks like it should be multiple arguments"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -3289,6 +3316,7 @@ impl_lint_pass!(Methods => [
     SEEK_FROM_CURRENT,
     SEEK_TO_START_INSTEAD_OF_REWIND,
     NEEDLESS_COLLECT,
+    SUSPICIOUS_COMMAND_ARG_SPACE,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -3496,6 +3524,9 @@ impl Methods {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
                     }
                 },
+                ("arg", [arg]) => {
+                    suspicious_command_arg_space::check(cx, recv, arg, span);
+                }
                 ("as_deref" | "as_deref_mut", []) => {
                     needless_option_as_deref::check(cx, expr, recv, name);
                 },
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 8ddbacc3d7a..0b0c6adc504 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -173,7 +173,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
         && let Some(iter_item) = cx.tcx
             .associated_items(iter_trait)
             .find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait)
-        && let substs = cx.tcx.intern_substs(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
+        && let substs = cx.tcx.mk_substs(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
         && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs)
         && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
new file mode 100644
index 00000000000..73632c5a357
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
@@ -0,0 +1,39 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths;
+use clippy_utils::ty::match_type;
+use rustc_ast as ast;
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+use super::SUSPICIOUS_COMMAND_ARG_SPACE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) {
+    let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+
+    if match_type(cx, ty, &paths::STD_PROCESS_COMMAND)
+        && let hir::ExprKind::Lit(lit) = &arg.kind
+        && let ast::LitKind::Str(s, _) = &lit.node
+        && let Some((arg1, arg2)) = s.as_str().split_once(' ')
+        && arg1.starts_with('-')
+        && arg1.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
+    {
+        span_lint_and_then(
+            cx,
+            SUSPICIOUS_COMMAND_ARG_SPACE,
+            arg.span,
+            "single argument that looks like it should be multiple arguments",
+            |diag: &mut Diagnostic| {
+                diag.multipart_suggestion_verbose(
+                    "consider splitting the argument",
+                    vec![
+                        (span, "args".to_string()),
+                        (arg.span, format!("[{arg1:?}, {arg2:?}]")),
+                    ],
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        );
+    }
+}
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 4e5af1c7c71..df26b36b7b3 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
@@ -414,7 +414,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                             }
                         });
 
-                        let new_subst = cx.tcx.mk_substs(
+                        let new_subst = cx.tcx.mk_substs_from_iter(
                             call_substs.iter()
                                 .enumerate()
                                 .map(|(i, t)|
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
index 90983f249cd..5e4c3daee64 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_in_cfg_test, is_lint_allowed};
+use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::sym;
@@ -27,7 +27,7 @@ pub(super) fn check(
 
     let method_suffix = if is_err { "_err" } else { "" };
 
-    if allow_unwrap_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
+    if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 6fd100762b4..9659ca8ced2 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -8,10 +8,12 @@
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_from_proc_macro;
+use hir::def_id::LocalDefId;
+use if_chain::if_chain;
 use rustc_ast::ast::{self, MetaItem, MetaItemKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::DefIdTree;
+use rustc_middle::ty::{DefIdTree, Visibility};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Span;
@@ -34,6 +36,9 @@ declare_clippy_lint! {
 }
 
 pub struct MissingDoc {
+    /// Whether to **only** check for missing documentation in items visible within the current
+    /// crate. For example, `pub(crate)` items.
+    crate_items_only: bool,
     /// Stack of whether #[doc(hidden)] is set
     /// at each level which has lint attributes.
     doc_hidden_stack: Vec<bool>,
@@ -42,14 +47,15 @@ pub struct MissingDoc {
 impl Default for MissingDoc {
     #[must_use]
     fn default() -> Self {
-        Self::new()
+        Self::new(false)
     }
 }
 
 impl MissingDoc {
     #[must_use]
-    pub fn new() -> Self {
+    pub fn new(crate_items_only: bool) -> Self {
         Self {
+            crate_items_only,
             doc_hidden_stack: vec![false],
         }
     }
@@ -75,6 +81,7 @@ impl MissingDoc {
     fn check_missing_docs_attrs(
         &self,
         cx: &LateContext<'_>,
+        def_id: LocalDefId,
         attrs: &[ast::Attribute],
         sp: Span,
         article: &'static str,
@@ -95,6 +102,13 @@ impl MissingDoc {
             return;
         }
 
+        if self.crate_items_only && def_id != CRATE_DEF_ID {
+            let vis = cx.tcx.visibility(def_id);
+            if vis == Visibility::Public || vis != Visibility::Restricted(CRATE_DEF_ID.into()) {
+                return;
+            }
+        }
+
         let has_doc = attrs
             .iter()
             .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
@@ -123,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
     fn check_crate(&mut self, cx: &LateContext<'tcx>) {
         let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
-        self.check_missing_docs_attrs(cx, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate");
+        self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate");
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
@@ -159,7 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
         let attrs = cx.tcx.hir().attrs(it.hir_id());
         if !is_from_proc_macro(cx, it) {
-            self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+            self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc);
         }
     }
 
@@ -168,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
         let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
         if !is_from_proc_macro(cx, trait_item) {
-            self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+            self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc);
         }
     }
 
@@ -185,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
         let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
         if !is_from_proc_macro(cx, impl_item) {
-            self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+            self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc);
         }
     }
 
@@ -193,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         if !sf.is_positional() {
             let attrs = cx.tcx.hir().attrs(sf.hir_id);
             if !is_from_proc_macro(cx, sf) {
-                self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+                self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field");
             }
         }
     }
@@ -201,7 +215,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
     fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
         let attrs = cx.tcx.hir().attrs(v.hir_id);
         if !is_from_proc_macro(cx, v) {
-            self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+            self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant");
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index 0742943dff2..349fcd2274d 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -134,7 +134,7 @@ fn process_paths_for_mod_files<'a>(
     mod_folders: &mut FxHashSet<&'a OsStr>,
 ) {
     let mut comp = path.components().rev().peekable();
-    let _ = comp.next();
+    let _: Option<_> = comp.next();
     if path.ends_with("mod.rs") {
         mod_folders.insert(comp.peek().map(|c| c.as_os_str()).unwrap_or_default());
     }
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 5a533261cad..8aa814b7405 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -166,7 +166,8 @@ impl MutableKeyType {
             Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty),
             Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty),
             Array(inner_ty, size) => {
-                size.try_eval_target_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
+                size.try_eval_target_usize(cx.tcx, cx.param_env)
+                    .map_or(true, |u| u != 0)
                     && self.is_interior_mutable_type(cx, inner_ty)
             },
             Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)),
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index da3b6fa9899..1ab81aee7b8 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -149,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
         };
 
         let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
-        let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);
+        let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig);
 
         for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() {
             // All spans generated from a proc-macro invocation are the same...
diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
new file mode 100644
index 00000000000..bc64ccb295c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
@@ -0,0 +1,65 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::Applicability;
+use rustc_hir::{Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_target::spec::abi::Abi;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for Rust ABI functions with the `#[no_mangle]` attribute.
+    ///
+    /// ### Why is this bad?
+    /// The Rust ABI is not stable, but in many simple cases matches
+    /// enough with the C ABI that it is possible to forget to add
+    /// `extern "C"` to a function called from C. Changes to the
+    /// Rust ABI can break this at any point.
+    ///
+    /// ### Example
+    /// ```rust
+    ///  #[no_mangle]
+    ///  fn example(arg_one: u32, arg_two: usize) {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    ///  #[no_mangle]
+    ///  extern "C" fn example(arg_one: u32, arg_two: usize) {}
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub NO_MANGLE_WITH_RUST_ABI,
+    pedantic,
+    "convert Rust ABI functions to C ABI"
+}
+declare_lint_pass!(NoMangleWithRustAbi => [NO_MANGLE_WITH_RUST_ABI]);
+
+impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if let ItemKind::Fn(fn_sig, _, _) = &item.kind {
+            let attrs = cx.tcx.hir().attrs(item.hir_id());
+            let mut applicability = Applicability::MachineApplicable;
+            let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut applicability);
+            for attr in attrs {
+                if let Some(ident) = attr.ident()
+                    && ident.name == rustc_span::sym::no_mangle
+                    && fn_sig.header.abi == Abi::Rust
+                    && !snippet.contains("extern") {
+
+                    let suggestion = snippet.split_once("fn")
+                        .map_or(String::new(), |(first, second)| format!(r#"{first}extern "C" fn{second}"#));
+
+                    span_lint_and_sugg(
+                        cx,
+                        NO_MANGLE_WITH_RUST_ABI,
+                        fn_sig.span,
+                        "attribute #[no_mangle] set on a Rust ABI function",
+                        "try",
+                        suggestion,
+                        applicability
+                    );
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index d592f6e814c..87a8a2ed12b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -1,8 +1,8 @@
 use super::ARITHMETIC_SIDE_EFFECTS;
 use clippy_utils::{
-    consts::{constant, constant_simple},
+    consts::{constant, constant_simple, Constant},
     diagnostics::span_lint,
-    peel_hir_expr_refs, peel_hir_expr_unary,
+    is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary,
 };
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -97,17 +97,19 @@ impl ArithmeticSideEffects {
         self.expr_span = Some(expr.span);
     }
 
-    /// If `expr` is not a literal integer like `1`, returns `None`.
+    /// Returns the numeric value of a literal integer originated from `expr`, if any.
     ///
-    /// Returns the absolute value of the expression, if this is an integer literal.
-    fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> {
+    /// Literal integers can be originated from adhoc declarations like `1`, associated constants
+    /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`,
+    fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
         let actual = peel_hir_expr_unary(expr).0;
         if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
-            Some(n)
+            return Some(n)
         }
-        else {
-            None
+        if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) {
+            return Some(n);
         }
+        None
     }
 
     /// Manages when the lint should be triggered. Operations in constant environments, hard coded
@@ -143,7 +145,10 @@ impl ArithmeticSideEffects {
         let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
             let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
             let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
-            match (Self::literal_integer(actual_lhs), Self::literal_integer(actual_rhs)) {
+            match (
+                Self::literal_integer(cx, actual_lhs),
+                Self::literal_integer(cx, actual_rhs),
+            ) {
                 (None, None) => false,
                 (None, Some(n)) | (Some(n), None) => match (&op.node, n) {
                     (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
@@ -180,20 +185,22 @@ impl ArithmeticSideEffects {
             return;
         }
         let actual_un_expr = peel_hir_expr_refs(un_expr).0;
-        if Self::literal_integer(actual_un_expr).is_some() {
+        if Self::literal_integer(cx, actual_un_expr).is_some() {
             return;
         }
         self.issue_lint(cx, expr);
     }
 
-    fn should_skip_expr(&mut self, expr: &hir::Expr<'_>) -> bool {
-        self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span))
+    fn should_skip_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+        is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id)
+            || self.expr_span.is_some()
+            || self.const_span.map_or(false, |sp| sp.contains(expr.span))
     }
 }
 
 impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
-        if self.should_skip_expr(expr) {
+        if self.should_skip_expr(cx, expr) {
             return;
         }
         match &expr.kind {
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index 24aeb82a37f..d3de9699fe9 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -49,10 +49,10 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
             (arg, arg.span)
         },
         ExprKind::Call(path, [arg])
-            if path_def_id(cx, path).map_or(false, |id| {
-                if match_def_path(cx, id, &paths::FROM_STR_METHOD) {
+            if path_def_id(cx, path).map_or(false, |did| {
+                if match_def_path(cx, did, &paths::FROM_STR_METHOD) {
                     true
-                } else if cx.tcx.lang_items().from_fn() == Some(id) {
+                } else if cx.tcx.is_diagnostic_item(sym::from_fn, did) {
                     !is_copy(cx, typeck.expr_ty(expr))
                 } else {
                     false
diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
new file mode 100644
index 00000000000..9b678e8d753
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
@@ -0,0 +1,52 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+
+use clippy_utils::macros::span_is_local;
+use rustc_hir::{Expr, ExprKind, MatchSource};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for expressions that use the question mark operator and rejects them.
+    ///
+    /// ### Why is this bad?
+    /// Sometimes code wants to avoid the question mark operator because for instance a local
+    /// block requires a macro to re-throw errors to attach additional information to the
+    /// error.
+    ///
+    /// ### Example
+    /// ```ignore
+    /// let result = expr?;
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```ignore
+    /// utility_macro!(expr);
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub QUESTION_MARK_USED,
+    restriction,
+    "complains if the question mark operator is used"
+}
+
+declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]);
+
+impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Match(_, _, MatchSource::TryDesugar) = expr.kind {
+            if !span_is_local(expr.span) {
+                return;
+            }
+
+            span_lint_and_help(
+                cx,
+                QUESTION_MARK_USED,
+                expr.span,
+                "question mark operator was used",
+                None,
+                "consider using a custom macro or match expression",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 398329e455b..2fdd775ad48 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                 } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
                     if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
                         cx.param_env,
-                        cx.tcx.mk_projection(target_id, cx.tcx.intern_substs(&[GenericArg::from(indexed_ty)])),
+                        cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(&[GenericArg::from(indexed_ty)])),
                     ) {
                         if deref_ty == expr_ty {
                             let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 84a0c6b9558..f0d7dd23a67 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -14,6 +14,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::{BytePos, Pos};
+use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -69,31 +70,41 @@ declare_clippy_lint! {
     "using a return statement like `return expr;` where an expression would suffice"
 }
 
-#[derive(PartialEq, Eq, Copy, Clone)]
-enum RetReplacement {
+#[derive(PartialEq, Eq, Clone)]
+enum RetReplacement<'tcx> {
     Empty,
     Block,
     Unit,
+    IfSequence(Cow<'tcx, str>, Applicability),
+    Expr(Cow<'tcx, str>, Applicability),
 }
 
-impl RetReplacement {
+impl<'tcx> RetReplacement<'tcx> {
     fn sugg_help(self) -> &'static str {
         match self {
-            Self::Empty => "remove `return`",
+            Self::Empty | Self::Expr(..) => "remove `return`",
             Self::Block => "replace `return` with an empty block",
             Self::Unit => "replace `return` with a unit value",
+            Self::IfSequence(..) => "remove `return` and wrap the sequence with parentheses",
+        }
+    }
+    fn applicability(&self) -> Option<Applicability> {
+        match self {
+            Self::Expr(_, ap) | Self::IfSequence(_, ap) => Some(*ap),
+            _ => None,
         }
     }
 }
 
-impl ToString for RetReplacement {
+impl<'tcx> ToString for RetReplacement<'tcx> {
     fn to_string(&self) -> String {
-        match *self {
-            Self::Empty => "",
-            Self::Block => "{}",
-            Self::Unit => "()",
+        match self {
+            Self::Empty => String::new(),
+            Self::Block => "{}".to_string(),
+            Self::Unit => "()".to_string(),
+            Self::IfSequence(inner, _) => format!("({inner})"),
+            Self::Expr(inner, _) => inner.to_string(),
         }
-        .to_string()
     }
 }
 
@@ -204,19 +215,38 @@ fn check_final_expr<'tcx>(
     expr: &'tcx Expr<'tcx>,
     semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
                             * needless return */
-    replacement: RetReplacement,
+    replacement: RetReplacement<'tcx>,
 ) {
     let peeled_drop_expr = expr.peel_drop_temps();
     match &peeled_drop_expr.kind {
         // simple return is always "bad"
         ExprKind::Ret(ref inner) => {
-            // if desugar of `do yeet`, don't lint
-            if let Some(inner_expr) = inner
-                && let ExprKind::Call(path_expr, _) = inner_expr.kind
-                && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind
-            {
-                return;
-            }
+            // check if expr return nothing
+            let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
+                extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
+            } else {
+                peeled_drop_expr.span
+            };
+
+            let replacement = if let Some(inner_expr) = inner {
+                // if desugar of `do yeet`, don't lint
+                if let ExprKind::Call(path_expr, _) = inner_expr.kind
+                    && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind
+                {
+                    return;
+                }
+
+                let mut applicability = Applicability::MachineApplicable;
+                let (snippet, _) = snippet_with_context(cx, inner_expr.span, ret_span.ctxt(), "..", &mut applicability);
+                if expr_contains_conjunctive_ifs(inner_expr) {
+                    RetReplacement::IfSequence(snippet, applicability)
+                } else {
+                    RetReplacement::Expr(snippet, applicability)
+                }
+            } else {
+                replacement
+            };
+
             if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
                 return;
             }
@@ -224,14 +254,8 @@ fn check_final_expr<'tcx>(
             if borrows {
                 return;
             }
-            // check if expr return nothing
-            let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
-                extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
-            } else {
-                peeled_drop_expr.span
-            };
 
-            emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
+            emit_return_lint(cx, ret_span, semi_spans, replacement);
         },
         ExprKind::If(_, then, else_clause_opt) => {
             check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
@@ -253,29 +277,25 @@ fn check_final_expr<'tcx>(
     }
 }
 
-fn emit_return_lint(
-    cx: &LateContext<'_>,
-    ret_span: Span,
-    semi_spans: Vec<Span>,
-    inner_span: Option<Span>,
-    replacement: RetReplacement,
-) {
+fn expr_contains_conjunctive_ifs<'tcx>(expr: &'tcx Expr<'tcx>) -> bool {
+    fn contains_if(expr: &Expr<'_>, on_if: bool) -> bool {
+        match expr.kind {
+            ExprKind::If(..) => on_if,
+            ExprKind::Binary(_, left, right) => contains_if(left, true) || contains_if(right, true),
+            _ => false,
+        }
+    }
+
+    contains_if(expr, false)
+}
+
+fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec<Span>, replacement: RetReplacement<'_>) {
     if ret_span.from_expansion() {
         return;
     }
-    let mut applicability = Applicability::MachineApplicable;
-    let return_replacement = inner_span.map_or_else(
-        || replacement.to_string(),
-        |inner_span| {
-            let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability);
-            snippet.to_string()
-        },
-    );
-    let sugg_help = if inner_span.is_some() {
-        "remove `return`"
-    } else {
-        replacement.sugg_help()
-    };
+    let applicability = replacement.applicability().unwrap_or(Applicability::MachineApplicable);
+    let return_replacement = replacement.to_string();
+    let sugg_help = replacement.sugg_help();
     span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
         diag.span_suggestion_hidden(ret_span, sugg_help, return_replacement, applicability);
         // for each parent statement, we need to remove the semicolon
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
new file mode 100644
index 00000000000..e2d90edec5a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -0,0 +1,399 @@
+use crate::FxHashSet;
+use clippy_utils::{
+    diagnostics::span_lint_and_then,
+    get_attr,
+    source::{indent_of, snippet},
+};
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir::{
+    self as hir,
+    intravisit::{walk_expr, Visitor},
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::{subst::GenericArgKind, Ty, TypeAndMut};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{symbol::Ident, Span, DUMMY_SP};
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Searches for elements marked with `#[clippy::significant_drop]` that could be early
+    /// dropped but are in fact dropped at the end of their scopes. In other words, enforces the
+    /// "tightening" of their possible lifetimes.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Elements marked with `#[clippy::has_significant_drop]` are generally synchronizing
+    /// primitives that manage shared resources, as such, it is desired to release them as soon as
+    /// possible to avoid unnecessary resource contention.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore
+    /// fn main() {
+    ///   let lock = some_sync_resource.lock();
+    ///   let owned_rslt = lock.do_stuff_with_resource();
+    ///   // Only `owned_rslt` is needed but `lock` is still held.
+    ///   do_heavy_computation_that_takes_time(owned_rslt);
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    ///
+    /// ```rust,ignore
+    /// fn main() {
+    ///     let owned_rslt = some_sync_resource.lock().do_stuff_with_resource();
+    ///     do_heavy_computation_that_takes_time(owned_rslt);
+    /// }
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub SIGNIFICANT_DROP_TIGHTENING,
+    nursery,
+    "Searches for elements marked with `#[clippy::has_significant_drop]` that could be early dropped but are in fact dropped at the end of their scopes"
+}
+
+impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]);
+
+#[derive(Default)]
+pub struct SignificantDropTightening<'tcx> {
+    /// Auxiliary structure used to avoid having to verify the same type multiple times.
+    seen_types: FxHashSet<Ty<'tcx>>,
+}
+
+impl<'tcx> SignificantDropTightening<'tcx> {
+    /// Unifies the statements of a block with its return expression.
+    fn all_block_stmts<'ret, 'rslt, 'stmts>(
+        block_stmts: &'stmts [hir::Stmt<'tcx>],
+        dummy_ret_stmt: Option<&'ret hir::Stmt<'tcx>>,
+    ) -> impl Iterator<Item = &'rslt hir::Stmt<'tcx>>
+    where
+        'ret: 'rslt,
+        'stmts: 'rslt,
+    {
+        block_stmts.iter().chain(dummy_ret_stmt)
+    }
+
+    /// Searches for at least one statement that could slow down the release of a significant drop.
+    fn at_least_one_stmt_is_expensive<'stmt>(stmts: impl Iterator<Item = &'stmt hir::Stmt<'tcx>>) -> bool
+    where
+        'tcx: 'stmt,
+    {
+        for stmt in stmts {
+            match stmt.kind {
+                hir::StmtKind::Expr(expr) if let hir::ExprKind::Path(_) = expr.kind => {}
+                hir::StmtKind::Local(local) if let Some(expr) = local.init
+                    && let hir::ExprKind::Path(_) = expr.kind => {},
+                _ => return true
+            };
+        }
+        false
+    }
+
+    /// Verifies if the expression is of type `drop(some_lock_path)` to assert that the temporary
+    /// is already being dropped before the end of its scope.
+    fn has_drop(expr: &'tcx hir::Expr<'_>, init_bind_ident: Ident) -> bool {
+        if let hir::ExprKind::Call(fun, args) = expr.kind
+            && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind
+            && let [fun_ident, ..] = fun_path.segments
+            && fun_ident.ident.name == rustc_span::sym::drop
+            && let [first_arg, ..] = args
+            && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind
+            && let [first_arg_ps, .. ] = arg_path.segments
+        {
+            first_arg_ps.ident == init_bind_ident
+        }
+        else {
+            false
+        }
+    }
+
+    /// Tries to find types marked with `#[has_significant_drop]` of an expression `expr` that is
+    /// originated from `stmt` and then performs common logic on `sdap`.
+    fn modify_sdap_if_sig_drop_exists(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        expr: &'tcx hir::Expr<'_>,
+        idx: usize,
+        sdap: &mut SigDropAuxParams,
+        stmt: &hir::Stmt<'_>,
+        cb: impl Fn(&mut SigDropAuxParams),
+    ) {
+        let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types);
+        sig_drop_finder.visit_expr(expr);
+        if sig_drop_finder.has_sig_drop {
+            cb(sdap);
+            if sdap.number_of_stmts > 0 {
+                sdap.last_use_stmt_idx = idx;
+                sdap.last_use_stmt_span = stmt.span;
+                if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind {
+                    sdap.last_use_method_span = span;
+                }
+            }
+            sdap.number_of_stmts = sdap.number_of_stmts.wrapping_add(1);
+        }
+    }
+
+    /// Shows generic overall messages as well as specialized messages depending on the usage.
+    fn set_suggestions(cx: &LateContext<'tcx>, block_span: Span, diag: &mut Diagnostic, sdap: &SigDropAuxParams) {
+        match sdap.number_of_stmts {
+            0 | 1 => {},
+            2 => {
+                let indent = " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0));
+                let init_method = snippet(cx, sdap.init_method_span, "..");
+                let usage_method = snippet(cx, sdap.last_use_method_span, "..");
+                let stmt = if let Some(last_use_bind_span) = sdap.last_use_bind_span {
+                    format!(
+                        "\n{indent}let {} = {init_method}.{usage_method};",
+                        snippet(cx, last_use_bind_span, ".."),
+                    )
+                } else {
+                    format!("\n{indent}{init_method}.{usage_method};")
+                };
+                diag.span_suggestion_verbose(
+                    sdap.init_stmt_span,
+                    "merge the temporary construction with its single usage",
+                    stmt,
+                    Applicability::MaybeIncorrect,
+                );
+                diag.span_suggestion(
+                    sdap.last_use_stmt_span,
+                    "remove separated single usage",
+                    "",
+                    Applicability::MaybeIncorrect,
+                );
+            },
+            _ => {
+                diag.span_suggestion(
+                    sdap.last_use_stmt_span.shrink_to_hi(),
+                    "drop the temporary after the end of its last usage",
+                    format!(
+                        "\n{}drop({});",
+                        " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0)),
+                        sdap.init_bind_ident
+                    ),
+                    Applicability::MaybeIncorrect,
+                );
+            },
+        }
+        diag.note("this might lead to unnecessary resource contention");
+        diag.span_label(
+            block_span,
+            format!(
+                "temporary `{}` is currently being dropped at the end of its contained scope",
+                sdap.init_bind_ident
+            ),
+        );
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
+        let dummy_ret_stmt = block.expr.map(|expr| hir::Stmt {
+            hir_id: hir::HirId::INVALID,
+            kind: hir::StmtKind::Expr(expr),
+            span: DUMMY_SP,
+        });
+        let mut sdap = SigDropAuxParams::default();
+        for (idx, stmt) in Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).enumerate() {
+            match stmt.kind {
+                hir::StmtKind::Expr(expr) => self.modify_sdap_if_sig_drop_exists(
+                    cx,
+                    expr,
+                    idx,
+                    &mut sdap,
+                    stmt,
+                    |_| {}
+                ),
+                hir::StmtKind::Local(local) if let Some(expr) = local.init => self.modify_sdap_if_sig_drop_exists(
+                    cx,
+                    expr,
+                    idx,
+                    &mut sdap,
+                    stmt,
+                    |local_sdap| {
+                        if local_sdap.number_of_stmts == 0 {
+                            if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
+                                local_sdap.init_bind_ident = ident;
+                            }
+                            if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr.kind {
+                                local_sdap.init_method_span = local_expr.span.to(span);
+                            }
+                            local_sdap.init_stmt_span = stmt.span;
+                        }
+                        else if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
+                            local_sdap.last_use_bind_span = Some(ident.span);
+                        }
+                    }
+                ),
+                hir::StmtKind::Semi(expr) => {
+                    if Self::has_drop(expr, sdap.init_bind_ident) {
+                        return;
+                    }
+                    self.modify_sdap_if_sig_drop_exists(cx, expr, idx, &mut sdap, stmt, |_| {});
+                },
+                _ => {}
+            };
+        }
+
+        let idx = sdap.last_use_stmt_idx.wrapping_add(1);
+        let stmts_after_last_use = Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).skip(idx);
+        if sdap.number_of_stmts > 1 && Self::at_least_one_stmt_is_expensive(stmts_after_last_use) {
+            span_lint_and_then(
+                cx,
+                SIGNIFICANT_DROP_TIGHTENING,
+                sdap.init_bind_ident.span,
+                "temporary with significant `Drop` can be early dropped",
+                |diag| {
+                    Self::set_suggestions(cx, block.span, diag, &sdap);
+                },
+            );
+        }
+    }
+}
+
+/// Auxiliary parameters used on each block check.
+struct SigDropAuxParams {
+    /// The binding or variable that references the initial construction of the type marked with
+    /// `#[has_significant_drop]`.
+    init_bind_ident: Ident,
+    /// Similar to `init_bind_ident` but encompasses the right-hand method call.
+    init_method_span: Span,
+    /// Similar to `init_bind_ident` but encompasses the whole contained statement.
+    init_stmt_span: Span,
+
+    /// The last visited binding or variable span within a block that had any referenced inner type
+    /// marked with `#[has_significant_drop]`.
+    last_use_bind_span: Option<Span>,
+    /// Index of the last visited statement within a block that had any referenced inner type
+    /// marked with `#[has_significant_drop]`.
+    last_use_stmt_idx: usize,
+    /// Similar to `last_use_bind_span` but encompasses the whole contained statement.
+    last_use_stmt_span: Span,
+    /// Similar to `last_use_bind_span` but encompasses the right-hand method call.
+    last_use_method_span: Span,
+
+    /// Total number of statements within a block that have any referenced inner type marked with
+    /// `#[has_significant_drop]`.
+    number_of_stmts: usize,
+}
+
+impl Default for SigDropAuxParams {
+    fn default() -> Self {
+        Self {
+            init_bind_ident: Ident::empty(),
+            init_method_span: DUMMY_SP,
+            init_stmt_span: DUMMY_SP,
+            last_use_bind_span: None,
+            last_use_method_span: DUMMY_SP,
+            last_use_stmt_idx: 0,
+            last_use_stmt_span: DUMMY_SP,
+            number_of_stmts: 0,
+        }
+    }
+}
+
+/// Checks the existence of the `#[has_significant_drop]` attribute
+struct SigDropChecker<'cx, 'sdt, 'tcx> {
+    cx: &'cx LateContext<'tcx>,
+    seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
+}
+
+impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> {
+    pub(crate) fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>) -> Self {
+        seen_types.clear();
+        Self { cx, seen_types }
+    }
+
+    pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
+        if let Some(adt) = ty.ty_adt_def() {
+            let mut iter = get_attr(
+                self.cx.sess(),
+                self.cx.tcx.get_attrs_unchecked(adt.did()),
+                "has_significant_drop",
+            );
+            if iter.next().is_some() {
+                return true;
+            }
+        }
+        match ty.kind() {
+            rustc_middle::ty::Adt(a, b) => {
+                for f in a.all_fields() {
+                    let ty = f.ty(self.cx.tcx, b);
+                    if !self.has_seen_ty(ty) && self.has_sig_drop_attr(ty) {
+                        return true;
+                    }
+                }
+                for generic_arg in b.iter() {
+                    if let GenericArgKind::Type(ty) = generic_arg.unpack() {
+                        if self.has_sig_drop_attr(ty) {
+                            return true;
+                        }
+                    }
+                }
+                false
+            },
+            rustc_middle::ty::Array(ty, _)
+            | rustc_middle::ty::RawPtr(TypeAndMut { ty, .. })
+            | rustc_middle::ty::Ref(_, ty, _)
+            | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(*ty),
+            _ => false,
+        }
+    }
+
+    fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool {
+        !self.seen_types.insert(ty)
+    }
+}
+
+/// Performs recursive calls to find any inner type marked with `#[has_significant_drop]`.
+struct SigDropFinder<'cx, 'sdt, 'tcx> {
+    cx: &'cx LateContext<'tcx>,
+    has_sig_drop: bool,
+    sig_drop_checker: SigDropChecker<'cx, 'sdt, 'tcx>,
+}
+
+impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> {
+    fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>) -> Self {
+        Self {
+            cx,
+            has_sig_drop: false,
+            sig_drop_checker: SigDropChecker::new(cx, seen_types),
+        }
+    }
+}
+
+impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> {
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'_>) {
+        if self
+            .sig_drop_checker
+            .has_sig_drop_attr(self.cx.typeck_results().expr_ty(ex))
+        {
+            self.has_sig_drop = true;
+            return;
+        }
+
+        match ex.kind {
+            hir::ExprKind::MethodCall(_, expr, ..) => {
+                self.visit_expr(expr);
+            },
+            hir::ExprKind::Array(..)
+            | hir::ExprKind::Assign(..)
+            | hir::ExprKind::AssignOp(..)
+            | hir::ExprKind::Binary(..)
+            | hir::ExprKind::Box(..)
+            | hir::ExprKind::Call(..)
+            | hir::ExprKind::Field(..)
+            | hir::ExprKind::If(..)
+            | hir::ExprKind::Index(..)
+            | hir::ExprKind::Match(..)
+            | hir::ExprKind::Repeat(..)
+            | hir::ExprKind::Ret(..)
+            | hir::ExprKind::Tup(..)
+            | hir::ExprKind::Unary(..)
+            | hir::ExprKind::Yield(..) => {
+                walk_expr(self, ex);
+            },
+            _ => {},
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 17e9cc5f6b7..0f062cecf88 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Spanned;
-use rustc_span::{sym, Span};
+use rustc_span::{sym, symbol::Ident, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -174,53 +174,74 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
 
 /// Implementation of the `ALMOST_SWAPPED` lint.
 fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
-    for w in block.stmts.windows(2) {
-        if_chain! {
-            if let StmtKind::Semi(first) = w[0].kind;
-            if let StmtKind::Semi(second) = w[1].kind;
-            if first.span.ctxt() == second.span.ctxt();
-            if let ExprKind::Assign(lhs0, rhs0, _) = first.kind;
-            if let ExprKind::Assign(lhs1, rhs1, _) = second.kind;
-            if eq_expr_value(cx, lhs0, rhs1);
-            if eq_expr_value(cx, lhs1, rhs0);
-            then {
-                let lhs0 = Sugg::hir_opt(cx, lhs0);
-                let rhs0 = Sugg::hir_opt(cx, rhs0);
-                let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
-                    (
-                        format!(" `{first}` and `{second}`"),
-                        first.mut_addr().to_string(),
-                        second.mut_addr().to_string(),
-                    )
-                } else {
-                    (String::new(), String::new(), String::new())
-                };
+    for [first, second] in block.stmts.array_windows() {
+        if let Some((lhs0, rhs0)) = parse(first)
+            && let Some((lhs1, rhs1)) = parse(second)
+            && first.span.eq_ctxt(second.span)
+            && is_same(cx, lhs0, rhs1)
+            && is_same(cx, lhs1, rhs0)
+            && let Some(lhs_sugg) = match &lhs0 {
+                ExprOrIdent::Expr(expr) => Sugg::hir_opt(cx, expr),
+                ExprOrIdent::Ident(ident) => Some(Sugg::NonParen(ident.as_str().into())),
+            }
+            && let Some(rhs_sugg) = Sugg::hir_opt(cx, rhs0)
+        {
+            let span = first.span.to(rhs1.span);
+            let Some(sugg) = std_or_core(cx) else { return };
+            span_lint_and_then(
+                cx,
+                ALMOST_SWAPPED,
+                span,
+                &format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"),
+                |diag| {
+                    diag.span_suggestion(
+                        span,
+                        "try",
+                        format!("{sugg}::mem::swap({}, {})", lhs_sugg.mut_addr(), rhs_sugg.mut_addr()),
+                        Applicability::MaybeIncorrect,
+                    );
+                    diag.note(format!("or maybe you should use `{sugg}::mem::replace`?"));
+                },
+            );
+        }
+    }
+}
+
+fn is_same(cx: &LateContext<'_>, lhs: ExprOrIdent<'_>, rhs: &Expr<'_>) -> bool {
+    match lhs {
+        ExprOrIdent::Expr(expr) => eq_expr_value(cx, expr, rhs),
+        ExprOrIdent::Ident(ident) => {
+            if let ExprKind::Path(QPath::Resolved(None, path)) = rhs.kind
+                && let [segment] = &path.segments
+                && segment.ident == ident
+            {
+                true
+            } else {
+                false
+            }
+        }
+    }
+}
 
-                let span = first.span.to(second.span);
-                let Some(sugg) = std_or_core(cx) else { return };
+#[derive(Debug, Clone, Copy)]
+enum ExprOrIdent<'a> {
+    Expr(&'a Expr<'a>),
+    Ident(Ident),
+}
 
-                span_lint_and_then(cx,
-                    ALMOST_SWAPPED,
-                    span,
-                    &format!("this looks like you are trying to swap{what}"),
-                    |diag| {
-                        if !what.is_empty() {
-                            diag.span_suggestion(
-                                span,
-                                "try",
-                                format!(
-                                    "{sugg}::mem::swap({lhs}, {rhs})",
-                                ),
-                                Applicability::MaybeIncorrect,
-                            );
-                            diag.note(
-                                format!("or maybe you should use `{sugg}::mem::replace`?")
-                            );
-                        }
-                    });
+fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr<'hir>)> {
+    if let StmtKind::Semi(expr) = stmt.kind {
+        if let ExprKind::Assign(lhs, rhs, _) = expr.kind {
+            return Some((ExprOrIdent::Expr(lhs), rhs));
+        }
+    } else if let StmtKind::Local(expr) = stmt.kind {
+        if let Some(rhs) = expr.init {
+            if let PatKind::Binding(_, _, ident_l, _) = expr.pat.kind {
+                return Some((ExprOrIdent::Ident(ident_l), rhs));
             }
         }
     }
+    None
 }
 
 /// Implementation of the xor case for `MANUAL_SWAP` lint.
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index c0d290b5adc..c01cbe5090f 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -3,6 +3,7 @@ mod transmute_float_to_int;
 mod transmute_int_to_bool;
 mod transmute_int_to_char;
 mod transmute_int_to_float;
+mod transmute_int_to_non_zero;
 mod transmute_null_to_fn;
 mod transmute_num_to_bytes;
 mod transmute_ptr_to_ptr;
@@ -255,6 +256,31 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for transmutes from integers to `NonZero*` types, and suggests their `new_unchecked`
+    /// method instead.
+    ///
+    /// ### Why is this bad?
+    /// Transmutes work on any types and thus might cause unsoundness when those types change
+    /// elsewhere. `new_unchecked` only works for the appropriate types instead.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use core::num::NonZeroU32;
+    /// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use core::num::NonZeroU32;
+    /// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) };
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub TRANSMUTE_INT_TO_NON_ZERO,
+    complexity,
+    "transmutes from an integer to a non-zero wrapper"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for transmutes from a float to an integer.
     ///
     /// ### Why is this bad?
@@ -451,6 +477,7 @@ impl_lint_pass!(Transmute => [
     TRANSMUTE_BYTES_TO_STR,
     TRANSMUTE_INT_TO_BOOL,
     TRANSMUTE_INT_TO_FLOAT,
+    TRANSMUTE_INT_TO_NON_ZERO,
     TRANSMUTE_FLOAT_TO_INT,
     TRANSMUTE_NUM_TO_BYTES,
     UNSOUND_COLLECTION_TRANSMUTE,
@@ -501,6 +528,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                     | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
                     | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
                     | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
+                    | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
                     | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
                     | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
                     | (
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
new file mode 100644
index 00000000000..5503653253c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
@@ -0,0 +1,61 @@
+use super::TRANSMUTE_INT_TO_NON_ZERO;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sugg;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::{
+    query::Key,
+    ty::{self, Ty},
+};
+use rustc_span::symbol::sym;
+
+/// Checks for `transmute_int_to_non_zero` lint.
+/// Returns `true` if it's triggered, otherwise returns `false`.
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    e: &'tcx Expr<'_>,
+    from_ty: Ty<'tcx>,
+    to_ty: Ty<'tcx>,
+    arg: &'tcx Expr<'_>,
+) -> bool {
+    let (ty::Int(_) | ty::Uint(_), Some(to_ty_id)) = (&from_ty.kind(), to_ty.ty_adt_id()) else {
+        return false;
+    };
+    let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_id) else {
+        return false;
+    };
+
+    if !matches!(
+        to_type_sym,
+        sym::NonZeroU8
+            | sym::NonZeroU16
+            | sym::NonZeroU32
+            | sym::NonZeroU64
+            | sym::NonZeroU128
+            | sym::NonZeroI8
+            | sym::NonZeroI16
+            | sym::NonZeroI32
+            | sym::NonZeroI64
+            | sym::NonZeroI128
+    ) {
+        return false;
+    }
+
+    span_lint_and_then(
+        cx,
+        TRANSMUTE_INT_TO_NON_ZERO,
+        e.span,
+        &format!("transmute from a `{from_ty}` to a `{to_type_sym}`"),
+        |diag| {
+            let arg = sugg::Sugg::hir(cx, arg, "..");
+            diag.span_suggestion(
+                e.span,
+                "consider using",
+                format!("{to_type_sym}::{}({arg})", sym::new_unchecked),
+                Applicability::Unspecified,
+            );
+        },
+    );
+    true
+}
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
index 9f207d32fcf..6e802794f5a 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
@@ -7,6 +7,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -54,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
                         );
                 } else {
                     if_chain! {
-                        if Some(fun_def_id) == cx.tcx.lang_items().from_fn();
+                        if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id);
                         if let [.., last_arg] = args;
                         if let ExprKind::Lit(spanned) = &last_arg.kind;
                         if let LitKind::Str(symbol, _) = spanned.node;
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 06d248204c1..a57bf7ee822 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -400,7 +400,7 @@ fn drain_matching(
 
     // If `ThinVec` had the `drain_filter` method, this loop could be rewritten
     // like so:
-    // 
+    //
     //   for pat in alternatives.drain_filter(|p| {
     //       // Check if we should extract, but only if `idx >= start`.
     //       idx += 1;
@@ -412,12 +412,12 @@ fn drain_matching(
     while i < alternatives.len() {
         idx += 1;
         // Check if we should extract, but only if `idx >= start`.
-	if idx > start && predicate(&alternatives[i].kind) {
-	    let pat = alternatives.remove(i);
+        if idx > start && predicate(&alternatives[i].kind) {
+            let pat = alternatives.remove(i);
             tail_or.push(extract(pat.into_inner().kind));
-	} else {
-	    i += 1;
-	}
+        } else {
+            i += 1;
+        }
     }
 
     tail_or
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index a95e7b61374..fede625f72a 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                         }
 
                         if_chain! {
-                            if Some(def_id) == cx.tcx.lang_items().from_fn();
+                            if cx.tcx.is_diagnostic_item(sym::from_fn, def_id);
                             if same_type_and_consts(a, b);
 
                             then {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index bd7daf0773c..c37e5bb6716 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -588,7 +588,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                     },
                 }
             },
-            ExprKind::Err => kind!("Err"),
+            ExprKind::Err(_) => kind!("Err"),
             ExprKind::DropTemps(expr) => {
                 bind!(self, expr);
                 kind!("DropTemps({expr})");
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 1d78c7cfae0..5f74de5a288 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -419,19 +419,19 @@ define_Conf! {
     (max_include_file_size: u64 = 1_000_000),
     /// Lint: EXPECT_USED.
     ///
-    /// Whether `expect` should be allowed within `#[cfg(test)]`
+    /// Whether `expect` should be allowed in test functions or `#[cfg(test)]`
     (allow_expect_in_tests: bool = false),
     /// Lint: UNWRAP_USED.
     ///
-    /// Whether `unwrap` should be allowed in test cfg
+    /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
     (allow_unwrap_in_tests: bool = false),
     /// Lint: DBG_MACRO.
     ///
-    /// Whether `dbg!` should be allowed in test functions
+    /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
     (allow_dbg_in_tests: bool = false),
     /// Lint: PRINT_STDOUT, PRINT_STDERR.
     ///
-    /// Whether print macros (ex. `println!`) should be allowed in test functions
+    /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
     (allow_print_in_tests: bool = false),
     /// Lint: RESULT_LARGE_ERR.
     ///
@@ -454,6 +454,11 @@ define_Conf! {
     /// configuration will cause restriction lints to trigger even
     /// if no suggestion can be made.
     (suppress_restriction_lint_in_const: bool = false),
+    /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS.
+    ///
+    /// Whether to **only** check for missing documentation in items visible within the current
+    /// crate. For example, `pub(crate)` items.
+    (missing_docs_in_crate_items: bool = false),
 }
 
 /// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index ee5e42bae0f..b59ef4086cd 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -44,7 +44,7 @@ impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]);
 
 #[derive(Default)]
 pub struct UnnecessaryDefPath {
-    array_def_ids: FxHashSet<(DefId, Span)>,
+    array_def_ids: FxIndexSet<(DefId, Span)>,
     linted_def_ids: FxHashSet<DefId>,
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 8b00ce2cc25..bb8890dcaf9 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -237,7 +237,7 @@ pub fn constant<'tcx>(
         typeck_results,
         param_env: lcx.param_env,
         needed_resolution: false,
-        substs: lcx.tcx.intern_substs(&[]),
+        substs: ty::List::empty(),
     };
     cx.expr(e).map(|cst| (cst, cx.needed_resolution))
 }
@@ -306,7 +306,7 @@ pub fn constant_context<'a, 'tcx>(
         typeck_results,
         param_env: lcx.param_env,
         needed_resolution: false,
-        substs: lcx.tcx.intern_substs(&[]),
+        substs: ty::List::empty(),
     }
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 6ff7728374f..ee2f816f181 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -193,7 +193,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 | ExprKind::Ret(_)
                 | ExprKind::InlineAsm(_)
                 | ExprKind::Yield(..)
-                | ExprKind::Err => {
+                | ExprKind::Err(_) => {
                     self.eagerness = ForceNoChange;
                     return;
                 },
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 2bbe1a19b62..0603755f8a9 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -714,7 +714,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
                 self.hash_pat(pat);
             },
-            ExprKind::Err => {},
+            ExprKind::Err(_) => {},
             ExprKind::Lit(ref l) => {
                 l.node.hash(&mut self.s);
             },
@@ -986,7 +986,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             TyKind::Typeof(anon_const) => {
                 self.hash_body(anon_const.body);
             },
-            TyKind::Err | TyKind::Infer | TyKind::Never => {},
+            TyKind::Err(_) | TyKind::Infer | TyKind::Never => {},
         }
     }
 
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 63dccbf697c..be6133d3202 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -391,11 +391,18 @@ impl FormatString {
         };
 
         let mut unescaped = String::with_capacity(inner.len());
+        // Sometimes the original string comes from a macro which accepts a malformed string, such as in a
+        // #[display(""somestring)] attribute (accepted by the `displaythis` crate). Reconstructing the
+        // string from the span will not be possible, so we will just return None here.
+        let mut unparsable = false;
         unescape_literal(inner, mode, &mut |_, ch| match ch {
             Ok(ch) => unescaped.push(ch),
             Err(e) if !e.is_fatal() => (),
-            Err(e) => panic!("{e:?}"),
+            Err(_) => unparsable = true,
         });
+        if unparsable {
+            return None;
+        }
 
         let mut parts = Vec::new();
         let _: Option<!> = for_each_expr(pieces, |expr| {
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index 42bdfd4827f..c225398ad2a 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -186,7 +186,7 @@ impl<'a> NumericLiteral<'a> {
         // The exponent may have a sign, output it early, otherwise it will be
         // treated as a digit
         if digits.clone().next() == Some('-') {
-            let _ = digits.next();
+            let _: Option<char> = digits.next();
             output.push('-');
         }
 
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 95eebab7567..4aae0f7284e 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -115,6 +115,7 @@ pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
 pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"];
 pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"];
 pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"];
+pub const STD_PROCESS_COMMAND: [&str; 3] = ["std", "process", "Command"];
 pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
 pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
 pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 78fb2e0eb7e..07feadca2b0 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -20,7 +20,7 @@ use rustc_middle::mir::{FakeReadCause, Mutability};
 use rustc_middle::ty;
 use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
 use std::borrow::Cow;
-use std::fmt::{Display, Write as _};
+use std::fmt::{self, Display, Write as _};
 use std::ops::{Add, Neg, Not, Sub};
 
 /// A helper type to build suggestion correctly handling parentheses.
@@ -157,7 +157,7 @@ impl<'a> Sugg<'a> {
             | hir::ExprKind::Ret(..)
             | hir::ExprKind::Struct(..)
             | hir::ExprKind::Tup(..)
-            | hir::ExprKind::Err => Sugg::NonParen(get_snippet(expr.span)),
+            | hir::ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)),
             hir::ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
             hir::ExprKind::Assign(lhs, rhs, _) => {
                 Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
@@ -932,7 +932,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
             if cmt.place.projections.is_empty() {
                 // handle item without any projection, that needs an explicit borrowing
                 // i.e.: suggest `&x` instead of `x`
-                let _ = write!(self.suggestion_start, "{start_snip}&{ident_str}");
+                let _: fmt::Result = write!(self.suggestion_start, "{start_snip}&{ident_str}");
             } else {
                 // cases where a parent `Call` or `MethodCall` is using the item
                 // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()`
@@ -947,7 +947,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
                         // given expression is the self argument and will be handled completely by the compiler
                         // i.e.: `|x| x.is_something()`
                         ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => {
-                            let _ = write!(self.suggestion_start, "{start_snip}{ident_str_with_proj}");
+                            let _: fmt::Result = write!(self.suggestion_start, "{start_snip}{ident_str_with_proj}");
                             self.next_pos = span.hi();
                             return;
                         },
@@ -1055,7 +1055,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
                     }
                 }
 
-                let _ = write!(self.suggestion_start, "{start_snip}{replacement_str}");
+                let _: fmt::Result = write!(self.suggestion_start, "{start_snip}{replacement_str}");
             }
             self.next_pos = span.hi();
         }
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 34b9bb5994e..25654e6957b 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -17,8 +17,8 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
-    PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
-    VariantDef, VariantDiscr, TypeVisitableExt,
+    PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 use rustc_span::symbol::Ident;
@@ -237,7 +237,7 @@ pub fn implements_trait_with_env<'tcx>(
         kind: TypeVariableOriginKind::MiscVariable,
         span: DUMMY_SP,
     };
-    let ty_params = tcx.mk_substs(
+    let ty_params = tcx.mk_substs_from_iter(
         ty_params
             .into_iter()
             .map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())),
@@ -894,16 +894,29 @@ impl AdtVariantInfo {
 }
 
 /// Gets the struct or enum variant from the given `Res`
-pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> {
+pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<(AdtDef<'tcx>, &'tcx VariantDef)> {
     match res {
-        Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()),
-        Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)),
-        Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()),
+        Res::Def(DefKind::Struct, id) => {
+            let adt = cx.tcx.adt_def(id);
+            Some((adt, adt.non_enum_variant()))
+        },
+        Res::Def(DefKind::Variant, id) => {
+            let adt = cx.tcx.adt_def(cx.tcx.parent(id));
+            Some((adt, adt.variant_with_id(id)))
+        },
+        Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => {
+            let adt = cx.tcx.adt_def(cx.tcx.parent(id));
+            Some((adt, adt.non_enum_variant()))
+        },
         Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => {
             let var_id = cx.tcx.parent(id);
-            Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id))
+            let adt = cx.tcx.adt_def(cx.tcx.parent(var_id));
+            Some((adt, adt.variant_with_id(var_id)))
+        },
+        Res::SelfCtor(id) => {
+            let adt = cx.tcx.type_of(id).subst_identity().ty_adt_def().unwrap();
+            Some((adt, adt.non_enum_variant()))
         },
-        Res::SelfCtor(id) => Some(cx.tcx.type_of(id).subst_identity().ty_adt_def().unwrap().non_enum_variant()),
         _ => None,
     }
 }
@@ -1065,7 +1078,7 @@ pub fn make_projection<'tcx>(
         tcx,
         container_id,
         assoc_ty,
-        tcx.mk_substs(substs.into_iter().map(Into::into)),
+        tcx.mk_substs_from_iter(substs.into_iter().map(Into::into)),
     )
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 00073bcd82a..d27a20bd4df 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -665,7 +665,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
             | ExprKind::Path(_)
             | ExprKind::Continue(_)
             | ExprKind::InlineAsm(_)
-            | ExprKind::Err => (),
+            | ExprKind::Err(_) => (),
         }
         ControlFlow::Continue(())
     }
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index b8824024e6c..e0244ddcecb 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -35,7 +35,7 @@ fn get_clap_config() -> ArgMatches {
                 .long("markdown")
                 .help("Change the reports table to use markdown links"),
             Arg::new("recursive")
-                .long("--recursive")
+                .long("recursive")
                 .help("Run clippy on the dependencies of crates specified in crates-toml")
                 .conflicts_with("threads")
                 .conflicts_with("fix"),
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index bd49f096072..23c85298027 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -17,9 +17,9 @@ use crate::recursive::LintcheckServer;
 use std::collections::{HashMap, HashSet};
 use std::env;
 use std::env::consts::EXE_SUFFIX;
-use std::fmt::Write as _;
+use std::fmt::{self, Write as _};
 use std::fs;
-use std::io::ErrorKind;
+use std::io::{self, ErrorKind};
 use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::sync::atomic::{AtomicUsize, Ordering};
@@ -145,8 +145,8 @@ impl ClippyWarning {
             }
 
             let mut output = String::from("| ");
-            let _ = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line);
-            let _ = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message);
+            let _: fmt::Result = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line);
+            let _: fmt::Result = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message);
             output.push('\n');
             output
         } else {
@@ -632,7 +632,7 @@ fn main() {
         .unwrap();
 
     let server = config.recursive.then(|| {
-        let _ = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive");
+        let _: io::Result<()> = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive");
 
         LintcheckServer::spawn(recursive_options)
     });
@@ -689,7 +689,7 @@ fn main() {
     write!(text, "{}", all_msgs.join("")).unwrap();
     text.push_str("\n\n### ICEs:\n");
     for (cratename, msg) in &ices {
-        let _ = write!(text, "{cratename}: '{msg}'");
+        let _: fmt::Result = write!(text, "{cratename}: '{msg}'");
     }
 
     println!("Writing logs to {}", config.lintcheck_results_path.display());
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index adea8c53df2..cfe845ec78f 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-02-10"
+channel = "nightly-2023-02-25"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 9ac849aecf1..dd183362f27 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -209,10 +209,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     // Separate the output with an empty line
     eprintln!();
 
-    let fallback_bundle = rustc_errors::fallback_fluent_bundle(
-        rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
-        false
-    );
+    let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
     let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
         rustc_errors::ColorConfig::Auto,
         None,
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
index 4be04f77f5b..837811bdf1e 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
@@ -1,8 +1,9 @@
 // rustc-env:RUST_BACKTRACE=0
 // normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo"
-// normalize-stderr-test: "internal_lints.rs:\d*:\d*" -> "internal_lints.rs"
+// normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs"
 // normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints"
 // normalize-stderr-test: "'rustc'" -> "'<unnamed>'"
+// normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> ""
 
 #![deny(clippy::internal)]
 #![allow(clippy::missing_clippy_version_attribute)]
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index 2ba5890660f..7ed0ef0274f 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -1,4 +1,4 @@
-thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs:28:9
+thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 error: internal compiler error: unexpected panic
@@ -9,5 +9,3 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy
 
 note: Clippy version: foo
 
-query stack during panic:
-end of query stack
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
index c1a10ba55ef..3ca45404e44 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
@@ -1,19 +1,11 @@
 error: hardcoded path to a diagnostic item
-  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
-   |
-LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: convert all references to use `sym::deref_method`
-   = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
-
-error: hardcoded path to a diagnostic item
   --> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
    |
 LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: convert all references to use `sym::Deref`
+   = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
 
 error: hardcoded path to a language item
   --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
@@ -23,5 +15,13 @@ LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
    |
    = help: convert all references to use `LangItem::DerefMut`
 
+error: hardcoded path to a diagnostic item
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
+   |
+LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: convert all references to use `sym::deref_method`
+
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs
index bff97d97df7..89f142a150d 100644
--- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs
+++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs
@@ -16,6 +16,18 @@ fn main() {
     expect_result();
 }
 
+#[test]
+fn test_expect_option() {
+    let opt = Some(0);
+    let _ = opt.expect("");
+}
+
+#[test]
+fn test_expect_result() {
+    let res: Result<u8, ()> = Ok(0);
+    let _ = res.expect("");
+}
+
 #[cfg(test)]
 mod issue9612 {
     // should not lint in `#[cfg(test)]` modules
diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/clippy.toml b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/clippy.toml
new file mode 100644
index 00000000000..ec210a98783
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/clippy.toml
@@ -0,0 +1 @@
+missing-docs-in-crate-items = true
diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
new file mode 100644
index 00000000000..830d71f61dd
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
@@ -0,0 +1,59 @@
+//! this is crate
+#![allow(missing_docs)]
+#![warn(clippy::missing_docs_in_private_items)]
+
+/// this is mod
+mod my_mod {
+    /// some docs
+    fn priv_with_docs() {}
+    fn priv_no_docs() {}
+    /// some docs
+    pub(crate) fn crate_with_docs() {}
+    pub(crate) fn crate_no_docs() {}
+    /// some docs
+    pub(super) fn super_with_docs() {}
+    pub(super) fn super_no_docs() {}
+
+    mod my_sub {
+        /// some docs
+        fn sub_priv_with_docs() {}
+        fn sub_priv_no_docs() {}
+        /// some docs
+        pub(crate) fn sub_crate_with_docs() {}
+        pub(crate) fn sub_crate_no_docs() {}
+        /// some docs
+        pub(super) fn sub_super_with_docs() {}
+        pub(super) fn sub_super_no_docs() {}
+    }
+
+    /// some docs
+    pub(crate) struct CrateStructWithDocs {
+        /// some docs
+        pub(crate) crate_field_with_docs: (),
+        pub(crate) crate_field_no_docs: (),
+        /// some docs
+        priv_field_with_docs: (),
+        priv_field_no_docs: (),
+    }
+
+    pub(crate) struct CrateStructNoDocs {
+        /// some docs
+        pub(crate) crate_field_with_docs: (),
+        pub(crate) crate_field_no_docs: (),
+        /// some docs
+        priv_field_with_docs: (),
+        priv_field_no_docs: (),
+    }
+}
+
+/// some docs
+type CrateTypedefWithDocs = String;
+type CrateTypedefNoDocs = String;
+/// some docs
+pub type PubTypedefWithDocs = String;
+pub type PubTypedefNoDocs = String;
+
+fn main() {
+    my_mod::crate_with_docs();
+    my_mod::crate_no_docs();
+}
diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
new file mode 100644
index 00000000000..a474187050c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
@@ -0,0 +1,52 @@
+error: missing documentation for a function
+  --> $DIR/pub_crate_missing_doc.rs:12:5
+   |
+LL |     pub(crate) fn crate_no_docs() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: missing documentation for a function
+  --> $DIR/pub_crate_missing_doc.rs:15:5
+   |
+LL |     pub(super) fn super_no_docs() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/pub_crate_missing_doc.rs:23:9
+   |
+LL |         pub(crate) fn sub_crate_no_docs() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+  --> $DIR/pub_crate_missing_doc.rs:33:9
+   |
+LL |         pub(crate) crate_field_no_docs: (),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a struct
+  --> $DIR/pub_crate_missing_doc.rs:39:5
+   |
+LL | /     pub(crate) struct CrateStructNoDocs {
+LL | |         /// some docs
+LL | |         pub(crate) crate_field_with_docs: (),
+LL | |         pub(crate) crate_field_no_docs: (),
+...  |
+LL | |         priv_field_no_docs: (),
+LL | |     }
+   | |_____^
+
+error: missing documentation for a struct field
+  --> $DIR/pub_crate_missing_doc.rs:42:9
+   |
+LL |         pub(crate) crate_field_no_docs: (),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a type alias
+  --> $DIR/pub_crate_missing_doc.rs:51:1
+   |
+LL | type CrateTypedefNoDocs = String;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index a22c6a5a060..6a246afac76 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -33,6 +33,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            max-struct-bools
            max-suggested-slice-pattern-length
            max-trait-bounds
+           missing-docs-in-crate-items
            msrv
            pass-by-value-size-limit
            single-char-binding-names-threshold
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
index bc8e8c1f070..6525ea5bfc3 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
@@ -66,6 +66,12 @@ fn main() {
     }
 }
 
+#[test]
+fn test() {
+    let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+    let _ = boxed_slice.get(1).unwrap();
+}
+
 #[cfg(test)]
 mod issue9612 {
     // should not lint in `#[cfg(test)]` modules
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
index 94b5ef663ad..8a32750e3c9 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -188,10 +188,16 @@ LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/unwrap_used.rs:84:17
+  --> $DIR/unwrap_used.rs:72:13
+   |
+LL |     let _ = boxed_slice.get(1).unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
+
+error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/unwrap_used.rs:90:17
    |
 LL |         let _ = Box::new([0]).get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&Box::new([0])[1]`
 
-error: aborting due to 27 previous errors
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index 918cf81c600..2611e3a785f 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -13,6 +13,9 @@
 
 use core::num::{Saturating, Wrapping};
 
+const ONE: i32 = 1;
+const ZERO: i32 = 0;
+
 #[derive(Clone, Copy)]
 pub struct Custom;
 
@@ -182,6 +185,10 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
     _n += &0;
     _n -= 0;
     _n -= &0;
+    _n += ZERO;
+    _n += &ZERO;
+    _n -= ZERO;
+    _n -= &ZERO;
     _n /= 99;
     _n /= &99;
     _n %= 99;
@@ -190,10 +197,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
     _n *= &0;
     _n *= 1;
     _n *= &1;
+    _n *= ZERO;
+    _n *= &ZERO;
+    _n *= ONE;
+    _n *= &ONE;
     _n += -0;
     _n += &-0;
     _n -= -0;
     _n -= &-0;
+    _n += -ZERO;
+    _n += &-ZERO;
+    _n -= -ZERO;
+    _n -= &-ZERO;
     _n /= -99;
     _n /= &-99;
     _n %= -99;
@@ -208,10 +223,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
     _n = _n + &0;
     _n = 0 + _n;
     _n = &0 + _n;
+    _n = _n + ZERO;
+    _n = _n + &ZERO;
+    _n = ZERO + _n;
+    _n = &ZERO + _n;
     _n = _n - 0;
     _n = _n - &0;
     _n = 0 - _n;
     _n = &0 - _n;
+    _n = _n - ZERO;
+    _n = _n - &ZERO;
+    _n = ZERO - _n;
+    _n = &ZERO - _n;
     _n = _n / 99;
     _n = _n / &99;
     _n = _n % 99;
@@ -222,6 +245,10 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
     _n = &0 * _n;
     _n = _n * 1;
     _n = _n * &1;
+    _n = ZERO * _n;
+    _n = &ZERO * _n;
+    _n = _n * ONE;
+    _n = _n * &ONE;
     _n = 1 * _n;
     _n = &1 * _n;
     _n = 23 + 85;
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
index 5e349f6b497..17a2448fbfc 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
@@ -1,5 +1,5 @@
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:243:5
+  --> $DIR/arithmetic_side_effects.rs:270:5
    |
 LL |     _n += 1;
    |     ^^^^^^^
@@ -7,589 +7,589 @@ LL |     _n += 1;
    = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:244:5
+  --> $DIR/arithmetic_side_effects.rs:271:5
    |
 LL |     _n += &1;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:245:5
+  --> $DIR/arithmetic_side_effects.rs:272:5
    |
 LL |     _n -= 1;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:246:5
+  --> $DIR/arithmetic_side_effects.rs:273:5
    |
 LL |     _n -= &1;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:247:5
+  --> $DIR/arithmetic_side_effects.rs:274:5
    |
 LL |     _n /= 0;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:248:5
+  --> $DIR/arithmetic_side_effects.rs:275:5
    |
 LL |     _n /= &0;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:249:5
+  --> $DIR/arithmetic_side_effects.rs:276:5
    |
 LL |     _n %= 0;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:250:5
+  --> $DIR/arithmetic_side_effects.rs:277:5
    |
 LL |     _n %= &0;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:251:5
+  --> $DIR/arithmetic_side_effects.rs:278:5
    |
 LL |     _n *= 2;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:252:5
+  --> $DIR/arithmetic_side_effects.rs:279:5
    |
 LL |     _n *= &2;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:253:5
+  --> $DIR/arithmetic_side_effects.rs:280:5
    |
 LL |     _n += -1;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:254:5
+  --> $DIR/arithmetic_side_effects.rs:281:5
    |
 LL |     _n += &-1;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:255:5
+  --> $DIR/arithmetic_side_effects.rs:282:5
    |
 LL |     _n -= -1;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:256:5
+  --> $DIR/arithmetic_side_effects.rs:283:5
    |
 LL |     _n -= &-1;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:257:5
+  --> $DIR/arithmetic_side_effects.rs:284:5
    |
 LL |     _n /= -0;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:258:5
+  --> $DIR/arithmetic_side_effects.rs:285:5
    |
 LL |     _n /= &-0;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:259:5
+  --> $DIR/arithmetic_side_effects.rs:286:5
    |
 LL |     _n %= -0;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:260:5
+  --> $DIR/arithmetic_side_effects.rs:287:5
    |
 LL |     _n %= &-0;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:261:5
+  --> $DIR/arithmetic_side_effects.rs:288:5
    |
 LL |     _n *= -2;
    |     ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:262:5
+  --> $DIR/arithmetic_side_effects.rs:289:5
    |
 LL |     _n *= &-2;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:263:5
+  --> $DIR/arithmetic_side_effects.rs:290:5
    |
 LL |     _custom += Custom;
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:264:5
+  --> $DIR/arithmetic_side_effects.rs:291:5
    |
 LL |     _custom += &Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:265:5
+  --> $DIR/arithmetic_side_effects.rs:292:5
    |
 LL |     _custom -= Custom;
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:266:5
+  --> $DIR/arithmetic_side_effects.rs:293:5
    |
 LL |     _custom -= &Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:267:5
+  --> $DIR/arithmetic_side_effects.rs:294:5
    |
 LL |     _custom /= Custom;
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:268:5
+  --> $DIR/arithmetic_side_effects.rs:295:5
    |
 LL |     _custom /= &Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:269:5
+  --> $DIR/arithmetic_side_effects.rs:296:5
    |
 LL |     _custom %= Custom;
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:270:5
+  --> $DIR/arithmetic_side_effects.rs:297:5
    |
 LL |     _custom %= &Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:271:5
+  --> $DIR/arithmetic_side_effects.rs:298:5
    |
 LL |     _custom *= Custom;
    |     ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:272:5
+  --> $DIR/arithmetic_side_effects.rs:299:5
    |
 LL |     _custom *= &Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:273:5
+  --> $DIR/arithmetic_side_effects.rs:300:5
    |
 LL |     _custom += -Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:274:5
+  --> $DIR/arithmetic_side_effects.rs:301:5
    |
 LL |     _custom += &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:275:5
+  --> $DIR/arithmetic_side_effects.rs:302:5
    |
 LL |     _custom -= -Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:276:5
+  --> $DIR/arithmetic_side_effects.rs:303:5
    |
 LL |     _custom -= &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:277:5
+  --> $DIR/arithmetic_side_effects.rs:304:5
    |
 LL |     _custom /= -Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:278:5
+  --> $DIR/arithmetic_side_effects.rs:305:5
    |
 LL |     _custom /= &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:279:5
+  --> $DIR/arithmetic_side_effects.rs:306:5
    |
 LL |     _custom %= -Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:280:5
+  --> $DIR/arithmetic_side_effects.rs:307:5
    |
 LL |     _custom %= &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:281:5
+  --> $DIR/arithmetic_side_effects.rs:308:5
    |
 LL |     _custom *= -Custom;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:282:5
+  --> $DIR/arithmetic_side_effects.rs:309:5
    |
 LL |     _custom *= &-Custom;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:285:10
+  --> $DIR/arithmetic_side_effects.rs:312:10
    |
 LL |     _n = _n + 1;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:286:10
+  --> $DIR/arithmetic_side_effects.rs:313:10
    |
 LL |     _n = _n + &1;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:287:10
+  --> $DIR/arithmetic_side_effects.rs:314:10
    |
 LL |     _n = 1 + _n;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:288:10
+  --> $DIR/arithmetic_side_effects.rs:315:10
    |
 LL |     _n = &1 + _n;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:289:10
+  --> $DIR/arithmetic_side_effects.rs:316:10
    |
 LL |     _n = _n - 1;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:290:10
+  --> $DIR/arithmetic_side_effects.rs:317:10
    |
 LL |     _n = _n - &1;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:291:10
+  --> $DIR/arithmetic_side_effects.rs:318:10
    |
 LL |     _n = 1 - _n;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:292:10
+  --> $DIR/arithmetic_side_effects.rs:319:10
    |
 LL |     _n = &1 - _n;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:293:10
+  --> $DIR/arithmetic_side_effects.rs:320:10
    |
 LL |     _n = _n / 0;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:294:10
+  --> $DIR/arithmetic_side_effects.rs:321:10
    |
 LL |     _n = _n / &0;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:295:10
+  --> $DIR/arithmetic_side_effects.rs:322:10
    |
 LL |     _n = _n % 0;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:296:10
+  --> $DIR/arithmetic_side_effects.rs:323:10
    |
 LL |     _n = _n % &0;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:297:10
+  --> $DIR/arithmetic_side_effects.rs:324:10
    |
 LL |     _n = _n * 2;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:298:10
+  --> $DIR/arithmetic_side_effects.rs:325:10
    |
 LL |     _n = _n * &2;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:299:10
+  --> $DIR/arithmetic_side_effects.rs:326:10
    |
 LL |     _n = 2 * _n;
    |          ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:300:10
+  --> $DIR/arithmetic_side_effects.rs:327:10
    |
 LL |     _n = &2 * _n;
    |          ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:301:10
+  --> $DIR/arithmetic_side_effects.rs:328:10
    |
 LL |     _n = 23 + &85;
    |          ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:302:10
+  --> $DIR/arithmetic_side_effects.rs:329:10
    |
 LL |     _n = &23 + 85;
    |          ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:303:10
+  --> $DIR/arithmetic_side_effects.rs:330:10
    |
 LL |     _n = &23 + &85;
    |          ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:304:15
+  --> $DIR/arithmetic_side_effects.rs:331:15
    |
 LL |     _custom = _custom + _custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:305:15
+  --> $DIR/arithmetic_side_effects.rs:332:15
    |
 LL |     _custom = _custom + &_custom;
    |               ^^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:306:15
+  --> $DIR/arithmetic_side_effects.rs:333:15
    |
 LL |     _custom = Custom + _custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:307:15
+  --> $DIR/arithmetic_side_effects.rs:334:15
    |
 LL |     _custom = &Custom + _custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:308:15
+  --> $DIR/arithmetic_side_effects.rs:335:15
    |
 LL |     _custom = _custom - Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:309:15
+  --> $DIR/arithmetic_side_effects.rs:336:15
    |
 LL |     _custom = _custom - &Custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:310:15
+  --> $DIR/arithmetic_side_effects.rs:337:15
    |
 LL |     _custom = Custom - _custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:311:15
+  --> $DIR/arithmetic_side_effects.rs:338:15
    |
 LL |     _custom = &Custom - _custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:312:15
+  --> $DIR/arithmetic_side_effects.rs:339:15
    |
 LL |     _custom = _custom / Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:313:15
+  --> $DIR/arithmetic_side_effects.rs:340:15
    |
 LL |     _custom = _custom / &Custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:314:15
+  --> $DIR/arithmetic_side_effects.rs:341:15
    |
 LL |     _custom = _custom % Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:315:15
+  --> $DIR/arithmetic_side_effects.rs:342:15
    |
 LL |     _custom = _custom % &Custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:316:15
+  --> $DIR/arithmetic_side_effects.rs:343:15
    |
 LL |     _custom = _custom * Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:317:15
+  --> $DIR/arithmetic_side_effects.rs:344:15
    |
 LL |     _custom = _custom * &Custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:318:15
+  --> $DIR/arithmetic_side_effects.rs:345:15
    |
 LL |     _custom = Custom * _custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:319:15
+  --> $DIR/arithmetic_side_effects.rs:346:15
    |
 LL |     _custom = &Custom * _custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:320:15
+  --> $DIR/arithmetic_side_effects.rs:347:15
    |
 LL |     _custom = Custom + &Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:321:15
+  --> $DIR/arithmetic_side_effects.rs:348:15
    |
 LL |     _custom = &Custom + Custom;
    |               ^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:322:15
+  --> $DIR/arithmetic_side_effects.rs:349:15
    |
 LL |     _custom = &Custom + &Custom;
    |               ^^^^^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:325:10
+  --> $DIR/arithmetic_side_effects.rs:352:10
    |
 LL |     _n = -_n;
    |          ^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:326:10
+  --> $DIR/arithmetic_side_effects.rs:353:10
    |
 LL |     _n = -&_n;
    |          ^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:327:15
+  --> $DIR/arithmetic_side_effects.rs:354:15
    |
 LL |     _custom = -_custom;
    |               ^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:328:15
+  --> $DIR/arithmetic_side_effects.rs:355:15
    |
 LL |     _custom = -&_custom;
    |               ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:337:5
+  --> $DIR/arithmetic_side_effects.rs:364:5
    |
 LL |     1 + i;
    |     ^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:338:5
+  --> $DIR/arithmetic_side_effects.rs:365:5
    |
 LL |     i * 2;
    |     ^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:340:5
+  --> $DIR/arithmetic_side_effects.rs:367:5
    |
 LL |     i - 2 + 2 - i;
    |     ^^^^^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:341:5
+  --> $DIR/arithmetic_side_effects.rs:368:5
    |
 LL |     -i;
    |     ^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:342:5
+  --> $DIR/arithmetic_side_effects.rs:369:5
    |
 LL |     i >> 1;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:343:5
+  --> $DIR/arithmetic_side_effects.rs:370:5
    |
 LL |     i << 1;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:352:5
+  --> $DIR/arithmetic_side_effects.rs:379:5
    |
 LL |     i += 1;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:353:5
+  --> $DIR/arithmetic_side_effects.rs:380:5
    |
 LL |     i -= 1;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:354:5
+  --> $DIR/arithmetic_side_effects.rs:381:5
    |
 LL |     i *= 2;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:356:5
+  --> $DIR/arithmetic_side_effects.rs:383:5
    |
 LL |     i /= 0;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:358:5
+  --> $DIR/arithmetic_side_effects.rs:385:5
    |
 LL |     i /= var1;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:359:5
+  --> $DIR/arithmetic_side_effects.rs:386:5
    |
 LL |     i /= var2;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:361:5
+  --> $DIR/arithmetic_side_effects.rs:388:5
    |
 LL |     i %= 0;
    |     ^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:363:5
+  --> $DIR/arithmetic_side_effects.rs:390:5
    |
 LL |     i %= var1;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:364:5
+  --> $DIR/arithmetic_side_effects.rs:391:5
    |
 LL |     i %= var2;
    |     ^^^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:365:5
+  --> $DIR/arithmetic_side_effects.rs:392:5
    |
 LL |     i <<= 3;
    |     ^^^^^^^
 
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:366:5
+  --> $DIR/arithmetic_side_effects.rs:393:5
    |
 LL |     i >>= 2;
    |     ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
index 7e9f074fdca..59c0baf8718 100644
--- a/src/tools/clippy/tests/ui/box_default.fixed
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -33,6 +33,7 @@ fn main() {
     let _vec4: Box<_> = Box::<Vec<bool>>::default();
     let _more = ret_ty_fn();
     call_ty_fn(Box::default());
+    issue_10381();
 }
 
 fn ret_ty_fn() -> Box<bool> {
@@ -65,3 +66,20 @@ fn issue_10089() {
         let _ = Box::<WeirdPathed>::default();
     };
 }
+
+fn issue_10381() {
+    #[derive(Default)]
+    pub struct Foo {}
+    pub trait Bar {}
+    impl Bar for Foo {}
+
+    fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
+        if i % 2 == 0 {
+            Some(Box::<Foo>::default())
+        } else {
+            None
+        }
+    }
+
+    assert!(maybe_get_bar(2).is_some());
+}
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
index 5c8d0b8354c..f7d832193a3 100644
--- a/src/tools/clippy/tests/ui/box_default.rs
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -33,6 +33,7 @@ fn main() {
     let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
     let _more = ret_ty_fn();
     call_ty_fn(Box::new(u8::default()));
+    issue_10381();
 }
 
 fn ret_ty_fn() -> Box<bool> {
@@ -65,3 +66,20 @@ fn issue_10089() {
         let _ = Box::new(WeirdPathed::default());
     };
 }
+
+fn issue_10381() {
+    #[derive(Default)]
+    pub struct Foo {}
+    pub trait Bar {}
+    impl Bar for Foo {}
+
+    fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
+        if i % 2 == 0 {
+            Some(Box::new(Foo::default()))
+        } else {
+            None
+        }
+    }
+
+    assert!(maybe_get_bar(2).is_some());
+}
diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr
index 249eb340f96..78e17b9f035 100644
--- a/src/tools/clippy/tests/ui/box_default.stderr
+++ b/src/tools/clippy/tests/ui/box_default.stderr
@@ -73,22 +73,28 @@ LL |     call_ty_fn(Box::new(u8::default()));
    |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:39:5
+  --> $DIR/box_default.rs:40:5
    |
 LL |     Box::new(bool::default())
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:56:28
+  --> $DIR/box_default.rs:57:28
    |
 LL |     let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:65:17
+  --> $DIR/box_default.rs:66:17
    |
 LL |         let _ = Box::new(WeirdPathed::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
 
-error: aborting due to 15 previous errors
+error: `Box::new(_)` of default value
+  --> $DIR/box_default.rs:78:18
+   |
+LL |             Some(Box::new(Foo::default()))
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()`
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/bytes_nth.fixed b/src/tools/clippy/tests/ui/bytes_nth.fixed
index b1fb2e16bd5..a35c679afb7 100644
--- a/src/tools/clippy/tests/ui/bytes_nth.fixed
+++ b/src/tools/clippy/tests/ui/bytes_nth.fixed
@@ -5,7 +5,7 @@
 
 fn main() {
     let s = String::from("String");
-    let _ = s.as_bytes().get(3);
-    let _ = &s.as_bytes().get(3);
-    let _ = s[..].as_bytes().get(3);
+    let _ = s.as_bytes().get(3).copied();
+    let _ = &s.as_bytes()[3];
+    let _ = s[..].as_bytes().get(3).copied();
 }
diff --git a/src/tools/clippy/tests/ui/bytes_nth.rs b/src/tools/clippy/tests/ui/bytes_nth.rs
index 034c54e6a42..1ecffea5303 100644
--- a/src/tools/clippy/tests/ui/bytes_nth.rs
+++ b/src/tools/clippy/tests/ui/bytes_nth.rs
@@ -6,6 +6,6 @@
 fn main() {
     let s = String::from("String");
     let _ = s.bytes().nth(3);
-    let _ = &s.bytes().nth(3);
+    let _ = &s.bytes().nth(3).unwrap();
     let _ = s[..].bytes().nth(3);
 }
diff --git a/src/tools/clippy/tests/ui/bytes_nth.stderr b/src/tools/clippy/tests/ui/bytes_nth.stderr
index 9851d4791d8..e8b15027829 100644
--- a/src/tools/clippy/tests/ui/bytes_nth.stderr
+++ b/src/tools/clippy/tests/ui/bytes_nth.stderr
@@ -2,21 +2,21 @@ error: called `.bytes().nth()` on a `String`
   --> $DIR/bytes_nth.rs:8:13
    |
 LL |     let _ = s.bytes().nth(3);
-   |             ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)`
+   |             ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3).copied()`
    |
    = note: `-D clippy::bytes-nth` implied by `-D warnings`
 
-error: called `.bytes().nth()` on a `String`
+error: called `.bytes().nth().unwrap()` on a `String`
   --> $DIR/bytes_nth.rs:9:14
    |
-LL |     let _ = &s.bytes().nth(3);
-   |              ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)`
+LL |     let _ = &s.bytes().nth(3).unwrap();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.as_bytes()[3]`
 
 error: called `.bytes().nth()` on a `str`
   --> $DIR/bytes_nth.rs:10:13
    |
 LL |     let _ = s[..].bytes().nth(3);
-   |             ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3)`
+   |             ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3).copied()`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index 4af1de9aa38..451078de23b 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -42,7 +42,7 @@ error: casting `f32` to `i32` may truncate the value
 LL |     1f32 as i32;
    |     ^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
    = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
 help: ... or use `try_from` and handle the error accordingly
    |
@@ -55,7 +55,7 @@ error: casting `f32` to `u32` may truncate the value
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     u32::try_from(1f32);
@@ -75,7 +75,7 @@ error: casting `f64` to `f32` may truncate the value
 LL |     1f64 as f32;
    |     ^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     f32::try_from(1f64);
@@ -87,7 +87,7 @@ error: casting `i32` to `i8` may truncate the value
 LL |     1i32 as i8;
    |     ^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     i8::try_from(1i32);
@@ -99,7 +99,7 @@ error: casting `i32` to `u8` may truncate the value
 LL |     1i32 as u8;
    |     ^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     u8::try_from(1i32);
@@ -111,7 +111,7 @@ error: casting `f64` to `isize` may truncate the value
 LL |     1f64 as isize;
    |     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     isize::try_from(1f64);
@@ -123,7 +123,7 @@ error: casting `f64` to `usize` may truncate the value
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     usize::try_from(1f64);
@@ -141,7 +141,7 @@ error: casting `u32` to `u16` may truncate the value
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     u16::try_from(1f32 as u32);
@@ -153,7 +153,7 @@ error: casting `f32` to `u32` may truncate the value
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     u32::try_from(1f32) as u16;
@@ -215,7 +215,7 @@ error: casting `i64` to `i8` may truncate the value
 LL |     (-99999999999i64).min(1) as i8; // should be linted because signed
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     i8::try_from((-99999999999i64).min(1)); // should be linted because signed
@@ -227,7 +227,7 @@ error: casting `u64` to `u8` may truncate the value
 LL |     999999u64.clamp(0, 256) as u8; // should still be linted
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     u8::try_from(999999u64.clamp(0, 256)); // should still be linted
@@ -239,7 +239,7 @@ error: casting `main::E2` to `u8` may truncate the value
 LL |             let _ = self as u8;
    |                     ^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |             let _ = u8::try_from(self);
@@ -259,7 +259,7 @@ error: casting `main::E5` to `i8` may truncate the value
 LL |             let _ = self as i8;
    |                     ^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |             let _ = i8::try_from(self);
@@ -277,7 +277,7 @@ error: casting `main::E6` to `i16` may truncate the value
 LL |             let _ = self as i16;
    |                     ^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |             let _ = i16::try_from(self);
@@ -289,7 +289,7 @@ error: casting `main::E7` to `usize` may truncate the value on targets with 32-b
 LL |             let _ = self as usize;
    |                     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |             let _ = usize::try_from(self);
@@ -301,7 +301,7 @@ error: casting `main::E10` to `u16` may truncate the value
 LL |             let _ = self as u16;
    |                     ^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |             let _ = u16::try_from(self);
@@ -313,7 +313,7 @@ error: casting `u32` to `u8` may truncate the value
 LL |     let c = (q >> 16) as u8;
    |             ^^^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     let c = u8::try_from((q >> 16));
@@ -325,7 +325,7 @@ error: casting `u32` to `u8` may truncate the value
 LL |     let c = (q / 1000) as u8;
    |             ^^^^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     let c = u8::try_from((q / 1000));
diff --git a/src/tools/clippy/tests/ui/cast_size.stderr b/src/tools/clippy/tests/ui/cast_size.stderr
index 8acf26049f4..6d2d49d9ed2 100644
--- a/src/tools/clippy/tests/ui/cast_size.stderr
+++ b/src/tools/clippy/tests/ui/cast_size.stderr
@@ -4,7 +4,7 @@ error: casting `isize` to `i8` may truncate the value
 LL |     1isize as i8;
    |     ^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
    = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
 help: ... or use `try_from` and handle the error accordingly
    |
@@ -43,7 +43,7 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi
 LL |     1isize as i32;
    |     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     i32::try_from(1isize);
@@ -55,7 +55,7 @@ error: casting `isize` to `u32` may truncate the value on targets with 64-bit wi
 LL |     1isize as u32;
    |     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     u32::try_from(1isize);
@@ -67,7 +67,7 @@ error: casting `usize` to `u32` may truncate the value on targets with 64-bit wi
 LL |     1usize as u32;
    |     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     u32::try_from(1usize);
@@ -79,7 +79,7 @@ error: casting `usize` to `i32` may truncate the value on targets with 64-bit wi
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     i32::try_from(1usize);
@@ -99,7 +99,7 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi
 LL |     1i64 as isize;
    |     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     isize::try_from(1i64);
@@ -111,7 +111,7 @@ error: casting `i64` to `usize` may truncate the value on targets with 32-bit wi
 LL |     1i64 as usize;
    |     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     usize::try_from(1i64);
@@ -123,7 +123,7 @@ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wi
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     isize::try_from(1u64);
@@ -141,7 +141,7 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi
 LL |     1u64 as usize;
    |     ^^^^^^^^^^^^^
    |
-   = help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
+   = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 help: ... or use `try_from` and handle the error accordingly
    |
 LL |     usize::try_from(1u64);
diff --git a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs
new file mode 100644
index 00000000000..dd3d8b8b6d1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs
@@ -0,0 +1,9 @@
+// https://github.com/rust-lang/rust/issues/107147
+
+#![warn(clippy::needless_pass_by_value)]
+
+struct Foo<'a>(&'a [(); 100]);
+
+fn test(x: Foo<'_>) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr
new file mode 100644
index 00000000000..7a0a648974f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr
@@ -0,0 +1,15 @@
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value-w-late-bound.rs:7:12
+   |
+LL | fn test(x: Foo<'_>) {}
+   |            ^^^^^^^ help: consider taking a reference instead: `&Foo<'_>`
+   |
+help: consider marking this type as `Copy`
+  --> $DIR/needless_pass_by_value-w-late-bound.rs:5:1
+   |
+LL | struct Foo<'a>(&'a [(); 100]);
+   | ^^^^^^^^^^^^^^
+   = note: `-D clippy::needless-pass-by-value` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index 747801b40ee..ecb0bf3644e 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -78,7 +78,7 @@ fn test_allowed() {
 /// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
 /// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
 /// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
-/// It can also be [`inline_link2`].
+/// It can also be [inline_link2]. A link to [StackOverflow](https://stackoverflow.com) is also acceptable.
 ///
 /// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
 /// [inline_link]: https://foobar
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index f3cf966157a..11c48dd103d 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -75,10 +75,10 @@ fn test_units() {
 fn test_allowed() {
 }
 
-/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
 /// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
 /// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
-/// It can also be [inline_link2].
+/// It can also be [inline_link2]. A link to [StackOverflow](https://stackoverflow.com) is also acceptable.
 ///
 /// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
 /// [inline_link]: https://foobar
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
index 40345370c04..6c67c903c75 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
@@ -143,28 +143,6 @@ LL | /// `be_sure_we_got_to_the_end_of_it`
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: item in documentation is missing backticks
-  --> $DIR/doc-fixable.rs:78:22
-   |
-LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
-   |                      ^^^^^^^^^^^^^^^^^^^^^
-   |
-help: try
-   |
-LL | /// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
-   |                      ~~~~~~~~~~~~~~~~~~~~~~~
-
-error: item in documentation is missing backticks
-  --> $DIR/doc-fixable.rs:81:21
-   |
-LL | /// It can also be [inline_link2].
-   |                     ^^^^^^^^^^^^
-   |
-help: try
-   |
-LL | /// It can also be [`inline_link2`].
-   |                     ~~~~~~~~~~~~~~
-
-error: item in documentation is missing backticks
   --> $DIR/doc-fixable.rs:91:5
    |
 LL | /// be_sure_we_got_to_the_end_of_it
@@ -329,5 +307,5 @@ help: try
 LL | /// An iterator over `mycrate::Collection`'s values.
    |                      ~~~~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 30 previous errors
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed
index 79c29c04e05..dbe09e0ff3c 100644
--- a/src/tools/clippy/tests/ui/entry.fixed
+++ b/src/tools/clippy/tests/ui/entry.fixed
@@ -152,4 +152,18 @@ fn hash_map<K: Eq + Hash + Copy, V: Copy>(m: &mut HashMap<K, V>, m2: &mut HashMa
     });
 }
 
+// Issue 10331
+// do not suggest a bad expansion because the compiler unrolls the first
+// occurrence of the loop
+pub fn issue_10331() {
+    let mut m = HashMap::new();
+    let mut i = 0;
+    let mut x = 0;
+    while !m.contains_key(&x) {
+        m.insert(x, i);
+        i += 1;
+        x += 1;
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs
index 2d7985457d8..30fed34fc5d 100644
--- a/src/tools/clippy/tests/ui/entry.rs
+++ b/src/tools/clippy/tests/ui/entry.rs
@@ -156,4 +156,18 @@ fn hash_map<K: Eq + Hash + Copy, V: Copy>(m: &mut HashMap<K, V>, m2: &mut HashMa
     }
 }
 
+// Issue 10331
+// do not suggest a bad expansion because the compiler unrolls the first
+// occurrence of the loop
+pub fn issue_10331() {
+    let mut m = HashMap::new();
+    let mut i = 0;
+    let mut x = 0;
+    while !m.contains_key(&x) {
+        m.insert(x, i);
+        i += 1;
+        x += 1;
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
index 475fae5e823..5d40c850424 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
@@ -269,6 +269,9 @@ fn main() {
 
     trait WithAssoc {
         type Assoc: ?Sized;
+        fn to_assoc(&self) -> &Self::Assoc {
+            panic!()
+        }
     }
     impl WithAssoc for String {
         type Assoc = str;
@@ -281,4 +284,15 @@ fn main() {
     // Issue #9901
     fn takes_ref(_: &i32) {}
     takes_ref(*Box::new(&0i32));
+
+    // Issue #10384
+    impl<'a> WithAssoc for &'a u32 {
+        type Assoc = dyn core::fmt::Display;
+        fn to_assoc(&self) -> &Self::Assoc {
+            *self
+        }
+    }
+    fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
+        *x
+    }
 }
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
index c1894258f4d..79e03f4d76c 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
@@ -269,6 +269,9 @@ fn main() {
 
     trait WithAssoc {
         type Assoc: ?Sized;
+        fn to_assoc(&self) -> &Self::Assoc {
+            panic!()
+        }
     }
     impl WithAssoc for String {
         type Assoc = str;
@@ -281,4 +284,15 @@ fn main() {
     // Issue #9901
     fn takes_ref(_: &i32) {}
     takes_ref(*Box::new(&0i32));
+
+    // Issue #10384
+    impl<'a> WithAssoc for &'a u32 {
+        type Assoc = dyn core::fmt::Display;
+        fn to_assoc(&self) -> &Self::Assoc {
+            *self
+        }
+    }
+    fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
+        *x
+    }
 }
diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs b/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs
index 5cb80cb6233..48017434276 100644
--- a/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs
@@ -1,11 +1,17 @@
 #![allow(unused, clippy::needless_lifetimes)]
 #![warn(clippy::extra_unused_type_parameters)]
 
-fn unused_ty<T>(x: u8) {}
+fn unused_ty<T>(x: u8) {
+    unimplemented!()
+}
 
-fn unused_multi<T, U>(x: u8) {}
+fn unused_multi<T, U>(x: u8) {
+    unimplemented!()
+}
 
-fn unused_with_lt<'a, T>(x: &'a u8) {}
+fn unused_with_lt<'a, T>(x: &'a u8) {
+    unimplemented!()
+}
 
 fn used_ty<T>(x: T, y: u8) {}
 
@@ -15,15 +21,20 @@ fn used_ret<T: Default>(x: u8) -> T {
     T::default()
 }
 
-fn unused_bounded<T: Default, U>(x: U) {}
+fn unused_bounded<T: Default, U>(x: U) {
+    unimplemented!();
+}
 
 fn unused_where_clause<T, U>(x: U)
 where
     T: Default,
 {
+    unimplemented!();
 }
 
-fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {}
+fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {
+    unimplemented!();
+}
 
 fn used_opaque<A>(iter: impl Iterator<Item = A>) -> usize {
     iter.count()
@@ -46,7 +57,9 @@ fn used_closure<T: Default + ToString>() -> impl Fn() {
 struct S;
 
 impl S {
-    fn unused_ty_impl<T>(&self) {}
+    fn unused_ty_impl<T>(&self) {
+        unimplemented!()
+    }
 }
 
 // Don't lint on trait methods
@@ -66,4 +79,32 @@ where
         .filter_map(move |(i, a)| if i == index { None } else { Some(a) })
 }
 
+fn unused_opaque<A, B>(dummy: impl Default) {
+    unimplemented!()
+}
+
+mod unexported_trait_bounds {
+    mod private {
+        pub trait Private {}
+    }
+
+    fn priv_trait_bound<T: private::Private>() {
+        unimplemented!();
+    }
+
+    fn unused_with_priv_trait_bound<T: private::Private, U>() {
+        unimplemented!();
+    }
+}
+
+mod issue10319 {
+    fn assert_send<T: Send>() {}
+
+    fn assert_send_where<T>()
+    where
+        T: Send,
+    {
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr b/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr
index 1c8dd53e638..86c88fc9bf0 100644
--- a/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr
+++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr
@@ -1,38 +1,38 @@
 error: type parameter goes unused in function definition
   --> $DIR/extra_unused_type_parameters.rs:4:13
    |
-LL | fn unused_ty<T>(x: u8) {}
+LL | fn unused_ty<T>(x: u8) {
    |             ^^^
    |
    = help: consider removing the parameter
    = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings`
 
 error: type parameters go unused in function definition
-  --> $DIR/extra_unused_type_parameters.rs:6:16
+  --> $DIR/extra_unused_type_parameters.rs:8:16
    |
-LL | fn unused_multi<T, U>(x: u8) {}
+LL | fn unused_multi<T, U>(x: u8) {
    |                ^^^^^^
    |
    = help: consider removing the parameters
 
 error: type parameter goes unused in function definition
-  --> $DIR/extra_unused_type_parameters.rs:8:23
+  --> $DIR/extra_unused_type_parameters.rs:12:23
    |
-LL | fn unused_with_lt<'a, T>(x: &'a u8) {}
+LL | fn unused_with_lt<'a, T>(x: &'a u8) {
    |                       ^
    |
    = help: consider removing the parameter
 
 error: type parameter goes unused in function definition
-  --> $DIR/extra_unused_type_parameters.rs:18:19
+  --> $DIR/extra_unused_type_parameters.rs:24:19
    |
-LL | fn unused_bounded<T: Default, U>(x: U) {}
+LL | fn unused_bounded<T: Default, U>(x: U) {
    |                   ^^^^^^^^^^^
    |
    = help: consider removing the parameter
 
 error: type parameter goes unused in function definition
-  --> $DIR/extra_unused_type_parameters.rs:20:24
+  --> $DIR/extra_unused_type_parameters.rs:28:24
    |
 LL | fn unused_where_clause<T, U>(x: U)
    |                        ^^
@@ -40,20 +40,36 @@ LL | fn unused_where_clause<T, U>(x: U)
    = help: consider removing the parameter
 
 error: type parameters go unused in function definition
-  --> $DIR/extra_unused_type_parameters.rs:26:16
+  --> $DIR/extra_unused_type_parameters.rs:35:16
    |
-LL | fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {}
+LL | fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {
    |                ^^       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
    |
    = help: consider removing the parameters
 
 error: type parameter goes unused in function definition
-  --> $DIR/extra_unused_type_parameters.rs:49:22
+  --> $DIR/extra_unused_type_parameters.rs:60:22
    |
-LL |     fn unused_ty_impl<T>(&self) {}
+LL |     fn unused_ty_impl<T>(&self) {
    |                      ^^^
    |
    = help: consider removing the parameter
 
-error: aborting due to 7 previous errors
+error: type parameters go unused in function definition
+  --> $DIR/extra_unused_type_parameters.rs:82:17
+   |
+LL | fn unused_opaque<A, B>(dummy: impl Default) {
+   |                 ^^^^^^
+   |
+   = help: consider removing the parameters
+
+error: type parameter goes unused in function definition
+  --> $DIR/extra_unused_type_parameters.rs:95:58
+   |
+LL |     fn unused_with_priv_trait_bound<T: private::Private, U>() {
+   |                                                          ^
+   |
+   = help: consider removing the parameter
+
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed
index beedf2c1db2..cd2f70ee8b0 100644
--- a/src/tools/clippy/tests/ui/format.fixed
+++ b/src/tools/clippy/tests/ui/format.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+// aux-build: proc_macro_with_span.rs
 #![warn(clippy::useless_format)]
 #![allow(
     unused_tuple_struct_fields,
@@ -9,6 +10,8 @@
     clippy::uninlined_format_args
 )]
 
+extern crate proc_macro_with_span;
+
 struct Foo(pub String);
 
 macro_rules! foo {
@@ -87,4 +90,7 @@ fn main() {
     let _ = abc.to_string();
     let xx = "xx";
     let _ = xx.to_string();
+
+    // Issue #10148
+    println!(proc_macro_with_span::with_span!(""something ""));
 }
diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs
index e805f181889..c22345a79d4 100644
--- a/src/tools/clippy/tests/ui/format.rs
+++ b/src/tools/clippy/tests/ui/format.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+// aux-build: proc_macro_with_span.rs
 #![warn(clippy::useless_format)]
 #![allow(
     unused_tuple_struct_fields,
@@ -9,6 +10,8 @@
     clippy::uninlined_format_args
 )]
 
+extern crate proc_macro_with_span;
+
 struct Foo(pub String);
 
 macro_rules! foo {
@@ -89,4 +92,7 @@ fn main() {
     let _ = format!("{abc}");
     let xx = "xx";
     let _ = format!("{xx}");
+
+    // Issue #10148
+    println!(proc_macro_with_span::with_span!(""something ""));
 }
diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr
index 0ef0ac655d3..a0e5d5c8ad2 100644
--- a/src/tools/clippy/tests/ui/format.stderr
+++ b/src/tools/clippy/tests/ui/format.stderr
@@ -1,5 +1,5 @@
 error: useless use of `format!`
-  --> $DIR/format.rs:19:5
+  --> $DIR/format.rs:22:5
    |
 LL |     format!("foo");
    |     ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
@@ -7,19 +7,19 @@ LL |     format!("foo");
    = note: `-D clippy::useless-format` implied by `-D warnings`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:20:5
+  --> $DIR/format.rs:23:5
    |
 LL |     format!("{{}}");
    |     ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:21:5
+  --> $DIR/format.rs:24:5
    |
 LL |     format!("{{}} abc {{}}");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:22:5
+  --> $DIR/format.rs:25:5
    |
 LL | /     format!(
 LL | |         r##"foo {{}}
@@ -34,67 +34,67 @@ LL ~ " bar"##.to_string();
    |
 
 error: useless use of `format!`
-  --> $DIR/format.rs:27:13
+  --> $DIR/format.rs:30:13
    |
 LL |     let _ = format!("");
    |             ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:29:5
+  --> $DIR/format.rs:32:5
    |
 LL |     format!("{}", "foo");
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:37:5
+  --> $DIR/format.rs:40:5
    |
 LL |     format!("{}", arg);
    |     ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:67:5
+  --> $DIR/format.rs:70:5
    |
 LL |     format!("{}", 42.to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:69:5
+  --> $DIR/format.rs:72:5
    |
 LL |     format!("{}", x.display().to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:73:18
+  --> $DIR/format.rs:76:18
    |
 LL |     let _ = Some(format!("{}", a + "bar"));
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:77:22
+  --> $DIR/format.rs:80:22
    |
 LL |     let _s: String = format!("{}", &*v.join("/n"));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:83:13
+  --> $DIR/format.rs:86:13
    |
 LL |     let _ = format!("{x}");
    |             ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:85:13
+  --> $DIR/format.rs:88:13
    |
 LL |     let _ = format!("{y}", y = x);
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:89:13
+  --> $DIR/format.rs:92:13
    |
 LL |     let _ = format!("{abc}");
    |             ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:91:13
+  --> $DIR/format.rs:94:13
    |
 LL |     let _ = format!("{xx}");
    |             ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.rs b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
new file mode 100644
index 00000000000..07560101a41
--- /dev/null
+++ b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
@@ -0,0 +1,17 @@
+#![allow(unused)]
+#![warn(clippy::impl_trait_in_params)]
+
+pub trait Trait {}
+pub trait AnotherTrait<T> {}
+
+// Should warn
+pub fn a(_: impl Trait) {}
+pub fn c<C: Trait>(_: C, _: impl Trait) {}
+fn d(_: impl AnotherTrait<u32>) {}
+
+// Shouldn't warn
+
+pub fn b<B: Trait>(_: B) {}
+fn e<T: AnotherTrait<u32>>(_: T) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.stderr b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr
new file mode 100644
index 00000000000..acfcc21445e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr
@@ -0,0 +1,25 @@
+error: '`impl Trait` used as a function parameter'
+  --> $DIR/impl_trait_in_params.rs:8:13
+   |
+LL | pub fn a(_: impl Trait) {}
+   |             ^^^^^^^^^^
+   |
+   = note: `-D clippy::impl-trait-in-params` implied by `-D warnings`
+help: add a type paremeter
+   |
+LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {}
+   |         +++++++++++++++++++++++++++++++
+
+error: '`impl Trait` used as a function parameter'
+  --> $DIR/impl_trait_in_params.rs:9:29
+   |
+LL | pub fn c<C: Trait>(_: C, _: impl Trait) {}
+   |                             ^^^^^^^^^^
+   |
+help: add a type paremeter
+   |
+LL | pub fn c<C: Trait, { /* Generic name */ }: Trait>(_: C, _: impl Trait) {}
+   |                  +++++++++++++++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/large_digit_groups.fixed b/src/tools/clippy/tests/ui/large_digit_groups.fixed
index 3430c137ec2..ea18dac0683 100644
--- a/src/tools/clippy/tests/ui/large_digit_groups.fixed
+++ b/src/tools/clippy/tests/ui/large_digit_groups.fixed
@@ -11,7 +11,7 @@ fn main() {
     let _good = (
         0b1011_i64,
         0o1_234_u32,
-        0x0123_4567,
+        0x1_234_567,
         1_2345_6789,
         1234_f32,
         1_234.12_f32,
@@ -19,7 +19,7 @@ fn main() {
         1.123_4_f32,
     );
     let _bad = (
-        0b11_0110_i64,
+        0b1_10110_i64,
         0xdead_beef_usize,
         123_456_f32,
         123_456.12_f32,
diff --git a/src/tools/clippy/tests/ui/large_digit_groups.stderr b/src/tools/clippy/tests/ui/large_digit_groups.stderr
index 13d108b56e0..19c0fae98a6 100644
--- a/src/tools/clippy/tests/ui/large_digit_groups.stderr
+++ b/src/tools/clippy/tests/ui/large_digit_groups.stderr
@@ -1,22 +1,10 @@
-error: digits of hex or binary literal not grouped by four
-  --> $DIR/large_digit_groups.rs:14:9
-   |
-LL |         0x1_234_567,
-   |         ^^^^^^^^^^^ help: consider: `0x0123_4567`
-   |
-   = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
-
-error: digits of hex or binary literal not grouped by four
-  --> $DIR/large_digit_groups.rs:22:9
-   |
-LL |         0b1_10110_i64,
-   |         ^^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
-
-error: digits of hex or binary literal not grouped by four
+error: digits of hex, binary or octal literal not in groups of equal size
   --> $DIR/large_digit_groups.rs:23:9
    |
 LL |         0xd_e_adbee_f_usize,
    |         ^^^^^^^^^^^^^^^^^^^ help: consider: `0xdead_beef_usize`
+   |
+   = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
 
 error: digit groups should be smaller
   --> $DIR/large_digit_groups.rs:24:9
@@ -44,5 +32,5 @@ error: digit groups should be smaller
 LL |         1_23456.12345_6_f64,
    |         ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f64`
 
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.rs b/src/tools/clippy/tests/ui/let_underscore_untyped.rs
new file mode 100644
index 00000000000..bcb33c5c7e3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_underscore_untyped.rs
@@ -0,0 +1,54 @@
+#![allow(unused)]
+#![warn(clippy::let_underscore_untyped)]
+
+use std::future::Future;
+use std::{boxed::Box, fmt::Display};
+
+fn a() -> u32 {
+    1
+}
+
+fn b<T>(x: T) -> T {
+    x
+}
+
+fn c() -> impl Display {
+    1
+}
+
+fn d(x: &u32) -> &u32 {
+    x
+}
+
+fn e() -> Result<u32, ()> {
+    Ok(1)
+}
+
+fn f() -> Box<dyn Display> {
+    Box::new(1)
+}
+
+fn main() {
+    let _ = a();
+    let _ = b(1);
+    let _ = c();
+    let _ = d(&1);
+    let _ = e();
+    let _ = f();
+
+    _ = a();
+    _ = b(1);
+    _ = c();
+    _ = d(&1);
+    _ = e();
+    _ = f();
+
+    let _: u32 = a();
+    let _: u32 = b(1);
+    let _: &u32 = d(&1);
+    let _: Result<_, _> = e();
+    let _: Box<_> = f();
+
+    #[allow(clippy::let_underscore_untyped)]
+    let _ = a();
+}
diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
new file mode 100644
index 00000000000..36c3d1214d6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
@@ -0,0 +1,51 @@
+error: non-binding `let` without a type annotation
+  --> $DIR/let_underscore_untyped.rs:32:5
+   |
+LL |     let _ = a();
+   |     ^^^^^^^^^^^^
+   |
+   = help: consider adding a type annotation or removing the `let` keyword
+   = note: `-D clippy::let-underscore-untyped` implied by `-D warnings`
+
+error: non-binding `let` without a type annotation
+  --> $DIR/let_underscore_untyped.rs:33:5
+   |
+LL |     let _ = b(1);
+   |     ^^^^^^^^^^^^^
+   |
+   = help: consider adding a type annotation or removing the `let` keyword
+
+error: non-binding `let` without a type annotation
+  --> $DIR/let_underscore_untyped.rs:34:5
+   |
+LL |     let _ = c();
+   |     ^^^^^^^^^^^^
+   |
+   = help: consider adding a type annotation or removing the `let` keyword
+
+error: non-binding `let` without a type annotation
+  --> $DIR/let_underscore_untyped.rs:35:5
+   |
+LL |     let _ = d(&1);
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider adding a type annotation or removing the `let` keyword
+
+error: non-binding `let` without a type annotation
+  --> $DIR/let_underscore_untyped.rs:36:5
+   |
+LL |     let _ = e();
+   |     ^^^^^^^^^^^^
+   |
+   = help: consider adding a type annotation or removing the `let` keyword
+
+error: non-binding `let` without a type annotation
+  --> $DIR/let_underscore_untyped.rs:37:5
+   |
+LL |     let _ = f();
+   |     ^^^^^^^^^^^^
+   |
+   = help: consider adding a type annotation or removing the `let` keyword
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/literals.stderr b/src/tools/clippy/tests/ui/literals.stderr
index 603d47bacca..9bc7948c7cc 100644
--- a/src/tools/clippy/tests/ui/literals.stderr
+++ b/src/tools/clippy/tests/ui/literals.stderr
@@ -121,7 +121,7 @@ error: digits grouped inconsistently by underscores
 LL |     let fail23 = 3__16___23;
    |                  ^^^^^^^^^^ help: consider: `31_623`
 
-error: digits of hex or binary literal not grouped by four
+error: digits of hex, binary or octal literal not in groups of equal size
   --> $DIR/literals.rs:38:18
    |
 LL |     let fail24 = 0xAB_ABC_AB;
@@ -129,12 +129,6 @@ LL |     let fail24 = 0xAB_ABC_AB;
    |
    = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
 
-error: digits of hex or binary literal not grouped by four
-  --> $DIR/literals.rs:39:18
-   |
-LL |     let fail25 = 0b01_100_101;
-   |                  ^^^^^^^^^^^^ help: consider: `0b0110_0101`
-
 error: this is a decimal constant
   --> $DIR/literals.rs:46:13
    |
@@ -168,5 +162,5 @@ help: if you mean to use a decimal constant, remove the `0` to avoid confusion
 LL |     let _ = 89;
    |             ~~
 
-error: aborting due to 21 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs
index 48a162c1360..d175597a44a 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else.rs
@@ -248,4 +248,15 @@ fn not_fire() {
         Some(value) => value,
         _ => macro_call!(),
     };
+
+    // Issue 10296
+    // The let/else block in the else part is not divergent despite the presence of return
+    let _x = if let Some(x) = Some(1) {
+        x
+    } else {
+        let Some(_z) = Some(3) else {
+            return
+        };
+        1
+    };
 }
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.rs b/src/tools/clippy/tests/ui/manual_let_else_match.rs
index 28caed9d79d..73b74679125 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.rs
@@ -42,13 +42,13 @@ fn fire() {
     loop {
         // More complex pattern for the identity arm and diverging arm
         let v = match h() {
-            (Some(_), Some(_)) | (None, None) => continue,
             (Some(v), None) | (None, Some(v)) => v,
+            (Some(_), Some(_)) | (None, None) => continue,
         };
         // Custom enums are supported as long as the "else" arm is a simple _
         let v = match build_enum() {
-            _ => continue,
             Variant::Bar(v) | Variant::Baz(v) => v,
+            _ => continue,
         };
     }
 
@@ -71,6 +71,12 @@ fn fire() {
         Variant::Bar(_) | Variant::Baz(_) => (),
         _ => return,
     };
+
+    let data = [1_u8, 2, 3, 4, 0, 0, 0, 0];
+    let data = match data.as_slice() {
+        [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data,
+        _ => return,
+    };
 }
 
 fn not_fire() {
@@ -125,4 +131,23 @@ fn not_fire() {
         Ok(v) | Err(Variant::Bar(v) | Variant::Baz(v)) => v,
         Err(Variant::Foo) => return,
     };
+
+    // Issue 10241
+    // The non-divergent arm arrives in second position and
+    // may cover values already matched in the first arm.
+    let v = match h() {
+        (Some(_), Some(_)) | (None, None) => return,
+        (Some(v), _) | (None, Some(v)) => v,
+    };
+
+    let v = match build_enum() {
+        _ => return,
+        Variant::Bar(v) | Variant::Baz(v) => v,
+    };
+
+    let data = [1_u8, 2, 3, 4, 0, 0, 0, 0];
+    let data = match data.as_slice() {
+        [] | [0, 0] => return,
+        [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data,
+    };
 }
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.stderr b/src/tools/clippy/tests/ui/manual_let_else_match.stderr
index cd5e9a9ac39..7abaa0b85d2 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr
@@ -22,8 +22,8 @@ error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else_match.rs:44:9
    |
 LL | /         let v = match h() {
-LL | |             (Some(_), Some(_)) | (None, None) => continue,
 LL | |             (Some(v), None) | (None, Some(v)) => v,
+LL | |             (Some(_), Some(_)) | (None, None) => continue,
 LL | |         };
    | |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };`
 
@@ -31,8 +31,8 @@ error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else_match.rs:49:9
    |
 LL | /         let v = match build_enum() {
-LL | |             _ => continue,
 LL | |             Variant::Bar(v) | Variant::Baz(v) => v,
+LL | |             _ => continue,
 LL | |         };
    | |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };`
 
@@ -63,5 +63,14 @@ LL | |         _ => return,
 LL | |     };
    | |______^ help: consider writing: `let (Variant::Bar(_) | Variant::Baz(_)) = f else { return };`
 
-error: aborting due to 7 previous errors
+error: this could be rewritten as `let...else`
+  --> $DIR/manual_let_else_match.rs:76:5
+   |
+LL | /     let data = match data.as_slice() {
+LL | |         [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data,
+LL | |         _ => return,
+LL | |     };
+   | |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };`
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
index 53628ef6531..8e2f11389f8 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::let_underscore_untyped)]
 #![allow(clippy::missing_docs_in_private_items)]
 #![allow(clippy::map_identity)]
 #![allow(clippy::redundant_closure)]
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.rs b/src/tools/clippy/tests/ui/map_flatten_fixable.rs
index 76016c8ed3c..a783a99c4ff 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.rs
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::let_underscore_untyped)]
 #![allow(clippy::missing_docs_in_private_items)]
 #![allow(clippy::map_identity)]
 #![allow(clippy::redundant_closure)]
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
index b6b0c4d09c3..c91f0b9ae94 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
@@ -1,5 +1,5 @@
 error: called `map(..).flatten()` on `Iterator`
-  --> $DIR/map_flatten_fixable.rs:17:47
+  --> $DIR/map_flatten_fixable.rs:18:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)`
@@ -7,43 +7,43 @@ LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll
    = note: `-D clippy::map-flatten` implied by `-D warnings`
 
 error: called `map(..).flatten()` on `Iterator`
-  --> $DIR/map_flatten_fixable.rs:18:47
+  --> $DIR/map_flatten_fixable.rs:19:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)`
 
 error: called `map(..).flatten()` on `Iterator`
-  --> $DIR/map_flatten_fixable.rs:19:47
+  --> $DIR/map_flatten_fixable.rs:20:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)`
 
 error: called `map(..).flatten()` on `Iterator`
-  --> $DIR/map_flatten_fixable.rs:20:47
+  --> $DIR/map_flatten_fixable.rs:21:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))`
 
 error: called `map(..).flatten()` on `Iterator`
-  --> $DIR/map_flatten_fixable.rs:23:47
+  --> $DIR/map_flatten_fixable.rs:24:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)`
 
 error: called `map(..).flatten()` on `Option`
-  --> $DIR/map_flatten_fixable.rs:26:40
+  --> $DIR/map_flatten_fixable.rs:27:40
    |
 LL |     let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
    |                                        ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
 
 error: called `map(..).flatten()` on `Result`
-  --> $DIR/map_flatten_fixable.rs:29:42
+  --> $DIR/map_flatten_fixable.rs:30:42
    |
 LL |     let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
    |                                          ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
 
 error: called `map(..).flatten()` on `Iterator`
-  --> $DIR/map_flatten_fixable.rs:38:10
+  --> $DIR/map_flatten_fixable.rs:39:10
    |
 LL |           .map(|n| match n {
    |  __________^
@@ -72,7 +72,7 @@ LL ~         });
    |
 
 error: called `map(..).flatten()` on `Option`
-  --> $DIR/map_flatten_fixable.rs:58:10
+  --> $DIR/map_flatten_fixable.rs:59:10
    |
 LL |           .map(|_| {
    |  __________^
diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs
index 6f22366eab2..1519e4da934 100644
--- a/src/tools/clippy/tests/ui/methods.rs
+++ b/src/tools/clippy/tests/ui/methods.rs
@@ -4,6 +4,7 @@
 #![allow(
     clippy::disallowed_names,
     clippy::default_trait_access,
+    clippy::let_underscore_untyped,
     clippy::missing_docs_in_private_items,
     clippy::missing_safety_doc,
     clippy::non_ascii_literal,
diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr
index b63672dd6fd..4643e09e270 100644
--- a/src/tools/clippy/tests/ui/methods.stderr
+++ b/src/tools/clippy/tests/ui/methods.stderr
@@ -1,5 +1,5 @@
 error: methods called `new` usually return `Self`
-  --> $DIR/methods.rs:104:5
+  --> $DIR/methods.rs:105:5
    |
 LL | /     fn new() -> i32 {
 LL | |         0
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 
 error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
-  --> $DIR/methods.rs:125:13
+  --> $DIR/methods.rs:126:13
    |
 LL |       let _ = v.iter().filter(|&x| {
    |  _____________^
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed
index 04a74a009e0..bbbb3cf621e 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.fixed
+++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed
@@ -84,7 +84,7 @@ pub unsafe fn mutates_static() -> usize {
 }
 
 #[no_mangle]
-pub fn unmangled(i: bool) -> bool {
+pub extern "C" fn unmangled(i: bool) -> bool {
     !i
 }
 
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs
index f04122f4eea..94d3c83bdb9 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.rs
+++ b/src/tools/clippy/tests/ui/must_use_candidates.rs
@@ -84,7 +84,7 @@ pub unsafe fn mutates_static() -> usize {
 }
 
 #[no_mangle]
-pub fn unmangled(i: bool) -> bool {
+pub extern "C" fn unmangled(i: bool) -> bool {
     !i
 }
 
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
index d286ef4ba37..f0f1f9298ac 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
@@ -516,6 +516,16 @@ mod in_macro {
 
     // no lint on external macro
     macro_rules::needless_lifetime!();
+
+    macro_rules! expanded_lifetime {
+        ($l:lifetime) => {
+            fn f<$l>(arg: &$l str) -> &$l str {
+                arg
+            }
+        }
+    }
+
+    expanded_lifetime!('a);
 }
 
 mod issue5787 {
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
index 409528b291d..ddfd1043003 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -516,6 +516,16 @@ mod in_macro {
 
     // no lint on external macro
     macro_rules::needless_lifetime!();
+
+    macro_rules! expanded_lifetime {
+        ($l:lifetime) => {
+            fn f<$l>(arg: &$l str) -> &$l str {
+                arg
+            }
+        }
+    }
+
+    expanded_lifetime!('a);
 }
 
 mod issue5787 {
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index 079e3531def..0f525dd294c 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -297,4 +297,14 @@ fn issue10051() -> Result<String, String> {
     }
 }
 
+mod issue10049 {
+    fn single() -> u32 {
+        if true { 1 } else { 2 }
+    }
+
+    fn multiple(b1: bool, b2: bool, b3: bool) -> u32 {
+        (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 })
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index c1c48284f08..a1db8375d95 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -307,4 +307,14 @@ fn issue10051() -> Result<String, String> {
     }
 }
 
+mod issue10049 {
+    fn single() -> u32 {
+        return if true { 1 } else { 2 };
+    }
+
+    fn multiple(b1: bool, b2: bool, b3: bool) -> u32 {
+        return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 };
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index 08b04bfe9d8..87d0cd3e14c 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -418,5 +418,21 @@ LL |         return Err(format!("err!"));
    |
    = help: remove `return`
 
-error: aborting due to 50 previous errors
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:312:9
+   |
+LL |         return if true { 1 } else { 2 };
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove `return`
+
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:316:9
+   |
+LL |         return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 };
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove `return` and wrap the sequence with parentheses
+
+error: aborting due to 52 previous errors
 
diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs
index 28e8f459d44..29821ff96fc 100644
--- a/src/tools/clippy/tests/ui/never_loop.rs
+++ b/src/tools/clippy/tests/ui/never_loop.rs
@@ -250,6 +250,51 @@ pub fn test20() {
     }
 }
 
+pub fn test21() {
+    loop {
+        'a: {
+            {}
+            break 'a;
+        }
+    }
+}
+
+// Issue 10304: code after break from block was not considered
+// unreachable code and was considered for further analysis of
+// whether the loop would ever be executed or not.
+pub fn test22() {
+    for _ in 0..10 {
+        'block: {
+            break 'block;
+            return;
+        }
+        println!("looped");
+    }
+}
+
+pub fn test23() {
+    for _ in 0..10 {
+        'block: {
+            for _ in 0..20 {
+                break 'block;
+            }
+        }
+        println!("looped");
+    }
+}
+
+pub fn test24() {
+    'a: for _ in 0..10 {
+        'b: {
+            let x = Some(1);
+            match x {
+                None => break 'a,
+                Some(_) => break 'b,
+            }
+        }
+    }
+}
+
 fn main() {
     test1();
     test2();
diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr
index b7029bf8bed..704d448644e 100644
--- a/src/tools/clippy/tests/ui/never_loop.stderr
+++ b/src/tools/clippy/tests/ui/never_loop.stderr
@@ -126,5 +126,18 @@ LL | |         }
 LL | |     }
    | |_____^
 
-error: aborting due to 11 previous errors
+error: this loop never actually loops
+  --> $DIR/never_loop.rs:278:13
+   |
+LL | /             for _ in 0..20 {
+LL | |                 break 'block;
+LL | |             }
+   | |_____________^
+   |
+help: if you need the first element of the iterator, try writing
+   |
+LL |             if let Some(_) = (0..20).next() {
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed
new file mode 100644
index 00000000000..d18dec22a8b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed
@@ -0,0 +1,48 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::no_mangle_with_rust_abi)]
+
+#[no_mangle]
+extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
+
+/// # Safety
+/// This function shouldn't be called unless the horsemen are ready
+#[no_mangle]
+pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
+
+/// # Safety
+/// This function shouldn't be called unless the horsemen are ready
+#[no_mangle]
+unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
+    arg_one: u32,
+    arg_two: usize,
+) -> u32 {
+    0
+}
+
+// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"`
+#[no_mangle]
+#[rustfmt::skip]
+extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {}
+
+fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {}
+
+extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {}
+
+extern "C" {
+    fn c_abi_in_block(arg_one: u32, arg_two: usize);
+}
+
+fn main() {
+    // test code goes here
+}
diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
new file mode 100644
index 00000000000..481e1b6d961
--- /dev/null
+++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
@@ -0,0 +1,48 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::no_mangle_with_rust_abi)]
+
+#[no_mangle]
+fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
+
+/// # Safety
+/// This function shouldn't be called unless the horsemen are ready
+#[no_mangle]
+pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
+
+/// # Safety
+/// This function shouldn't be called unless the horsemen are ready
+#[no_mangle]
+unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
+    arg_one: u32,
+    arg_two: usize,
+) -> u32 {
+    0
+}
+
+// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"`
+#[no_mangle]
+#[rustfmt::skip]
+extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {}
+
+fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {}
+
+extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {}
+
+extern "C" {
+    fn c_abi_in_block(arg_one: u32, arg_two: usize);
+}
+
+fn main() {
+    // test code goes here
+}
diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr
new file mode 100644
index 00000000000..71517d31809
--- /dev/null
+++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr
@@ -0,0 +1,45 @@
+error: attribute #[no_mangle] set on a Rust ABI function
+  --> $DIR/no_mangle_with_rust_abi.rs:7:1
+   |
+LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize)`
+   |
+   = note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings`
+
+error: attribute #[no_mangle] set on a Rust ABI function
+  --> $DIR/no_mangle_with_rust_abi.rs:10:1
+   |
+LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize)`
+
+error: attribute #[no_mangle] set on a Rust ABI function
+  --> $DIR/no_mangle_with_rust_abi.rs:15:1
+   |
+LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize)`
+
+error: attribute #[no_mangle] set on a Rust ABI function
+  --> $DIR/no_mangle_with_rust_abi.rs:20:1
+   |
+LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize)`
+
+error: attribute #[no_mangle] set on a Rust ABI function
+  --> $DIR/no_mangle_with_rust_abi.rs:23:1
+   |
+LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
+LL | |     arg_one: u32,
+LL | |     arg_two: usize,
+LL | | ) -> u32 {
+   | |________^
+   |
+help: try
+   |
+LL + extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
+LL +     arg_one: u32,
+LL +     arg_two: usize,
+LL ~ ) -> u32 {
+   |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/question_mark_used.rs b/src/tools/clippy/tests/ui/question_mark_used.rs
new file mode 100644
index 00000000000..8c3ef789697
--- /dev/null
+++ b/src/tools/clippy/tests/ui/question_mark_used.rs
@@ -0,0 +1,15 @@
+// non rustfixable
+#![allow(unreachable_code)]
+#![allow(dead_code)]
+#![warn(clippy::question_mark_used)]
+
+fn other_function() -> Option<i32> {
+    Some(32)
+}
+
+fn my_function() -> Option<i32> {
+    other_function()?;
+    None
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/question_mark_used.stderr b/src/tools/clippy/tests/ui/question_mark_used.stderr
new file mode 100644
index 00000000000..8b5fcbcdbfd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/question_mark_used.stderr
@@ -0,0 +1,11 @@
+error: question mark operator was used
+  --> $DIR/question_mark_used.rs:11:5
+   |
+LL |     other_function()?;
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using a custom macro or match expression
+   = note: `-D clippy::question-mark-used` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
new file mode 100644
index 00000000000..da998c610bd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
@@ -0,0 +1,84 @@
+// run-rustfix
+
+#![warn(clippy::significant_drop_tightening)]
+
+use std::sync::Mutex;
+
+pub fn complex_return_triggers_the_lint() -> i32 {
+    fn foo() -> i32 {
+        1
+    }
+    let mutex = Mutex::new(1);
+    let lock = mutex.lock().unwrap();
+    let _ = *lock;
+    let _ = *lock;
+    drop(lock);
+    foo()
+}
+
+pub fn path_return_can_be_ignored() -> i32 {
+    let mutex = Mutex::new(1);
+    let lock = mutex.lock().unwrap();
+    let rslt = *lock;
+    let _ = *lock;
+    rslt
+}
+
+pub fn post_bindings_can_be_ignored() {
+    let mutex = Mutex::new(1);
+    let lock = mutex.lock().unwrap();
+    let rslt = *lock;
+    let another = rslt;
+    let _ = another;
+}
+
+pub fn unnecessary_contention_with_multiple_owned_results() {
+    {
+        let mutex = Mutex::new(1i32);
+        let lock = mutex.lock().unwrap();
+        let _ = lock.abs();
+        let _ = lock.is_positive();
+    }
+
+    {
+        let mutex = Mutex::new(1i32);
+        let lock = mutex.lock().unwrap();
+        let rslt0 = lock.abs();
+        let rslt1 = lock.is_positive();
+        drop(lock);
+        do_heavy_computation_that_takes_time((rslt0, rslt1));
+    }
+}
+
+pub fn unnecessary_contention_with_single_owned_results() {
+    {
+        let mutex = Mutex::new(1i32);
+        let lock = mutex.lock().unwrap();
+        let _ = lock.abs();
+    }
+    {
+        let mutex = Mutex::new(vec![1i32]);
+        let mut lock = mutex.lock().unwrap();
+        lock.clear();
+    }
+
+    {
+        let mutex = Mutex::new(1i32);
+        
+        let rslt0 = mutex.lock().unwrap().abs();
+        
+        do_heavy_computation_that_takes_time(rslt0);
+    }
+    {
+        let mutex = Mutex::new(vec![1i32]);
+        
+        mutex.lock().unwrap().clear();
+        
+        do_heavy_computation_that_takes_time(());
+    }
+}
+
+// Marker used for illustration purposes.
+pub fn do_heavy_computation_that_takes_time<T>(_: T) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.rs b/src/tools/clippy/tests/ui/significant_drop_tightening.rs
new file mode 100644
index 00000000000..83823f95f68
--- /dev/null
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.rs
@@ -0,0 +1,80 @@
+// run-rustfix
+
+#![warn(clippy::significant_drop_tightening)]
+
+use std::sync::Mutex;
+
+pub fn complex_return_triggers_the_lint() -> i32 {
+    fn foo() -> i32 {
+        1
+    }
+    let mutex = Mutex::new(1);
+    let lock = mutex.lock().unwrap();
+    let _ = *lock;
+    let _ = *lock;
+    foo()
+}
+
+pub fn path_return_can_be_ignored() -> i32 {
+    let mutex = Mutex::new(1);
+    let lock = mutex.lock().unwrap();
+    let rslt = *lock;
+    let _ = *lock;
+    rslt
+}
+
+pub fn post_bindings_can_be_ignored() {
+    let mutex = Mutex::new(1);
+    let lock = mutex.lock().unwrap();
+    let rslt = *lock;
+    let another = rslt;
+    let _ = another;
+}
+
+pub fn unnecessary_contention_with_multiple_owned_results() {
+    {
+        let mutex = Mutex::new(1i32);
+        let lock = mutex.lock().unwrap();
+        let _ = lock.abs();
+        let _ = lock.is_positive();
+    }
+
+    {
+        let mutex = Mutex::new(1i32);
+        let lock = mutex.lock().unwrap();
+        let rslt0 = lock.abs();
+        let rslt1 = lock.is_positive();
+        do_heavy_computation_that_takes_time((rslt0, rslt1));
+    }
+}
+
+pub fn unnecessary_contention_with_single_owned_results() {
+    {
+        let mutex = Mutex::new(1i32);
+        let lock = mutex.lock().unwrap();
+        let _ = lock.abs();
+    }
+    {
+        let mutex = Mutex::new(vec![1i32]);
+        let mut lock = mutex.lock().unwrap();
+        lock.clear();
+    }
+
+    {
+        let mutex = Mutex::new(1i32);
+        let lock = mutex.lock().unwrap();
+        let rslt0 = lock.abs();
+        do_heavy_computation_that_takes_time(rslt0);
+    }
+    {
+        let mutex = Mutex::new(vec![1i32]);
+        let mut lock = mutex.lock().unwrap();
+        lock.clear();
+        do_heavy_computation_that_takes_time(());
+    }
+}
+
+// Marker used for illustration purposes.
+pub fn do_heavy_computation_that_takes_time<T>(_: T) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
new file mode 100644
index 00000000000..ab8ce356ec7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
@@ -0,0 +1,94 @@
+error: temporary with significant `Drop` can be early dropped
+  --> $DIR/significant_drop_tightening.rs:12:9
+   |
+LL |   pub fn complex_return_triggers_the_lint() -> i32 {
+   |  __________________________________________________-
+LL | |     fn foo() -> i32 {
+LL | |         1
+LL | |     }
+LL | |     let mutex = Mutex::new(1);
+LL | |     let lock = mutex.lock().unwrap();
+   | |         ^^^^
+...  |
+LL | |     foo()
+LL | | }
+   | |_- temporary `lock` is currently being dropped at the end of its contained scope
+   |
+   = note: this might lead to unnecessary resource contention
+   = note: `-D clippy::significant-drop-tightening` implied by `-D warnings`
+help: drop the temporary after the end of its last usage
+   |
+LL ~     let _ = *lock;
+LL +     drop(lock);
+   |
+
+error: temporary with significant `Drop` can be early dropped
+  --> $DIR/significant_drop_tightening.rs:44:13
+   |
+LL | /     {
+LL | |         let mutex = Mutex::new(1i32);
+LL | |         let lock = mutex.lock().unwrap();
+   | |             ^^^^
+LL | |         let rslt0 = lock.abs();
+LL | |         let rslt1 = lock.is_positive();
+LL | |         do_heavy_computation_that_takes_time((rslt0, rslt1));
+LL | |     }
+   | |_____- temporary `lock` is currently being dropped at the end of its contained scope
+   |
+   = note: this might lead to unnecessary resource contention
+help: drop the temporary after the end of its last usage
+   |
+LL ~         let rslt1 = lock.is_positive();
+LL +         drop(lock);
+   |
+
+error: temporary with significant `Drop` can be early dropped
+  --> $DIR/significant_drop_tightening.rs:65:13
+   |
+LL | /     {
+LL | |         let mutex = Mutex::new(1i32);
+LL | |         let lock = mutex.lock().unwrap();
+   | |             ^^^^
+LL | |         let rslt0 = lock.abs();
+LL | |         do_heavy_computation_that_takes_time(rslt0);
+LL | |     }
+   | |_____- temporary `lock` is currently being dropped at the end of its contained scope
+   |
+   = note: this might lead to unnecessary resource contention
+help: merge the temporary construction with its single usage
+   |
+LL ~         
+LL +         let rslt0 = mutex.lock().unwrap().abs();
+   |
+help: remove separated single usage
+   |
+LL -         let rslt0 = lock.abs();
+LL +         
+   |
+
+error: temporary with significant `Drop` can be early dropped
+  --> $DIR/significant_drop_tightening.rs:71:17
+   |
+LL | /     {
+LL | |         let mutex = Mutex::new(vec![1i32]);
+LL | |         let mut lock = mutex.lock().unwrap();
+   | |                 ^^^^
+LL | |         lock.clear();
+LL | |         do_heavy_computation_that_takes_time(());
+LL | |     }
+   | |_____- temporary `lock` is currently being dropped at the end of its contained scope
+   |
+   = note: this might lead to unnecessary resource contention
+help: merge the temporary construction with its single usage
+   |
+LL ~         
+LL +         mutex.lock().unwrap().clear();
+   |
+help: remove separated single usage
+   |
+LL -         lock.clear();
+LL +         
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs b/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs
new file mode 100644
index 00000000000..bdc6113a250
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs
@@ -0,0 +1,10 @@
+fn main() {
+    // Things it should warn about:
+    std::process::Command::new("echo").arg("-n hello").spawn().unwrap();
+    std::process::Command::new("cat").arg("--number file").spawn().unwrap();
+
+    // Things it should not warn about:
+    std::process::Command::new("echo").arg("hello world").spawn().unwrap();
+    std::process::Command::new("a").arg("--fmt=%a %b %c").spawn().unwrap();
+    std::process::Command::new("b").arg("-ldflags=-s -w").spawn().unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr b/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr
new file mode 100644
index 00000000000..9bc0ca93aec
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr
@@ -0,0 +1,25 @@
+error: single argument that looks like it should be multiple arguments
+  --> $DIR/suspicious_command_arg_space.rs:3:44
+   |
+LL |     std::process::Command::new("echo").arg("-n hello").spawn().unwrap();
+   |                                            ^^^^^^^^^^
+   |
+   = note: `-D clippy::suspicious-command-arg-space` implied by `-D warnings`
+help: consider splitting the argument
+   |
+LL |     std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap();
+   |                                        ~~~~ ~~~~~~~~~~~~~~~
+
+error: single argument that looks like it should be multiple arguments
+  --> $DIR/suspicious_command_arg_space.rs:4:43
+   |
+LL |     std::process::Command::new("cat").arg("--number file").spawn().unwrap();
+   |                                           ^^^^^^^^^^^^^^^
+   |
+help: consider splitting the argument
+   |
+LL |     std::process::Command::new("cat").args(["--number", "file"]).spawn().unwrap();
+   |                                       ~~~~ ~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed
index 805a2ba5a59..fa89706a815 100644
--- a/src/tools/clippy/tests/ui/swap.fixed
+++ b/src/tools/clippy/tests/ui/swap.fixed
@@ -7,7 +7,8 @@
     clippy::redundant_clone,
     redundant_semicolons,
     dead_code,
-    unused_assignments
+    unused_assignments,
+    unused_variables
 )]
 
 struct Foo(u32);
@@ -121,6 +122,27 @@ fn main() {
     std::mem::swap(&mut c.0, &mut a);
 
     ; std::mem::swap(&mut c.0, &mut a);
+
+    std::mem::swap(&mut a, &mut b);
+
+    let mut c = 1;
+    let mut d = 2;
+    std::mem::swap(&mut d, &mut c);
+
+    let mut b = 1;
+    std::mem::swap(&mut a, &mut b);
+
+    let b = 1;
+    let a = 2;
+
+    let t = b;
+    let b = a;
+    let a = t;
+
+    let mut b = 1;
+    let mut a = 2;
+
+    std::mem::swap(&mut b, &mut a);
 }
 
 fn issue_8154() {
diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs
index a8c87847952..ef8a81c8341 100644
--- a/src/tools/clippy/tests/ui/swap.rs
+++ b/src/tools/clippy/tests/ui/swap.rs
@@ -7,7 +7,8 @@
     clippy::redundant_clone,
     redundant_semicolons,
     dead_code,
-    unused_assignments
+    unused_assignments,
+    unused_variables
 )]
 
 struct Foo(u32);
@@ -143,6 +144,32 @@ fn main() {
     ; let t = c.0;
     c.0 = a;
     a = t;
+
+    let a = b;
+    let b = a;
+
+    let mut c = 1;
+    let mut d = 2;
+    d = c;
+    c = d;
+
+    let mut b = 1;
+    let a = b;
+    b = a;
+
+    let b = 1;
+    let a = 2;
+
+    let t = b;
+    let b = a;
+    let a = t;
+
+    let mut b = 1;
+    let mut a = 2;
+
+    let t = b;
+    b = a;
+    a = t;
 }
 
 fn issue_8154() {
diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr
index ee4b7a508a5..f0acbfe253f 100644
--- a/src/tools/clippy/tests/ui/swap.stderr
+++ b/src/tools/clippy/tests/ui/swap.stderr
@@ -1,5 +1,5 @@
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:24:5
+  --> $DIR/swap.rs:25:5
    |
 LL | /     let temp = bar.a;
 LL | |     bar.a = bar.b;
@@ -10,7 +10,7 @@ LL | |     bar.b = temp;
    = note: `-D clippy::manual-swap` implied by `-D warnings`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:36:5
+  --> $DIR/swap.rs:37:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -18,7 +18,7 @@ LL | |     foo[1] = temp;
    | |_________________^ help: try: `foo.swap(0, 1)`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:45:5
+  --> $DIR/swap.rs:46:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -26,7 +26,7 @@ LL | |     foo[1] = temp;
    | |_________________^ help: try: `foo.swap(0, 1)`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:64:5
+  --> $DIR/swap.rs:65:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -34,7 +34,7 @@ LL | |     foo[1] = temp;
    | |_________________^ help: try: `foo.swap(0, 1)`
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:75:5
+  --> $DIR/swap.rs:76:5
    |
 LL | /     a ^= b;
 LL | |     b ^= a;
@@ -42,7 +42,7 @@ LL | |     a ^= b;
    | |___________^ help: try: `std::mem::swap(&mut a, &mut b)`
 
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:83:5
+  --> $DIR/swap.rs:84:5
    |
 LL | /     bar.a ^= bar.b;
 LL | |     bar.b ^= bar.a;
@@ -50,7 +50,7 @@ LL | |     bar.a ^= bar.b;
    | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b)`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:91:5
+  --> $DIR/swap.rs:92:5
    |
 LL | /     foo[0] ^= foo[1];
 LL | |     foo[1] ^= foo[0];
@@ -58,7 +58,7 @@ LL | |     foo[0] ^= foo[1];
    | |_____________________^ help: try: `foo.swap(0, 1)`
 
 error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually
-  --> $DIR/swap.rs:120:5
+  --> $DIR/swap.rs:121:5
    |
 LL | /     let temp = foo[0][1];
 LL | |     foo[0][1] = bar[1][0];
@@ -68,7 +68,7 @@ LL | |     bar[1][0] = temp;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:134:7
+  --> $DIR/swap.rs:135:7
    |
 LL |       ; let t = a;
    |  _______^
@@ -79,7 +79,7 @@ LL | |     b = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `c.0` and `a` manually
-  --> $DIR/swap.rs:143:7
+  --> $DIR/swap.rs:144:7
    |
 LL |       ; let t = c.0;
    |  _______^
@@ -89,8 +89,18 @@ LL | |     a = t;
    |
    = note: or maybe you should use `std::mem::replace`?
 
+error: this looks like you are swapping `b` and `a` manually
+  --> $DIR/swap.rs:170:5
+   |
+LL | /     let t = b;
+LL | |     b = a;
+LL | |     a = t;
+   | |_________^ help: try: `std::mem::swap(&mut b, &mut a)`
+   |
+   = note: or maybe you should use `std::mem::replace`?
+
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:131:5
+  --> $DIR/swap.rs:132:5
    |
 LL | /     a = b;
 LL | |     b = a;
@@ -100,7 +110,7 @@ LL | |     b = a;
    = note: `-D clippy::almost-swapped` implied by `-D warnings`
 
 error: this looks like you are trying to swap `c.0` and `a`
-  --> $DIR/swap.rs:140:5
+  --> $DIR/swap.rs:141:5
    |
 LL | /     c.0 = a;
 LL | |     a = c.0;
@@ -108,8 +118,35 @@ LL | |     a = c.0;
    |
    = note: or maybe you should use `std::mem::replace`?
 
+error: this looks like you are trying to swap `a` and `b`
+  --> $DIR/swap.rs:148:5
+   |
+LL | /     let a = b;
+LL | |     let b = a;
+   | |_____________^ help: try: `std::mem::swap(&mut a, &mut b)`
+   |
+   = note: or maybe you should use `std::mem::replace`?
+
+error: this looks like you are trying to swap `d` and `c`
+  --> $DIR/swap.rs:153:5
+   |
+LL | /     d = c;
+LL | |     c = d;
+   | |_________^ help: try: `std::mem::swap(&mut d, &mut c)`
+   |
+   = note: or maybe you should use `std::mem::replace`?
+
+error: this looks like you are trying to swap `a` and `b`
+  --> $DIR/swap.rs:157:5
+   |
+LL | /     let a = b;
+LL | |     b = a;
+   | |_________^ help: try: `std::mem::swap(&mut a, &mut b)`
+   |
+   = note: or maybe you should use `std::mem::replace`?
+
 error: this looks like you are swapping `s.0.x` and `s.0.y` manually
-  --> $DIR/swap.rs:178:5
+  --> $DIR/swap.rs:205:5
    |
 LL | /     let t = s.0.x;
 LL | |     s.0.x = s.0.y;
@@ -118,5 +155,5 @@ LL | |     s.0.y = t;
    |
    = note: or maybe you should use `std::mem::replace`?
 
-error: aborting due to 13 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs
new file mode 100644
index 00000000000..a3840678250
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs
@@ -0,0 +1,41 @@
+#![warn(clippy::transmute_int_to_non_zero)]
+
+use core::num::*;
+
+fn main() {
+    let int_u8: u8 = 1;
+    let int_u16: u16 = 1;
+    let int_u32: u32 = 1;
+    let int_u64: u64 = 1;
+    let int_u128: u128 = 1;
+
+    let int_i8: i8 = 1;
+    let int_i16: i16 = 1;
+    let int_i32: i32 = 1;
+    let int_i64: i64 = 1;
+    let int_i128: i128 = 1;
+
+    let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) };
+    let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) };
+    let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) };
+    let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) };
+    let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) };
+
+    let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) };
+    let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) };
+    let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) };
+    let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) };
+    let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) };
+
+    let _: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(int_u8) };
+    let _: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(int_u16) };
+    let _: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(int_u32) };
+    let _: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(int_u64) };
+    let _: NonZeroU128 = unsafe { NonZeroU128::new_unchecked(int_u128) };
+
+    let _: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(int_i8) };
+    let _: NonZeroI16 = unsafe { NonZeroI16::new_unchecked(int_i16) };
+    let _: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(int_i32) };
+    let _: NonZeroI64 = unsafe { NonZeroI64::new_unchecked(int_i64) };
+    let _: NonZeroI128 = unsafe { NonZeroI128::new_unchecked(int_i128) };
+}
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr
new file mode 100644
index 00000000000..33f8ce79ea7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr
@@ -0,0 +1,64 @@
+error: transmute from a `u8` to a `NonZeroU8`
+  --> $DIR/transmute_int_to_non_zero.rs:18:33
+   |
+LL |     let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) };
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU8::new_unchecked(int_u8)`
+   |
+   = note: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings`
+
+error: transmute from a `u16` to a `NonZeroU16`
+  --> $DIR/transmute_int_to_non_zero.rs:19:34
+   |
+LL |     let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU16::new_unchecked(int_u16)`
+
+error: transmute from a `u32` to a `NonZeroU32`
+  --> $DIR/transmute_int_to_non_zero.rs:20:34
+   |
+LL |     let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU32::new_unchecked(int_u32)`
+
+error: transmute from a `u64` to a `NonZeroU64`
+  --> $DIR/transmute_int_to_non_zero.rs:21:34
+   |
+LL |     let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU64::new_unchecked(int_u64)`
+
+error: transmute from a `u128` to a `NonZeroU128`
+  --> $DIR/transmute_int_to_non_zero.rs:22:35
+   |
+LL |     let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU128::new_unchecked(int_u128)`
+
+error: transmute from a `i8` to a `NonZeroI8`
+  --> $DIR/transmute_int_to_non_zero.rs:24:33
+   |
+LL |     let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) };
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI8::new_unchecked(int_i8)`
+
+error: transmute from a `i16` to a `NonZeroI16`
+  --> $DIR/transmute_int_to_non_zero.rs:25:34
+   |
+LL |     let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI16::new_unchecked(int_i16)`
+
+error: transmute from a `i32` to a `NonZeroI32`
+  --> $DIR/transmute_int_to_non_zero.rs:26:34
+   |
+LL |     let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI32::new_unchecked(int_i32)`
+
+error: transmute from a `i64` to a `NonZeroI64`
+  --> $DIR/transmute_int_to_non_zero.rs:27:34
+   |
+LL |     let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI64::new_unchecked(int_i64)`
+
+error: transmute from a `i128` to a `NonZeroI128`
+  --> $DIR/transmute_int_to_non_zero.rs:28:35
+   |
+LL |     let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI128::new_unchecked(int_i128)`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.fixed b/src/tools/clippy/tests/ui/uninlined_format_args.fixed
index 9d08e80cf9a..cbd5cc5fcee 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args.fixed
+++ b/src/tools/clippy/tests/ui/uninlined_format_args.fixed
@@ -174,3 +174,7 @@ fn _meets_msrv() {
     let local_i32 = 1;
     println!("expand='{local_i32}'");
 }
+
+fn _do_not_fire() {
+    println!("{:?}", None::<()>);
+}
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.rs b/src/tools/clippy/tests/ui/uninlined_format_args.rs
index 35b3677a896..cf0ea5be481 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args.rs
+++ b/src/tools/clippy/tests/ui/uninlined_format_args.rs
@@ -179,3 +179,7 @@ fn _meets_msrv() {
     let local_i32 = 1;
     println!("expand='{}'", local_i32);
 }
+
+fn _do_not_fire() {
+    println!("{:?}", None::<()>);
+}
diff --git a/src/tools/clippy/tests/ui/unreadable_literal.fixed b/src/tools/clippy/tests/ui/unreadable_literal.fixed
index a67363b09ea..13e5feb1926 100644
--- a/src/tools/clippy/tests/ui/unreadable_literal.fixed
+++ b/src/tools/clippy/tests/ui/unreadable_literal.fixed
@@ -23,7 +23,7 @@ fn main() {
     let _good = (
         0b1011_i64,
         0o1_234_u32,
-        0x0123_4567,
+        0x1_234_567,
         65536,
         1_2345_6789,
         1234_f32,
diff --git a/src/tools/clippy/tests/ui/unreadable_literal.stderr b/src/tools/clippy/tests/ui/unreadable_literal.stderr
index b51130c6a6a..450121b1c5a 100644
--- a/src/tools/clippy/tests/ui/unreadable_literal.stderr
+++ b/src/tools/clippy/tests/ui/unreadable_literal.stderr
@@ -1,11 +1,3 @@
-error: digits of hex or binary literal not grouped by four
-  --> $DIR/unreadable_literal.rs:26:9
-   |
-LL |         0x1_234_567,
-   |         ^^^^^^^^^^^ help: consider: `0x0123_4567`
-   |
-   = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
-
 error: long literal lacking separators
   --> $DIR/unreadable_literal.rs:34:17
    |
@@ -68,5 +60,5 @@ error: long literal lacking separators
 LL |     let _fail5 = 1.100300400;
    |                  ^^^^^^^^^^^ help: consider: `1.100_300_400`
 
-error: aborting due to 11 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml
index f4dac6e947e..76c2e330b21 100644
--- a/src/tools/error_index_generator/Cargo.toml
+++ b/src/tools/error_index_generator/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 mdbook = { version = "0.4", default-features = false, features = ["search"] }
+rustc_error_codes = { version = "0.0.0", path = "../../../compiler/rustc_error_codes" }
 
 [[bin]]
 name = "error_index_generator"
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index 98eda97e236..f984275b164 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -2,9 +2,6 @@
 
 extern crate rustc_driver;
 
-// We use the function we generate from `register_diagnostics!`.
-use crate::error_codes::error_codes;
-
 use std::env;
 use std::error::Error;
 use std::fs::{self, File};
@@ -17,22 +14,6 @@ use std::str::FromStr;
 use mdbook::book::{parse_summary, BookItem, Chapter};
 use mdbook::{Config, MDBook};
 
-macro_rules! register_diagnostics {
-    ($($error_code:ident: $message:expr,)+ ; $($undocumented:ident,)* ) => {
-        pub fn error_codes() -> Vec<(&'static str, Option<&'static str>)> {
-            let mut errors: Vec<(&str, Option<&str>)> = vec![
-                $((stringify!($error_code), Some($message)),)+
-                $((stringify!($undocumented), None),)+
-            ];
-            errors.sort();
-            errors
-        }
-    }
-}
-
-#[path = "../../../compiler/rustc_error_codes/src/error_codes.rs"]
-mod error_codes;
-
 enum OutputFormat {
     HTML,
     Markdown,
@@ -55,11 +36,8 @@ fn render_markdown(output_path: &Path) -> Result<(), Box<dyn Error>> {
 
     write!(output_file, "# Rust Compiler Error Index\n")?;
 
-    for (err_code, description) in error_codes().iter() {
-        match description {
-            Some(ref desc) => write!(output_file, "## {}\n{}\n", err_code, desc)?,
-            None => {}
-        }
+    for (err_code, description) in rustc_error_codes::DIAGNOSTICS.iter() {
+        write!(output_file, "## {}\n{}\n", err_code, description)?
     }
 
     Ok(())
@@ -105,27 +83,23 @@ This page lists all the error codes emitted by the Rust compiler.
 "
     );
 
-    let err_codes = error_codes();
+    let err_codes = rustc_error_codes::DIAGNOSTICS;
     let mut chapters = Vec::with_capacity(err_codes.len());
 
     for (err_code, explanation) in err_codes.iter() {
-        if let Some(explanation) = explanation {
-            introduction.push_str(&format!(" * [{0}](./{0}.html)\n", err_code));
-
-            let content = add_rust_attribute_on_codeblock(explanation);
-            chapters.push(BookItem::Chapter(Chapter {
-                name: err_code.to_string(),
-                content: format!("# Error code {}\n\n{}\n", err_code, content),
-                number: None,
-                sub_items: Vec::new(),
-                // We generate it into the `error_codes` folder.
-                path: Some(PathBuf::from(&format!("{}.html", err_code))),
-                source_path: None,
-                parent_names: Vec::new(),
-            }));
-        } else {
-            introduction.push_str(&format!(" * {}\n", err_code));
-        }
+        introduction.push_str(&format!(" * [{0}](./{0}.html)\n", err_code));
+
+        let content = add_rust_attribute_on_codeblock(explanation);
+        chapters.push(BookItem::Chapter(Chapter {
+            name: err_code.to_string(),
+            content: format!("# Error code {}\n\n{}\n", err_code, content),
+            number: None,
+            sub_items: Vec::new(),
+            // We generate it into the `error_codes` folder.
+            path: Some(PathBuf::from(&format!("{}.html", err_code))),
+            source_path: None,
+            parent_names: Vec::new(),
+        }));
     }
 
     let mut config = Config::from_str(include_str!("book_config.toml"))?;
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index c6f55410e44..a1f675a3b40 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -71,6 +71,19 @@ impl<'a> Validator<'a> {
         }
     }
 
+    fn check_items(&mut self, id: &Id, items: &[Id]) {
+        let mut visited_ids = HashSet::with_capacity(items.len());
+
+        for item in items {
+            if !visited_ids.insert(item) {
+                self.fail(
+                    id,
+                    ErrorKind::Custom(format!("Duplicated entry in `items` field: `{item:?}`")),
+                );
+            }
+        }
+    }
+
     fn check_item(&mut self, id: &'a Id) {
         if let Some(item) = &self.krate.index.get(id) {
             item.links.values().for_each(|id| self.add_any_id(id));
@@ -83,9 +96,9 @@ impl<'a> Validator<'a> {
                 ItemEnum::Enum(x) => self.check_enum(x),
                 ItemEnum::Variant(x) => self.check_variant(x, id),
                 ItemEnum::Function(x) => self.check_function(x),
-                ItemEnum::Trait(x) => self.check_trait(x),
+                ItemEnum::Trait(x) => self.check_trait(x, id),
                 ItemEnum::TraitAlias(x) => self.check_trait_alias(x),
-                ItemEnum::Impl(x) => self.check_impl(x),
+                ItemEnum::Impl(x) => self.check_impl(x, id),
                 ItemEnum::Typedef(x) => self.check_typedef(x),
                 ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x),
                 ItemEnum::Constant(x) => self.check_constant(x),
@@ -94,7 +107,7 @@ impl<'a> Validator<'a> {
                 ItemEnum::Macro(x) => self.check_macro(x),
                 ItemEnum::ProcMacro(x) => self.check_proc_macro(x),
                 ItemEnum::Primitive(x) => self.check_primitive_type(x),
-                ItemEnum::Module(x) => self.check_module(x),
+                ItemEnum::Module(x) => self.check_module(x, id),
                 // FIXME: Why don't these have their own structs?
                 ItemEnum::ExternCrate { .. } => {}
                 ItemEnum::AssocConst { type_, default: _ } => self.check_type(type_),
@@ -112,7 +125,8 @@ impl<'a> Validator<'a> {
     }
 
     // Core checkers
-    fn check_module(&mut self, module: &'a Module) {
+    fn check_module(&mut self, module: &'a Module, id: &Id) {
+        self.check_items(id, &module.items);
         module.items.iter().for_each(|i| self.add_mod_item_id(i));
     }
 
@@ -181,7 +195,8 @@ impl<'a> Validator<'a> {
         self.check_fn_decl(&x.decl);
     }
 
-    fn check_trait(&mut self, x: &'a Trait) {
+    fn check_trait(&mut self, x: &'a Trait, id: &Id) {
+        self.check_items(id, &x.items);
         self.check_generics(&x.generics);
         x.items.iter().for_each(|i| self.add_trait_item_id(i));
         x.bounds.iter().for_each(|i| self.check_generic_bound(i));
@@ -193,7 +208,8 @@ impl<'a> Validator<'a> {
         x.params.iter().for_each(|i| self.check_generic_bound(i));
     }
 
-    fn check_impl(&mut self, x: &'a Impl) {
+    fn check_impl(&mut self, x: &'a Impl, id: &Id) {
+        self.check_items(id, &x.items);
         self.check_generics(&x.generics);
         if let Some(path) = &x.trait_ {
             self.check_path(path, PathKind::Trait);
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index 5b538691de1..476075e9c91 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -242,6 +242,13 @@ josh-proxy --local=$HOME/.cache/josh --remote=https://github.com --no-background
 
 This uses a directory `$HOME/.cache/josh` as a cache, to speed up repeated pulling/pushing.
 
+To make josh push via ssh instead of https, you can add the following to your `.gitconfig`:
+
+```toml
+[url "git@github.com:"]
+    pushInsteadOf = https://github.com/
+```
+
 ### Importing changes from the rustc repo
 
 Josh needs to be running, as described above.
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 48581f6bbff..1086d0481c8 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -213,7 +213,9 @@ degree documented below):
 - The best-supported target is `x86_64-unknown-linux-gnu`. Miri releases are
   blocked on things working with this target. Most other Linux targets should
   also work well; we do run the test suite on `i686-unknown-linux-gnu` as a
-  32bit target and `mips64-unknown-linux-gnuabi64` as a big-endian target.
+  32bit target and `mips64-unknown-linux-gnuabi64` as a big-endian target, as
+  well as the ARM targets `aarch64-unknown-linux-gnu` and
+  `arm-unknown-linux-gnueabi`.
 - `x86_64-apple-darwin` should work basically as well as Linux. We also test
   `aarch64-apple-darwin`. However, we might ship Miri with a nightly even when
   some features on these targets regress.
@@ -590,7 +592,7 @@ extern "Rust" {
     /// `out` must point to at least `out_size` many bytes, and the result will be stored there
     /// with a null terminator.
     /// Returns 0 if the `out` buffer was large enough, and the required size otherwise.
-    fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+    fn miri_host_to_target_path(path: *const std::ffi::c_char, out: *mut std::ffi::c_char, out_size: usize) -> usize;
 }
 ```
 
diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index 37926db0166..76badcf94af 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -193,9 +193,9 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb"
 
 [[package]]
 name = "rustc_tools_util"
-version = "0.2.1"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "598f48ce2a421542b3e64828aa742b687cc1b91d2f96591cfdb7ac5988cd6366"
+checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
 
 [[package]]
 name = "rustc_version"
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index 2197160bc9d..09079dbb818 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -30,4 +30,4 @@ rustc-workspace-hack = "1.0.0"
 serde = { version = "*", features = ["derive"] }
 
 [build-dependencies]
-rustc_tools_util = "0.2"
+rustc_tools_util = "0.3"
diff --git a/src/tools/miri/cargo-miri/build.rs b/src/tools/miri/cargo-miri/build.rs
index c1110115455..52e2a083512 100644
--- a/src/tools/miri/cargo-miri/build.rs
+++ b/src/tools/miri/cargo-miri/build.rs
@@ -2,12 +2,5 @@ fn main() {
     // Don't rebuild miri when nothing changed.
     println!("cargo:rerun-if-changed=build.rs");
     // gather version info
-    println!(
-        "cargo:rustc-env=GIT_HASH={}",
-        rustc_tools_util::get_commit_hash().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=COMMIT_DATE={}",
-        rustc_tools_util::get_commit_date().unwrap_or_default()
-    );
+    rustc_tools_util::setup_version_info!();
 }
diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh
index e01bfbc74d9..60450d09815 100755
--- a/src/tools/miri/ci.sh
+++ b/src/tools/miri/ci.sh
@@ -104,6 +104,7 @@ run_tests
 case $HOST_TARGET in
   x86_64-unknown-linux-gnu)
     MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
+    MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
     MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
     MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
     MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
@@ -118,6 +119,7 @@ case $HOST_TARGET in
     MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests
     ;;
   i686-pc-windows-msvc)
+    MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests
     MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests
     MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests
     ;;
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index cf6d9c28080..53ec1ba0821 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-c54c8cbac882e149e04a9e1f2d146fd548ae30ae
+c4e0cd966062ca67daed20775f4e8a60c28e57df
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index cf1ff603281..b766916402e 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -148,8 +148,7 @@ impl NewPermission {
             NewPermission::Uniform {
                 perm: Permission::Unique,
                 access: Some(AccessKind::Write),
-                protector: (kind == RetagKind::FnEntry)
-                    .then_some(ProtectorKind::WeakProtector),
+                protector: (kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),
             }
         } else {
             // `!Unpin` boxes do not get `noalias` nor `dereferenceable`.
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index ebb71b57ae3..8443e907938 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -363,7 +363,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
                 tcx,
                 ty::ParamEnv::reveal_all(),
                 start_id,
-                tcx.intern_substs(&[ty::subst::GenericArg::from(main_ret_ty)]),
+                tcx.mk_substs(&[ty::subst::GenericArg::from(main_ret_ty)]),
             )
             .unwrap()
             .unwrap();
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 7024927b205..f64f216520f 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -13,6 +13,7 @@
 #![allow(
     clippy::collapsible_else_if,
     clippy::collapsible_if,
+    clippy::if_same_then_else,
     clippy::comparison_chain,
     clippy::enum_variant_names,
     clippy::field_reassign_with_default,
@@ -21,7 +22,7 @@
     clippy::single_match,
     clippy::useless_format,
     clippy::derive_partial_eq_without_eq,
-    clippy::derive_hash_xor_eq,
+    clippy::derived_hash_with_manual_eq,
     clippy::too_many_arguments,
     clippy::type_complexity,
     clippy::single_element_loop,
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 8bd1e802f8a..8bbf9f87b43 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -477,7 +477,8 @@ pub struct MiriMachine<'mir, 'tcx> {
 
 impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
     pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self {
-        let local_crates = helpers::get_local_crates(layout_cx.tcx);
+        let tcx = layout_cx.tcx;
+        let local_crates = helpers::get_local_crates(tcx);
         let layouts =
             PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types");
         let profiler = config.measureme_out.as_ref().map(|out| {
@@ -486,10 +487,13 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
         let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
         let borrow_tracker = config.borrow_tracker.map(|bt| bt.instanciate_global_state(config));
         let data_race = config.data_race_detector.then(|| data_race::GlobalState::new(config));
+        // Determinine page size, stack address, and stack size.
+        // These values are mostly meaningless, but the stack address is also where we start
+        // allocating physical integer addresses for all allocations.
         let page_size = if let Some(page_size) = config.page_size {
             page_size
         } else {
-            let target = &layout_cx.tcx.sess.target;
+            let target = &tcx.sess.target;
             match target.arch.as_ref() {
                 "wasm32" | "wasm64" => 64 * 1024, // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances
                 "aarch64" =>
@@ -504,10 +508,12 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
                 _ => 4 * 1024,
             }
         };
-        let stack_addr = page_size * 32;
-        let stack_size = page_size * 16;
+        // On 16bit targets, 32 pages is more than the entire address space!
+        let stack_addr = if tcx.pointer_size().bits() < 32 { page_size } else { page_size * 32 };
+        let stack_size =
+            if tcx.pointer_size().bits() < 32 { page_size * 4 } else { page_size * 16 };
         MiriMachine {
-            tcx: layout_cx.tcx,
+            tcx,
             borrow_tracker,
             data_race,
             intptrcast: RefCell::new(intptrcast::GlobalStateInner::new(config, stack_addr)),
@@ -902,8 +908,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
             };
             let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id);
             let def_ty = ecx.tcx.type_of(def_id).subst_identity();
-            let extern_decl_layout =
-                ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap();
+            let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap();
             if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align {
                 throw_unsup_format!(
                     "`extern` static `{name}` from crate `{krate}` has been declared \
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 2d9eb37a258..03275ed4ed1 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -885,6 +885,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     }
                 }
             }
+            "llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => {
+                let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
+                let arg = this.read_scalar(arg)?.to_i32()?;
+                match arg {
+                    // YIELD
+                    1 => {
+                        this.yield_active_thread();
+                    }
+                    _ => {
+                        throw_unsup_format!("unsupported llvm.arm.hint argument {}", arg);
+                    }
+                }
+            }
 
             // Platform-specific shims
             _ =>
diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/fd.rs
index 212b7936341..fd4927fa10c 100644
--- a/src/tools/miri/src/shims/unix/linux/fd.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd.rs
@@ -7,6 +7,8 @@ use socketpair::SocketPair;
 
 use shims::unix::fs::EvalContextExt as _;
 
+use std::cell::Cell;
+
 pub mod epoll;
 pub mod event;
 pub mod socketpair;
@@ -101,6 +103,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
     }
 
+    /// The `epoll_wait()` system call waits for events on the `Epoll`
+    /// instance referred to by the file descriptor `epfd`. The buffer
+    /// pointed to by `events` is used to return information from the ready
+    /// list about file descriptors in the interest list that have some
+    /// events available. Up to `maxevents` are returned by `epoll_wait()`.
+    /// The `maxevents` argument must be greater than zero.
+
+    /// The `timeout` argument specifies the number of milliseconds that
+    /// `epoll_wait()` will block. Time is measured against the
+    /// CLOCK_MONOTONIC clock.
+
+    /// A call to `epoll_wait()` will block until either:
+    /// • a file descriptor delivers an event;
+    /// • the call is interrupted by a signal handler; or
+    /// • the timeout expires.
+
+    /// Note that the timeout interval will be rounded up to the system
+    /// clock granularity, and kernel scheduling delays mean that the
+    /// blocking interval may overrun by a small amount. Specifying a
+    /// timeout of -1 causes `epoll_wait()` to block indefinitely, while
+    /// specifying a timeout equal to zero cause `epoll_wait()` to return
+    /// immediately, even if no events are available.
+    ///
+    /// On success, `epoll_wait()` returns the number of file descriptors
+    /// ready for the requested I/O, or zero if no file descriptor became
+    /// ready during the requested timeout milliseconds. On failure,
+    /// `epoll_wait()` returns -1 and errno is set to indicate the error.
+    ///
+    /// <https://man7.org/linux/man-pages/man2/epoll_wait.2.html>
+    fn epoll_wait(
+        &mut self,
+        epfd: &OpTy<'tcx, Provenance>,
+        events: &OpTy<'tcx, Provenance>,
+        maxevents: &OpTy<'tcx, Provenance>,
+        timeout: &OpTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, Scalar<Provenance>> {
+        let this = self.eval_context_mut();
+
+        let epfd = this.read_scalar(epfd)?.to_i32()?;
+        let _events = this.read_scalar(events)?.to_pointer(this)?;
+        let _maxevents = this.read_scalar(maxevents)?.to_i32()?;
+        let _timeout = this.read_scalar(timeout)?.to_i32()?;
+
+        let numevents = 0;
+        if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
+            let _epfd = epfd.as_epoll_handle()?;
+
+            // FIXME return number of events ready when scheme for marking events ready exists
+            Ok(Scalar::from_i32(numevents))
+        } else {
+            Ok(Scalar::from_i32(this.handle_not_found()?))
+        }
+    }
+
     /// This function creates an `Event` that is used as an event wait/notify mechanism by
     /// user-space applications, and by the kernel to notify user-space applications of events.
     /// The `Event` contains an `u64` counter maintained by the kernel. The counter is initialized
@@ -142,7 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
 
         let fh = &mut this.machine.file_handler;
-        let fd = fh.insert_fd(Box::new(Event { val }));
+        let fd = fh.insert_fd(Box::new(Event { val: Cell::new(val.into()) }));
         Ok(Scalar::from_i32(fd))
     }
 
diff --git a/src/tools/miri/src/shims/unix/linux/fd/event.rs b/src/tools/miri/src/shims/unix/linux/fd/event.rs
index 239eb462a1d..b28a6e0c56e 100644
--- a/src/tools/miri/src/shims/unix/linux/fd/event.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd/event.rs
@@ -2,6 +2,7 @@ use crate::shims::unix::fs::FileDescriptor;
 
 use rustc_const_eval::interpret::InterpResult;
 
+use std::cell::Cell;
 use std::io;
 
 /// A kind of file descriptor created by `eventfd`.
@@ -13,7 +14,9 @@ use std::io;
 /// <https://man.netbsd.org/eventfd.2>
 #[derive(Debug)]
 pub struct Event {
-    pub val: u32,
+    /// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the
+    /// kernel. This counter is initialized with the value specified in the argument initval.
+    pub val: Cell<u64>,
 }
 
 impl FileDescriptor for Event {
@@ -22,7 +25,7 @@ impl FileDescriptor for Event {
     }
 
     fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
-        Ok(Box::new(Event { val: self.val }))
+        Ok(Box::new(Event { val: self.val.clone() }))
     }
 
     fn is_tty(&self) -> bool {
@@ -35,4 +38,32 @@ impl FileDescriptor for Event {
     ) -> InterpResult<'tcx, io::Result<i32>> {
         Ok(Ok(0))
     }
+
+    /// A write call adds the 8-byte integer value supplied in
+    /// its buffer to the counter.  The maximum value that may be
+    /// stored in the counter is the largest unsigned 64-bit value
+    /// minus 1 (i.e., 0xfffffffffffffffe).  If the addition would
+    /// cause the counter's value to exceed the maximum, then the
+    /// write either blocks until a read is performed on the
+    /// file descriptor, or fails with the error EAGAIN if the
+    /// file descriptor has been made nonblocking.
+
+    /// A write fails with the error EINVAL if the size of the
+    /// supplied buffer is less than 8 bytes, or if an attempt is
+    /// made to write the value 0xffffffffffffffff.
+    ///
+    /// FIXME: use endianness
+    fn write<'tcx>(
+        &self,
+        _communicate_allowed: bool,
+        bytes: &[u8],
+    ) -> InterpResult<'tcx, io::Result<usize>> {
+        let v1 = self.val.get();
+        // FIXME handle blocking when addition results in exceeding the max u64 value
+        // or fail with EAGAIN if the file descriptor is nonblocking.
+        let v2 = v1.checked_add(u64::from_be_bytes(bytes.try_into().unwrap())).unwrap();
+        self.val.set(v2);
+        assert_eq!(8, bytes.len());
+        Ok(Ok(8))
+    }
 }
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index 9f6938424fb..f4e7824d91d 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -55,6 +55,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let result = this.epoll_ctl(epfd, op, fd, event)?;
                 this.write_scalar(result, dest)?;
             }
+            "epoll_wait" => {
+                let [epfd, events, maxevents, timeout] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let result = this.epoll_wait(epfd, events, maxevents, timeout)?;
+                this.write_scalar(result, dest)?;
+            }
             "eventfd" => {
                 let [val, flag] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
diff --git a/src/tools/miri/test-cargo-miri/src/main.rs b/src/tools/miri/test-cargo-miri/src/main.rs
index 048dbbbaa0f..048577ef15a 100644
--- a/src/tools/miri/test-cargo-miri/src/main.rs
+++ b/src/tools/miri/test-cargo-miri/src/main.rs
@@ -23,7 +23,7 @@ fn main() {
     // (We rely on the test runner to always disable isolation when passing no arguments.)
     if std::env::args().len() <= 1 {
         fn host_to_target_path(path: String) -> PathBuf {
-            use std::ffi::{CStr, CString};
+            use std::ffi::{c_char, CStr, CString};
 
             let path = CString::new(path).unwrap();
             let mut out = Vec::with_capacity(1024);
@@ -31,8 +31,8 @@ fn main() {
             unsafe {
                 extern "Rust" {
                     fn miri_host_to_target_path(
-                        path: *const i8,
-                        out: *mut i8,
+                        path: *const c_char,
+                        out: *mut c_char,
                         out_size: usize,
                     ) -> usize;
                 }
diff --git a/src/tools/miri/test-cargo-miri/subcrate/main.rs b/src/tools/miri/test-cargo-miri/subcrate/main.rs
index 1cb8091f877..52161098788 100644
--- a/src/tools/miri/test-cargo-miri/subcrate/main.rs
+++ b/src/tools/miri/test-cargo-miri/subcrate/main.rs
@@ -5,7 +5,7 @@ fn main() {
     println!("subcrate running");
 
     fn host_to_target_path(path: String) -> PathBuf {
-        use std::ffi::{CStr, CString};
+        use std::ffi::{c_char, CStr, CString};
 
         let path = CString::new(path).unwrap();
         let mut out = Vec::with_capacity(1024);
@@ -13,8 +13,8 @@ fn main() {
         unsafe {
             extern "Rust" {
                 fn miri_host_to_target_path(
-                    path: *const i8,
-                    out: *mut i8,
+                    path: *const c_char,
+                    out: *mut c_char,
                     out_size: usize,
                 ) -> usize;
             }
diff --git a/src/tools/miri/test-cargo-miri/subcrate/test.rs b/src/tools/miri/test-cargo-miri/subcrate/test.rs
index 619d8c72fd0..1681c721dc2 100644
--- a/src/tools/miri/test-cargo-miri/subcrate/test.rs
+++ b/src/tools/miri/test-cargo-miri/subcrate/test.rs
@@ -8,7 +8,7 @@ fn main() {
     println!("subcrate testing");
 
     fn host_to_target_path(path: String) -> PathBuf {
-        use std::ffi::{CStr, CString};
+        use std::ffi::{c_char, CStr, CString};
 
         let path = CString::new(path).unwrap();
         let mut out = Vec::with_capacity(1024);
@@ -16,8 +16,8 @@ fn main() {
         unsafe {
             extern "Rust" {
                 fn miri_host_to_target_path(
-                    path: *const i8,
-                    out: *mut i8,
+                    path: *const c_char,
+                    out: *mut c_char,
                     out_size: usize,
                 ) -> usize;
             }
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index a84ed859763..8be1ee54672 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -292,9 +292,9 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "1.23.1"
+version = "1.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8"
+checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb"
 dependencies = [
  "autocfg",
  "bytes",
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index f5ab6acf008..d1ff33379e4 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -18,6 +18,6 @@ rand = { version = "0.8", features = ["small_rng"] }
 
 [target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
 page_size = "0.5"
-tokio = { version = "1.23", features = ["full"] }
+tokio = { version = "1.24", features = ["full"] }
 
 [workspace]
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs
index 816b6ab9fb3..4a43db0aac5 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs
@@ -3,7 +3,7 @@
 
 #![allow(dead_code, unused_variables)]
 
-use std::{ptr, mem};
+use std::{mem, ptr};
 
 #[repr(packed)]
 struct Foo {
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs b/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
index ba5b269f652..cd071a7f32a 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
@@ -5,7 +5,7 @@
 #![feature(io_error_uncategorized)]
 
 use std::convert::TryInto;
-use std::ffi::{CStr, CString};
+use std::ffi::{c_char, CStr, CString};
 use std::fs::{canonicalize, remove_dir_all, remove_file, File};
 use std::io::{Error, ErrorKind, Write};
 use std::os::unix::ffi::OsStrExt;
@@ -31,7 +31,11 @@ fn tmp() -> PathBuf {
 
     unsafe {
         extern "Rust" {
-            fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+            fn miri_host_to_target_path(
+                path: *const c_char,
+                out: *mut c_char,
+                out_size: usize,
+            ) -> usize;
         }
         let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
         assert_eq!(ret, 0);
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
index 20e96a92c7c..98e1c3a0adb 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
@@ -7,7 +7,7 @@ use std::os::unix::io::AsRawFd;
 use std::path::PathBuf;
 
 fn tmp() -> PathBuf {
-    use std::ffi::{CStr, CString};
+    use std::ffi::{c_char, CStr, CString};
 
     let path = std::env::var("MIRI_TEMP")
         .unwrap_or_else(|_| std::env::temp_dir().into_os_string().into_string().unwrap());
@@ -17,7 +17,11 @@ fn tmp() -> PathBuf {
 
     unsafe {
         extern "Rust" {
-            fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+            fn miri_host_to_target_path(
+                path: *const c_char,
+                out: *mut c_char,
+                out_size: usize,
+            ) -> usize;
         }
         let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
         assert_eq!(ret, 0);
diff --git a/src/tools/miri/tests/pass-dep/tokio/sleep.rs b/src/tools/miri/tests/pass-dep/tokio/sleep.rs
new file mode 100644
index 00000000000..1341484dda4
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/tokio/sleep.rs
@@ -0,0 +1,14 @@
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance -Zmiri-backtrace=full
+//@only-target-x86_64-unknown-linux: support for tokio only on linux and x86
+
+use tokio::time::{sleep, Duration, Instant};
+
+#[tokio::main]
+async fn main() {
+    let start = Instant::now();
+    sleep(Duration::from_secs(1)).await;
+    // It takes 96 millisecond to sleep for 1 millisecond
+    // It takes 1025 millisecond to sleep for 1 second
+    let time_elapsed = &start.elapsed().as_millis();
+    assert!(time_elapsed > &1000, "{}", time_elapsed);
+}
diff --git a/src/tools/miri/tests/pass-dep/tokio_mvp.rs b/src/tools/miri/tests/pass-dep/tokio/tokio_mvp.rs
index 642168253c2..0bca7cc069a 100644
--- a/src/tools/miri/tests/pass-dep/tokio_mvp.rs
+++ b/src/tools/miri/tests/pass-dep/tokio/tokio_mvp.rs
@@ -1,5 +1,5 @@
 // Need to disable preemption to stay on the supported MVP codepath in mio.
-//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance
 //@only-target-x86_64-unknown-linux: support for tokio exists only on linux and x86
 
 #[tokio::main]
diff --git a/src/tools/miri/tests/pass/dyn-star.rs b/src/tools/miri/tests/pass/dyn-star.rs
index 16a8cec6cda..1fac16352a4 100644
--- a/src/tools/miri/tests/pass/dyn-star.rs
+++ b/src/tools/miri/tests/pass/dyn-star.rs
@@ -1,5 +1,8 @@
 #![feature(dyn_star)]
 #![allow(incomplete_features)]
+#![feature(custom_inner_attributes)]
+// rustfmt destroys `dyn* Trait` syntax
+#![rustfmt::skip]
 
 use std::fmt::{Debug, Display};
 
diff --git a/src/tools/miri/tests/pass/move-data-across-await-point.rs b/src/tools/miri/tests/pass/move-data-across-await-point.rs
new file mode 100644
index 00000000000..489fae66ffb
--- /dev/null
+++ b/src/tools/miri/tests/pass/move-data-across-await-point.rs
@@ -0,0 +1,81 @@
+use std::future::Future;
+use std::ptr;
+
+// This test:
+// - Compares addresses of non-Copy data before and after moving it
+// - Writes to the pointer after it has moved across the await point
+//
+// This is only meant to assert current behavior, not guarantee that this is
+// how it should work in the future. In fact, upcoming changes to rustc
+// *should* break these tests.
+// See: https://github.com/rust-lang/rust/issues/62958
+async fn data_moved_async() {
+    async fn helper(mut data: Vec<u8>, raw_pointer: *mut Vec<u8>) {
+        let raw_pointer2 = ptr::addr_of_mut!(data);
+        // `raw_pointer` points to the original location where the Vec was stored in the caller.
+        // `data` is where that Vec (to be precise, its ptr+capacity+len on-stack data)
+        // got moved to. Those will usually not be the same since the Vec got moved twice
+        // (into the function call, and then into the generator upvar).
+        assert_ne!(raw_pointer, raw_pointer2);
+        unsafe {
+            // This writes into the `x` in `data_moved_async`, re-initializing it.
+            std::ptr::write(raw_pointer, vec![3]);
+        }
+    }
+    // Vec<T> is not Copy
+    let mut x: Vec<u8> = vec![2];
+    let raw_pointer = ptr::addr_of_mut!(x);
+    helper(x, raw_pointer).await;
+    unsafe {
+        assert_eq!(*raw_pointer, vec![3]);
+        // Drop to prevent leak.
+        std::ptr::drop_in_place(raw_pointer);
+    }
+}
+
+// Same thing as above, but non-async.
+fn data_moved() {
+    fn helper(mut data: Vec<u8>, raw_pointer: *mut Vec<u8>) {
+        let raw_pointer2 = ptr::addr_of_mut!(data);
+        assert_ne!(raw_pointer, raw_pointer2);
+        unsafe {
+            std::ptr::write(raw_pointer, vec![3]);
+        }
+    }
+
+    let mut x: Vec<u8> = vec![2];
+    let raw_pointer = ptr::addr_of_mut!(x);
+    helper(x, raw_pointer);
+    unsafe {
+        assert_eq!(*raw_pointer, vec![3]);
+        std::ptr::drop_in_place(raw_pointer);
+    }
+}
+
+fn run_fut<T>(fut: impl Future<Output = T>) -> T {
+    use std::sync::Arc;
+    use std::task::{Context, Poll, Wake, Waker};
+
+    struct MyWaker;
+    impl Wake for MyWaker {
+        fn wake(self: Arc<Self>) {
+            unimplemented!()
+        }
+    }
+
+    let waker = Waker::from(Arc::new(MyWaker));
+    let mut context = Context::from_waker(&waker);
+
+    let mut pinned = Box::pin(fut);
+    loop {
+        match pinned.as_mut().poll(&mut context) {
+            Poll::Pending => continue,
+            Poll::Ready(v) => return v,
+        }
+    }
+}
+
+fn main() {
+    run_fut(data_moved_async());
+    data_moved();
+}
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index a7d4800faec..7a9974f3938 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -6,7 +6,7 @@
 #![feature(is_terminal)]
 
 use std::collections::HashMap;
-use std::ffi::OsString;
+use std::ffi::{c_char, OsString};
 use std::fs::{
     canonicalize, create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename,
     File, OpenOptions,
@@ -39,7 +39,11 @@ fn host_to_target_path(path: String) -> PathBuf {
 
     unsafe {
         extern "Rust" {
-            fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+            fn miri_host_to_target_path(
+                path: *const c_char,
+                out: *mut c_char,
+                out_size: usize,
+            ) -> usize;
         }
         let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
         assert_eq!(ret, 0);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index c82c274524a..f21b4f84c4c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -173,7 +173,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
 
             // let pointee = tcx.normalize_erasing_regions(param_env, pointee);
             // if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
-            //     return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
+            //     return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
             // }
 
             let unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index dd2fd1911f2..c60caa0d49c 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -31,7 +31,7 @@ const IGNORE_DOCTEST_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E06
 
 // Error codes that don't yet have a UI test. This list will eventually be removed.
 const IGNORE_UI_TEST_CHECK: &[&str] =
-    &["E0461", "E0465", "E0476", "E0514", "E0554", "E0640", "E0717", "E0729"];
+    &["E0461", "E0465", "E0514", "E0554", "E0640", "E0717", "E0729"];
 
 macro_rules! verbose_print {
     ($verbose:expr, $($fmt:tt)*) => {
@@ -45,7 +45,7 @@ pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut
     let mut errors = Vec::new();
 
     // Stage 1: create list
-    let error_codes = extract_error_codes(root_path, &mut errors, verbose);
+    let error_codes = extract_error_codes(root_path, &mut errors);
     println!("Found {} error codes", error_codes.len());
     println!("Highest error code: `{}`", error_codes.iter().max().unwrap());
 
@@ -65,18 +65,17 @@ pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut
 }
 
 /// Stage 1: Parses a list of error codes from `error_codes.rs`.
-fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>, verbose: bool) -> Vec<String> {
+fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String> {
     let path = root_path.join(Path::new(ERROR_CODES_PATH));
     let file =
         fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read `{path:?}`: {e}"));
 
     let mut error_codes = Vec::new();
-    let mut reached_undocumented_codes = false;
 
     for line in file.lines() {
         let line = line.trim();
 
-        if !reached_undocumented_codes && line.starts_with('E') {
+        if line.starts_with('E') {
             let split_line = line.split_once(':');
 
             // Extract the error code from the line, emitting a fatal error if it is not in a correct format.
@@ -111,23 +110,6 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>, verbose: bool
             }
 
             error_codes.push(err_code);
-        } else if reached_undocumented_codes && line.starts_with('E') {
-            let err_code = match line.split_once(',') {
-                None => line,
-                Some((err_code, _)) => err_code,
-            }
-            .to_string();
-
-            verbose_print!(verbose, "warning: Error code `{}` is undocumented.", err_code);
-
-            if error_codes.contains(&err_code) {
-                errors.push(format!("Found duplicate error code: `{}`", err_code));
-            }
-
-            error_codes.push(err_code);
-        } else if line == ";" {
-            // Once we reach the undocumented error codes, adapt to different syntax.
-            reached_undocumented_codes = true;
         }
     }
 
diff --git a/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.diff
new file mode 100644
index 00000000000..c4002d65e5d
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/enum.multiple.DataflowConstProp.diff
@@ -0,0 +1,82 @@
+- // MIR for `multiple` before DataflowConstProp
++ // MIR for `multiple` after DataflowConstProp
+  
+  fn multiple(_1: bool, _2: u8) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/enum.rs:+0:13: +0:14
+      debug i => _2;                       // in scope 0 at $DIR/enum.rs:+0:22: +0:23
+      let mut _0: ();                      // return place in scope 0 at $DIR/enum.rs:+0:29: +0:29
+      let _3: std::option::Option<u8>;     // in scope 0 at $DIR/enum.rs:+1:9: +1:10
+      let mut _4: bool;                    // in scope 0 at $DIR/enum.rs:+1:16: +1:17
+      let mut _5: u8;                      // in scope 0 at $DIR/enum.rs:+2:14: +2:15
+      let mut _7: isize;                   // in scope 0 at $DIR/enum.rs:+9:23: +9:30
+      scope 1 {
+          debug e => _3;                   // in scope 1 at $DIR/enum.rs:+1:9: +1:10
+          let _6: u8;                      // in scope 1 at $DIR/enum.rs:+9:9: +9:10
+          let _8: u8;                      // in scope 1 at $DIR/enum.rs:+9:28: +9:29
+          scope 2 {
+              debug x => _6;               // in scope 2 at $DIR/enum.rs:+9:9: +9:10
+              let _9: u8;                  // in scope 2 at $DIR/enum.rs:+11:9: +11:10
+              scope 4 {
+                  debug y => _9;           // in scope 4 at $DIR/enum.rs:+11:9: +11:10
+              }
+          }
+          scope 3 {
+              debug i => _8;               // in scope 3 at $DIR/enum.rs:+9:28: +9:29
+          }
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/enum.rs:+1:9: +1:10
+          StorageLive(_4);                 // scope 0 at $DIR/enum.rs:+1:16: +1:17
+          _4 = _1;                         // scope 0 at $DIR/enum.rs:+1:16: +1:17
+          switchInt(move _4) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/enum.rs:+1:16: +1:17
+      }
+  
+      bb1: {
+          StorageLive(_5);                 // scope 0 at $DIR/enum.rs:+2:14: +2:15
+          _5 = _2;                         // scope 0 at $DIR/enum.rs:+2:14: +2:15
+          _3 = Option::<u8>::Some(move _5); // scope 0 at $DIR/enum.rs:+2:9: +2:16
+          StorageDead(_5);                 // scope 0 at $DIR/enum.rs:+2:15: +2:16
+          goto -> bb3;                     // scope 0 at $DIR/enum.rs:+1:13: +5:6
+      }
+  
+      bb2: {
+          _3 = Option::<u8>::None;         // scope 0 at $DIR/enum.rs:+4:9: +4:13
+          goto -> bb3;                     // scope 0 at $DIR/enum.rs:+1:13: +5:6
+      }
+  
+      bb3: {
+          StorageDead(_4);                 // scope 0 at $DIR/enum.rs:+5:5: +5:6
+          StorageLive(_6);                 // scope 1 at $DIR/enum.rs:+9:9: +9:10
+          _7 = discriminant(_3);           // scope 1 at $DIR/enum.rs:+9:19: +9:20
+          switchInt(move _7) -> [0: bb4, 1: bb6, otherwise: bb5]; // scope 1 at $DIR/enum.rs:+9:13: +9:20
+      }
+  
+      bb4: {
+          _6 = const 0_u8;                 // scope 1 at $DIR/enum.rs:+9:45: +9:46
+          goto -> bb7;                     // scope 1 at $DIR/enum.rs:+9:45: +9:46
+      }
+  
+      bb5: {
+          unreachable;                     // scope 1 at $DIR/enum.rs:+9:19: +9:20
+      }
+  
+      bb6: {
+          StorageLive(_8);                 // scope 1 at $DIR/enum.rs:+9:28: +9:29
+          _8 = ((_3 as Some).0: u8);       // scope 1 at $DIR/enum.rs:+9:28: +9:29
+          _6 = _8;                         // scope 3 at $DIR/enum.rs:+9:34: +9:35
+          StorageDead(_8);                 // scope 1 at $DIR/enum.rs:+9:34: +9:35
+          goto -> bb7;                     // scope 1 at $DIR/enum.rs:+9:34: +9:35
+      }
+  
+      bb7: {
+          StorageLive(_9);                 // scope 2 at $DIR/enum.rs:+11:9: +11:10
+          _9 = _6;                         // scope 2 at $DIR/enum.rs:+11:13: +11:14
+          _0 = const ();                   // scope 0 at $DIR/enum.rs:+0:29: +12:2
+          StorageDead(_9);                 // scope 2 at $DIR/enum.rs:+12:1: +12:2
+          StorageDead(_6);                 // scope 1 at $DIR/enum.rs:+12:1: +12:2
+          StorageDead(_3);                 // scope 0 at $DIR/enum.rs:+12:1: +12:2
+          return;                          // scope 0 at $DIR/enum.rs:+12:2: +12:2
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/enum.rs b/tests/mir-opt/dataflow-const-prop/enum.rs
index 7ea405bd9c4..79a20d7ef45 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.rs
+++ b/tests/mir-opt/dataflow-const-prop/enum.rs
@@ -46,7 +46,23 @@ fn mutate_discriminant() -> u8 {
     )
 }
 
+// EMIT_MIR enum.multiple.DataflowConstProp.diff
+fn multiple(x: bool, i: u8) {
+    let e = if x {
+        Some(i)
+    } else {
+        None
+    };
+    // The dataflow state must have:
+    //   discriminant(e) => Top
+    //   (e as Some).0 => Top
+    let x = match e { Some(i) => i, None => 0 };
+    // Therefore, `x` should be `Top` here, and no replacement shall happen.
+    let y = x;
+}
+
 fn main() {
     simple();
     mutate_discriminant();
+    multiple(false, 5);
 }
diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.diff
index 1fb65e65845..22bdc35d694 100644
--- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.diff
@@ -45,8 +45,10 @@
   
       bb3: {
           StorageLive(_4);                 // scope 1 at $DIR/enum.rs:+2:29: +2:30
-          _4 = ((_1 as V1).0: i32);        // scope 1 at $DIR/enum.rs:+2:29: +2:30
-          _2 = _4;                         // scope 3 at $DIR/enum.rs:+2:35: +2:36
+-         _4 = ((_1 as V1).0: i32);        // scope 1 at $DIR/enum.rs:+2:29: +2:30
+-         _2 = _4;                         // scope 3 at $DIR/enum.rs:+2:35: +2:36
++         _4 = const 0_i32;                // scope 1 at $DIR/enum.rs:+2:29: +2:30
++         _2 = const 0_i32;                // scope 3 at $DIR/enum.rs:+2:35: +2:36
           StorageDead(_4);                 // scope 1 at $DIR/enum.rs:+2:35: +2:36
           goto -> bb4;                     // scope 1 at $DIR/enum.rs:+2:35: +2:36
       }
diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff b/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff
index e30a5e116ea..c7978ac328f 100644
--- a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff
+++ b/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff
@@ -4,14 +4,14 @@
   fn inlined_no_sanitize() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_compatibility.rs:+0:37: +0:37
       let _1: ();                          // in scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
-+     scope 1 (inlined no_sanitize) {      // at $DIR/inline_compatibility.rs:24:5: 24:18
++     scope 1 (inlined no_sanitize) {      // at $DIR/inline_compatibility.rs:23:5: 23:18
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
 -         _1 = no_sanitize() -> bb1;       // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
 -                                          // mir::Constant
--                                          // + span: $DIR/inline_compatibility.rs:24:5: 24:16
+-                                          // + span: $DIR/inline_compatibility.rs:23:5: 23:16
 -                                          // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) }
 -     }
 - 
diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff b/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff
index c2b3c46a30c..2fe277ae37b 100644
--- a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff
+++ b/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff
@@ -4,14 +4,14 @@
   fn inlined_target_feature() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_compatibility.rs:+0:40: +0:40
       let _1: ();                          // in scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
-+     scope 1 (inlined target_feature) {   // at $DIR/inline_compatibility.rs:13:5: 13:21
++     scope 1 (inlined target_feature) {   // at $DIR/inline_compatibility.rs:12:5: 12:21
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
 -         _1 = target_feature() -> bb1;    // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
 -                                          // mir::Constant
--                                          // + span: $DIR/inline_compatibility.rs:13:5: 13:19
+-                                          // + span: $DIR/inline_compatibility.rs:12:5: 12:19
 -                                          // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) }
 -     }
 - 
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff
index 0ca5a5f70b7..9803ca0f8a4 100644
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff
+++ b/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff
@@ -12,7 +12,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/inline_compatibility.rs:+1:9: +1:10
           _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:13: +1:52
                                            // mir::Constant
-                                           // + span: $DIR/inline_compatibility.rs:42:13: 42:16
+                                           // + span: $DIR/inline_compatibility.rs:41:13: 41:16
                                            // + literal: Const { ty: unsafe extern "C" fn(u32, ...) -> u32 {sum}, val: Value(<ZST>) }
       }
   
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff
index 00d405c77f9..356ab4b51c2 100644
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff
+++ b/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff
@@ -9,7 +9,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
           _1 = no_sanitize() -> bb1;       // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
                                            // mir::Constant
-                                           // + span: $DIR/inline_compatibility.rs:29:5: 29:16
+                                           // + span: $DIR/inline_compatibility.rs:28:5: 28:16
                                            // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) }
       }
   
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff
index 8b9c86f5515..f0fee4ca98a 100644
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff
+++ b/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff
@@ -9,7 +9,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
           _1 = target_feature() -> bb1;    // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
                                            // mir::Constant
-                                           // + span: $DIR/inline_compatibility.rs:18:5: 18:19
+                                           // + span: $DIR/inline_compatibility.rs:17:5: 17:19
                                            // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) }
       }
   
diff --git a/tests/mir-opt/inline/inline_compatibility.rs b/tests/mir-opt/inline/inline_compatibility.rs
index 30aff0a64ef..ec6ce3d0258 100644
--- a/tests/mir-opt/inline/inline_compatibility.rs
+++ b/tests/mir-opt/inline/inline_compatibility.rs
@@ -4,7 +4,6 @@
 
 #![crate_type = "lib"]
 #![feature(no_sanitize)]
-#![feature(target_feature_11)]
 #![feature(c_variadic)]
 
 // EMIT_MIR inline_compatibility.inlined_target_feature.Inline.diff
diff --git a/tests/mir-opt/issue_41110.main.ElaborateDrops.after.mir b/tests/mir-opt/issue_41110.main.ElaborateDrops.after.mir
deleted file mode 100644
index c2ea3ac502f..00000000000
--- a/tests/mir-opt/issue_41110.main.ElaborateDrops.after.mir
+++ /dev/null
@@ -1,70 +0,0 @@
-// MIR for `main` after ElaborateDrops
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/issue_41110.rs:+0:11: +0:11
-    let _1: ();                          // in scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
-    let mut _2: S;                       // in scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
-    let mut _3: S;                       // in scope 0 at $DIR/issue_41110.rs:+1:21: +1:27
-    let mut _4: S;                       // in scope 0 at $DIR/issue_41110.rs:+1:21: +1:22
-    let mut _5: bool;                    // in scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
-    scope 1 {
-        debug x => _1;                   // in scope 1 at $DIR/issue_41110.rs:+1:9: +1:10
-    }
-
-    bb0: {
-        _5 = const false;                // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
-        StorageLive(_1);                 // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
-        StorageLive(_2);                 // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
-        _5 = const true;                 // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
-        _2 = S;                          // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
-        StorageLive(_3);                 // scope 0 at $DIR/issue_41110.rs:+1:21: +1:27
-        StorageLive(_4);                 // scope 0 at $DIR/issue_41110.rs:+1:21: +1:22
-        _4 = S;                          // scope 0 at $DIR/issue_41110.rs:+1:21: +1:22
-        _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue_41110.rs:+1:21: +1:27
-                                         // mir::Constant
-                                         // + span: $DIR/issue_41110.rs:8:23: 8:25
-                                         // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        StorageDead(_4);                 // scope 0 at $DIR/issue_41110.rs:+1:26: +1:27
-        _5 = const false;                // scope 0 at $DIR/issue_41110.rs:+1:13: +1:28
-        _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue_41110.rs:+1:13: +1:28
-                                         // mir::Constant
-                                         // + span: $DIR/issue_41110.rs:8:15: 8:20
-                                         // + literal: Const { ty: fn(S, S) {S::other}, val: Value(<ZST>) }
-    }
-
-    bb2: {
-        StorageDead(_3);                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
-        _5 = const false;                // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
-        StorageDead(_2);                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
-        _0 = const ();                   // scope 0 at $DIR/issue_41110.rs:+0:11: +2:2
-        StorageDead(_1);                 // scope 0 at $DIR/issue_41110.rs:+2:1: +2:2
-        return;                          // scope 0 at $DIR/issue_41110.rs:+2:2: +2:2
-    }
-
-    bb3 (cleanup): {
-        goto -> bb5;                     // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
-    }
-
-    bb4 (cleanup): {
-        goto -> bb5;                     // scope 0 at $DIR/issue_41110.rs:+1:26: +1:27
-    }
-
-    bb5 (cleanup): {
-        goto -> bb8;                     // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
-    }
-
-    bb6 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue_41110.rs:+0:1: +2:2
-    }
-
-    bb7 (cleanup): {
-        drop(_2) -> bb6;                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
-    }
-
-    bb8 (cleanup): {
-        switchInt(_5) -> [0: bb6, otherwise: bb7]; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
-    }
-}
diff --git a/tests/mir-opt/issue_41110.main.ElaborateDrops.diff b/tests/mir-opt/issue_41110.main.ElaborateDrops.diff
new file mode 100644
index 00000000000..7ac75b51a37
--- /dev/null
+++ b/tests/mir-opt/issue_41110.main.ElaborateDrops.diff
@@ -0,0 +1,75 @@
+- // MIR for `main` before ElaborateDrops
++ // MIR for `main` after ElaborateDrops
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue_41110.rs:+0:11: +0:11
+      let _1: ();                          // in scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+      let mut _2: S;                       // in scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+      let mut _3: S;                       // in scope 0 at $DIR/issue_41110.rs:+1:21: +1:27
+      let mut _4: S;                       // in scope 0 at $DIR/issue_41110.rs:+1:21: +1:22
++     let mut _5: bool;                    // in scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/issue_41110.rs:+1:9: +1:10
+      }
+  
+      bb0: {
++         _5 = const false;                // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+          StorageLive(_1);                 // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+          StorageLive(_2);                 // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
++         _5 = const true;                 // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+          _2 = S;                          // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+          StorageLive(_3);                 // scope 0 at $DIR/issue_41110.rs:+1:21: +1:27
+          StorageLive(_4);                 // scope 0 at $DIR/issue_41110.rs:+1:21: +1:22
+          _4 = S;                          // scope 0 at $DIR/issue_41110.rs:+1:21: +1:22
+          _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue_41110.rs:+1:21: +1:27
+                                           // mir::Constant
+                                           // + span: $DIR/issue_41110.rs:8:23: 8:25
+                                           // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_4);                 // scope 0 at $DIR/issue_41110.rs:+1:26: +1:27
++         _5 = const false;                // scope 0 at $DIR/issue_41110.rs:+1:13: +1:28
+          _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue_41110.rs:+1:13: +1:28
+                                           // mir::Constant
+                                           // + span: $DIR/issue_41110.rs:8:15: 8:20
+                                           // + literal: Const { ty: fn(S, S) {S::other}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          StorageDead(_3);                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
++         _5 = const false;                // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+          StorageDead(_2);                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+          _0 = const ();                   // scope 0 at $DIR/issue_41110.rs:+0:11: +2:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue_41110.rs:+2:1: +2:2
+          return;                          // scope 0 at $DIR/issue_41110.rs:+2:2: +2:2
+      }
+  
+      bb3 (cleanup): {
+-         drop(_3) -> bb5;                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
++         goto -> bb5;                     // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+      }
+  
+      bb4 (cleanup): {
+-         drop(_4) -> bb5;                 // scope 0 at $DIR/issue_41110.rs:+1:26: +1:27
++         goto -> bb5;                     // scope 0 at $DIR/issue_41110.rs:+1:26: +1:27
+      }
+  
+      bb5 (cleanup): {
+-         drop(_2) -> bb6;                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
++         goto -> bb8;                     // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+      }
+  
+      bb6 (cleanup): {
+          resume;                          // scope 0 at $DIR/issue_41110.rs:+0:1: +2:2
++     }
++ 
++     bb7 (cleanup): {
++         drop(_2) -> bb6;                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
++     }
++ 
++     bb8 (cleanup): {
++         switchInt(_5) -> [0: bb6, otherwise: bb7]; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+      }
+  }
+  
diff --git a/tests/mir-opt/issue_41110.rs b/tests/mir-opt/issue_41110.rs
index 638dc601ec8..e1067ce53e4 100644
--- a/tests/mir-opt/issue_41110.rs
+++ b/tests/mir-opt/issue_41110.rs
@@ -3,14 +3,14 @@
 // check that we don't emit multiple drop flags when they are not needed.
 
 
-// EMIT_MIR issue_41110.main.ElaborateDrops.after.mir
+// EMIT_MIR issue_41110.main.ElaborateDrops.diff
 fn main() {
     let x = S.other(S.id());
 }
 
 // no_mangle to make sure this gets instantiated even in an executable.
 #[no_mangle]
-// EMIT_MIR issue_41110.test.ElaborateDrops.after.mir
+// EMIT_MIR issue_41110.test.ElaborateDrops.diff
 pub fn test() {
     let u = S;
     let mut v = S;
diff --git a/tests/mir-opt/issue_41110.test.ElaborateDrops.after.mir b/tests/mir-opt/issue_41110.test.ElaborateDrops.after.mir
deleted file mode 100644
index 82989c3f071..00000000000
--- a/tests/mir-opt/issue_41110.test.ElaborateDrops.after.mir
+++ /dev/null
@@ -1,101 +0,0 @@
-// MIR for `test` after ElaborateDrops
-
-fn test() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/issue_41110.rs:+0:15: +0:15
-    let _1: S;                           // in scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
-    let _3: ();                          // in scope 0 at $DIR/issue_41110.rs:+3:5: +3:12
-    let mut _4: S;                       // in scope 0 at $DIR/issue_41110.rs:+3:10: +3:11
-    let mut _5: S;                       // in scope 0 at $DIR/issue_41110.rs:+4:9: +4:10
-    let mut _6: bool;                    // in scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
-    scope 1 {
-        debug u => _1;                   // in scope 1 at $DIR/issue_41110.rs:+1:9: +1:10
-        let mut _2: S;                   // in scope 1 at $DIR/issue_41110.rs:+2:9: +2:14
-        scope 2 {
-            debug v => _2;               // in scope 2 at $DIR/issue_41110.rs:+2:9: +2:14
-        }
-    }
-
-    bb0: {
-        _6 = const false;                // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
-        StorageLive(_1);                 // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
-        _6 = const true;                 // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
-        _1 = S;                          // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
-        StorageLive(_2);                 // scope 1 at $DIR/issue_41110.rs:+2:9: +2:14
-        _2 = S;                          // scope 1 at $DIR/issue_41110.rs:+2:17: +2:18
-        StorageLive(_3);                 // scope 2 at $DIR/issue_41110.rs:+3:5: +3:12
-        StorageLive(_4);                 // scope 2 at $DIR/issue_41110.rs:+3:10: +3:11
-        _4 = move _2;                    // scope 2 at $DIR/issue_41110.rs:+3:10: +3:11
-        _3 = std::mem::drop::<S>(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue_41110.rs:+3:5: +3:12
-                                         // mir::Constant
-                                         // + span: $DIR/issue_41110.rs:17:5: 17:9
-                                         // + literal: Const { ty: fn(S) {std::mem::drop::<S>}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        StorageDead(_4);                 // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
-        StorageDead(_3);                 // scope 2 at $DIR/issue_41110.rs:+3:12: +3:13
-        StorageLive(_5);                 // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
-        _6 = const false;                // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
-        _5 = move _1;                    // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
-        goto -> bb12;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-    }
-
-    bb2: {
-        goto -> bb3;                     // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
-    }
-
-    bb3: {
-        StorageDead(_5);                 // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
-        _0 = const ();                   // scope 0 at $DIR/issue_41110.rs:+0:15: +5:2
-        drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
-    }
-
-    bb4: {
-        StorageDead(_2);                 // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
-        goto -> bb5;                     // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
-    }
-
-    bb5: {
-        _6 = const false;                // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
-        StorageDead(_1);                 // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
-        return;                          // scope 0 at $DIR/issue_41110.rs:+5:2: +5:2
-    }
-
-    bb6 (cleanup): {
-        goto -> bb8;                     // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
-    }
-
-    bb7 (cleanup): {
-        goto -> bb8;                     // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
-    }
-
-    bb8 (cleanup): {
-        goto -> bb9;                     // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
-    }
-
-    bb9 (cleanup): {
-        goto -> bb14;                    // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
-    }
-
-    bb10 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue_41110.rs:+0:1: +5:2
-    }
-
-    bb11 (cleanup): {
-        _2 = move _5;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-        goto -> bb6;                     // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-    }
-
-    bb12: {
-        _2 = move _5;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-        goto -> bb2;                     // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-    }
-
-    bb13 (cleanup): {
-        drop(_1) -> bb10;                // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
-    }
-
-    bb14 (cleanup): {
-        switchInt(_6) -> [0: bb10, otherwise: bb13]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
-    }
-}
diff --git a/tests/mir-opt/issue_41110.test.ElaborateDrops.diff b/tests/mir-opt/issue_41110.test.ElaborateDrops.diff
new file mode 100644
index 00000000000..79e3d073be5
--- /dev/null
+++ b/tests/mir-opt/issue_41110.test.ElaborateDrops.diff
@@ -0,0 +1,109 @@
+- // MIR for `test` before ElaborateDrops
++ // MIR for `test` after ElaborateDrops
+  
+  fn test() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue_41110.rs:+0:15: +0:15
+      let _1: S;                           // in scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+      let _3: ();                          // in scope 0 at $DIR/issue_41110.rs:+3:5: +3:12
+      let mut _4: S;                       // in scope 0 at $DIR/issue_41110.rs:+3:10: +3:11
+      let mut _5: S;                       // in scope 0 at $DIR/issue_41110.rs:+4:9: +4:10
++     let mut _6: bool;                    // in scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+      scope 1 {
+          debug u => _1;                   // in scope 1 at $DIR/issue_41110.rs:+1:9: +1:10
+          let mut _2: S;                   // in scope 1 at $DIR/issue_41110.rs:+2:9: +2:14
+          scope 2 {
+              debug v => _2;               // in scope 2 at $DIR/issue_41110.rs:+2:9: +2:14
+          }
+      }
+  
+      bb0: {
++         _6 = const false;                // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+          StorageLive(_1);                 // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
++         _6 = const true;                 // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+          _1 = S;                          // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+          StorageLive(_2);                 // scope 1 at $DIR/issue_41110.rs:+2:9: +2:14
+          _2 = S;                          // scope 1 at $DIR/issue_41110.rs:+2:17: +2:18
+          StorageLive(_3);                 // scope 2 at $DIR/issue_41110.rs:+3:5: +3:12
+          StorageLive(_4);                 // scope 2 at $DIR/issue_41110.rs:+3:10: +3:11
+          _4 = move _2;                    // scope 2 at $DIR/issue_41110.rs:+3:10: +3:11
+          _3 = std::mem::drop::<S>(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue_41110.rs:+3:5: +3:12
+                                           // mir::Constant
+                                           // + span: $DIR/issue_41110.rs:17:5: 17:9
+                                           // + literal: Const { ty: fn(S) {std::mem::drop::<S>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_4);                 // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
+          StorageDead(_3);                 // scope 2 at $DIR/issue_41110.rs:+3:12: +3:13
+          StorageLive(_5);                 // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
++         _6 = const false;                // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+          _5 = move _1;                    // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+-         replace(_2 <- move _5) -> [return: bb2, unwind: bb6]; // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
++         goto -> bb12;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
+      }
+  
+      bb2: {
+-         drop(_5) -> [return: bb3, unwind: bb8]; // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
++         goto -> bb3;                     // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+      }
+  
+      bb3: {
+          StorageDead(_5);                 // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+          _0 = const ();                   // scope 0 at $DIR/issue_41110.rs:+0:15: +5:2
+          drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
+      }
+  
+      bb4: {
+          StorageDead(_2);                 // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
+-         drop(_1) -> bb5;                 // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
++         goto -> bb5;                     // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+      }
+  
+      bb5: {
++         _6 = const false;                // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+          return;                          // scope 0 at $DIR/issue_41110.rs:+5:2: +5:2
+      }
+  
+      bb6 (cleanup): {
+          drop(_5) -> bb8;                 // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+      }
+  
+      bb7 (cleanup): {
+-         drop(_4) -> bb8;                 // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
++         goto -> bb8;                     // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
+      }
+  
+      bb8 (cleanup): {
+-         drop(_2) -> bb9;                 // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
++         goto -> bb9;                     // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
+      }
+  
+      bb9 (cleanup): {
+-         drop(_1) -> bb10;                // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
++         goto -> bb14;                    // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+      }
+  
+      bb10 (cleanup): {
+          resume;                          // scope 0 at $DIR/issue_41110.rs:+0:1: +5:2
++     }
++ 
++     bb11 (cleanup): {
++         _2 = move _5;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
++         goto -> bb10;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
++     }
++ 
++     bb12: {
++         _2 = move _5;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
++         goto -> bb2;                     // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
++     }
++ 
++     bb13 (cleanup): {
++         drop(_1) -> bb10;                // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
++     }
++ 
++     bb14 (cleanup): {
++         switchInt(_6) -> [0: bb10, otherwise: bb13]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+      }
+  }
+  
diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.after.mir b/tests/mir-opt/issue_41888.main.ElaborateDrops.after.mir
deleted file mode 100644
index 00504273245..00000000000
--- a/tests/mir-opt/issue_41888.main.ElaborateDrops.after.mir
+++ /dev/null
@@ -1,152 +0,0 @@
-// MIR for `main` after ElaborateDrops
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/issue_41888.rs:+0:11: +0:11
-    let _1: E;                           // in scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
-    let mut _2: bool;                    // in scope 0 at $DIR/issue_41888.rs:+2:8: +2:14
-    let mut _3: E;                       // in scope 0 at $DIR/issue_41888.rs:+3:13: +3:20
-    let mut _4: K;                       // in scope 0 at $DIR/issue_41888.rs:+3:18: +3:19
-    let mut _5: isize;                   // in scope 0 at $DIR/issue_41888.rs:+4:16: +4:24
-    let mut _7: bool;                    // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    let mut _8: bool;                    // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    let mut _9: bool;                    // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    let mut _10: isize;                  // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    let mut _11: isize;                  // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    scope 1 {
-        debug e => _1;                   // in scope 1 at $DIR/issue_41888.rs:+1:9: +1:10
-        scope 2 {
-            debug _k => _6;              // in scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
-            let _6: K;                   // in scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
-        }
-    }
-
-    bb0: {
-        _9 = const false;                // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
-        _7 = const false;                // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
-        _8 = const false;                // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
-        StorageLive(_1);                 // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
-        StorageLive(_2);                 // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
-        _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
-                                         // mir::Constant
-                                         // + span: $DIR/issue_41888.rs:8:8: 8:12
-                                         // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        switchInt(move _2) -> [0: bb7, otherwise: bb2]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
-    }
-
-    bb2: {
-        StorageLive(_3);                 // scope 1 at $DIR/issue_41888.rs:+3:13: +3:20
-        StorageLive(_4);                 // scope 1 at $DIR/issue_41888.rs:+3:18: +3:19
-        _4 = K;                          // scope 1 at $DIR/issue_41888.rs:+3:18: +3:19
-        _3 = E::F(move _4);              // scope 1 at $DIR/issue_41888.rs:+3:13: +3:20
-        StorageDead(_4);                 // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
-        goto -> bb14;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-    }
-
-    bb3: {
-        goto -> bb4;                     // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
-    }
-
-    bb4: {
-        StorageDead(_3);                 // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
-        _5 = discriminant(_1);           // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
-        switchInt(move _5) -> [0: bb5, otherwise: bb6]; // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
-    }
-
-    bb5: {
-        StorageLive(_6);                 // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
-        _9 = const false;                // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
-        _6 = move ((_1 as F).0: K);      // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
-        _0 = const ();                   // scope 2 at $DIR/issue_41888.rs:+4:29: +7:10
-        StorageDead(_6);                 // scope 1 at $DIR/issue_41888.rs:+7:9: +7:10
-        goto -> bb8;                     // scope 1 at $DIR/issue_41888.rs:+4:9: +7:10
-    }
-
-    bb6: {
-        _0 = const ();                   // scope 1 at $DIR/issue_41888.rs:+7:10: +7:10
-        goto -> bb8;                     // scope 1 at $DIR/issue_41888.rs:+4:9: +7:10
-    }
-
-    bb7: {
-        _0 = const ();                   // scope 1 at $DIR/issue_41888.rs:+8:6: +8:6
-        goto -> bb8;                     // scope 1 at $DIR/issue_41888.rs:+2:5: +8:6
-    }
-
-    bb8: {
-        StorageDead(_2);                 // scope 1 at $DIR/issue_41888.rs:+8:5: +8:6
-        goto -> bb20;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    }
-
-    bb9: {
-        _7 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-        _8 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-        _9 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-        StorageDead(_1);                 // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-        return;                          // scope 0 at $DIR/issue_41888.rs:+9:2: +9:2
-    }
-
-    bb10 (cleanup): {
-        goto -> bb11;                    // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
-    }
-
-    bb11 (cleanup): {
-        goto -> bb12;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    }
-
-    bb12 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue_41888.rs:+0:1: +9:2
-    }
-
-    bb13 (cleanup): {
-        _7 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-        _8 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-        _9 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-        _1 = move _3;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-        goto -> bb10;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-    }
-
-    bb14: {
-        _7 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-        _8 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-        _9 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-        _1 = move _3;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-        goto -> bb3;                     // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-    }
-
-    bb15: {
-        _7 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-        goto -> bb9;                     // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    }
-
-    bb16 (cleanup): {
-        goto -> bb12;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    }
-
-    bb17: {
-        drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    }
-
-    bb18 (cleanup): {
-        drop(_1) -> bb12;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    }
-
-    bb19: {
-        _10 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-        switchInt(move _10) -> [0: bb15, otherwise: bb17]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    }
-
-    bb20: {
-        switchInt(_7) -> [0: bb15, otherwise: bb19]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    }
-
-    bb21 (cleanup): {
-        _11 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-        switchInt(move _11) -> [0: bb16, otherwise: bb18]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    }
-
-    bb22 (cleanup): {
-        switchInt(_7) -> [0: bb12, otherwise: bb21]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-    }
-}
diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
new file mode 100644
index 00000000000..257f0b1e6e8
--- /dev/null
+++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
@@ -0,0 +1,158 @@
+- // MIR for `main` before ElaborateDrops
++ // MIR for `main` after ElaborateDrops
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue_41888.rs:+0:11: +0:11
+      let _1: E;                           // in scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
+      let mut _2: bool;                    // in scope 0 at $DIR/issue_41888.rs:+2:8: +2:14
+      let mut _3: E;                       // in scope 0 at $DIR/issue_41888.rs:+3:13: +3:20
+      let mut _4: K;                       // in scope 0 at $DIR/issue_41888.rs:+3:18: +3:19
+      let mut _5: isize;                   // in scope 0 at $DIR/issue_41888.rs:+4:16: +4:24
++     let mut _7: bool;                    // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     let mut _8: bool;                    // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     let mut _9: bool;                    // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     let mut _10: isize;                  // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     let mut _11: isize;                  // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+      scope 1 {
+          debug e => _1;                   // in scope 1 at $DIR/issue_41888.rs:+1:9: +1:10
+          scope 2 {
+              debug _k => _6;              // in scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
+              let _6: K;                   // in scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
+          }
+      }
+  
+      bb0: {
++         _9 = const false;                // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
++         _7 = const false;                // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
++         _8 = const false;                // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
+          StorageLive(_1);                 // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
+          StorageLive(_2);                 // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
+          _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
+                                           // mir::Constant
+                                           // + span: $DIR/issue_41888.rs:8:8: 8:12
+                                           // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          switchInt(move _2) -> [0: bb7, otherwise: bb2]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
+      }
+  
+      bb2: {
+          StorageLive(_3);                 // scope 1 at $DIR/issue_41888.rs:+3:13: +3:20
+          StorageLive(_4);                 // scope 1 at $DIR/issue_41888.rs:+3:18: +3:19
+          _4 = K;                          // scope 1 at $DIR/issue_41888.rs:+3:18: +3:19
+          _3 = E::F(move _4);              // scope 1 at $DIR/issue_41888.rs:+3:13: +3:20
+          StorageDead(_4);                 // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
+-         replace(_1 <- move _3) -> [return: bb3, unwind: bb10]; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         goto -> bb14;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+      }
+  
+      bb3: {
+-         drop(_3) -> [return: bb4, unwind: bb11]; // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
++         goto -> bb4;                     // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
+      }
+  
+      bb4: {
+          StorageDead(_3);                 // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
+          _5 = discriminant(_1);           // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
+          switchInt(move _5) -> [0: bb5, otherwise: bb6]; // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
+      }
+  
+      bb5: {
+          StorageLive(_6);                 // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
++         _9 = const false;                // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
+          _6 = move ((_1 as F).0: K);      // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
+          _0 = const ();                   // scope 2 at $DIR/issue_41888.rs:+4:29: +7:10
+          StorageDead(_6);                 // scope 1 at $DIR/issue_41888.rs:+7:9: +7:10
+          goto -> bb8;                     // scope 1 at $DIR/issue_41888.rs:+4:9: +7:10
+      }
+  
+      bb6: {
+          _0 = const ();                   // scope 1 at $DIR/issue_41888.rs:+7:10: +7:10
+          goto -> bb8;                     // scope 1 at $DIR/issue_41888.rs:+4:9: +7:10
+      }
+  
+      bb7: {
+          _0 = const ();                   // scope 1 at $DIR/issue_41888.rs:+8:6: +8:6
+          goto -> bb8;                     // scope 1 at $DIR/issue_41888.rs:+2:5: +8:6
+      }
+  
+      bb8: {
+          StorageDead(_2);                 // scope 1 at $DIR/issue_41888.rs:+8:5: +8:6
+-         drop(_1) -> bb9;                 // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         goto -> bb20;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+      }
+  
+      bb9: {
++         _7 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         _8 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         _9 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+          return;                          // scope 0 at $DIR/issue_41888.rs:+9:2: +9:2
+      }
+  
+      bb10 (cleanup): {
+          drop(_3) -> bb11;                // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
+      }
+  
+      bb11 (cleanup): {
+-         drop(_1) -> bb12;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         goto -> bb12;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+      }
+  
+      bb12 (cleanup): {
+          resume;                          // scope 0 at $DIR/issue_41888.rs:+0:1: +9:2
++     }
++ 
++     bb13 (cleanup): {
++         _7 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         _8 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         _9 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         _1 = move _3;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         goto -> bb12;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++     }
++ 
++     bb14: {
++         _7 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         _8 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         _9 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         _1 = move _3;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         goto -> bb3;                     // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++     }
++ 
++     bb15: {
++         _7 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         goto -> bb9;                     // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     }
++ 
++     bb16 (cleanup): {
++         goto -> bb12;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     }
++ 
++     bb17: {
++         drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     }
++ 
++     bb18 (cleanup): {
++         drop(_1) -> bb12;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     }
++ 
++     bb19: {
++         _10 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         switchInt(move _10) -> [0: bb15, otherwise: bb17]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     }
++ 
++     bb20: {
++         switchInt(_7) -> [0: bb15, otherwise: bb19]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     }
++ 
++     bb21 (cleanup): {
++         _11 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         switchInt(move _11) -> [0: bb16, otherwise: bb18]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     }
++ 
++     bb22 (cleanup): {
++         switchInt(_7) -> [0: bb12, otherwise: bb21]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+      }
+  }
+  
diff --git a/tests/mir-opt/issue_41888.rs b/tests/mir-opt/issue_41888.rs
index c1046c14dbf..0f10c0a1d09 100644
--- a/tests/mir-opt/issue_41888.rs
+++ b/tests/mir-opt/issue_41888.rs
@@ -2,7 +2,7 @@
 // check that we clear the "ADT master drop flag" even when there are
 // no fields to be dropped.
 
-// EMIT_MIR issue_41888.main.ElaborateDrops.after.mir
+// EMIT_MIR issue_41888.main.ElaborateDrops.diff
 fn main() {
     let e;
     if cond() {
diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml
index 5f4c1ba2f85..6e2321a6963 100644
--- a/tests/rustdoc-gui/help-page.goml
+++ b/tests/rustdoc-gui/help-page.goml
@@ -68,5 +68,4 @@ size: (1000, 1000) // Popover only appears when the screen width is >700px.
 assert-false: "#help"
 click: "#help-button > a"
 click: ".popover a[href='https://doc.rust-lang.org/rustdoc/']"
-wait-for: 2000
-assert-document-property: {"URL": "https://doc.rust-lang.org/rustdoc/"}
+wait-for-document-property: {"URL": "https://doc.rust-lang.org/rustdoc/"}
diff --git a/tests/rustdoc-ui/auxiliary/panic-handler.rs b/tests/rustdoc-ui/auxiliary/panic-handler.rs
new file mode 100644
index 00000000000..0aaaeee1051
--- /dev/null
+++ b/tests/rustdoc-ui/auxiliary/panic-handler.rs
@@ -0,0 +1,9 @@
+// compile-flags: -C panic=abort
+
+#![no_std]
+#![no_main]
+
+#[panic_handler]
+fn panic(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/tests/rustdoc-ui/issue-107918.rs b/tests/rustdoc-ui/issue-107918.rs
new file mode 100644
index 00000000000..13788df0fc9
--- /dev/null
+++ b/tests/rustdoc-ui/issue-107918.rs
@@ -0,0 +1,12 @@
+// aux-build:panic-handler.rs
+// compile-flags: --document-private-items
+// build-pass
+// ignore-windows
+
+#![no_std]
+#![no_main]
+
+#[panic_handler]
+fn panic(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/tests/rustdoc-ui/proc_macro_bug.rs b/tests/rustdoc-ui/proc_macro_bug.rs
new file mode 100644
index 00000000000..e384e4863ad
--- /dev/null
+++ b/tests/rustdoc-ui/proc_macro_bug.rs
@@ -0,0 +1,12 @@
+// regression test for failing to pass `--crate-type proc-macro` to rustdoc
+// when documenting a proc macro crate https://github.com/rust-lang/rust/pull/107291
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(DeriveA)]
+//~^ ERROR the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
+pub fn a_derive(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/tests/rustdoc-ui/proc_macro_bug.stderr b/tests/rustdoc-ui/proc_macro_bug.stderr
new file mode 100644
index 00000000000..5b048097c49
--- /dev/null
+++ b/tests/rustdoc-ui/proc_macro_bug.stderr
@@ -0,0 +1,8 @@
+error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
+  --> $DIR/proc_macro_bug.rs:8:1
+   |
+LL | #[proc_macro_derive(DeriveA)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/rustdoc-ui/unable-fulfill-trait.stderr b/tests/rustdoc-ui/unable-fulfill-trait.stderr
index a16b5b6eb2f..72f35cb9224 100644
--- a/tests/rustdoc-ui/unable-fulfill-trait.stderr
+++ b/tests/rustdoc-ui/unable-fulfill-trait.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/unable-fulfill-trait.rs:4:17
    |
 LL |     field1: dyn Bar<'a, 'b,>,
diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout
index 58b2f92d150..6aa9785f44e 100644
--- a/tests/rustdoc-ui/z-help.stdout
+++ b/tests/rustdoc-ui/z-help.stdout
@@ -81,6 +81,7 @@
          Multiple options can be combined with commas.
     -Z                     keep-hygiene-data=val -- keep hygiene data after analysis (default: no)
     -Z                           layout-seed=val -- seed layout randomization
+    -Z                       link-directives=val -- honor #[link] directives in the compiled crate (default: yes)
     -Z                 link-native-libraries=val -- link native libraries in the linker invocation (default: yes)
     -Z                             link-only=val -- link the `.rlink` file generated by `-Z no-link` (default: no)
     -Z                          llvm-plugins=val -- a list LLVM plugins to enable (space separated)
diff --git a/tests/rustdoc/item-desc-list-at-start.item-table.html b/tests/rustdoc/item-desc-list-at-start.item-table.html
new file mode 100644
index 00000000000..72bde573cea
--- /dev/null
+++ b/tests/rustdoc/item-desc-list-at-start.item-table.html
@@ -0,0 +1 @@
+<ul class="item-table"><li><div class="item-name"><a class="constant" href="constant.MY_CONSTANT.html" title="constant item_desc_list_at_start::MY_CONSTANT">MY_CONSTANT</a></div><div class="desc docblock-short">Groups: <code>SamplePatternSGIS</code>, <code>SamplePatternEXT</code></div></li></ul>
\ No newline at end of file
diff --git a/tests/rustdoc/item-desc-list-at-start.rs b/tests/rustdoc/item-desc-list-at-start.rs
new file mode 100644
index 00000000000..d88c61d333e
--- /dev/null
+++ b/tests/rustdoc/item-desc-list-at-start.rs
@@ -0,0 +1,9 @@
+// @has item_desc_list_at_start/index.html
+// @count - '//ul[@class="item-table"]/li/div/li' 0
+// @count - '//ul[@class="item-table"]/li' 1
+// @snapshot item-table - '//ul[@class="item-table"]'
+
+// based on https://docs.rs/gl_constants/0.1.1/src/gl_constants/lib.rs.html#16
+
+/// * Groups: `SamplePatternSGIS`, `SamplePatternEXT`
+pub const MY_CONSTANT: usize = 0;
diff --git a/tests/rustdoc/reexports-of-same-name.rs b/tests/rustdoc/reexports-of-same-name.rs
new file mode 100644
index 00000000000..fe6f1b38ca6
--- /dev/null
+++ b/tests/rustdoc/reexports-of-same-name.rs
@@ -0,0 +1,26 @@
+// This test ensures that there are 4 imports as expected:
+// * 2 for `Foo`
+// * 2 for `Bar`
+
+#![crate_name = "foo"]
+
+// @has 'foo/index.html'
+
+pub mod nested {
+    /// Foo the struct
+    pub struct Foo {}
+
+    #[allow(non_snake_case)]
+    /// Foo the function
+    pub fn Foo() {}
+}
+
+// @count - '//*[@id="main-content"]//code' 'pub use nested::Foo;' 2
+// @has - '//*[@id="reexport.Foo"]//a[@href="nested/struct.Foo.html"]' 'Foo'
+// @has - '//*[@id="reexport.Foo-1"]//a[@href="nested/fn.Foo.html"]' 'Foo'
+pub use nested::Foo;
+
+// @count - '//*[@id="main-content"]//code' 'pub use Foo as Bar;' 2
+// @has - '//*[@id="reexport.Bar"]//a[@href="nested/struct.Foo.html"]' 'Foo'
+// @has - '//*[@id="reexport.Bar-1"]//a[@href="nested/fn.Foo.html"]' 'Foo'
+pub use Foo as Bar;
diff --git a/tests/ui-fulldeps/create-dir-all-bare.rs b/tests/ui-fulldeps/create-dir-all-bare.rs
deleted file mode 100644
index 4554680ec24..00000000000
--- a/tests/ui-fulldeps/create-dir-all-bare.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// run-pass
-
-use std::env;
-use std::fs;
-use std::path::PathBuf;
-
-fn main() {
-    let path = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap());
-    env::set_current_dir(&path).unwrap();
-    fs::create_dir_all("create-dir-all-bare").unwrap();
-}
diff --git a/tests/ui-fulldeps/rename-directory.rs b/tests/ui-fulldeps/rename-directory.rs
deleted file mode 100644
index 8fc340cb918..00000000000
--- a/tests/ui-fulldeps/rename-directory.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// run-pass
-
-#![allow(unused_must_use)]
-#![allow(unused_imports)]
-// This test can't be a unit test in std,
-// because it needs TempDir, which is in extra
-
-// ignore-cross-compile
-
-use std::env;
-use std::ffi::CString;
-use std::fs::{self, File};
-use std::path::PathBuf;
-
-fn rename_directory() {
-    let tmpdir = PathBuf::from(env::var_os("RUST_TEST_TMPDIR").unwrap());
-    let old_path = tmpdir.join("foo/bar/baz");
-    fs::create_dir_all(&old_path).unwrap();
-    let test_file = &old_path.join("temp.txt");
-
-    File::create(test_file).unwrap();
-
-    let new_path = tmpdir.join("quux/blat");
-    fs::create_dir_all(&new_path).unwrap();
-    fs::rename(&old_path, &new_path.join("newdir"));
-    assert!(new_path.join("newdir").is_dir());
-    assert!(new_path.join("newdir/temp.txt").exists());
-}
-
-pub fn main() { rename_directory() }
diff --git a/tests/ui-fulldeps/issue-15149.rs b/tests/ui-fulldeps/std/issue-15149.rs
index 064472f5785..064472f5785 100644
--- a/tests/ui-fulldeps/issue-15149.rs
+++ b/tests/ui-fulldeps/std/issue-15149.rs
diff --git a/tests/ui-fulldeps/issue-81357-unsound-file-methods.rs b/tests/ui-fulldeps/std/issue-81357-unsound-file-methods.rs
index fdf1150f8d2..fdf1150f8d2 100644
--- a/tests/ui-fulldeps/issue-81357-unsound-file-methods.rs
+++ b/tests/ui-fulldeps/std/issue-81357-unsound-file-methods.rs
diff --git a/tests/ui-fulldeps/stdio-from.rs b/tests/ui-fulldeps/std/stdio-from.rs
index fef9f27fcdf..fef9f27fcdf 100644
--- a/tests/ui-fulldeps/stdio-from.rs
+++ b/tests/ui-fulldeps/std/stdio-from.rs
diff --git a/tests/ui-fulldeps/switch-stdout.rs b/tests/ui-fulldeps/std/switch-stdout.rs
index e9501a80930..e9501a80930 100644
--- a/tests/ui-fulldeps/switch-stdout.rs
+++ b/tests/ui-fulldeps/std/switch-stdout.rs
diff --git a/tests/ui/argument-suggestions/issue-100154.stderr b/tests/ui/argument-suggestions/issue-100154.stderr
index 1499229c3ce..2504f616fb7 100644
--- a/tests/ui/argument-suggestions/issue-100154.stderr
+++ b/tests/ui/argument-suggestions/issue-100154.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this function takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-100154.rs:4:5
    |
 LL |     foo::<()>(());
diff --git a/tests/ui/asm/x86_64/issue-89875.rs b/tests/ui/asm/x86_64/issue-89875.rs
index 669fd7e7e46..e793690ddbe 100644
--- a/tests/ui/asm/x86_64/issue-89875.rs
+++ b/tests/ui/asm/x86_64/issue-89875.rs
@@ -2,8 +2,6 @@
 // needs-asm-support
 // only-x86_64
 
-#![feature(target_feature_11)]
-
 use std::arch::asm;
 
 #[target_feature(enable = "avx")]
diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr
index 08570d4a5d9..bbafc55dac3 100644
--- a/tests/ui/associated-consts/issue-105330.stderr
+++ b/tests/ui/associated-consts/issue-105330.stderr
@@ -33,7 +33,7 @@ LL | fn main<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[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl header
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl headers
   --> $DIR/issue-105330.rs:6:27
    |
 LL | impl TraitWAssocConst for impl Demo {
diff --git a/tests/ui/associated-type-bounds/bad-universal-in-dyn-in-where-clause.rs b/tests/ui/associated-type-bounds/bad-universal-in-dyn-in-where-clause.rs
new file mode 100644
index 00000000000..8cab1f66c27
--- /dev/null
+++ b/tests/ui/associated-type-bounds/bad-universal-in-dyn-in-where-clause.rs
@@ -0,0 +1,14 @@
+#![feature(associated_type_bounds)]
+
+trait B {
+    type AssocType;
+}
+
+fn f()
+where
+    dyn for<'j> B<AssocType: 'j>:,
+    //~^ ERROR associated type bounds are only allowed in where clauses and function signatures
+{
+}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/bad-universal-in-dyn-in-where-clause.stderr b/tests/ui/associated-type-bounds/bad-universal-in-dyn-in-where-clause.stderr
new file mode 100644
index 00000000000..6fa266d23d4
--- /dev/null
+++ b/tests/ui/associated-type-bounds/bad-universal-in-dyn-in-where-clause.stderr
@@ -0,0 +1,8 @@
+error: associated type bounds are only allowed in where clauses and function signatures, not in bounds
+  --> $DIR/bad-universal-in-dyn-in-where-clause.rs:9:19
+   |
+LL |     dyn for<'j> B<AssocType: 'j>:,
+   |                   ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/associated-type-bounds/bad-universal-in-impl-sig.rs b/tests/ui/associated-type-bounds/bad-universal-in-impl-sig.rs
new file mode 100644
index 00000000000..1d5d181efcc
--- /dev/null
+++ b/tests/ui/associated-type-bounds/bad-universal-in-impl-sig.rs
@@ -0,0 +1,13 @@
+#![feature(associated_type_bounds)]
+
+trait Trait {
+    type Item;
+}
+
+trait Trait2 {}
+
+// It's not possible to insert a universal `impl Trait` here!
+impl dyn Trait<Item: Trait2> {}
+//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/bad-universal-in-impl-sig.stderr b/tests/ui/associated-type-bounds/bad-universal-in-impl-sig.stderr
new file mode 100644
index 00000000000..8b66627d57f
--- /dev/null
+++ b/tests/ui/associated-type-bounds/bad-universal-in-impl-sig.stderr
@@ -0,0 +1,8 @@
+error: associated type bounds are only allowed in where clauses and function signatures, not in impl headers
+  --> $DIR/bad-universal-in-impl-sig.rs:10:16
+   |
+LL | impl dyn Trait<Item: Trait2> {}
+   |                ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/associated-type-bounds/inside-adt.rs b/tests/ui/associated-type-bounds/inside-adt.rs
index 8eb8c44bb42..057966941dc 100644
--- a/tests/ui/associated-type-bounds/inside-adt.rs
+++ b/tests/ui/associated-type-bounds/inside-adt.rs
@@ -3,28 +3,24 @@
 use std::mem::ManuallyDrop;
 
 struct S1 { f: dyn Iterator<Item: Copy> }
-//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
+//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
 struct S2 { f: Box<dyn Iterator<Item: Copy>> }
-//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
+//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
 struct S3 { f: dyn Iterator<Item: 'static> }
-//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
+//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
 
 enum E1 { V(dyn Iterator<Item: Copy>) }
-//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)`
+//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
 enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
-//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
+//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
 enum E3 { V(dyn Iterator<Item: 'static>) }
-//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized + 'static> + 'static)`
+//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
 
 union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> }
-//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)`
+//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
 union U2 { f: ManuallyDrop<Box<dyn Iterator<Item: Copy>>> }
-//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
+//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
 union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> }
-//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized + 'static> + 'static)`
+//~^ ERROR associated type bounds are only allowed in where clauses and function signatures
 
 fn main() {}
diff --git a/tests/ui/associated-type-bounds/inside-adt.stderr b/tests/ui/associated-type-bounds/inside-adt.stderr
index 1668b613b25..f848bd798ee 100644
--- a/tests/ui/associated-type-bounds/inside-adt.stderr
+++ b/tests/ui/associated-type-bounds/inside-adt.stderr
@@ -1,131 +1,56 @@
-error: associated type bounds are not allowed within structs, enums, or unions
+error: associated type bounds are only allowed in where clauses and function signatures, not in field types
   --> $DIR/inside-adt.rs:5:29
    |
 LL | struct S1 { f: dyn Iterator<Item: Copy> }
    |                             ^^^^^^^^^^
 
-error: associated type bounds are not allowed within structs, enums, or unions
+error: associated type bounds are only allowed in where clauses and function signatures, not in field types
   --> $DIR/inside-adt.rs:7:33
    |
 LL | struct S2 { f: Box<dyn Iterator<Item: Copy>> }
    |                                 ^^^^^^^^^^
 
-error: associated type bounds are not allowed within structs, enums, or unions
+error: associated type bounds are only allowed in where clauses and function signatures, not in field types
   --> $DIR/inside-adt.rs:9:29
    |
 LL | struct S3 { f: dyn Iterator<Item: 'static> }
    |                             ^^^^^^^^^^^^^
 
-error: associated type bounds are not allowed within structs, enums, or unions
+error: associated type bounds are only allowed in where clauses and function signatures, not in field types
   --> $DIR/inside-adt.rs:12:26
    |
 LL | enum E1 { V(dyn Iterator<Item: Copy>) }
    |                          ^^^^^^^^^^
 
-error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:15:30
+error: associated type bounds are only allowed in where clauses and function signatures, not in field types
+  --> $DIR/inside-adt.rs:14:30
    |
 LL | enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
    |                              ^^^^^^^^^^
 
-error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:17:26
+error: associated type bounds are only allowed in where clauses and function signatures, not in field types
+  --> $DIR/inside-adt.rs:16:26
    |
 LL | enum E3 { V(dyn Iterator<Item: 'static>) }
    |                          ^^^^^^^^^^^^^
 
-error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:21:41
+error: associated type bounds are only allowed in where clauses and function signatures, not in field types
+  --> $DIR/inside-adt.rs:19:41
    |
 LL | union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> }
    |                                         ^^^^^^^^^^
 
-error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:24:45
+error: associated type bounds are only allowed in where clauses and function signatures, not in field types
+  --> $DIR/inside-adt.rs:21:45
    |
 LL | union U2 { f: ManuallyDrop<Box<dyn Iterator<Item: Copy>>> }
    |                                             ^^^^^^^^^^
 
-error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:26:41
+error: associated type bounds are only allowed in where clauses and function signatures, not in field types
+  --> $DIR/inside-adt.rs:23:41
    |
 LL | union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> }
    |                                         ^^^^^^^^^^^^^
 
-error[E0277]: the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)` cannot be known at compilation time
-  --> $DIR/inside-adt.rs:12:13
-   |
-LL | enum E1 { V(dyn Iterator<Item: Copy>) }
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Copy> + 'static)`
-   = note: no field of an enum variant may have a dynamically sized type
-   = help: change the field's type to have a statically known size
-help: borrowed types always have a statically known size
-   |
-LL | enum E1 { V(&dyn Iterator<Item: Copy>) }
-   |             +
-help: the `Box` type always has a statically known size and allocates its contents in the heap
-   |
-LL | enum E1 { V(Box<dyn Iterator<Item: Copy>>) }
-   |             ++++                        +
-
-error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized + 'static> + 'static)` cannot be known at compilation time
-  --> $DIR/inside-adt.rs:17:13
-   |
-LL | enum E3 { V(dyn Iterator<Item: 'static>) }
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized + 'static> + 'static)`
-   = note: no field of an enum variant may have a dynamically sized type
-   = help: change the field's type to have a statically known size
-help: borrowed types always have a statically known size
-   |
-LL | enum E3 { V(&dyn Iterator<Item: 'static>) }
-   |             +
-help: the `Box` type always has a statically known size and allocates its contents in the heap
-   |
-LL | enum E3 { V(Box<dyn Iterator<Item: 'static>>) }
-   |             ++++                           +
-
-error[E0277]: the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)` cannot be known at compilation time
-  --> $DIR/inside-adt.rs:21:15
-   |
-LL | union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> }
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |
-   = help: within `ManuallyDrop<(dyn Iterator<Item = impl Copy> + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Copy> + 'static)`
-   = note: required because it appears within the type `ManuallyDrop<dyn Iterator<Item = impl Copy>>`
-   = note: no field of a union may have a dynamically sized type
-   = help: change the field's type to have a statically known size
-help: borrowed types always have a statically known size
-   |
-LL | union U1 { f: &ManuallyDrop<dyn Iterator<Item: Copy>> }
-   |               +
-help: the `Box` type always has a statically known size and allocates its contents in the heap
-   |
-LL | union U1 { f: Box<ManuallyDrop<dyn Iterator<Item: Copy>>> }
-   |               ++++                                      +
-
-error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized + 'static> + 'static)` cannot be known at compilation time
-  --> $DIR/inside-adt.rs:26:15
-   |
-LL | union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> }
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |
-   = help: within `ManuallyDrop<(dyn Iterator<Item = impl Sized + 'static> + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized + 'static> + 'static)`
-   = note: required because it appears within the type `ManuallyDrop<dyn Iterator<Item = impl Sized>>`
-   = note: no field of a union may have a dynamically sized type
-   = help: change the field's type to have a statically known size
-help: borrowed types always have a statically known size
-   |
-LL | union U3 { f: &ManuallyDrop<dyn Iterator<Item: 'static>> }
-   |               +
-help: the `Box` type always has a statically known size and allocates its contents in the heap
-   |
-LL | union U3 { f: Box<ManuallyDrop<dyn Iterator<Item: 'static>>> }
-   |               ++++                                         +
-
-error: aborting due to 13 previous errors
+error: aborting due to 9 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
new file mode 100644
index 00000000000..afd3db5e052
--- /dev/null
+++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs
@@ -0,0 +1,71 @@
+// edition: 2021
+// known-bug: #108309
+
+#![feature(async_fn_in_trait)]
+#![feature(min_specialization)]
+
+struct MyStruct;
+
+trait MyTrait<T> {
+    async fn foo(_: T) -> &'static str;
+}
+
+impl<T> MyTrait<T> for MyStruct {
+    default async fn foo(_: T) -> &'static str {
+        "default"
+    }
+}
+
+impl MyTrait<i32> for MyStruct {
+    async fn foo(_: i32) -> &'static str {
+        "specialized"
+    }
+}
+
+async fn async_main() {
+    assert_eq!(MyStruct::foo(42).await, "specialized");
+    assert_eq!(indirection(42).await, "specialized");
+}
+
+async fn indirection<T>(x: T) -> &'static str {
+    //explicit type coercion is currently necessary
+    // because of https://github.com/rust-lang/rust/issues/67918
+    <MyStruct as MyTrait<T>>::foo(x).await
+}
+
+// ------------------------------------------------------------------------- //
+// Implementation Details Below...
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::*;
+
+pub fn noop_waker() -> Waker {
+    let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
+
+    // SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
+    unsafe { Waker::from_raw(raw) }
+}
+
+const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
+
+unsafe fn noop_clone(_p: *const ()) -> RawWaker {
+    RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
+}
+
+unsafe fn noop(_p: *const ()) {}
+
+fn main() {
+    let mut fut = async_main();
+
+    // Poll loop, just to test the future...
+    let waker = noop_waker();
+    let ctx = &mut Context::from_waker(&waker);
+
+    loop {
+        match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
+            Poll::Pending => {}
+            Poll::Ready(()) => break,
+        }
+    }
+}
diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
new file mode 100644
index 00000000000..371122ea71e
--- /dev/null
+++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
@@ -0,0 +1,26 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/dont-project-to-specializable-projection.rs:4:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0053]: method `foo` has an incompatible type for trait
+  --> $DIR/dont-project-to-specializable-projection.rs:14:35
+   |
+LL |     default async fn foo(_: T) -> &'static str {
+   |                                   ^^^^^^^^^^^^ expected associated type, found future
+   |
+note: type in trait
+  --> $DIR/dont-project-to-specializable-projection.rs:10:27
+   |
+LL |     async fn foo(_: T) -> &'static str;
+   |                           ^^^^^^^^^^^^
+   = note: expected signature `fn(_) -> impl Future<Output = &'static str>`
+              found signature `fn(_) -> impl Future<Output = &'static str>`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/async-await/in-trait/fn-not-async-err2.rs b/tests/ui/async-await/in-trait/fn-not-async-err2.rs
index 2c4ed553580..78017429f73 100644
--- a/tests/ui/async-await/in-trait/fn-not-async-err2.rs
+++ b/tests/ui/async-await/in-trait/fn-not-async-err2.rs
@@ -11,7 +11,7 @@ trait MyTrait {
 
 impl MyTrait for i32 {
     fn foo(&self) -> impl Future<Output = i32> {
-        //~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `impl` method return [E0562]
+        //~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `impl` method return types
         async { *self }
     }
 }
diff --git a/tests/ui/async-await/in-trait/fn-not-async-err2.stderr b/tests/ui/async-await/in-trait/fn-not-async-err2.stderr
index f591f184772..37d9669c012 100644
--- a/tests/ui/async-await/in-trait/fn-not-async-err2.stderr
+++ b/tests/ui/async-await/in-trait/fn-not-async-err2.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return types
   --> $DIR/fn-not-async-err2.rs:13:22
    |
 LL |     fn foo(&self) -> impl Future<Output = i32> {
diff --git a/tests/ui/async-await/issues/issue-65159.rs b/tests/ui/async-await/issues/issue-65159.rs
index df2ca025705..6e547508bd4 100644
--- a/tests/ui/async-await/issues/issue-65159.rs
+++ b/tests/ui/async-await/issues/issue-65159.rs
@@ -3,7 +3,7 @@
 // edition:2018
 
 async fn copy() -> Result<()>
-//~^ ERROR this enum takes 2 generic arguments
+//~^ ERROR enum takes 2 generic arguments
 {
     Ok(())
 }
diff --git a/tests/ui/async-await/issues/issue-65159.stderr b/tests/ui/async-await/issues/issue-65159.stderr
index 40c0e72b203..b8741333c32 100644
--- a/tests/ui/async-await/issues/issue-65159.stderr
+++ b/tests/ui/async-await/issues/issue-65159.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
+error[E0107]: enum takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-65159.rs:5:20
    |
 LL | async fn copy() -> Result<()>
diff --git a/tests/ui/attributes/invalid_macro_export_argument.rs b/tests/ui/attributes/invalid_macro_export_argument.rs
new file mode 100644
index 00000000000..85d009f11a6
--- /dev/null
+++ b/tests/ui/attributes/invalid_macro_export_argument.rs
@@ -0,0 +1,26 @@
+// check-pass
+#[macro_export(hello, world)] //~ WARN `#[macro_export]` can only take 1 or 0 arguments
+macro_rules! a {
+    () => ()
+}
+
+#[macro_export(not_local_inner_macros)] //~ WARN `not_local_inner_macros` isn't a valid `#[macro_export]` argument
+macro_rules! b {
+    () => ()
+}
+
+#[macro_export]
+macro_rules! c {
+    () => ()
+}
+#[macro_export(local_inner_macros)]
+macro_rules! d {
+    () => ()
+}
+
+#[macro_export()]
+macro_rules! e {
+    () => ()
+}
+
+fn main() {}
diff --git a/tests/ui/attributes/invalid_macro_export_argument.stderr b/tests/ui/attributes/invalid_macro_export_argument.stderr
new file mode 100644
index 00000000000..a4e17642c2a
--- /dev/null
+++ b/tests/ui/attributes/invalid_macro_export_argument.stderr
@@ -0,0 +1,16 @@
+warning: `#[macro_export]` can only take 1 or 0 arguments
+  --> $DIR/invalid_macro_export_argument.rs:2:1
+   |
+LL | #[macro_export(hello, world)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(invalid_macro_export_arguments)]` on by default
+
+warning: `not_local_inner_macros` isn't a valid `#[macro_export]` argument
+  --> $DIR/invalid_macro_export_argument.rs:7:16
+   |
+LL | #[macro_export(not_local_inner_macros)]
+   |                ^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/auto-traits/auto-trait-validation.stderr b/tests/ui/auto-traits/auto-trait-validation.stderr
index 2c380e5b09a..89b63d23d4c 100644
--- a/tests/ui/auto-traits/auto-trait-validation.stderr
+++ b/tests/ui/auto-traits/auto-trait-validation.stderr
@@ -12,7 +12,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
 LL | auto trait Bound : Copy {}
    |            -----^^^^^^^ help: remove the super traits or lifetime bounds
    |            |
-   |            auto trait cannot have super traits or lifetime bounds
+   |            auto traits cannot have super traits or lifetime bounds
 
 error[E0568]: auto traits cannot have super traits or lifetime bounds
   --> $DIR/auto-trait-validation.rs:9:25
@@ -20,7 +20,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
 LL | auto trait LifetimeBound : 'static {}
    |            -------------^^^^^^^^^^ help: remove the super traits or lifetime bounds
    |            |
-   |            auto trait cannot have super traits or lifetime bounds
+   |            auto traits cannot have super traits or lifetime bounds
 
 error[E0380]: auto traits cannot have associated items
   --> $DIR/auto-trait-validation.rs:11:25
@@ -29,7 +29,7 @@ LL | auto trait MyTrait { fn foo() {} }
    |            -------   ---^^^-----
    |            |         |
    |            |         help: remove these associated items
-   |            auto trait cannot have associated items
+   |            auto traits cannot have associated items
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/auto-traits/issue-23080-2.stderr b/tests/ui/auto-traits/issue-23080-2.stderr
index 267a712f62f..fed485612da 100644
--- a/tests/ui/auto-traits/issue-23080-2.stderr
+++ b/tests/ui/auto-traits/issue-23080-2.stderr
@@ -2,7 +2,7 @@ error[E0380]: auto traits cannot have associated items
   --> $DIR/issue-23080-2.rs:5:10
    |
 LL | unsafe auto trait Trait {
-   |                   ----- auto trait cannot have associated items
+   |                   ----- auto traits cannot have associated items
 LL |     type Output;
    |     -----^^^^^^- help: remove these associated items
 
diff --git a/tests/ui/auto-traits/issue-23080.stderr b/tests/ui/auto-traits/issue-23080.stderr
index c1b16b2f403..f5d607298b7 100644
--- a/tests/ui/auto-traits/issue-23080.stderr
+++ b/tests/ui/auto-traits/issue-23080.stderr
@@ -2,7 +2,7 @@ error[E0380]: auto traits cannot have associated items
   --> $DIR/issue-23080.rs:5:8
    |
 LL |   unsafe auto trait Trait {
-   |                     ----- auto trait cannot have associated items
+   |                     ----- auto traits cannot have associated items
 LL |       fn method(&self) {
    |  _____-  ^^^^^^
 LL | |         println!("Hello");
diff --git a/tests/ui/auto-traits/issue-84075.stderr b/tests/ui/auto-traits/issue-84075.stderr
index 02dca598ec2..6fbdc669b6f 100644
--- a/tests/ui/auto-traits/issue-84075.stderr
+++ b/tests/ui/auto-traits/issue-84075.stderr
@@ -4,7 +4,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
 LL | auto trait Magic where Self: Copy {}
    |            ----- ^^^^^^^^^^^^^^^^ help: remove the super traits or lifetime bounds
    |            |
-   |            auto trait cannot have super traits or lifetime bounds
+   |            auto traits cannot have super traits or lifetime bounds
 
 error: aborting due to previous error
 
diff --git a/tests/ui/auto-traits/str-contains-slice-conceptually.rs b/tests/ui/auto-traits/str-contains-slice-conceptually.rs
new file mode 100644
index 00000000000..6a16fdcf284
--- /dev/null
+++ b/tests/ui/auto-traits/str-contains-slice-conceptually.rs
@@ -0,0 +1,13 @@
+#![feature(negative_impls)]
+#![feature(auto_traits)]
+
+auto trait AutoTrait {}
+
+impl<T> !AutoTrait for [T] {}
+
+fn needs_auto_trait<T: AutoTrait + ?Sized>() {}
+
+fn main() {
+  needs_auto_trait::<str>();
+  //~^ ERROR the trait bound `[u8]: AutoTrait` is not satisfied in `str`
+}
diff --git a/tests/ui/auto-traits/str-contains-slice-conceptually.stderr b/tests/ui/auto-traits/str-contains-slice-conceptually.stderr
new file mode 100644
index 00000000000..1cf16cebddd
--- /dev/null
+++ b/tests/ui/auto-traits/str-contains-slice-conceptually.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `[u8]: AutoTrait` is not satisfied in `str`
+  --> $DIR/str-contains-slice-conceptually.rs:11:22
+   |
+LL |   needs_auto_trait::<str>();
+   |                      ^^^ within `str`, the trait `AutoTrait` is not implemented for `[u8]`
+   |
+   = note: `str` is considered to contain a `[u8]` slice for auto trait purposes
+note: required by a bound in `needs_auto_trait`
+  --> $DIR/str-contains-slice-conceptually.rs:8:24
+   |
+LL | fn needs_auto_trait<T: AutoTrait + ?Sized>() {}
+   |                        ^^^^^^^^^ required by this bound in `needs_auto_trait`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
index 4827916fa5c..547b4bb5448 100644
--- a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
+++ b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
@@ -4,7 +4,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
 LL | auto trait Magic : Sized where Option<Self> : Magic {}
    |            -----^^^^^^^^ help: remove the super traits or lifetime bounds
    |            |
-   |            auto trait cannot have super traits or lifetime bounds
+   |            auto traits cannot have super traits or lifetime bounds
 
 error[E0568]: auto traits cannot have super traits or lifetime bounds
   --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:26
@@ -12,7 +12,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
 LL | auto trait Magic : Sized where Option<Self> : Magic {}
    |            -----         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the super traits or lifetime bounds
    |            |
-   |            auto trait cannot have super traits or lifetime bounds
+   |            auto traits cannot have super traits or lifetime bounds
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr
index d7716f4b61f..80f07410381 100644
--- a/tests/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr
+++ b/tests/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr
@@ -4,7 +4,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
 LL | auto trait Magic: Copy {}
    |            -----^^^^^^ help: remove the super traits or lifetime bounds
    |            |
-   |            auto trait cannot have super traits or lifetime bounds
+   |            auto traits cannot have super traits or lifetime bounds
 
 error: aborting due to previous error
 
diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs
index dd0320bc53b..d067ff44704 100644
--- a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs
+++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs
@@ -14,8 +14,8 @@ impl MarketMultiplier {
 }
 
 async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
-    //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
-    //~^^ ERROR this struct takes 1 generic argument but 0 generic arguments were supplied
+    //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+    //~^^ ERROR struct takes 1 generic argument but 0 generic arguments were supplied
     LockedMarket(generator.lock().unwrap().buy())
 }
 
diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
index d2b927fb664..73e0aaf1e45 100644
--- a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
+++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59
    |
 LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
@@ -12,7 +12,7 @@ note: struct defined here, with 0 lifetime parameters
 LL | struct LockedMarket<T>(T);
    |        ^^^^^^^^^^^^
 
-error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59
    |
 LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.rs b/tests/ui/const-generics/generic_const_exprs/issue-102768.rs
index 7aea0d30d1a..18a9b53cf76 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-102768.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.rs
@@ -7,8 +7,8 @@ trait X {
 
 const _: () = {
     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
-    //~^ ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
-    //~| ERROR this associated type takes 0 generic arguments but 1 generic argument
+    //~^ ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
+    //~| ERROR associated type takes 0 generic arguments but 1 generic argument
 };
 
 fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
index 8278edabe3a..175d54e4184 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/issue-102768.rs:9:30
    |
 LL |     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
@@ -14,7 +14,7 @@ help: add missing lifetime argument
 LL |     fn f2<'a>(arg: Box<dyn X<Y<'_, 1> = &'a ()>>) {}
    |                                +++
 
-error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-102768.rs:9:30
    |
 LL |     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-76595.stderr b/tests/ui/const-generics/generic_const_exprs/issue-76595.stderr
index c587a7e153f..302da59651c 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-76595.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-76595.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this function takes 2 generic arguments but 1 generic argument was supplied
+error[E0107]: function takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-76595.rs:15:5
    |
 LL |     test::<2>();
diff --git a/tests/ui/const-generics/incorrect-number-of-const-args.stderr b/tests/ui/const-generics/incorrect-number-of-const-args.stderr
index a845454f762..01ac4e69a05 100644
--- a/tests/ui/const-generics/incorrect-number-of-const-args.stderr
+++ b/tests/ui/const-generics/incorrect-number-of-const-args.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this function takes 2 generic arguments but 1 generic argument was supplied
+error[E0107]: function takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/incorrect-number-of-const-args.rs:6:5
    |
 LL |     foo::<0>();
@@ -16,7 +16,7 @@ help: add missing generic argument
 LL |     foo::<0, Y>();
    |            +++
 
-error[E0107]: this function takes 2 generic arguments but 3 generic arguments were supplied
+error[E0107]: function takes 2 generic arguments but 3 generic arguments were supplied
   --> $DIR/incorrect-number-of-const-args.rs:9:5
    |
 LL |     foo::<0, 0, 0>();
diff --git a/tests/ui/const-generics/invalid-const-arg-for-type-param.rs b/tests/ui/const-generics/invalid-const-arg-for-type-param.rs
index cdc54b214a8..bf10f471dc5 100644
--- a/tests/ui/const-generics/invalid-const-arg-for-type-param.rs
+++ b/tests/ui/const-generics/invalid-const-arg-for-type-param.rs
@@ -4,11 +4,11 @@ struct S;
 
 fn main() {
     let _: u32 = 5i32.try_into::<32>().unwrap();
-    //~^ ERROR this method takes
+    //~^ ERROR method takes
 
     S.f::<0>();
     //~^ ERROR no method named `f`
 
     S::<0>;
-    //~^ ERROR this struct takes 0
+    //~^ ERROR struct takes 0
 }
diff --git a/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr b/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr
index a9754bc46d7..4a649d8a7e8 100644
--- a/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr
+++ b/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this method takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/invalid-const-arg-for-type-param.rs:6:23
    |
 LL |     let _: u32 = 5i32.try_into::<32>().unwrap();
@@ -23,7 +23,7 @@ LL | struct S;
 LL |     S.f::<0>();
    |       ^ method not found in `S`
 
-error[E0107]: this struct takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/invalid-const-arg-for-type-param.rs:12:5
    |
 LL |     S::<0>;
diff --git a/tests/ui/const-generics/invalid-constant-in-args.rs b/tests/ui/const-generics/invalid-constant-in-args.rs
index 7419d4a25ce..fd259197d29 100644
--- a/tests/ui/const-generics/invalid-constant-in-args.rs
+++ b/tests/ui/const-generics/invalid-constant-in-args.rs
@@ -2,5 +2,5 @@ use std::cell::Cell;
 
 fn main() {
     let _: Cell<&str, "a"> = Cell::new("");
-    //~^ ERROR this struct takes 1 generic argument but 2 generic arguments were supplied
+    //~^ ERROR struct takes 1 generic argument but 2 generic arguments were supplied
 }
diff --git a/tests/ui/const-generics/invalid-constant-in-args.stderr b/tests/ui/const-generics/invalid-constant-in-args.stderr
index 993b63518e4..2545cc6f396 100644
--- a/tests/ui/const-generics/invalid-constant-in-args.stderr
+++ b/tests/ui/const-generics/invalid-constant-in-args.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/invalid-constant-in-args.rs:4:12
    |
 LL |     let _: Cell<&str, "a"> = Cell::new("");
diff --git a/tests/ui/const-generics/issues/issue-87493.rs b/tests/ui/const-generics/issues/issue-87493.rs
index d8599ab22a3..80472e6bd9c 100644
--- a/tests/ui/const-generics/issues/issue-87493.rs
+++ b/tests/ui/const-generics/issues/issue-87493.rs
@@ -7,7 +7,7 @@ where
     S: MyTrait,
     T: MyTrait<Assoc == S::Assoc>,
     //~^ ERROR: expected one of `,` or `>`, found `==`
-    //~| ERROR: this trait takes 0 generic arguments but 1 generic argument was supplied
+    //~| ERROR: trait takes 0 generic arguments but 1 generic argument was supplied
 {
 }
 
diff --git a/tests/ui/const-generics/issues/issue-87493.stderr b/tests/ui/const-generics/issues/issue-87493.stderr
index 653afae2191..73bd6ed73e6 100644
--- a/tests/ui/const-generics/issues/issue-87493.stderr
+++ b/tests/ui/const-generics/issues/issue-87493.stderr
@@ -9,7 +9,7 @@ help: if you meant to use an associated type binding, replace `==` with `=`
 LL |     T: MyTrait<Assoc = S::Assoc>,
    |                      ~
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-87493.rs:8:8
    |
 LL |     T: MyTrait<Assoc == S::Assoc>,
diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
index b126b24853f..79743abe409 100644
--- a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
+++ b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
@@ -7,7 +7,7 @@ struct Bar;
 const T: usize = 42;
 
 impl Foo<N = 3> for Bar {
-//~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied
+//~^ ERROR 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] {
diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
index acfdde8e1a0..4f4e1aa3a04 100644
--- a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
+++ b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
@@ -7,7 +7,7 @@ LL | impl Foo<N = 3> for Bar {
    = 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
+error[E0107]: 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 {
diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013.rs b/tests/ui/const-generics/parser-error-recovery/issue-89013.rs
index 9431779faf8..335d0d94e83 100644
--- a/tests/ui/const-generics/parser-error-recovery/issue-89013.rs
+++ b/tests/ui/const-generics/parser-error-recovery/issue-89013.rs
@@ -8,7 +8,7 @@ const T: usize = 42;
 
 impl Foo<N = const 3> for Bar {
 //~^ ERROR expected lifetime, type, or constant, found keyword `const`
-//~| ERROR this trait takes 1 generic
+//~| ERROR trait takes 1 generic
 //~| ERROR associated type bindings are not allowed here
 //~| ERROR associated const equality is incomplete
     fn do_x(&self) -> [u8; 3] {
diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr
index 583749a8573..3d2b98feb39 100644
--- a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr
+++ b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr
@@ -19,7 +19,7 @@ LL | impl Foo<N = const 3> for Bar {
    = 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
+error[E0107]: 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 {
diff --git a/tests/ui/constructor-lifetime-args.rs b/tests/ui/constructor-lifetime-args.rs
index a824a44c9c2..f5802e7d8b1 100644
--- a/tests/ui/constructor-lifetime-args.rs
+++ b/tests/ui/constructor-lifetime-args.rs
@@ -15,12 +15,12 @@ enum E<'a, 'b> {
 fn main() {
     S(&0, &0); // OK
     S::<'static>(&0, &0);
-    //~^ ERROR this struct takes 2 lifetime arguments
+    //~^ ERROR struct takes 2 lifetime arguments
     S::<'static, 'static, 'static>(&0, &0);
-    //~^ ERROR this struct takes 2 lifetime arguments
+    //~^ ERROR struct takes 2 lifetime arguments
     E::V(&0); // OK
     E::V::<'static>(&0);
-    //~^ ERROR this enum takes 2 lifetime arguments
+    //~^ ERROR enum takes 2 lifetime arguments
     E::V::<'static, 'static, 'static>(&0);
-    //~^ ERROR this enum takes 2 lifetime arguments
+    //~^ ERROR enum takes 2 lifetime arguments
 }
diff --git a/tests/ui/constructor-lifetime-args.stderr b/tests/ui/constructor-lifetime-args.stderr
index bc1141b16c5..a18123fe19c 100644
--- a/tests/ui/constructor-lifetime-args.stderr
+++ b/tests/ui/constructor-lifetime-args.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: struct takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/constructor-lifetime-args.rs:17:5
    |
 LL |     S::<'static>(&0, &0);
@@ -16,7 +16,7 @@ help: add missing lifetime argument
 LL |     S::<'static, 'static>(&0, &0);
    |                +++++++++
 
-error[E0107]: this struct takes 2 lifetime arguments but 3 lifetime arguments were supplied
+error[E0107]: struct takes 2 lifetime arguments but 3 lifetime arguments were supplied
   --> $DIR/constructor-lifetime-args.rs:19:5
    |
 LL |     S::<'static, 'static, 'static>(&0, &0);
@@ -30,7 +30,7 @@ note: struct defined here, with 2 lifetime parameters: `'a`, `'b`
 LL | struct S<'a, 'b>(&'a u8, &'b u8);
    |        ^ --  --
 
-error[E0107]: this enum takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: enum takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/constructor-lifetime-args.rs:22:8
    |
 LL |     E::V::<'static>(&0);
@@ -48,7 +48,7 @@ help: add missing lifetime argument
 LL |     E::V::<'static, 'static>(&0);
    |                   +++++++++
 
-error[E0107]: this enum takes 2 lifetime arguments but 3 lifetime arguments were supplied
+error[E0107]: enum takes 2 lifetime arguments but 3 lifetime arguments were supplied
   --> $DIR/constructor-lifetime-args.rs:24:8
    |
 LL |     E::V::<'static, 'static, 'static>(&0);
diff --git a/tests/ui/consts/gate-do-not-const-check.rs b/tests/ui/consts/gate-do-not-const-check.rs
new file mode 100644
index 00000000000..be7e70dfabb
--- /dev/null
+++ b/tests/ui/consts/gate-do-not-const-check.rs
@@ -0,0 +1,5 @@
+#[rustc_do_not_const_check]
+//~^ ERROR this is an internal attribute that will never be stable
+const fn foo() {}
+
+fn main() {}
diff --git a/tests/ui/consts/gate-do-not-const-check.stderr b/tests/ui/consts/gate-do-not-const-check.stderr
new file mode 100644
index 00000000000..3bb1360166a
--- /dev/null
+++ b/tests/ui/consts/gate-do-not-const-check.stderr
@@ -0,0 +1,11 @@
+error[E0658]: this is an internal attribute that will never be stable
+  --> $DIR/gate-do-not-const-check.rs:1:1
+   |
+LL | #[rustc_do_not_const_check]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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/tests/ui/error-codes/E0107.rs b/tests/ui/error-codes/E0107.rs
index d369fc2a565..fd23e7c00f2 100644
--- a/tests/ui/error-codes/E0107.rs
+++ b/tests/ui/error-codes/E0107.rs
@@ -11,39 +11,39 @@ enum Bar {
 
 struct Baz<'a, 'b, 'c> {
     buzz: Buzz<'a>,
-    //~^ ERROR this struct takes 2 lifetime arguments
+    //~^ ERROR struct takes 2 lifetime arguments
     //~| HELP add missing lifetime argument
 
     bar: Bar<'a>,
-    //~^ ERROR this enum takes 0 lifetime arguments
+    //~^ ERROR enum takes 0 lifetime arguments
     //~| HELP remove these generics
 
     foo2: Foo<'a, 'b, 'c>,
-    //~^ ERROR this struct takes 1 lifetime argument
+    //~^ ERROR struct takes 1 lifetime argument
     //~| HELP remove these lifetime arguments
 
     qux1: Qux<'a, 'b, i32>,
-    //~^ ERROR this struct takes 1 lifetime argument
+    //~^ ERROR struct takes 1 lifetime argument
     //~| HELP remove this lifetime argument
 
     qux2: Qux<'a, i32, 'b>,
-    //~^ ERROR this struct takes 1 lifetime argument
+    //~^ ERROR struct takes 1 lifetime argument
     //~| HELP remove this lifetime argument
 
     qux3: Qux<'a, 'b, 'c, i32>,
-    //~^ ERROR this struct takes 1 lifetime argument
+    //~^ ERROR struct takes 1 lifetime argument
     //~| HELP remove these lifetime arguments
 
     qux4: Qux<'a, i32, 'b, 'c>,
-    //~^ ERROR this struct takes 1 lifetime argument
+    //~^ ERROR struct takes 1 lifetime argument
     //~| HELP remove these lifetime arguments
 
     qux5: Qux<'a, 'b, i32, 'c>,
-    //~^ ERROR this struct takes 1 lifetime argument
+    //~^ ERROR struct takes 1 lifetime argument
     //~| HELP remove this lifetime argument
 
     quux: Quux<'a, i32, 'b>,
-    //~^ ERROR this struct takes 0 lifetime arguments
+    //~^ ERROR struct takes 0 lifetime arguments
     //~| HELP remove this lifetime argument
 }
 
@@ -53,7 +53,7 @@ pub trait T {
 }
 
 fn trait_bound_generic<I: T<u8, u16>>(_i: I) {
-    //~^ ERROR this trait takes 0 generic arguments
+    //~^ ERROR trait takes 0 generic arguments
     //~| HELP replace the generic bounds with the associated types
 }
 
diff --git a/tests/ui/error-codes/E0107.stderr b/tests/ui/error-codes/E0107.stderr
index 03430f8fa3a..3f540eb08bc 100644
--- a/tests/ui/error-codes/E0107.stderr
+++ b/tests/ui/error-codes/E0107.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: struct takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/E0107.rs:13:11
    |
 LL |     buzz: Buzz<'a>,
@@ -16,7 +16,7 @@ help: add missing lifetime argument
 LL |     buzz: Buzz<'a, 'a>,
    |                  ++++
 
-error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: enum takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/E0107.rs:17:10
    |
 LL |     bar: Bar<'a>,
@@ -30,7 +30,7 @@ note: enum defined here, with 0 lifetime parameters
 LL | enum Bar {
    |      ^^^
 
-error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were supplied
   --> $DIR/E0107.rs:21:11
    |
 LL |     foo2: Foo<'a, 'b, 'c>,
@@ -44,7 +44,7 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct Foo<'a>(&'a str);
    |        ^^^ --
 
-error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/E0107.rs:25:11
    |
 LL |     qux1: Qux<'a, 'b, i32>,
@@ -58,7 +58,7 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct Qux<'a, T>(&'a T);
    |        ^^^ --
 
-error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/E0107.rs:29:11
    |
 LL |     qux2: Qux<'a, i32, 'b>,
@@ -72,7 +72,7 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct Qux<'a, T>(&'a T);
    |        ^^^ --
 
-error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were supplied
   --> $DIR/E0107.rs:33:11
    |
 LL |     qux3: Qux<'a, 'b, 'c, i32>,
@@ -86,7 +86,7 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct Qux<'a, T>(&'a T);
    |        ^^^ --
 
-error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were supplied
   --> $DIR/E0107.rs:37:11
    |
 LL |     qux4: Qux<'a, i32, 'b, 'c>,
@@ -100,7 +100,7 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct Qux<'a, T>(&'a T);
    |        ^^^ --
 
-error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were supplied
   --> $DIR/E0107.rs:41:11
    |
 LL |     qux5: Qux<'a, 'b, i32, 'c>,
@@ -114,7 +114,7 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct Qux<'a, T>(&'a T);
    |        ^^^ --
 
-error[E0107]: this struct takes 0 lifetime arguments but 2 lifetime arguments were supplied
+error[E0107]: struct takes 0 lifetime arguments but 2 lifetime arguments were supplied
   --> $DIR/E0107.rs:45:11
    |
 LL |     quux: Quux<'a, i32, 'b>,
@@ -128,7 +128,7 @@ note: struct defined here, with 0 lifetime parameters
 LL | struct Quux<T>(T);
    |        ^^^^
 
-error[E0107]: this trait takes 0 generic arguments but 2 generic arguments were supplied
+error[E0107]: trait takes 0 generic arguments but 2 generic arguments were supplied
   --> $DIR/E0107.rs:55:27
    |
 LL | fn trait_bound_generic<I: T<u8, u16>>(_i: I) {
diff --git a/tests/ui/error-codes/E0476.rs b/tests/ui/error-codes/E0476.rs
new file mode 100644
index 00000000000..d5e4b8d2372
--- /dev/null
+++ b/tests/ui/error-codes/E0476.rs
@@ -0,0 +1,13 @@
+#![feature(coerce_unsized)]
+#![feature(unsize)]
+
+use std::marker::Unsize;
+use std::ops::CoerceUnsized;
+
+struct Wrapper<T>(T);
+
+impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
+//~^ ERROR lifetime of the source pointer does not outlive lifetime bound of the object type [E0476]
+//~^^ ERROR E0119
+
+fn main() {}
diff --git a/tests/ui/error-codes/E0476.stderr b/tests/ui/error-codes/E0476.stderr
new file mode 100644
index 00000000000..a4bb26532a2
--- /dev/null
+++ b/tests/ui/error-codes/E0476.stderr
@@ -0,0 +1,31 @@
+error[E0119]: conflicting implementations of trait `CoerceUnsized<&Wrapper<_>>` for type `&Wrapper<_>`
+  --> $DIR/E0476.rs:9:1
+   |
+LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `core`:
+           - impl<'a, 'b, T, U> CoerceUnsized<&'a U> for &'b T
+             where 'b: 'a, T: Unsize<U>, T: ?Sized, U: ?Sized;
+
+error[E0476]: lifetime of the source pointer does not outlive lifetime bound of the object type
+  --> $DIR/E0476.rs:9:1
+   |
+LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: object type is valid for the lifetime `'a` as defined here
+  --> $DIR/E0476.rs:9:6
+   |
+LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
+   |      ^^
+note: source pointer is only valid for the lifetime `'b` as defined here
+  --> $DIR/E0476.rs:9:10
+   |
+LL | impl<'a, 'b, T, S> CoerceUnsized<&'a Wrapper<T>> for &'b Wrapper<S> where S: Unsize<T> {}
+   |          ^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0119, E0476.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/expr/malformed_closure/missing_braces_around_block.fixed b/tests/ui/expr/malformed_closure/missing_braces_around_block.fixed
index c50b9a12b6d..a7a9db7d977 100644
--- a/tests/ui/expr/malformed_closure/missing_braces_around_block.fixed
+++ b/tests/ui/expr/malformed_closure/missing_braces_around_block.fixed
@@ -4,16 +4,23 @@
 // If this recovery happens, then plenty of errors are emitted. Here, we expect
 // only one error.
 //
-// This is part of issue #88065:
+// This is part of the following issues:
 // https://github.com/rust-lang/rust/issues/88065
+// https://github.com/rust-lang/rust/issues/107959
 
 // run-rustfix
 
 fn main() {
+    // Closure with multiple expressions delimited by semicolon.
     let num = 5;
     (1..num).reduce(|a, b| {
         //~^ ERROR: closure bodies that contain statements must be surrounded by braces
         println!("{}", a);
         a * b
     }).unwrap();
+
+    // Closure with a single expression ended by a semicolon.
+    let mut v = vec![1, 2, 3];
+    v.iter_mut().for_each(|x| {*x = *x+1;});
+        //~^ ERROR: closure bodies that contain statements must be surrounded by braces
 }
diff --git a/tests/ui/expr/malformed_closure/missing_braces_around_block.rs b/tests/ui/expr/malformed_closure/missing_braces_around_block.rs
index 58c81f3a6e2..b5690b2eca7 100644
--- a/tests/ui/expr/malformed_closure/missing_braces_around_block.rs
+++ b/tests/ui/expr/malformed_closure/missing_braces_around_block.rs
@@ -4,16 +4,23 @@
 // If this recovery happens, then plenty of errors are emitted. Here, we expect
 // only one error.
 //
-// This is part of issue #88065:
+// This is part of the following issues:
 // https://github.com/rust-lang/rust/issues/88065
+// https://github.com/rust-lang/rust/issues/107959
 
 // run-rustfix
 
 fn main() {
+    // Closure with multiple expressions delimited by semicolon.
     let num = 5;
     (1..num).reduce(|a, b|
         //~^ ERROR: closure bodies that contain statements must be surrounded by braces
         println!("{}", a);
         a * b
     ).unwrap();
+
+    // Closure with a single expression ended by a semicolon.
+    let mut v = vec![1, 2, 3];
+    v.iter_mut().for_each(|x|*x = *x+1;);
+        //~^ ERROR: closure bodies that contain statements must be surrounded by braces
 }
diff --git a/tests/ui/expr/malformed_closure/missing_braces_around_block.stderr b/tests/ui/expr/malformed_closure/missing_braces_around_block.stderr
index dac9a8cfc69..039eef909fc 100644
--- a/tests/ui/expr/malformed_closure/missing_braces_around_block.stderr
+++ b/tests/ui/expr/malformed_closure/missing_braces_around_block.stderr
@@ -1,5 +1,5 @@
 error: closure bodies that contain statements must be surrounded by braces
-  --> $DIR/missing_braces_around_block.rs:14:26
+  --> $DIR/missing_braces_around_block.rs:16:26
    |
 LL |     (1..num).reduce(|a, b|
    |                          ^
@@ -8,14 +8,14 @@ LL |     ).unwrap();
    |     ^
    |
 note: statement found outside of a block
-  --> $DIR/missing_braces_around_block.rs:16:26
+  --> $DIR/missing_braces_around_block.rs:18:26
    |
 LL |         println!("{}", a);
    |         -----------------^ this `;` turns the preceding closure into a statement
    |         |
    |         this expression is a statement because of the trailing semicolon
 note: the closure body may be incorrectly delimited
-  --> $DIR/missing_braces_around_block.rs:14:21
+  --> $DIR/missing_braces_around_block.rs:16:21
    |
 LL |       (1..num).reduce(|a, b|
    |  _____________________^
@@ -34,5 +34,30 @@ LL |         a * b
 LL ~     }).unwrap();
    |
 
-error: aborting due to previous error
+error: closure bodies that contain statements must be surrounded by braces
+  --> $DIR/missing_braces_around_block.rs:24:29
+   |
+LL |     v.iter_mut().for_each(|x|*x = *x+1;);
+   |                             ^          ^
+   |
+note: statement found outside of a block
+  --> $DIR/missing_braces_around_block.rs:24:39
+   |
+LL |     v.iter_mut().for_each(|x|*x = *x+1;);
+   |                              ---------^ this `;` turns the preceding closure into a statement
+   |                              |
+   |                              this expression is a statement because of the trailing semicolon
+note: the closure body may be incorrectly delimited
+  --> $DIR/missing_braces_around_block.rs:24:27
+   |
+LL |     v.iter_mut().for_each(|x|*x = *x+1;);
+   |                           ^^^^^^^^^^^^ - ...but likely you meant the closure to end here
+   |                           |
+   |                           this is the parsed closure...
+help: try adding braces
+   |
+LL |     v.iter_mut().for_each(|x| {*x = *x+1;});
+   |                               +          +
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr
index edbbf7db565..4233a8af9b6 100644
--- a/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr
+++ b/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr
@@ -115,19 +115,19 @@ LL |     let _: impl Tr1<As1: Copy> = S1;
    = note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in const type
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in const types
   --> $DIR/feature-gate-associated_type_bounds.rs:55:14
    |
 LL | const _cdef: impl Tr1<As1: Copy> = S1;
    |              ^^^^^^^^^^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in const type
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in const types
   --> $DIR/feature-gate-associated_type_bounds.rs:61:15
    |
 LL | static _sdef: impl Tr1<As1: Copy> = S1;
    |               ^^^^^^^^^^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/feature-gate-associated_type_bounds.rs:68:12
    |
 LL |     let _: impl Tr1<As1: Copy> = S1;
diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.stderr b/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.stderr
index 760dcb615c8..c8c3e13d7fc 100644
--- a/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.stderr
+++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_fn_trait_return.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return types
   --> $DIR/feature-gate-impl_trait_in_fn_trait_return.rs:1:24
    |
 LL | fn f() -> impl Fn() -> impl Sized { || () }
@@ -7,7 +7,7 @@ LL | fn f() -> impl Fn() -> impl Sized { || () }
    = note: see issue #99697 <https://github.com/rust-lang/rust/issues/99697> for more information
    = help: add `#![feature(impl_trait_in_fn_trait_return)]` to the crate attributes to enable
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return types
   --> $DIR/feature-gate-impl_trait_in_fn_trait_return.rs:3:32
    |
 LL | fn g() -> &'static dyn Fn() -> impl Sized { &|| () }
diff --git a/tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr b/tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr
index aeabed4a6ab..0082b6fafee 100644
--- a/tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr
+++ b/tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return types
   --> $DIR/feature-gate-return_position_impl_trait_in_trait.rs:8:17
    |
 LL |     fn bar() -> impl Sized;
@@ -7,7 +7,7 @@ LL |     fn bar() -> impl Sized;
    = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
    = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return types
   --> $DIR/feature-gate-return_position_impl_trait_in_trait.rs:9:21
    |
 LL |     fn baz() -> Box<impl std::fmt::Display>;
@@ -16,7 +16,7 @@ LL |     fn baz() -> Box<impl std::fmt::Display>;
    = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
    = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return types
   --> $DIR/feature-gate-return_position_impl_trait_in_trait.rs:15:23
    |
 LL |     async fn bar() -> impl Sized;
diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
index 9eb069637c6..5738dfa83ee 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
+++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
@@ -5,12 +5,12 @@ trait X {
 fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
   //~^ ERROR: lifetime in trait object type must be followed by `+`
   //~| ERROR: parenthesized generic arguments cannot be used
-  //~| ERROR this associated type takes 0 generic arguments but 1 generic argument
-  //~| ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
+  //~| ERROR associated type takes 0 generic arguments but 1 generic argument
+  //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
 
 
 fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
   //~^ ERROR: parenthesized generic arguments cannot be used
-  //~| ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
+  //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
index 165779796e0..461853379b5 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
+++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
@@ -23,7 +23,7 @@ LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
    |                            |
    |                            help: remove these parentheses
 
-error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/gat-trait-path-parenthesised-args.rs:5:27
    |
 LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
@@ -39,7 +39,7 @@ help: add missing lifetime argument
 LL | fn foo<'a>(arg: Box<dyn X<Y('_, 'a) = &'a ()>>) {}
    |                             +++
 
-error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/gat-trait-path-parenthesised-args.rs:5:27
    |
 LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
@@ -53,7 +53,7 @@ note: associated type defined here, with 0 generic parameters
 LL |   type Y<'a>;
    |        ^
 
-error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/gat-trait-path-parenthesised-args.rs:12:27
    |
 LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.rs b/tests/ui/generic-associated-types/missing_lifetime_args.rs
index 78def80925a..331511ba61a 100644
--- a/tests/ui/generic-associated-types/missing_lifetime_args.rs
+++ b/tests/ui/generic-associated-types/missing_lifetime_args.rs
@@ -12,9 +12,9 @@ fn foo<'c, 'd>(_arg: Box<dyn X<Y = (&'c u32, &'d u32)>>) {}
 //~^ ERROR missing generics for associated type
 
 fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b>) {}
-//~^ ERROR this struct takes 3 lifetime arguments but 2 lifetime
+//~^ ERROR struct takes 3 lifetime arguments but 2 lifetime
 
 fn f<'a>(_arg: Foo<'a>) {}
-//~^ ERROR this struct takes 3 lifetime arguments but 1 lifetime
+//~^ ERROR struct takes 3 lifetime arguments but 1 lifetime
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.stderr b/tests/ui/generic-associated-types/missing_lifetime_args.stderr
index 8f74b12c008..1a7a2e787a1 100644
--- a/tests/ui/generic-associated-types/missing_lifetime_args.stderr
+++ b/tests/ui/generic-associated-types/missing_lifetime_args.stderr
@@ -14,7 +14,7 @@ help: add missing lifetime arguments
 LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y<'_, '_> = (&'c u32, &'d u32)>>) {}
    |                                 ++++++++
 
-error[E0107]: this struct takes 3 lifetime arguments but 2 lifetime arguments were supplied
+error[E0107]: struct takes 3 lifetime arguments but 2 lifetime arguments were supplied
   --> $DIR/missing_lifetime_args.rs:14:26
    |
 LL | fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b>) {}
@@ -32,7 +32,7 @@ help: add missing lifetime argument
 LL | fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b, 'a>) {}
    |                                    ++++
 
-error[E0107]: this struct takes 3 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: struct takes 3 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing_lifetime_args.rs:17:16
    |
 LL | fn f<'a>(_arg: Foo<'a>) {}
diff --git a/tests/ui/generic-associated-types/missing_lifetime_const.rs b/tests/ui/generic-associated-types/missing_lifetime_const.rs
index 8b174b9e971..6e395dfdec1 100644
--- a/tests/ui/generic-associated-types/missing_lifetime_const.rs
+++ b/tests/ui/generic-associated-types/missing_lifetime_const.rs
@@ -4,7 +4,7 @@ trait Foo {
 
 fn foo<T: Foo>() {
     let _: <T as Foo>::Assoc<3>;
-      //~^ ERROR  this associated type
+      //~^ ERROR  associated type
 }
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/missing_lifetime_const.stderr b/tests/ui/generic-associated-types/missing_lifetime_const.stderr
index 62d2e9f49dd..41945aabfb5 100644
--- a/tests/ui/generic-associated-types/missing_lifetime_const.stderr
+++ b/tests/ui/generic-associated-types/missing_lifetime_const.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/missing_lifetime_const.rs:6:24
    |
 LL |     let _: <T as Foo>::Assoc<3>;
diff --git a/tests/ui/generic-associated-types/parameter_number_and_kind.rs b/tests/ui/generic-associated-types/parameter_number_and_kind.rs
index 8428e7763fb..ae2f7c00ea4 100644
--- a/tests/ui/generic-associated-types/parameter_number_and_kind.rs
+++ b/tests/ui/generic-associated-types/parameter_number_and_kind.rs
@@ -9,10 +9,10 @@ trait Foo {
     // Test parameters in default values
     type FOk<T> = Self::E<'static, T>;
     type FErr1 = Self::E<'static, 'static>;
-    //~^ ERROR this associated type takes 1 lifetime argument but 2 lifetime arguments were supplied
-    //~| ERROR this associated type takes 1
+    //~^ ERROR associated type takes 1 lifetime argument but 2 lifetime arguments were supplied
+    //~| ERROR associated type takes 1
     type FErr2<T> = Self::E<'static, T, u32>;
-    //~^ ERROR this associated type takes 1
+    //~^ ERROR associated type takes 1
 }
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/parameter_number_and_kind.stderr b/tests/ui/generic-associated-types/parameter_number_and_kind.stderr
index c20b9669e81..4523044b588 100644
--- a/tests/ui/generic-associated-types/parameter_number_and_kind.stderr
+++ b/tests/ui/generic-associated-types/parameter_number_and_kind.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this associated type takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: associated type takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/parameter_number_and_kind.rs:11:24
    |
 LL |     type FErr1 = Self::E<'static, 'static>;
@@ -12,7 +12,7 @@ note: associated type defined here, with 1 lifetime parameter: `'a`
 LL |     type E<'a, T>;
    |          ^ --
 
-error[E0107]: this associated type takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: associated type takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/parameter_number_and_kind.rs:11:24
    |
 LL |     type FErr1 = Self::E<'static, 'static>;
@@ -28,7 +28,7 @@ help: add missing generic argument
 LL |     type FErr1 = Self::E<'static, 'static, T>;
    |                                          +++
 
-error[E0107]: this associated type takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: associated type takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/parameter_number_and_kind.rs:14:27
    |
 LL |     type FErr2<T> = Self::E<'static, T, u32>;
diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs
index 1622b92aa0c..c58f9cf1dfc 100644
--- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs
+++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs
@@ -4,8 +4,8 @@ trait X {
 
 const _: () = {
   fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
-      //~^ ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
-      //~| ERROR this associated type takes 0 generic arguments but 1 generic argument
+      //~^ ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
+      //~| ERROR associated type takes 0 generic arguments but 1 generic argument
 };
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
index 0a09ec5dc49..fab5b474d92 100644
--- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
+++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/trait-path-type-error-once-implemented.rs:6:29
    |
 LL |   fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
@@ -14,7 +14,7 @@ help: add missing lifetime argument
 LL |   fn f2<'a>(arg : Box<dyn X<Y<'_, 1> = &'a ()>>) {}
    |                               +++
 
-error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/trait-path-type-error-once-implemented.rs:6:29
    |
 LL |   fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
diff --git a/tests/ui/generics/bad-mid-path-type-params.rs b/tests/ui/generics/bad-mid-path-type-params.rs
index 23a5d1525d9..37d484cba0b 100644
--- a/tests/ui/generics/bad-mid-path-type-params.rs
+++ b/tests/ui/generics/bad-mid-path-type-params.rs
@@ -28,17 +28,17 @@ impl Trait<isize> for S2 {
 
 fn foo<'a>() {
     let _ = S::new::<isize,f64>(1, 1.0);
-    //~^ ERROR this associated function takes 1
+    //~^ ERROR associated function takes 1
 
     let _ = S::<'a,isize>::new::<f64>(1, 1.0);
-    //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+    //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied
 
     let _: S2 = Trait::new::<isize,f64>(1, 1.0);
-    //~^ ERROR this associated function takes 1
+    //~^ ERROR associated function takes 1
 
     let _: S2 = Trait::<'a,isize>::new::<f64,f64>(1, 1.0);
-    //~^ ERROR this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
-    //~| ERROR this associated function takes 1
+    //~^ ERROR trait takes 0 lifetime arguments but 1 lifetime argument was supplied
+    //~| ERROR associated function takes 1
 }
 
 fn main() {}
diff --git a/tests/ui/generics/bad-mid-path-type-params.stderr b/tests/ui/generics/bad-mid-path-type-params.stderr
index aee2b60159f..71e15dd4c92 100644
--- a/tests/ui/generics/bad-mid-path-type-params.stderr
+++ b/tests/ui/generics/bad-mid-path-type-params.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this associated function takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: associated function takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/bad-mid-path-type-params.rs:30:16
    |
 LL |     let _ = S::new::<isize,f64>(1, 1.0);
@@ -12,7 +12,7 @@ note: associated function defined here, with 1 generic parameter: `U`
 LL |     fn new<U>(x: T, _: U) -> S<T> {
    |        ^^^ -
 
-error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/bad-mid-path-type-params.rs:33:13
    |
 LL |     let _ = S::<'a,isize>::new::<f64>(1, 1.0);
@@ -26,7 +26,7 @@ note: struct defined here, with 0 lifetime parameters
 LL | struct S<T> {
    |        ^
 
-error[E0107]: this associated function takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: associated function takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/bad-mid-path-type-params.rs:36:24
    |
 LL |     let _: S2 = Trait::new::<isize,f64>(1, 1.0);
@@ -40,7 +40,7 @@ note: associated function defined here, with 1 generic parameter: `U`
 LL |     fn new<U>(x: T, y: U) -> Self;
    |        ^^^ -
 
-error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/bad-mid-path-type-params.rs:39:17
    |
 LL |     let _: S2 = Trait::<'a,isize>::new::<f64,f64>(1, 1.0);
@@ -54,7 +54,7 @@ note: trait defined here, with 0 lifetime parameters
 LL | trait Trait<T> {
    |       ^^^^^
 
-error[E0107]: this associated function takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: associated function takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/bad-mid-path-type-params.rs:39:36
    |
 LL |     let _: S2 = Trait::<'a,isize>::new::<f64,f64>(1, 1.0);
diff --git a/tests/ui/generics/generic-arg-mismatch-recover.rs b/tests/ui/generics/generic-arg-mismatch-recover.rs
index 2cf7f1d657b..947f33414db 100644
--- a/tests/ui/generics/generic-arg-mismatch-recover.rs
+++ b/tests/ui/generics/generic-arg-mismatch-recover.rs
@@ -4,9 +4,9 @@ struct Bar<'a>(&'a ());
 
 fn main() {
     Foo::<'static, 'static, ()>(&0);
-    //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+    //~^ ERROR struct takes 1 lifetime argument but 2 lifetime arguments were supplied
 
     Bar::<'static, 'static, ()>(&());
-    //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
-    //~| ERROR this struct takes 0
+    //~^ ERROR struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+    //~| ERROR struct takes 0
 }
diff --git a/tests/ui/generics/generic-arg-mismatch-recover.stderr b/tests/ui/generics/generic-arg-mismatch-recover.stderr
index 45fea925f27..f549a7180fc 100644
--- a/tests/ui/generics/generic-arg-mismatch-recover.stderr
+++ b/tests/ui/generics/generic-arg-mismatch-recover.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/generic-arg-mismatch-recover.rs:6:5
    |
 LL |     Foo::<'static, 'static, ()>(&0);
@@ -12,7 +12,7 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct Foo<'a, T: 'a>(&'a T);
    |        ^^^ --
 
-error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/generic-arg-mismatch-recover.rs:9:5
    |
 LL |     Bar::<'static, 'static, ()>(&());
@@ -26,7 +26,7 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct Bar<'a>(&'a ());
    |        ^^^ --
 
-error[E0107]: this struct takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/generic-arg-mismatch-recover.rs:9:5
    |
 LL |     Bar::<'static, 'static, ()>(&());
diff --git a/tests/ui/generics/generic-impl-less-params-with-defaults.rs b/tests/ui/generics/generic-impl-less-params-with-defaults.rs
index 66afbb58ad4..6c00411561e 100644
--- a/tests/ui/generics/generic-impl-less-params-with-defaults.rs
+++ b/tests/ui/generics/generic-impl-less-params-with-defaults.rs
@@ -9,5 +9,5 @@ impl<A, B, C> Foo<A, B, C> {
 
 fn main() {
     Foo::<isize>::new();
-    //~^ ERROR this struct takes at least 2 generic arguments but 1 generic argument
+    //~^ ERROR struct takes at least 2 generic arguments but 1 generic argument
 }
diff --git a/tests/ui/generics/generic-impl-less-params-with-defaults.stderr b/tests/ui/generics/generic-impl-less-params-with-defaults.stderr
index cdbb57902e4..262561fa81e 100644
--- a/tests/ui/generics/generic-impl-less-params-with-defaults.stderr
+++ b/tests/ui/generics/generic-impl-less-params-with-defaults.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
+error[E0107]: struct takes at least 2 generic arguments but 1 generic argument was supplied
   --> $DIR/generic-impl-less-params-with-defaults.rs:11:5
    |
 LL |     Foo::<isize>::new();
diff --git a/tests/ui/generics/generic-impl-more-params-with-defaults.rs b/tests/ui/generics/generic-impl-more-params-with-defaults.rs
index a283323742a..be633ec464f 100644
--- a/tests/ui/generics/generic-impl-more-params-with-defaults.rs
+++ b/tests/ui/generics/generic-impl-more-params-with-defaults.rs
@@ -11,5 +11,5 @@ impl<T, A> Vec<T, A> {
 
 fn main() {
     Vec::<isize, Heap, bool>::new();
-    //~^ ERROR this struct takes at most 2 generic arguments but 3 generic arguments were supplied
+    //~^ ERROR struct takes at most 2 generic arguments but 3 generic arguments were supplied
 }
diff --git a/tests/ui/generics/generic-impl-more-params-with-defaults.stderr b/tests/ui/generics/generic-impl-more-params-with-defaults.stderr
index fe9b670da79..2f4682c4e5a 100644
--- a/tests/ui/generics/generic-impl-more-params-with-defaults.stderr
+++ b/tests/ui/generics/generic-impl-more-params-with-defaults.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes at most 2 generic arguments but 3 generic arguments were supplied
+error[E0107]: struct takes at most 2 generic arguments but 3 generic arguments were supplied
   --> $DIR/generic-impl-more-params-with-defaults.rs:13:5
    |
 LL |     Vec::<isize, Heap, bool>::new();
diff --git a/tests/ui/generics/generic-type-more-params-with-defaults.rs b/tests/ui/generics/generic-type-more-params-with-defaults.rs
index 3dab03297c9..b83fdb5c455 100644
--- a/tests/ui/generics/generic-type-more-params-with-defaults.rs
+++ b/tests/ui/generics/generic-type-more-params-with-defaults.rs
@@ -7,5 +7,5 @@ struct Vec<T, A = Heap>(
 
 fn main() {
     let _: Vec<isize, Heap, bool>;
-    //~^ ERROR this struct takes at most 2 generic arguments but 3 generic arguments
+    //~^ ERROR struct takes at most 2 generic arguments but 3 generic arguments
 }
diff --git a/tests/ui/generics/generic-type-more-params-with-defaults.stderr b/tests/ui/generics/generic-type-more-params-with-defaults.stderr
index 7f0198f0e84..4d01ba1f453 100644
--- a/tests/ui/generics/generic-type-more-params-with-defaults.stderr
+++ b/tests/ui/generics/generic-type-more-params-with-defaults.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes at most 2 generic arguments but 3 generic arguments were supplied
+error[E0107]: struct takes at most 2 generic arguments but 3 generic arguments were supplied
   --> $DIR/generic-type-more-params-with-defaults.rs:9:12
    |
 LL |     let _: Vec<isize, Heap, bool>;
diff --git a/tests/ui/generics/wrong-number-of-args.rs b/tests/ui/generics/wrong-number-of-args.rs
index cd2f96a1819..e4eaff21af1 100644
--- a/tests/ui/generics/wrong-number-of-args.rs
+++ b/tests/ui/generics/wrong-number-of-args.rs
@@ -4,18 +4,18 @@ mod no_generics {
     type A = Ty;
 
     type B = Ty<'static>;
-    //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument
+    //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument
     //~| HELP remove these generics
 
     type C = Ty<'static, usize>;
-    //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument
-    //~| ERROR this struct takes 0 generic arguments but 1 generic argument
+    //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument
+    //~| ERROR struct takes 0 generic arguments but 1 generic argument
     //~| HELP remove this lifetime argument
     //~| HELP remove this generic argument
 
     type D = Ty<'static, usize, { 0 }>;
-    //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument
-    //~| ERROR this struct takes 0 generic arguments but 2 generic arguments
+    //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument
+    //~| ERROR struct takes 0 generic arguments but 2 generic arguments
     //~| HELP remove this lifetime argument
     //~| HELP remove these generic arguments
 }
@@ -28,17 +28,17 @@ mod type_and_type {
     //~| HELP add missing
 
     type B = Ty<usize>;
-    //~^ ERROR this struct takes 2 generic arguments but 1 generic argument
+    //~^ ERROR struct takes 2 generic arguments but 1 generic argument
     //~| HELP add missing
 
     type C = Ty<usize, String>;
 
     type D = Ty<usize, String, char>;
-    //~^ ERROR this struct takes 2 generic arguments but 3 generic arguments
+    //~^ ERROR struct takes 2 generic arguments but 3 generic arguments
     //~| HELP remove this
 
     type E = Ty<>;
-    //~^ ERROR this struct takes 2 generic arguments but 0 generic arguments were supplied
+    //~^ ERROR struct takes 2 generic arguments but 0 generic arguments were supplied
     //~| HELP add missing
 }
 
@@ -52,7 +52,7 @@ mod lifetime_and_type {
     //~| HELP consider introducing
 
     type B = Ty<'static>;
-    //~^ ERROR this struct takes 1 generic argument but 0 generic arguments
+    //~^ ERROR struct takes 1 generic argument but 0 generic arguments
     //~| HELP add missing
 
     type C = Ty<usize>;
@@ -62,14 +62,14 @@ mod lifetime_and_type {
     type D = Ty<'static, usize>;
 
     type E = Ty<>;
-    //~^ ERROR this struct takes 1 generic argument but 0 generic arguments
+    //~^ ERROR struct takes 1 generic argument but 0 generic arguments
     //~| ERROR missing lifetime specifier
     //~| HELP consider introducing
     //~| HELP add missing
 
     type F = Ty<'static, usize, 'static, usize>;
-    //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments
-    //~| ERROR this struct takes 1 generic argument but 2 generic arguments
+    //~^ ERROR struct takes 1 lifetime argument but 2 lifetime arguments
+    //~| ERROR struct takes 1 generic argument but 2 generic arguments
     //~| HELP remove this lifetime argument
     //~| HELP remove this generic argument
 }
@@ -82,7 +82,7 @@ mod type_and_type_and_type {
     //~| HELP add missing
 
     type B = Ty<usize>;
-    //~^ ERROR this struct takes at least 2
+    //~^ ERROR struct takes at least 2
     //~| HELP add missing
 
     type C = Ty<usize, String>;
@@ -90,11 +90,11 @@ mod type_and_type_and_type {
     type D = Ty<usize, String, char>;
 
     type E = Ty<usize, String, char, f64>;
-    //~^ ERROR this struct takes at most 3
+    //~^ ERROR struct takes at most 3
     //~| HELP remove
 
     type F = Ty<>;
-    //~^ ERROR this struct takes at least 2 generic arguments but 0 generic arguments
+    //~^ ERROR struct takes at least 2 generic arguments but 0 generic arguments
     //~| HELP add missing
 }
 
@@ -114,7 +114,7 @@ mod r#trait {
     }
 
     type A = Box<dyn NonGeneric<usize>>;
-    //~^ ERROR this trait takes 0 generic arguments but 1 generic argument
+    //~^ ERROR trait takes 0 generic arguments but 1 generic argument
     //~| HELP remove
 
     type B = Box<dyn GenericLifetime>;
@@ -123,7 +123,7 @@ mod r#trait {
     //~| HELP consider making the bound lifetime-generic
 
     type C = Box<dyn GenericLifetime<'static, 'static>>;
-    //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
+    //~^ ERROR trait takes 1 lifetime argument but 2 lifetime arguments were supplied
     //~| HELP remove
 
     type D = Box<dyn GenericType>;
@@ -131,7 +131,7 @@ mod r#trait {
     //~| HELP add missing
 
     type E = Box<dyn GenericType<String, usize>>;
-    //~^ ERROR this trait takes 1 generic argument but 2 generic arguments
+    //~^ ERROR trait takes 1 generic argument but 2 generic arguments
     //~| HELP remove
 
     type F = Box<dyn GenericLifetime<>>;
@@ -140,7 +140,7 @@ mod r#trait {
     //~| HELP consider making the bound lifetime-generic
 
     type G = Box<dyn GenericType<>>;
-    //~^ ERROR this trait takes 1 generic argument but 0 generic arguments
+    //~^ ERROR trait takes 1 generic argument but 0 generic arguments
     //~| HELP add missing
 }
 
@@ -151,7 +151,7 @@ mod associated_item {
         }
 
         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
-        //~^ ERROR this trait takes 0 generic arguments but 1 generic argument
+        //~^ ERROR trait takes 0 generic arguments but 1 generic argument
         //~| HELP remove
     }
 
@@ -166,14 +166,14 @@ mod associated_item {
         //~| HELP consider making the bound lifetime-generic
 
         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
-        //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
+        //~^ ERROR trait takes 1 lifetime argument but 2 lifetime arguments were supplied
         //~| HELP remove
 
         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
         //~| HELP consider making the bound lifetime-generic
-        //~| ERROR this trait takes 0 generic arguments but 1 generic argument
+        //~| ERROR trait takes 0 generic arguments but 1 generic argument
         //~| HELP remove
     }
 
@@ -183,17 +183,17 @@ mod associated_item {
         }
 
         type A = Box<dyn GenericTypeAT<AssocTy=()>>;
-        //~^ ERROR this trait takes 1 generic argument but 0 generic arguments
+        //~^ ERROR trait takes 1 generic argument but 0 generic arguments
         //~| HELP add missing
 
         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
-        //~^ ERROR this trait takes 1 generic argument but 2 generic arguments
+        //~^ ERROR trait takes 1 generic argument but 2 generic arguments
         //~| HELP remove
 
         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
-        //~^ ERROR this trait takes 1 generic argument but 0 generic arguments
+        //~^ ERROR trait takes 1 generic argument but 0 generic arguments
         //~| HELP add missing
-        //~| ERROR this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
+        //~| ERROR trait takes 0 lifetime arguments but 1 lifetime argument was supplied
         //~| HELP remove
     }
 
@@ -203,20 +203,20 @@ mod associated_item {
         }
 
         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
-        //~^ ERROR this trait takes 1 generic argument but 0 generic arguments
+        //~^ ERROR trait takes 1 generic argument but 0 generic arguments
         //~| HELP add missing
         //~| ERROR missing lifetime specifier
         //~| HELP consider introducing
         //~| HELP consider making the bound lifetime-generic
 
         type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
-        //~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied
+        //~^ ERROR trait takes 1 generic argument but 0 generic arguments were supplied
         //~| HELP add missing
 
         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
-        //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
+        //~^ ERROR trait takes 1 lifetime argument but 2 lifetime arguments were supplied
         //~| HELP remove
-        //~| ERROR this trait takes 1 generic argument but 0 generic arguments
+        //~| ERROR trait takes 1 generic argument but 0 generic arguments
         //~| HELP add missing
 
         type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
@@ -228,21 +228,21 @@ mod associated_item {
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
         //~| HELP consider making the bound lifetime-generic
-        //~| ERROR this trait takes 1 generic argument but 2 generic arguments
+        //~| ERROR trait takes 1 generic argument but 2 generic arguments
         //~| HELP remove
 
         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
-        //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
+        //~^ ERROR trait takes 1 lifetime argument but 2 lifetime arguments were supplied
         //~| HELP remove
 
         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>;
-        //~^ ERROR this trait takes 1 generic argument but 2 generic arguments
+        //~^ ERROR trait takes 1 generic argument but 2 generic arguments
         //~| HELP remove
 
         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
-        //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
+        //~^ ERROR trait takes 1 lifetime argument but 2 lifetime arguments were supplied
         //~| HELP remove
-        //~| ERROR this trait takes 1 generic argument but 2 generic arguments
+        //~| ERROR trait takes 1 generic argument but 2 generic arguments
         //~| HELP remove
     }
 
@@ -252,15 +252,15 @@ mod associated_item {
         }
 
         type A = Box<dyn GenericTypeTypeAT<AssocTy=()>>;
-        //~^ ERROR this trait takes 2 generic arguments but 0 generic arguments
+        //~^ ERROR trait takes 2 generic arguments but 0 generic arguments
         //~| HELP add missing
 
         type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
-        //~^ ERROR this trait takes 2 generic arguments but 1 generic argument
+        //~^ ERROR trait takes 2 generic arguments but 1 generic argument
         //~| HELP add missing
 
         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
-        //~^ ERROR this trait takes 2 generic arguments but 3 generic arguments
+        //~^ ERROR trait takes 2 generic arguments but 3 generic arguments
         //~| HELP remove
     }
 
@@ -275,7 +275,7 @@ mod associated_item {
         //~| HELP consider making the bound lifetime-generic
 
         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
-        //~^ ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+        //~^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied
         //~| HELP add missing lifetime argument
     }
 
@@ -288,17 +288,17 @@ mod associated_item {
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
         //~| HELP consider making the bound lifetime-generic
-        //~| ERROR this trait takes 1 generic argument but 0 generic arguments
+        //~| ERROR trait takes 1 generic argument but 0 generic arguments
         //~| HELP add missing
 
         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
-        //~^ ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+        //~^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied
         //~| HELP add missing lifetime argument
-        //~| ERROR this trait takes 1 generic argument but 0 generic arguments
+        //~| ERROR trait takes 1 generic argument but 0 generic arguments
         //~| HELP add missing
 
         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy=()>>;
-        //~^ ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+        //~^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied
         //~| HELP add missing lifetime argument
     }
 }
@@ -312,21 +312,21 @@ mod stdlib {
         //~| HELP add missing
 
         type B = HashMap<String>;
-        //~^ ERROR this struct takes at least
+        //~^ ERROR struct takes at least
         //~| HELP add missing
 
         type C = HashMap<'static>;
-        //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument
+        //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument
         //~| HELP remove these generics
-        //~| ERROR this struct takes at least 2
+        //~| ERROR struct takes at least 2
         //~| HELP add missing
 
         type D = HashMap<usize, String, char, f64>;
-        //~^ ERROR this struct takes at most 3
+        //~^ ERROR struct takes at most 3
         //~| HELP remove this
 
         type E = HashMap<>;
-        //~^ ERROR this struct takes at least 2 generic arguments but 0 generic arguments
+        //~^ ERROR struct takes at least 2 generic arguments but 0 generic arguments
         //~| HELP add missing
     }
 
@@ -336,21 +336,21 @@ mod stdlib {
         //~| HELP add missing
 
         type B = Result<String>;
-        //~^ ERROR this enum takes 2 generic arguments but 1 generic argument
+        //~^ ERROR enum takes 2 generic arguments but 1 generic argument
         //~| HELP add missing
 
         type C = Result<'static>;
-        //~^ ERROR this enum takes 0 lifetime arguments but 1 lifetime argument
+        //~^ ERROR enum takes 0 lifetime arguments but 1 lifetime argument
         //~| HELP remove these generics
-        //~| ERROR this enum takes 2 generic arguments but 0 generic arguments
+        //~| ERROR enum takes 2 generic arguments but 0 generic arguments
         //~| HELP add missing
 
         type D = Result<usize, String, char>;
-        //~^ ERROR this enum takes 2 generic arguments but 3 generic arguments
+        //~^ ERROR enum takes 2 generic arguments but 3 generic arguments
         //~| HELP remove
 
         type E = Result<>;
-        //~^ ERROR this enum takes 2 generic arguments but 0 generic arguments
+        //~^ ERROR enum takes 2 generic arguments but 0 generic arguments
         //~| HELP add missing
     }
 }
diff --git a/tests/ui/generics/wrong-number-of-args.stderr b/tests/ui/generics/wrong-number-of-args.stderr
index 75e33f680ea..9006fb10b67 100644
--- a/tests/ui/generics/wrong-number-of-args.stderr
+++ b/tests/ui/generics/wrong-number-of-args.stderr
@@ -167,7 +167,7 @@ help: consider introducing a named lifetime parameter
 LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>;
    |               ++++                                         +++++++
 
-error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:6:14
    |
 LL |     type B = Ty<'static>;
@@ -181,7 +181,7 @@ note: struct defined here, with 0 lifetime parameters
 LL |     struct Ty;
    |            ^^
 
-error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:10:14
    |
 LL |     type C = Ty<'static, usize>;
@@ -195,7 +195,7 @@ note: struct defined here, with 0 lifetime parameters
 LL |     struct Ty;
    |            ^^
 
-error[E0107]: this struct takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:10:14
    |
 LL |     type C = Ty<'static, usize>;
@@ -209,7 +209,7 @@ note: struct defined here, with 0 generic parameters
 LL |     struct Ty;
    |            ^^
 
-error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:16:14
    |
 LL |     type D = Ty<'static, usize, { 0 }>;
@@ -223,7 +223,7 @@ note: struct defined here, with 0 lifetime parameters
 LL |     struct Ty;
    |            ^^
 
-error[E0107]: this struct takes 0 generic arguments but 2 generic arguments were supplied
+error[E0107]: struct takes 0 generic arguments but 2 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:16:14
    |
 LL |     type D = Ty<'static, usize, { 0 }>;
@@ -253,7 +253,7 @@ help: add missing generic arguments
 LL |     type A = Ty<A, B>;
    |                ++++++
 
-error[E0107]: this struct takes 2 generic arguments but 1 generic argument was supplied
+error[E0107]: struct takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:30:14
    |
 LL |     type B = Ty<usize>;
@@ -271,7 +271,7 @@ help: add missing generic argument
 LL |     type B = Ty<usize, B>;
    |                      +++
 
-error[E0107]: this struct takes 2 generic arguments but 3 generic arguments were supplied
+error[E0107]: struct takes 2 generic arguments but 3 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:36:14
    |
 LL |     type D = Ty<usize, String, char>;
@@ -285,7 +285,7 @@ note: struct defined here, with 2 generic parameters: `A`, `B`
 LL |     struct Ty<A, B>;
    |            ^^ -  -
 
-error[E0107]: this struct takes 2 generic arguments but 0 generic arguments were supplied
+error[E0107]: struct takes 2 generic arguments but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:40:14
    |
 LL |     type E = Ty<>;
@@ -317,7 +317,7 @@ help: add missing generic argument
 LL |     type A = Ty<T>;
    |                +++
 
-error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:54:14
    |
 LL |     type B = Ty<'static>;
@@ -333,7 +333,7 @@ help: add missing generic argument
 LL |     type B = Ty<'static, T>;
    |                        +++
 
-error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:64:14
    |
 LL |     type E = Ty<>;
@@ -349,7 +349,7 @@ help: add missing generic argument
 LL |     type E = Ty<T>;
    |                 +
 
-error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/wrong-number-of-args.rs:70:14
    |
 LL |     type F = Ty<'static, usize, 'static, usize>;
@@ -363,7 +363,7 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL |     struct Ty<'a, T>;
    |            ^^ --
 
-error[E0107]: this struct takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:70:14
    |
 LL |     type F = Ty<'static, usize, 'static, usize>;
@@ -393,7 +393,7 @@ help: add missing generic arguments
 LL |     type A = Ty<A, B>;
    |                ++++++
 
-error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
+error[E0107]: struct takes at least 2 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:84:14
    |
 LL |     type B = Ty<usize>;
@@ -411,7 +411,7 @@ help: add missing generic argument
 LL |     type B = Ty<usize, B>;
    |                      +++
 
-error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
+error[E0107]: struct takes at most 3 generic arguments but 4 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:92:14
    |
 LL |     type E = Ty<usize, String, char, f64>;
@@ -425,7 +425,7 @@ note: struct defined here, with at most 3 generic parameters: `A`, `B`, `C`
 LL |     struct Ty<A, B, C = &'static str>;
    |            ^^ -  -  ----------------
 
-error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
+error[E0107]: struct takes at least 2 generic arguments but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:96:14
    |
 LL |     type F = Ty<>;
@@ -441,7 +441,7 @@ help: add missing generic arguments
 LL |     type F = Ty<A, B>;
    |                 ++++
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:116:22
    |
 LL |     type A = Box<dyn NonGeneric<usize>>;
@@ -455,7 +455,7 @@ note: trait defined here, with 0 generic parameters
 LL |     trait NonGeneric {
    |           ^^^^^^^^^^
 
-error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/wrong-number-of-args.rs:125:22
    |
 LL |     type C = Box<dyn GenericLifetime<'static, 'static>>;
@@ -485,7 +485,7 @@ help: add missing generic argument
 LL |     type D = Box<dyn GenericType<A>>;
    |                                 +++
 
-error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:133:22
    |
 LL |     type E = Box<dyn GenericType<String, usize>>;
@@ -499,7 +499,7 @@ note: trait defined here, with 1 generic parameter: `A`
 LL |     trait GenericType<A> {
    |           ^^^^^^^^^^^ -
 
-error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:142:22
    |
 LL |     type G = Box<dyn GenericType<>>;
@@ -515,7 +515,7 @@ help: add missing generic argument
 LL |     type G = Box<dyn GenericType<A>>;
    |                                  +
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:153:26
    |
 LL |         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
@@ -529,7 +529,7 @@ note: trait defined here, with 0 generic parameters
 LL |         trait NonGenericAT {
    |               ^^^^^^^^^^^^
 
-error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/wrong-number-of-args.rs:168:26
    |
 LL |         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
@@ -543,7 +543,7 @@ note: trait defined here, with 1 lifetime parameter: `'a`
 LL |         trait GenericLifetimeAT<'a> {
    |               ^^^^^^^^^^^^^^^^^ --
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:172:26
    |
 LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
@@ -557,7 +557,7 @@ note: trait defined here, with 0 generic parameters
 LL |         trait GenericLifetimeAT<'a> {
    |               ^^^^^^^^^^^^^^^^^
 
-error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:185:26
    |
 LL |         type A = Box<dyn GenericTypeAT<AssocTy=()>>;
@@ -573,7 +573,7 @@ help: add missing generic argument
 LL |         type A = Box<dyn GenericTypeAT<A, AssocTy=()>>;
    |                                        ++
 
-error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:189:26
    |
 LL |         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
@@ -587,7 +587,7 @@ note: trait defined here, with 1 generic parameter: `A`
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
 
-error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:193:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
@@ -601,7 +601,7 @@ note: trait defined here, with 0 lifetime parameters
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^
 
-error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:193:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
@@ -617,7 +617,7 @@ help: add missing generic argument
 LL |         type C = Box<dyn GenericTypeAT<'static, A, AssocTy=()>>;
    |                                               +++
 
-error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:205:26
    |
 LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
@@ -633,7 +633,7 @@ help: add missing generic argument
 LL |         type A = Box<dyn GenericLifetimeTypeAT<A, AssocTy=()>>;
    |                                                ++
 
-error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:212:26
    |
 LL |         type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
@@ -649,7 +649,7 @@ help: add missing generic argument
 LL |         type B = Box<dyn GenericLifetimeTypeAT<'static, A, AssocTy=()>>;
    |                                                       +++
 
-error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/wrong-number-of-args.rs:216:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
@@ -663,7 +663,7 @@ note: trait defined here, with 1 lifetime parameter: `'a`
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
-error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:216:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
@@ -679,7 +679,7 @@ help: add missing generic argument
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, A, AssocTy=()>>;
    |                                                                +++
 
-error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:227:26
    |
 LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
@@ -693,7 +693,7 @@ note: trait defined here, with 1 generic parameter: `A`
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
-error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/wrong-number-of-args.rs:234:26
    |
 LL |         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
@@ -707,7 +707,7 @@ note: trait defined here, with 1 lifetime parameter: `'a`
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
-error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:238:26
    |
 LL |         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>;
@@ -721,7 +721,7 @@ note: trait defined here, with 1 generic parameter: `A`
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
-error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/wrong-number-of-args.rs:242:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
@@ -735,7 +735,7 @@ note: trait defined here, with 1 lifetime parameter: `'a`
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
-error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:242:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
@@ -749,7 +749,7 @@ note: trait defined here, with 1 generic parameter: `A`
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
-error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied
+error[E0107]: trait takes 2 generic arguments but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:254:26
    |
 LL |         type A = Box<dyn GenericTypeTypeAT<AssocTy=()>>;
@@ -765,7 +765,7 @@ help: add missing generic arguments
 LL |         type A = Box<dyn GenericTypeTypeAT<A, B, AssocTy=()>>;
    |                                            +++++
 
-error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:258:26
    |
 LL |         type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
@@ -783,7 +783,7 @@ help: add missing generic argument
 LL |         type B = Box<dyn GenericTypeTypeAT<(), B, AssocTy=()>>;
    |                                              +++
 
-error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied
+error[E0107]: trait takes 2 generic arguments but 3 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:262:26
    |
 LL |         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
@@ -797,7 +797,7 @@ note: trait defined here, with 2 generic parameters: `A`, `B`
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
 
-error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:277:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
@@ -815,7 +815,7 @@ help: add missing lifetime argument
 LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, 'static, AssocTy=()>>;
    |                                                           +++++++++
 
-error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:287:26
    |
 LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
@@ -831,7 +831,7 @@ help: add missing generic argument
 LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<A, AssocTy=()>>;
    |                                                        ++
 
-error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:294:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
@@ -849,7 +849,7 @@ help: add missing lifetime argument
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'static, AssocTy=()>>;
    |                                                               +++++++++
 
-error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:294:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
@@ -865,7 +865,7 @@ help: add missing generic argument
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, A, AssocTy=()>>;
    |                                                               +++
 
-error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:300:26
    |
 LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy=()>>;
@@ -894,7 +894,7 @@ help: add missing generic arguments
 LL |         type A = HashMap<K, V>;
    |                         ++++++
 
-error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
+error[E0107]: struct takes at least 2 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:314:18
    |
 LL |         type B = HashMap<String>;
@@ -907,7 +907,7 @@ help: add missing generic argument
 LL |         type B = HashMap<String, V>;
    |                                +++
 
-error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:318:18
    |
 LL |         type C = HashMap<'static>;
@@ -915,7 +915,7 @@ LL |         type C = HashMap<'static>;
    |                  |
    |                  expected 0 lifetime arguments
 
-error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
+error[E0107]: struct takes at least 2 generic arguments but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:318:18
    |
 LL |         type C = HashMap<'static>;
@@ -926,7 +926,7 @@ help: add missing generic arguments
 LL |         type C = HashMap<'static, K, V>;
    |                                 ++++++
 
-error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
+error[E0107]: struct takes at most 3 generic arguments but 4 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:324:18
    |
 LL |         type D = HashMap<usize, String, char, f64>;
@@ -934,7 +934,7 @@ LL |         type D = HashMap<usize, String, char, f64>;
    |                  |
    |                  expected at most 3 generic arguments
 
-error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
+error[E0107]: struct takes at least 2 generic arguments but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:328:18
    |
 LL |         type E = HashMap<>;
@@ -956,7 +956,7 @@ help: add missing generic arguments
 LL |         type A = Result<T, E>;
    |                        ++++++
 
-error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
+error[E0107]: enum takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/wrong-number-of-args.rs:338:18
    |
 LL |         type B = Result<String>;
@@ -969,7 +969,7 @@ help: add missing generic argument
 LL |         type B = Result<String, E>;
    |                               +++
 
-error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: enum takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:342:18
    |
 LL |         type C = Result<'static>;
@@ -977,7 +977,7 @@ LL |         type C = Result<'static>;
    |                  |
    |                  expected 0 lifetime arguments
 
-error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
+error[E0107]: enum takes 2 generic arguments but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:342:18
    |
 LL |         type C = Result<'static>;
@@ -988,7 +988,7 @@ help: add missing generic arguments
 LL |         type C = Result<'static, T, E>;
    |                                ++++++
 
-error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied
+error[E0107]: enum takes 2 generic arguments but 3 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:348:18
    |
 LL |         type D = Result<usize, String, char>;
@@ -996,7 +996,7 @@ LL |         type D = Result<usize, String, char>;
    |                  |
    |                  expected 2 generic arguments
 
-error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
+error[E0107]: enum takes 2 generic arguments but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:352:18
    |
 LL |         type E = Result<>;
diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
index c8b82783ea8..9c101101870 100644
--- a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
+++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this function takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: function takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/explicit-generic-args-for-impl.rs:4:5
    |
 LL |     foo::<str, String>("".to_string());
diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr
index 9d6db88d364..a26460c8ecc 100644
--- a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr
+++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this function takes 2 generic arguments but 1 generic argument was supplied
+error[E0107]: function takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/not-enough-args.rs:4:5
    |
 LL |     f::<[u8]>("a", b"a");
diff --git a/tests/ui/impl-trait/issues/issue-54600.stderr b/tests/ui/impl-trait/issues/issue-54600.stderr
index 316566a57a8..7ef063af952 100644
--- a/tests/ui/impl-trait/issues/issue-54600.stderr
+++ b/tests/ui/impl-trait/issues/issue-54600.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/issue-54600.rs:4:19
    |
 LL |     let x: Option<impl Debug> = Some(44_u32);
diff --git a/tests/ui/impl-trait/issues/issue-54840.stderr b/tests/ui/impl-trait/issues/issue-54840.stderr
index 8d82133ac90..1d1316f0e11 100644
--- a/tests/ui/impl-trait/issues/issue-54840.stderr
+++ b/tests/ui/impl-trait/issues/issue-54840.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/issue-54840.rs:5:13
    |
 LL |     let j: &impl Add = &i;
diff --git a/tests/ui/impl-trait/issues/issue-58504.stderr b/tests/ui/impl-trait/issues/issue-58504.stderr
index 6656e9fc3fb..26ec2a4f9cf 100644
--- a/tests/ui/impl-trait/issues/issue-58504.stderr
+++ b/tests/ui/impl-trait/issues/issue-58504.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/issue-58504.rs:10:16
    |
 LL |     let gens: [impl Generator<Return=!, Yield=()>;2] = [ mk_gen(), mk_gen() ];
diff --git a/tests/ui/impl-trait/issues/issue-58956.stderr b/tests/ui/impl-trait/issues/issue-58956.stderr
index f591c07bcf5..2b4d0abdffc 100644
--- a/tests/ui/impl-trait/issues/issue-58956.stderr
+++ b/tests/ui/impl-trait/issues/issue-58956.stderr
@@ -1,10 +1,10 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in const type
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in const types
   --> $DIR/issue-58956.rs:7:11
    |
 LL | const _A: impl Lam = {
    |           ^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/issue-58956.rs:9:17
    |
 LL |     let x: Wrap<impl Lam> = Wrap(B);
diff --git a/tests/ui/impl-trait/issues/issue-70971.stderr b/tests/ui/impl-trait/issues/issue-70971.stderr
index 4dda4c22aa2..d066256bfb0 100644
--- a/tests/ui/impl-trait/issues/issue-70971.stderr
+++ b/tests/ui/impl-trait/issues/issue-70971.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/issue-70971.rs:2:14
    |
 LL |     let x : (impl Copy,) = (true,);
diff --git a/tests/ui/impl-trait/issues/issue-79099.stderr b/tests/ui/impl-trait/issues/issue-79099.stderr
index 362c67dafd2..580250a62fe 100644
--- a/tests/ui/impl-trait/issues/issue-79099.stderr
+++ b/tests/ui/impl-trait/issues/issue-79099.stderr
@@ -9,7 +9,7 @@ LL |         let f: impl core::future::Future<Output = u8> = async { 1 };
    = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/issue-79099.rs:3:16
    |
 LL |         let f: impl core::future::Future<Output = u8> = async { 1 };
diff --git a/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr b/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr
index a227f0ba7d1..656bd047061 100644
--- a/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr
+++ b/tests/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr
@@ -1,10 +1,10 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter default
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults
   --> $DIR/issue-83929-impl-trait-in-generic-default.rs:1:16
    |
 LL | struct Foo<T = impl Copy>(T);
    |                ^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter default
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults
   --> $DIR/issue-83929-impl-trait-in-generic-default.rs:4:20
    |
 LL | type Result<T, E = impl std::error::Error> = std::result::Result<T, E>;
diff --git a/tests/ui/impl-trait/issues/issue-84919.stderr b/tests/ui/impl-trait/issues/issue-84919.stderr
index 5abe1bd8779..36010fdef36 100644
--- a/tests/ui/impl-trait/issues/issue-84919.stderr
+++ b/tests/ui/impl-trait/issues/issue-84919.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/issue-84919.rs:5:13
    |
 LL |     let _x: impl Trait = ();
diff --git a/tests/ui/impl-trait/issues/issue-86642.stderr b/tests/ui/impl-trait/issues/issue-86642.stderr
index a137777840b..b6f8a54f35a 100644
--- a/tests/ui/impl-trait/issues/issue-86642.stderr
+++ b/tests/ui/impl-trait/issues/issue-86642.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in const type
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in const types
   --> $DIR/issue-86642.rs:1:11
    |
 LL | static x: impl Fn(&str) -> Result<&str, ()> = move |source| {
diff --git a/tests/ui/impl-trait/issues/issue-87295.stderr b/tests/ui/impl-trait/issues/issue-87295.stderr
index 0b043056b84..ec59b719c10 100644
--- a/tests/ui/impl-trait/issues/issue-87295.stderr
+++ b/tests/ui/impl-trait/issues/issue-87295.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/issue-87295.rs:16:31
    |
 LL |     let _do_not_waste: Struct<impl Trait<Output = i32>> = Struct::new(());
diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr
index 9a8f5a34068..ffe84b8e86f 100644
--- a/tests/ui/impl-trait/nested_impl_trait.stderr
+++ b/tests/ui/impl-trait/nested_impl_trait.stderr
@@ -34,7 +34,7 @@ LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
    |                                  |         nested `impl Trait` here
    |                                  outer `impl Trait`
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return types
   --> $DIR/nested_impl_trait.rs:10:32
    |
 LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr
index 201aba3adff..1cae3f77cc5 100644
--- a/tests/ui/impl-trait/where-allowed.stderr
+++ b/tests/ui/impl-trait/where-allowed.stderr
@@ -43,109 +43,109 @@ LL | type InReturnInTypeAlias<R> = fn() -> impl Debug;
    = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer param
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer params
   --> $DIR/where-allowed.rs:16:40
    |
 LL | fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() }
    |                                        ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return types
   --> $DIR/where-allowed.rs:20:42
    |
 LL | fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() }
    |                                          ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer param
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer params
   --> $DIR/where-allowed.rs:24:38
    |
 LL | fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() }
    |                                      ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return types
   --> $DIR/where-allowed.rs:28:40
    |
 LL | fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() }
    |                                        ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params
   --> $DIR/where-allowed.rs:32:49
    |
 LL | fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() }
    |                                                 ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return types
   --> $DIR/where-allowed.rs:36:51
    |
 LL | fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() }
    |                                                   ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params
   --> $DIR/where-allowed.rs:40:55
    |
 LL | fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() }
    |                                                       ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params
   --> $DIR/where-allowed.rs:47:51
    |
 LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() }
    |                                                   ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return types
   --> $DIR/where-allowed.rs:52:53
    |
 LL | fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() }
    |                                                     ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params
   --> $DIR/where-allowed.rs:56:57
    |
 LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
    |                                                         ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params
   --> $DIR/where-allowed.rs:64:38
    |
 LL | fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() }
    |                                      ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return types
   --> $DIR/where-allowed.rs:68:40
    |
 LL | fn in_Fn_return_in_generics<F: Fn() -> impl Debug> (_: F) { panic!() }
    |                                        ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field type
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field types
   --> $DIR/where-allowed.rs:81:32
    |
 LL | struct InBraceStructField { x: impl Debug }
    |                                ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field type
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field types
   --> $DIR/where-allowed.rs:85:41
    |
 LL | struct InAdtInBraceStructField { x: Vec<impl Debug> }
    |                                         ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field type
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field types
   --> $DIR/where-allowed.rs:89:27
    |
 LL | struct InTupleStructField(impl Debug);
    |                           ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field type
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field types
   --> $DIR/where-allowed.rs:94:25
    |
 LL |     InBraceVariant { x: impl Debug },
    |                         ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field type
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in field types
   --> $DIR/where-allowed.rs:96:20
    |
 LL |     InTupleVariant(impl Debug),
    |                    ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return types
   --> $DIR/where-allowed.rs:107:23
    |
 LL |     fn in_return() -> impl Debug;
@@ -154,7 +154,7 @@ LL |     fn in_return() -> impl Debug;
    = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
    = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return types
   --> $DIR/where-allowed.rs:124:34
    |
 LL |     fn in_trait_impl_return() -> impl Debug { () }
@@ -163,121 +163,121 @@ LL |     fn in_trait_impl_return() -> impl Debug { () }
    = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
    = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` param
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` params
   --> $DIR/where-allowed.rs:137:33
    |
 LL |     fn in_foreign_parameters(_: impl Debug);
    |                                 ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` return types
   --> $DIR/where-allowed.rs:140:31
    |
 LL |     fn in_foreign_return() -> impl Debug;
    |                               ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return types
   --> $DIR/where-allowed.rs:156:39
    |
 LL | type InReturnInTypeAlias<R> = fn() -> impl Debug;
    |                                       ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in traits
   --> $DIR/where-allowed.rs:161:16
    |
 LL | impl PartialEq<impl Debug> for () {
    |                ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl header
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl headers
   --> $DIR/where-allowed.rs:166:24
    |
 LL | impl PartialEq<()> for impl Debug {
    |                        ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl header
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl headers
   --> $DIR/where-allowed.rs:171:6
    |
 LL | impl impl Debug {
    |      ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl header
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in impl headers
   --> $DIR/where-allowed.rs:177:24
    |
 LL | impl InInherentImplAdt<impl Debug> {
    |                        ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bound
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bounds
   --> $DIR/where-allowed.rs:183:11
    |
 LL |     where impl Debug: Debug
    |           ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bound
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bounds
   --> $DIR/where-allowed.rs:190:15
    |
 LL |     where Vec<impl Debug>: Debug
    |               ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bound
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bounds
   --> $DIR/where-allowed.rs:197:24
    |
 LL |     where T: PartialEq<impl Debug>
    |                        ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait params
   --> $DIR/where-allowed.rs:204:17
    |
 LL |     where T: Fn(impl Debug)
    |                 ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return types
   --> $DIR/where-allowed.rs:211:22
    |
 LL |     where T: Fn() -> impl Debug
    |                      ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter default
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults
   --> $DIR/where-allowed.rs:217:40
    |
 LL | struct InStructGenericParamDefault<T = impl Debug>(T);
    |                                        ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter default
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults
   --> $DIR/where-allowed.rs:221:36
    |
 LL | enum InEnumGenericParamDefault<T = impl Debug> { Variant(T) }
    |                                    ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter default
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults
   --> $DIR/where-allowed.rs:225:38
    |
 LL | trait InTraitGenericParamDefault<T = impl Debug> {}
    |                                      ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter default
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults
   --> $DIR/where-allowed.rs:229:41
    |
 LL | type InTypeAliasGenericParamDefault<T = impl Debug> = T;
    |                                         ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter default
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults
   --> $DIR/where-allowed.rs:233:11
    |
 LL | impl <T = impl Debug> T {}
    |           ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter default
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic parameter defaults
   --> $DIR/where-allowed.rs:240:40
    |
 LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
    |                                        ^^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/where-allowed.rs:246:29
    |
 LL |     let _in_local_variable: impl Fn() = || {};
    |                             ^^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in closure return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in closure return types
   --> $DIR/where-allowed.rs:248:46
    |
 LL |     let _in_return_in_local_variable = || -> impl Fn() { || {} };
diff --git a/tests/ui/issues/issue-106755.rs b/tests/ui/issues/issue-106755.rs
new file mode 100644
index 00000000000..46ece725fb7
--- /dev/null
+++ b/tests/ui/issues/issue-106755.rs
@@ -0,0 +1,19 @@
+// compile-flags:-Ztranslate-lang=en_US
+
+#![feature(negative_impls)]
+#![feature(marker_trait_attr)]
+
+#[marker]
+trait MyTrait {}
+
+struct TestType<T>(::std::marker::PhantomData<T>);
+
+unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
+
+impl<T: MyTrait> !Send for TestType<T> {} //~ ERROR found both positive and negative implementation
+
+unsafe impl<T: 'static> Send for TestType<T> {} //~ ERROR conflicting implementations
+
+impl !Send for TestType<i32> {}
+
+fn main() {}
diff --git a/tests/ui/issues/issue-106755.stderr b/tests/ui/issues/issue-106755.stderr
new file mode 100644
index 00000000000..54397034062
--- /dev/null
+++ b/tests/ui/issues/issue-106755.stderr
@@ -0,0 +1,22 @@
+error[E0751]: found both positive and negative implementation of trait `Send` for type `TestType<_>`:
+  --> $DIR/issue-106755.rs:13:1
+   |
+LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
+   | ------------------------------------------------------ positive implementation here
+LL |
+LL | impl<T: MyTrait> !Send for TestType<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here
+
+error[E0119]: conflicting implementations of trait `Send` for type `TestType<_>`
+  --> $DIR/issue-106755.rs:15:1
+   |
+LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
+   | ------------------------------------------------------ first implementation here
+...
+LL | unsafe impl<T: 'static> Send for TestType<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0119, E0751.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/issues/issue-18423.rs b/tests/ui/issues/issue-18423.rs
index a81b32f050c..675fd041154 100644
--- a/tests/ui/issues/issue-18423.rs
+++ b/tests/ui/issues/issue-18423.rs
@@ -2,7 +2,7 @@
 
 struct Foo<'a> {
     x: Box<'a, isize>
-    //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+    //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied
 }
 
 fn main() { }
diff --git a/tests/ui/issues/issue-18423.stderr b/tests/ui/issues/issue-18423.stderr
index bbf79366244..5d154dbbbdd 100644
--- a/tests/ui/issues/issue-18423.stderr
+++ b/tests/ui/issues/issue-18423.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/issue-18423.rs:4:8
    |
 LL |     x: Box<'a, isize>
diff --git a/tests/ui/issues/issue-3214.rs b/tests/ui/issues/issue-3214.rs
index 928a65938b7..e3c07bb3f72 100644
--- a/tests/ui/issues/issue-3214.rs
+++ b/tests/ui/issues/issue-3214.rs
@@ -4,7 +4,7 @@ fn foo<T>() {
     }
 
     impl<T> Drop for Foo<T> {
-        //~^ ERROR this struct takes 0 generic arguments but 1 generic argument
+        //~^ ERROR struct takes 0 generic arguments but 1 generic argument
         fn drop(&mut self) {}
     }
 }
diff --git a/tests/ui/issues/issue-3214.stderr b/tests/ui/issues/issue-3214.stderr
index aa0b5ce64b4..7a2d772f0a1 100644
--- a/tests/ui/issues/issue-3214.stderr
+++ b/tests/ui/issues/issue-3214.stderr
@@ -8,7 +8,7 @@ LL |     struct Foo {
 LL |         x: T,
    |            ^ use of generic parameter from outer function
 
-error[E0107]: this struct takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-3214.rs:6:22
    |
 LL |     impl<T> Drop for Foo<T> {
diff --git a/tests/ui/issues/issue-47715.stderr b/tests/ui/issues/issue-47715.stderr
index 0ee9388bf2b..dadea34b688 100644
--- a/tests/ui/issues/issue-47715.stderr
+++ b/tests/ui/issues/issue-47715.stderr
@@ -1,22 +1,22 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generics
   --> $DIR/issue-47715.rs:9:37
    |
 LL | struct Container<T: Iterable<Item = impl Foo>> {
    |                                     ^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generics
   --> $DIR/issue-47715.rs:14:30
    |
 LL | enum Enum<T: Iterable<Item = impl Foo>> {
    |                              ^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generics
   --> $DIR/issue-47715.rs:19:32
    |
 LL | union Union<T: Iterable<Item = impl Foo> + Copy> {
    |                                ^^^^^^^^
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generics
   --> $DIR/issue-47715.rs:24:30
    |
 LL | type Type<T: Iterable<Item = impl Foo>> = T;
diff --git a/tests/ui/issues/issue-53251.rs b/tests/ui/issues/issue-53251.rs
index 240826a161d..da3ba63ef67 100644
--- a/tests/ui/issues/issue-53251.rs
+++ b/tests/ui/issues/issue-53251.rs
@@ -9,8 +9,8 @@ macro_rules! impl_add {
         $(
             fn $n() {
                 S::f::<i64>();
-                //~^ ERROR this associated function takes 0 generic
-                //~| ERROR this associated function takes 0 generic
+                //~^ ERROR associated function takes 0 generic
+                //~| ERROR associated function takes 0 generic
             }
         )*
     }
diff --git a/tests/ui/issues/issue-53251.stderr b/tests/ui/issues/issue-53251.stderr
index cee9a5deb05..d5f14e8deb9 100644
--- a/tests/ui/issues/issue-53251.stderr
+++ b/tests/ui/issues/issue-53251.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: associated function takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-53251.rs:11:20
    |
 LL |                 S::f::<i64>();
@@ -16,7 +16,7 @@ LL |     fn f() {}
    |        ^
    = note: this error originates in the macro `impl_add` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: associated function takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-53251.rs:11:20
    |
 LL |                 S::f::<i64>();
diff --git a/tests/ui/issues/issue-60622.rs b/tests/ui/issues/issue-60622.rs
index 7347957906c..7b9443eee50 100644
--- a/tests/ui/issues/issue-60622.rs
+++ b/tests/ui/issues/issue-60622.rs
@@ -9,7 +9,7 @@ impl Borked {
 fn run_wild<T>(b: &Borked) {
     b.a::<'_, T>();
     //~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-    //~| ERROR this method takes 0 generic arguments but 1 generic argument
+    //~| ERROR method takes 0 generic arguments but 1 generic argument
     //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 }
 
diff --git a/tests/ui/issues/issue-60622.stderr b/tests/ui/issues/issue-60622.stderr
index 69b532b8f97..43da2773940 100644
--- a/tests/ui/issues/issue-60622.stderr
+++ b/tests/ui/issues/issue-60622.stderr
@@ -16,7 +16,7 @@ LL | #![deny(warnings)]
    |         ^^^^^^^^
    = note: `#[deny(late_bound_lifetime_arguments)]` implied by `#[deny(warnings)]`
 
-error[E0107]: this method takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-60622.rs:10:7
    |
 LL |     b.a::<'_, T>();
diff --git a/tests/ui/issues/issue-70093/issue-70093-link-directives.rs b/tests/ui/issues/issue-70093/issue-70093-link-directives.rs
new file mode 100644
index 00000000000..83f9b16c408
--- /dev/null
+++ b/tests/ui/issues/issue-70093/issue-70093-link-directives.rs
@@ -0,0 +1,10 @@
+// run-pass
+// compile-flags: -Zlink-directives=no
+// ignore-windows - this will probably only work on unixish systems
+// ignore-fuchsia - missing __libc_start_main for some reason (#84733)
+// ignore-cross-compile - default-linker-libraries=yes doesn't play well with cross compiling
+
+#[link(name = "some-random-non-existent-library", kind = "static")]
+extern "C" {}
+
+fn main() {}
diff --git a/tests/ui/issues/issue-70093.rs b/tests/ui/issues/issue-70093/issue-70093.rs
index 86459dc904a..86459dc904a 100644
--- a/tests/ui/issues/issue-70093.rs
+++ b/tests/ui/issues/issue-70093/issue-70093.rs
diff --git a/tests/ui/late-bound-lifetimes/mismatched_arg_count.rs b/tests/ui/late-bound-lifetimes/mismatched_arg_count.rs
index 0b331e2039f..792563fd82b 100644
--- a/tests/ui/late-bound-lifetimes/mismatched_arg_count.rs
+++ b/tests/ui/late-bound-lifetimes/mismatched_arg_count.rs
@@ -7,6 +7,6 @@ trait Trait<'a> {
 type Alias<'a, T> = <T as Trait<'a>>::Assoc;
 
 fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
-//~^ error: this type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
+//~^ error: type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
 
 fn main() {}
diff --git a/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr b/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr
index 3704d9bb957..de58a014ee8 100644
--- a/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr
+++ b/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/mismatched_arg_count.rs:9:29
    |
 LL | fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
diff --git a/tests/ui/lifetimes/issue-107988.rs b/tests/ui/lifetimes/issue-107988.rs
new file mode 100644
index 00000000000..92cb60a06a2
--- /dev/null
+++ b/tests/ui/lifetimes/issue-107988.rs
@@ -0,0 +1,13 @@
+pub trait TraitEngine<'tcx>: 'tcx {}
+
+pub trait TraitEngineExt<'tcx> {
+    fn register_predicate_obligations(&mut self);
+}
+
+impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
+  //~^ ERROR use of undeclared lifetime name `'tcx`
+  //~| ERROR use of undeclared lifetime name `'tcx`
+    fn register_predicate_obligations(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/lifetimes/issue-107988.stderr b/tests/ui/lifetimes/issue-107988.stderr
new file mode 100644
index 00000000000..c2d8c7050e9
--- /dev/null
+++ b/tests/ui/lifetimes/issue-107988.stderr
@@ -0,0 +1,27 @@
+error[E0261]: use of undeclared lifetime name `'tcx`
+  --> $DIR/issue-107988.rs:7:52
+   |
+LL | impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
+   |      -                                             ^^^^ undeclared lifetime
+   |      |
+   |      help: consider introducing lifetime `'tcx` here: `'tcx,`
+
+error[E0261]: use of undeclared lifetime name `'tcx`
+  --> $DIR/issue-107988.rs:7:30
+   |
+LL | impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
+   |                              ^^^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'tcx` lifetime
+   |
+LL | impl<T: ?Sized + for<'tcx> TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
+   |                  +++++++++
+help: consider introducing lifetime `'tcx` here
+   |
+LL | impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
+   |      +++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0261`.
diff --git a/tests/ui/lint/issue-106991.rs b/tests/ui/lint/issue-106991.rs
new file mode 100644
index 00000000000..e4d7f765b4a
--- /dev/null
+++ b/tests/ui/lint/issue-106991.rs
@@ -0,0 +1,13 @@
+fn foo(items: &mut Vec<u8>) {
+    items.sort();
+}
+
+fn bar() -> impl Iterator<Item = i32> {
+    //~^ ERROR expected `foo` to be a fn item that returns `i32`, but it returns `()` [E0271]
+    let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]];
+    x.iter_mut().map(foo)
+}
+
+fn main() {
+    bar();
+}
diff --git a/tests/ui/lint/issue-106991.stderr b/tests/ui/lint/issue-106991.stderr
new file mode 100644
index 00000000000..7b43f0b2ca8
--- /dev/null
+++ b/tests/ui/lint/issue-106991.stderr
@@ -0,0 +1,11 @@
+error[E0271]: expected `foo` to be a fn item that returns `i32`, but it returns `()`
+  --> $DIR/issue-106991.rs:5:13
+   |
+LL | fn bar() -> impl Iterator<Item = i32> {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `i32`
+   |
+   = note: required for `Map<std::slice::IterMut<'_, Vec<u8>>, for<'a> fn(&'a mut Vec<u8>) {foo}>` to implement `Iterator`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/lint/lint_map_unit_fn.rs b/tests/ui/lint/lint_map_unit_fn.rs
new file mode 100644
index 00000000000..dc1ecbf8424
--- /dev/null
+++ b/tests/ui/lint/lint_map_unit_fn.rs
@@ -0,0 +1,20 @@
+#![deny(map_unit_fn)]
+
+fn foo(items: &mut Vec<u8>) {
+    items.sort();
+}
+
+fn main() {
+    let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]];
+    x.iter_mut().map(foo);
+    //~^ ERROR `Iterator::map` call that discard the iterator's values
+    x.iter_mut().map(|items| {
+    //~^ ERROR `Iterator::map` call that discard the iterator's values
+        items.sort();
+    });
+    let f = |items: &mut Vec<u8>| {
+        items.sort();
+    };
+    x.iter_mut().map(f);
+    //~^ ERROR `Iterator::map` call that discard the iterator's values
+}
diff --git a/tests/ui/lint/lint_map_unit_fn.stderr b/tests/ui/lint/lint_map_unit_fn.stderr
new file mode 100644
index 00000000000..fbf689c5421
--- /dev/null
+++ b/tests/ui/lint/lint_map_unit_fn.stderr
@@ -0,0 +1,66 @@
+error: `Iterator::map` call that discard the iterator's values
+  --> $DIR/lint_map_unit_fn.rs:9:18
+   |
+LL | fn foo(items: &mut Vec<u8>) {
+   | --------------------------- this function returns `()`, which is likely not what you wanted
+...
+LL |     x.iter_mut().map(foo);
+   |                  ^^^^---^
+   |                  |   |
+   |                  |   called `Iterator::map` with callable that returns `()`
+   |                  after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
+   |
+   = note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
+note: the lint level is defined here
+  --> $DIR/lint_map_unit_fn.rs:1:9
+   |
+LL | #![deny(map_unit_fn)]
+   |         ^^^^^^^^^^^
+help: you might have meant to use `Iterator::for_each`
+   |
+LL |     x.iter_mut().for_each(foo);
+   |                  ~~~~~~~~
+
+error: `Iterator::map` call that discard the iterator's values
+  --> $DIR/lint_map_unit_fn.rs:11:18
+   |
+LL |         x.iter_mut().map(|items| {
+   |                      ^   -------
+   |                      |   |
+   |  ____________________|___this function returns `()`, which is likely not what you wanted
+   | |  __________________|
+   | | |
+LL | | |
+LL | | |         items.sort();
+LL | | |     });
+   | | |     -^ after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
+   | | |_____||
+   | |_______|
+   |         called `Iterator::map` with callable that returns `()`
+   |
+   = note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
+help: you might have meant to use `Iterator::for_each`
+   |
+LL |     x.iter_mut().for_each(|items| {
+   |                  ~~~~~~~~
+
+error: `Iterator::map` call that discard the iterator's values
+  --> $DIR/lint_map_unit_fn.rs:18:18
+   |
+LL |     let f = |items: &mut Vec<u8>| {
+   |             --------------------- this function returns `()`, which is likely not what you wanted
+...
+LL |     x.iter_mut().map(f);
+   |                  ^^^^-^
+   |                  |   |
+   |                  |   called `Iterator::map` with callable that returns `()`
+   |                  after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
+   |
+   = note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
+help: you might have meant to use `Iterator::for_each`
+   |
+LL |     x.iter_mut().for_each(f);
+   |                  ~~~~~~~~
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/methods/issues/issue-105732.stderr b/tests/ui/methods/issues/issue-105732.stderr
index 7696642548d..19ccd2de685 100644
--- a/tests/ui/methods/issues/issue-105732.stderr
+++ b/tests/ui/methods/issues/issue-105732.stderr
@@ -2,7 +2,7 @@ error[E0380]: auto traits cannot have associated items
   --> $DIR/issue-105732.rs:4:8
    |
 LL | auto trait Foo {
-   |            --- auto trait cannot have associated items
+   |            --- auto traits cannot have associated items
 LL |     fn g(&self);
    |     ---^-------- help: remove these associated items
 
diff --git a/tests/ui/methods/method-call-lifetime-args-fail.rs b/tests/ui/methods/method-call-lifetime-args-fail.rs
index 2e5c9a0b891..1f13de094bb 100644
--- a/tests/ui/methods/method-call-lifetime-args-fail.rs
+++ b/tests/ui/methods/method-call-lifetime-args-fail.rs
@@ -14,9 +14,9 @@ impl S {
 fn method_call() {
     S.early(); // OK
     S.early::<'static>();
-    //~^ ERROR this method takes 2 lifetime arguments but 1 lifetime argument
+    //~^ ERROR method takes 2 lifetime arguments but 1 lifetime argument
     S.early::<'static, 'static, 'static>();
-    //~^ ERROR this method takes 2 lifetime arguments but 3 lifetime arguments were supplied
+    //~^ ERROR method takes 2 lifetime arguments but 3 lifetime arguments were supplied
     let _: &u8 = S.life_and_type::<'static>();
     S.life_and_type::<u8>();
     S.life_and_type::<'static, u8>();
@@ -61,9 +61,9 @@ fn ufcs() {
 
     S::early(S); // OK
     S::early::<'static>(S);
-    //~^ ERROR this method takes 2 lifetime arguments but 1 lifetime argument
+    //~^ ERROR method takes 2 lifetime arguments but 1 lifetime argument
     S::early::<'static, 'static, 'static>(S);
-    //~^ ERROR this method takes 2 lifetime arguments but 3 lifetime arguments were supplied
+    //~^ ERROR method takes 2 lifetime arguments but 3 lifetime arguments were supplied
     let _: &u8 = S::life_and_type::<'static>(S);
     S::life_and_type::<u8>(S);
     S::life_and_type::<'static, u8>(S);
diff --git a/tests/ui/methods/method-call-lifetime-args-fail.stderr b/tests/ui/methods/method-call-lifetime-args-fail.stderr
index 45ff32bdd4c..34526256f99 100644
--- a/tests/ui/methods/method-call-lifetime-args-fail.stderr
+++ b/tests/ui/methods/method-call-lifetime-args-fail.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this method takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: method takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/method-call-lifetime-args-fail.rs:16:7
    |
 LL |     S.early::<'static>();
@@ -16,7 +16,7 @@ help: add missing lifetime argument
 LL |     S.early::<'static, 'static>();
    |                      +++++++++
 
-error[E0107]: this method takes 2 lifetime arguments but 3 lifetime arguments were supplied
+error[E0107]: method takes 2 lifetime arguments but 3 lifetime arguments were supplied
   --> $DIR/method-call-lifetime-args-fail.rs:18:7
    |
 LL |     S.early::<'static, 'static, 'static>();
@@ -198,7 +198,7 @@ note: the late bound lifetime parameter is introduced here
 LL |     fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} }
    |                          ^^
 
-error[E0107]: this method takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: method takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/method-call-lifetime-args-fail.rs:63:8
    |
 LL |     S::early::<'static>(S);
@@ -216,7 +216,7 @@ help: add missing lifetime argument
 LL |     S::early::<'static, 'static>(S);
    |                       +++++++++
 
-error[E0107]: this method takes 2 lifetime arguments but 3 lifetime arguments were supplied
+error[E0107]: method takes 2 lifetime arguments but 3 lifetime arguments were supplied
   --> $DIR/method-call-lifetime-args-fail.rs:65:8
    |
 LL |     S::early::<'static, 'static, 'static>(S);
diff --git a/tests/ui/mir/validate/storage-live.rs b/tests/ui/mir/validate/storage-live.rs
new file mode 100644
index 00000000000..ed3c26ed6da
--- /dev/null
+++ b/tests/ui/mir/validate/storage-live.rs
@@ -0,0 +1,30 @@
+// compile-flags: -Zvalidate-mir -Ztreat-err-as-bug
+// failure-status: 101
+// error-pattern: broken MIR in
+// error-pattern: StorageLive(_1) which already has storage here
+// normalize-stderr-test "note: .*\n\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// normalize-stderr-test "storage_live\[....\]" -> "storage_live[HASH]"
+// rustc-env:RUST_BACKTRACE=0
+
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+use core::ptr::{addr_of, addr_of_mut};
+
+#[custom_mir(dialect = "built")]
+fn multiple_storage() {
+    mir!(
+        let a: usize;
+        {
+            StorageLive(a);
+            StorageLive(a);
+            Return()
+        }
+    )
+}
+
+fn main() {
+    multiple_storage()
+}
diff --git a/tests/ui/mir/validate/storage-live.stderr b/tests/ui/mir/validate/storage-live.stderr
new file mode 100644
index 00000000000..b586a865849
--- /dev/null
+++ b/tests/ui/mir/validate/storage-live.stderr
@@ -0,0 +1,13 @@
+error: internal compiler error: broken MIR in Item(WithOptConstParam { did: DefId(0:8 ~ storage_live[HASH]::multiple_storage), const_param_did: None }) (before pass CheckPackedRef) at bb0[1]:
+                                StorageLive(_1) which already has storage here
+  --> $DIR/storage-live.rs:22:13
+   |
+LL |             StorageLive(a);
+   |             ^^^^^^^^^^^^^^
+
+error: the compiler unexpectedly panicked. this is a bug.
+
+query stack during panic:
+#0 [mir_const] preparing `multiple_storage` for borrow checking
+#1 [mir_promoted] processing MIR for `multiple_storage`
+end of query stack
diff --git a/tests/ui/parser/match-arm-without-braces.stderr b/tests/ui/parser/match-arm-without-braces.stderr
index 37d55aa53f8..ee1c8e562fc 100644
--- a/tests/ui/parser/match-arm-without-braces.stderr
+++ b/tests/ui/parser/match-arm-without-braces.stderr
@@ -2,10 +2,14 @@ error: `match` arm body without braces
   --> $DIR/match-arm-without-braces.rs:26:27
    |
 LL |         Some(Val::Foo) => 3;
-   |                        -- ^- help: use a comma to end a `match` arm expression: `,`
-   |                        |  |
-   |                        |  this statement is not surrounded by a body
+   |                        -- ^ this statement is not surrounded by a body
+   |                        |
    |                        while parsing the `match` arm starting here
+   |
+help: replace `;` with `,` to end a `match` arm expression
+   |
+LL |         Some(Val::Foo) => 3,
+   |                            ~
 
 error: `match` arm body without braces
   --> $DIR/match-arm-without-braces.rs:31:11
diff --git a/tests/ui/resolve/issue-108529.rs b/tests/ui/resolve/issue-108529.rs
new file mode 100644
index 00000000000..8e3aafab6aa
--- /dev/null
+++ b/tests/ui/resolve/issue-108529.rs
@@ -0,0 +1,8 @@
+#![allow(nonstandard_style)]
+use f::f::f; //~ ERROR
+
+trait f {
+    extern "C" fn f();
+}
+
+fn main() {}
diff --git a/tests/ui/resolve/issue-108529.stderr b/tests/ui/resolve/issue-108529.stderr
new file mode 100644
index 00000000000..cf4e4759c37
--- /dev/null
+++ b/tests/ui/resolve/issue-108529.stderr
@@ -0,0 +1,9 @@
+error[E0432]: unresolved import `f::f`
+  --> $DIR/issue-108529.rs:2:8
+   |
+LL | use f::f::f;
+   |        ^ expected type, found associated function `f` in `f`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/rfc-2091-track-caller/error-with-main.stderr b/tests/ui/rfc-2091-track-caller/error-with-main.stderr
index 7e2ec352414..6d6562dae3b 100644
--- a/tests/ui/rfc-2091-track-caller/error-with-main.stderr
+++ b/tests/ui/rfc-2091-track-caller/error-with-main.stderr
@@ -2,7 +2,7 @@ error: `main` function is not allowed to be `#[track_caller]`
   --> $DIR/error-with-main.rs:1:1
    |
 LL | #[track_caller]
-   | ^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^ help: remove this annotation
 LL | fn main() {
    | --------- `main` function is not allowed to be `#[track_caller]`
 
diff --git a/tests/ui/rfc-2457/mod_file_nonascii_forbidden.stderr b/tests/ui/rfc-2457/mod_file_nonascii_forbidden.stderr
index dd0dac95e36..7639ae9f6a4 100644
--- a/tests/ui/rfc-2457/mod_file_nonascii_forbidden.stderr
+++ b/tests/ui/rfc-2457/mod_file_nonascii_forbidden.stderr
@@ -12,7 +12,7 @@ error[E0754]: trying to load file for module `řųśť` with non-ascii identifie
 LL | mod řųśť;
    |     ^^^^
    |
-   = help: consider using `#[path]` attribute to specify filesystem path
+   = help: consider using the `#[path]` attribute to specify filesystem path
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/rfc-2632-const-trait-impl/do-not-const-check-override.rs b/tests/ui/rfc-2632-const-trait-impl/do-not-const-check-override.rs
new file mode 100644
index 00000000000..730e268c091
--- /dev/null
+++ b/tests/ui/rfc-2632-const-trait-impl/do-not-const-check-override.rs
@@ -0,0 +1,19 @@
+// check-pass
+#![feature(const_trait_impl, rustc_attrs)]
+
+#[const_trait]
+trait Foo {
+    #[rustc_do_not_const_check]
+    fn into_iter(&self) { println!("FEAR ME!") }
+}
+
+
+impl const Foo for () {
+    fn into_iter(&self) {
+        // ^_^
+    }
+}
+
+const _: () = Foo::into_iter(&());
+
+fn main() {}
diff --git a/tests/ui/rfc-2632-const-trait-impl/do-not-const-check.rs b/tests/ui/rfc-2632-const-trait-impl/do-not-const-check.rs
new file mode 100644
index 00000000000..3c39c53de5f
--- /dev/null
+++ b/tests/ui/rfc-2632-const-trait-impl/do-not-const-check.rs
@@ -0,0 +1,18 @@
+// check-pass
+#![feature(const_trait_impl, rustc_attrs)]
+
+#[const_trait]
+trait IntoIter {
+    fn into_iter(self);
+}
+
+#[const_trait]
+trait Hmm: Sized {
+    #[rustc_do_not_const_check]
+    fn chain<U>(self, other: U) where U: IntoIter,
+    {
+        other.into_iter()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs
index e0842bfa4cd..2ae0dd92717 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs
@@ -11,8 +11,6 @@
 // revisions: mir thir
 // [thir]compile-flags: -Z thir-unsafeck
 
-#![feature(target_feature_11)]
-
 #[target_feature(enable = "sse2")]
 const fn sse2() {}
 
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
index a59d7c2d784..e96a3e5f6cd 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
@@ -5,8 +5,6 @@
 // [thir]compile-flags: -Z thir-unsafeck
 // only-x86_64
 
-#![feature(target_feature_11)]
-
 #[target_feature(enable="avx")]
 fn also_use_avx() {
     println!("Hello from AVX")
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs
deleted file mode 100644
index 975d7a1f694..00000000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// only-x86_64
-
-#[target_feature(enable = "sse2")] //~ ERROR can only be applied to `unsafe` functions
-fn foo() {}
-
-fn main() {}
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr
deleted file mode 100644
index 18917fd2556..00000000000
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
-  --> $DIR/feature-gate-target_feature_11.rs:3:1
-   |
-LL | #[target_feature(enable = "sse2")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL | fn foo() {}
-   | -------- not an `unsafe` function
-   |
-   = note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information
-   = help: add `#![feature(target_feature_11)]` 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/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
index b0ac5dc44ad..fa6561b74d9 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/fn-ptr.rs:11:21
+  --> $DIR/fn-ptr.rs:9:21
    |
 LL | #[target_feature(enable = "sse2")]
    | ---------------------------------- `#[target_feature]` added here
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs
index c95d4a08e48..7df172e80eb 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs
@@ -2,8 +2,6 @@
 // [thir]compile-flags: -Z thir-unsafeck
 // only-x86_64
 
-#![feature(target_feature_11)]
-
 #[target_feature(enable = "sse2")]
 fn foo() {}
 
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
index b0ac5dc44ad..fa6561b74d9 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/fn-ptr.rs:11:21
+  --> $DIR/fn-ptr.rs:9:21
    |
 LL | #[target_feature(enable = "sse2")]
    | ---------------------------------- `#[target_feature]` added here
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs
index 43bda49624e..392cdc4bd36 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs
@@ -1,7 +1,5 @@
 // only-x86_64
 
-#![feature(target_feature_11)]
-
 #[target_feature(enable = "avx")]
 fn foo() {}
 
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr
index fc7bf22775d..aa0f57dee41 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr
@@ -1,5 +1,5 @@
 error[E0277]: expected a `Fn<()>` closure, found `fn() {foo}`
-  --> $DIR/fn-traits.rs:24:10
+  --> $DIR/fn-traits.rs:22:10
    |
 LL |     call(foo);
    |     ---- ^^^ expected an `Fn<()>` closure, found `fn() {foo}`
@@ -10,13 +10,13 @@ LL |     call(foo);
    = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
    = note: `#[target_feature]` functions do not implement the `Fn` traits
 note: required by a bound in `call`
-  --> $DIR/fn-traits.rs:11:17
+  --> $DIR/fn-traits.rs:9:17
    |
 LL | fn call(f: impl Fn()) {
    |                 ^^^^ required by this bound in `call`
 
 error[E0277]: expected a `FnMut<()>` closure, found `fn() {foo}`
-  --> $DIR/fn-traits.rs:25:14
+  --> $DIR/fn-traits.rs:23:14
    |
 LL |     call_mut(foo);
    |     -------- ^^^ expected an `FnMut<()>` closure, found `fn() {foo}`
@@ -27,13 +27,13 @@ LL |     call_mut(foo);
    = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
    = note: `#[target_feature]` functions do not implement the `Fn` traits
 note: required by a bound in `call_mut`
-  --> $DIR/fn-traits.rs:15:21
+  --> $DIR/fn-traits.rs:13:21
    |
 LL | fn call_mut(f: impl FnMut()) {
    |                     ^^^^^^^ required by this bound in `call_mut`
 
 error[E0277]: expected a `FnOnce<()>` closure, found `fn() {foo}`
-  --> $DIR/fn-traits.rs:26:15
+  --> $DIR/fn-traits.rs:24:15
    |
 LL |     call_once(foo);
    |     --------- ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}`
@@ -44,13 +44,13 @@ LL |     call_once(foo);
    = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
    = note: `#[target_feature]` functions do not implement the `Fn` traits
 note: required by a bound in `call_once`
-  --> $DIR/fn-traits.rs:19:22
+  --> $DIR/fn-traits.rs:17:22
    |
 LL | fn call_once(f: impl FnOnce()) {
    |                      ^^^^^^^^ required by this bound in `call_once`
 
 error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
-  --> $DIR/fn-traits.rs:28:10
+  --> $DIR/fn-traits.rs:26:10
    |
 LL |     call(foo_unsafe);
    |     ---- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
@@ -61,13 +61,13 @@ LL |     call(foo_unsafe);
    = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
    = note: `#[target_feature]` functions do not implement the `Fn` traits
 note: required by a bound in `call`
-  --> $DIR/fn-traits.rs:11:17
+  --> $DIR/fn-traits.rs:9:17
    |
 LL | fn call(f: impl Fn()) {
    |                 ^^^^ required by this bound in `call`
 
 error[E0277]: expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
-  --> $DIR/fn-traits.rs:30:14
+  --> $DIR/fn-traits.rs:28:14
    |
 LL |     call_mut(foo_unsafe);
    |     -------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
@@ -78,13 +78,13 @@ LL |     call_mut(foo_unsafe);
    = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
    = note: `#[target_feature]` functions do not implement the `Fn` traits
 note: required by a bound in `call_mut`
-  --> $DIR/fn-traits.rs:15:21
+  --> $DIR/fn-traits.rs:13:21
    |
 LL | fn call_mut(f: impl FnMut()) {
    |                     ^^^^^^^ required by this bound in `call_mut`
 
 error[E0277]: expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
-  --> $DIR/fn-traits.rs:32:15
+  --> $DIR/fn-traits.rs:30:15
    |
 LL |     call_once(foo_unsafe);
    |     --------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
@@ -95,7 +95,7 @@ LL |     call_once(foo_unsafe);
    = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
    = note: `#[target_feature]` functions do not implement the `Fn` traits
 note: required by a bound in `call_once`
-  --> $DIR/fn-traits.rs:19:22
+  --> $DIR/fn-traits.rs:17:22
    |
 LL | fn call_once(f: impl FnOnce()) {
    |                      ^^^^^^^^ required by this bound in `call_once`
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs
index 033dcdfc08d..e4ee511d07f 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(target_feature_11)]
-
 struct S<T>(T)
 where
     [T; (|| {}, 1).1]: Copy;
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
index 0ef7b8b09f1..76b99dca842 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:23:5
+  --> $DIR/safe-calls.rs:21:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -7,7 +7,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:26:5
+  --> $DIR/safe-calls.rs:24:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -15,7 +15,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:29:5
+  --> $DIR/safe-calls.rs:27:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -23,7 +23,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:36:5
+  --> $DIR/safe-calls.rs:34:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -31,7 +31,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:39:5
+  --> $DIR/safe-calls.rs:37:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -39,7 +39,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:46:5
+  --> $DIR/safe-calls.rs:44:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -47,7 +47,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:49:5
+  --> $DIR/safe-calls.rs:47:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -55,7 +55,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:52:5
+  --> $DIR/safe-calls.rs:50:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -63,7 +63,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:60:5
+  --> $DIR/safe-calls.rs:58:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -71,7 +71,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:65:18
+  --> $DIR/safe-calls.rs:63:18
    |
 LL | const name: () = sse2();
    |                  ^^^^^^ call to function with `#[target_feature]`
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
index cebc6f94784..de78fbf0df4 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
@@ -2,8 +2,6 @@
 // [thir]compile-flags: -Z thir-unsafeck
 // only-x86_64
 
-#![feature(target_feature_11)]
-
 #[target_feature(enable = "sse2")]
 const fn sse2() {}
 
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
index c75ac6e8b9a..daca221fe5d 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:23:5
+  --> $DIR/safe-calls.rs:21:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -7,7 +7,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:26:5
+  --> $DIR/safe-calls.rs:24:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -15,7 +15,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:29:5
+  --> $DIR/safe-calls.rs:27:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -23,7 +23,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:36:5
+  --> $DIR/safe-calls.rs:34:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -31,7 +31,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:39:5
+  --> $DIR/safe-calls.rs:37:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -39,7 +39,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:46:5
+  --> $DIR/safe-calls.rs:44:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -47,7 +47,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:49:5
+  --> $DIR/safe-calls.rs:47:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -55,7 +55,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:52:5
+  --> $DIR/safe-calls.rs:50:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -63,7 +63,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:60:5
+  --> $DIR/safe-calls.rs:58:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -71,7 +71,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:65:18
+  --> $DIR/safe-calls.rs:63:18
    |
 LL | const name: () = sse2();
    |                  ^^^^^^ call to function with `#[target_feature]`
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs
index 7314fa8cced..3cdbf41d878 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs
@@ -1,7 +1,5 @@
 // only-x86_64
 
-#![feature(target_feature_11)]
-
 trait Foo {
     fn foo(&self);
     unsafe fn unsf_foo(&self);
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr
index 07d6e090059..eb385d359ac 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr
@@ -1,5 +1,5 @@
 error: `#[target_feature(..)]` cannot be applied to safe trait method
-  --> $DIR/trait-impl.rs:13:5
+  --> $DIR/trait-impl.rs:11:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
diff --git a/tests/ui/rust-2018/remove-extern-crate.fixed b/tests/ui/rust-2018/remove-extern-crate.fixed
index 832632268fb..15e0ccc5256 100644
--- a/tests/ui/rust-2018/remove-extern-crate.fixed
+++ b/tests/ui/rust-2018/remove-extern-crate.fixed
@@ -23,6 +23,7 @@ extern crate alloc;
 fn main() {
     another_name::mem::drop(3);
     another::foo();
+    with_visibility::foo();
     remove_extern_crate::foo!();
     bar!();
     alloc::vec![5];
@@ -37,3 +38,12 @@ mod another {
         remove_extern_crate::foo!();
     }
 }
+
+mod with_visibility {
+    pub use core; //~ WARNING `extern crate` is not idiomatic
+
+    pub fn foo() {
+        core::mem::drop(4);
+        remove_extern_crate::foo!();
+    }
+}
diff --git a/tests/ui/rust-2018/remove-extern-crate.rs b/tests/ui/rust-2018/remove-extern-crate.rs
index bbb84cd462d..aec0bc7c374 100644
--- a/tests/ui/rust-2018/remove-extern-crate.rs
+++ b/tests/ui/rust-2018/remove-extern-crate.rs
@@ -23,6 +23,7 @@ extern crate alloc;
 fn main() {
     another_name::mem::drop(3);
     another::foo();
+    with_visibility::foo();
     remove_extern_crate::foo!();
     bar!();
     alloc::vec![5];
@@ -37,3 +38,12 @@ mod another {
         remove_extern_crate::foo!();
     }
 }
+
+mod with_visibility {
+    pub extern crate core; //~ WARNING `extern crate` is not idiomatic
+
+    pub fn foo() {
+        core::mem::drop(4);
+        remove_extern_crate::foo!();
+    }
+}
diff --git a/tests/ui/rust-2018/remove-extern-crate.stderr b/tests/ui/rust-2018/remove-extern-crate.stderr
index bde4c180811..d07358e471b 100644
--- a/tests/ui/rust-2018/remove-extern-crate.stderr
+++ b/tests/ui/rust-2018/remove-extern-crate.stderr
@@ -12,10 +12,26 @@ LL | #![warn(rust_2018_idioms)]
    = note: `#[warn(unused_extern_crates)]` implied by `#[warn(rust_2018_idioms)]`
 
 warning: `extern crate` is not idiomatic in the new edition
-  --> $DIR/remove-extern-crate.rs:32:5
+  --> $DIR/remove-extern-crate.rs:33:5
    |
 LL |     extern crate core;
-   |     ^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+help: convert it to a `use`
+   |
+LL |     use core;
+   |     ~~~
+
+warning: `extern crate` is not idiomatic in the new edition
+  --> $DIR/remove-extern-crate.rs:43:5
+   |
+LL |     pub extern crate core;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert it to a `use`
+   |
+LL |     pub use core;
+   |         ~~~
 
-warning: 2 warnings emitted
+warning: 3 warnings emitted
 
diff --git a/tests/ui/seq-args.rs b/tests/ui/seq-args.rs
index a5ebeecd311..627dfcc3198 100644
--- a/tests/ui/seq-args.rs
+++ b/tests/ui/seq-args.rs
@@ -2,12 +2,12 @@ fn main() {
     trait Seq { }
 
     impl<T> Seq<T> for Vec<T> {
-        //~^ ERROR this trait takes 0 generic arguments but 1 generic argument
+        //~^ ERROR trait takes 0 generic arguments but 1 generic argument
         /* ... */
     }
 
     impl Seq<bool> for u32 {
-        //~^ ERROR this trait takes 0 generic arguments but 1 generic argument
+        //~^ ERROR trait takes 0 generic arguments but 1 generic argument
         /* Treat the integer as a sequence of bits */
     }
 }
diff --git a/tests/ui/seq-args.stderr b/tests/ui/seq-args.stderr
index c404d95748b..a5b0f8e98dc 100644
--- a/tests/ui/seq-args.stderr
+++ b/tests/ui/seq-args.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/seq-args.rs:4:13
    |
 LL |     impl<T> Seq<T> for Vec<T> {
@@ -12,7 +12,7 @@ note: trait defined here, with 0 generic parameters
 LL |     trait Seq { }
    |           ^^^
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/seq-args.rs:9:10
    |
 LL |     impl Seq<bool> for u32 {
diff --git a/tests/ui/stability-attribute/unresolved_stability_lint.rs b/tests/ui/stability-attribute/unresolved_stability_lint.rs
new file mode 100644
index 00000000000..818d228bc91
--- /dev/null
+++ b/tests/ui/stability-attribute/unresolved_stability_lint.rs
@@ -0,0 +1,8 @@
+#![feature(staged_api)]
+#![stable(feature = "uwu", since = "1.0.0")]
+
+#[unstable(feature = "foo", issue = "none")]
+impl Foo for () {}
+//~^ ERROR cannot find trait `Foo` in this scope
+
+fn main() {}
diff --git a/tests/ui/stability-attribute/unresolved_stability_lint.stderr b/tests/ui/stability-attribute/unresolved_stability_lint.stderr
new file mode 100644
index 00000000000..11d6abcaf36
--- /dev/null
+++ b/tests/ui/stability-attribute/unresolved_stability_lint.stderr
@@ -0,0 +1,9 @@
+error[E0405]: cannot find trait `Foo` in this scope
+  --> $DIR/unresolved_stability_lint.rs:5:6
+   |
+LL | impl Foo for () {}
+   |      ^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/tests/ui/structs/struct-path-associated-type.rs b/tests/ui/structs/struct-path-associated-type.rs
index 2dd7174a9be..74d9705d4b8 100644
--- a/tests/ui/structs/struct-path-associated-type.rs
+++ b/tests/ui/structs/struct-path-associated-type.rs
@@ -13,7 +13,7 @@ fn f<T: Tr>() {
     //~^ ERROR expected struct, variant or union type, found associated type
     let z = T::A::<u8> {};
     //~^ ERROR expected struct, variant or union type, found associated type
-    //~| ERROR this associated type takes 0 generic arguments but 1 generic argument was supplied
+    //~| ERROR associated type takes 0 generic arguments but 1 generic argument was supplied
     match S {
         T::A {} => {}
         //~^ ERROR expected struct, variant or union type, found associated type
@@ -22,7 +22,7 @@ fn f<T: Tr>() {
 
 fn g<T: Tr<A = S>>() {
     let s = T::A {}; // OK
-    let z = T::A::<u8> {}; //~ ERROR this associated type takes 0 generic arguments but 1 generic argument was supplied
+    let z = T::A::<u8> {}; //~ ERROR associated type takes 0 generic arguments but 1 generic argument was supplied
     match S {
         T::A {} => {} // OK
     }
diff --git a/tests/ui/structs/struct-path-associated-type.stderr b/tests/ui/structs/struct-path-associated-type.stderr
index ca5f0b7e21e..acfddaf3760 100644
--- a/tests/ui/structs/struct-path-associated-type.stderr
+++ b/tests/ui/structs/struct-path-associated-type.stderr
@@ -4,7 +4,7 @@ error[E0071]: expected struct, variant or union type, found associated type
 LL |     let s = T::A {};
    |             ^^^^ not a struct
 
-error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/struct-path-associated-type.rs:14:16
    |
 LL |     let z = T::A::<u8> {};
@@ -30,7 +30,7 @@ error[E0071]: expected struct, variant or union type, found associated type
 LL |         T::A {} => {}
    |         ^^^^ not a struct
 
-error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: associated type takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/struct-path-associated-type.rs:25:16
    |
 LL |     let z = T::A::<u8> {};
diff --git a/tests/ui/structs/structure-constructor-type-mismatch.rs b/tests/ui/structs/structure-constructor-type-mismatch.rs
index a03ef590cb3..21cd9d08b21 100644
--- a/tests/ui/structs/structure-constructor-type-mismatch.rs
+++ b/tests/ui/structs/structure-constructor-type-mismatch.rs
@@ -45,13 +45,13 @@ fn main() {
         y: 8,
     };
 
-    let pt3 = PointF::<i32> { //~ ERROR this type alias takes 0 generic arguments but 1 generic argument
+    let pt3 = PointF::<i32> { //~ ERROR type alias takes 0 generic arguments but 1 generic argument
         x: 9,  //~ ERROR mismatched types
         y: 10, //~ ERROR mismatched types
     };
 
     match (Point { x: 1, y: 2 }) {
-        PointF::<u32> { .. } => {} //~ ERROR this type alias takes 0 generic arguments but 1 generic argument
+        PointF::<u32> { .. } => {} //~ ERROR type alias takes 0 generic arguments but 1 generic argument
         //~^ ERROR mismatched types
     }
 
diff --git a/tests/ui/structs/structure-constructor-type-mismatch.stderr b/tests/ui/structs/structure-constructor-type-mismatch.stderr
index 3e3f9ea06ef..63dda459396 100644
--- a/tests/ui/structs/structure-constructor-type-mismatch.stderr
+++ b/tests/ui/structs/structure-constructor-type-mismatch.stderr
@@ -52,7 +52,7 @@ LL |         x: 7,
    |            expected `f32`, found integer
    |            help: use a float literal: `7.0`
 
-error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/structure-constructor-type-mismatch.rs:48:15
    |
 LL |     let pt3 = PointF::<i32> {
@@ -84,7 +84,7 @@ LL |         y: 10,
    |            expected `f32`, found integer
    |            help: use a float literal: `10.0`
 
-error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/structure-constructor-type-mismatch.rs:54:9
    |
 LL |         PointF::<u32> { .. } => {}
diff --git a/tests/ui/suggestions/issue-101421.rs b/tests/ui/suggestions/issue-101421.rs
index 53b1e885737..1407ebd277c 100644
--- a/tests/ui/suggestions/issue-101421.rs
+++ b/tests/ui/suggestions/issue-101421.rs
@@ -8,5 +8,5 @@ impl Ice for () {
 
 fn main() {
     ().f::<()>(());
-    //~^ ERROR this method takes 0 generic arguments but 1 generic argument was supplied
+    //~^ ERROR method takes 0 generic arguments but 1 generic argument was supplied
 }
diff --git a/tests/ui/suggestions/issue-101421.stderr b/tests/ui/suggestions/issue-101421.stderr
index 8362f02bbe4..2656ab3db0b 100644
--- a/tests/ui/suggestions/issue-101421.stderr
+++ b/tests/ui/suggestions/issue-101421.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this method takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-101421.rs:10:8
    |
 LL |     ().f::<()>(());
diff --git a/tests/ui/suggestions/issue-104287.rs b/tests/ui/suggestions/issue-104287.rs
index 752282e065d..37b3339fa92 100644
--- a/tests/ui/suggestions/issue-104287.rs
+++ b/tests/ui/suggestions/issue-104287.rs
@@ -8,6 +8,6 @@ impl S {
 fn main() {
     let x = S;
     foo::<()>(x);
-    //~^ ERROR this method takes 0 generic arguments but 1 generic argument was supplied
+    //~^ ERROR method takes 0 generic arguments but 1 generic argument was supplied
     //~| ERROR cannot find function `foo` in this scope
 }
diff --git a/tests/ui/suggestions/issue-104287.stderr b/tests/ui/suggestions/issue-104287.stderr
index d363601e952..ed59b2e7a2d 100644
--- a/tests/ui/suggestions/issue-104287.stderr
+++ b/tests/ui/suggestions/issue-104287.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this method takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-104287.rs:10:5
    |
 LL |     foo::<()>(x);
diff --git a/tests/ui/suggestions/issue-85347.rs b/tests/ui/suggestions/issue-85347.rs
index 02b5fb61894..04d4c47d8e5 100644
--- a/tests/ui/suggestions/issue-85347.rs
+++ b/tests/ui/suggestions/issue-85347.rs
@@ -1,7 +1,7 @@
 use std::ops::Deref;
 trait Foo {
     type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
-    //~^ ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+    //~^ ERROR associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
     //~| ERROR associated type bindings are not allowed here
     //~| HELP add missing
 }
diff --git a/tests/ui/suggestions/issue-85347.stderr b/tests/ui/suggestions/issue-85347.stderr
index 17c1b7dc4cc..f330b3c1fad 100644
--- a/tests/ui/suggestions/issue-85347.stderr
+++ b/tests/ui/suggestions/issue-85347.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/issue-85347.rs:3:42
    |
 LL |     type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
diff --git a/tests/ui/suggestions/issue-89064.stderr b/tests/ui/suggestions/issue-89064.stderr
index b238c1804ee..be09dd89512 100644
--- a/tests/ui/suggestions/issue-89064.stderr
+++ b/tests/ui/suggestions/issue-89064.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: associated function takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-89064.rs:17:16
    |
 LL |     let _ = A::foo::<S>();
@@ -20,7 +20,7 @@ LL -     let _ = A::foo::<S>();
 LL +     let _ = A::foo();
    |
 
-error[E0107]: this associated function takes 0 generic arguments but 2 generic arguments were supplied
+error[E0107]: associated function takes 0 generic arguments but 2 generic arguments were supplied
   --> $DIR/issue-89064.rs:22:16
    |
 LL |     let _ = B::bar::<S, S>();
@@ -42,7 +42,7 @@ LL -     let _ = B::bar::<S, S>();
 LL +     let _ = B::bar();
    |
 
-error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: associated function takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-89064.rs:27:21
    |
 LL |     let _ = A::<S>::foo::<S>();
@@ -56,7 +56,7 @@ note: associated function defined here, with 0 generic parameters
 LL |     fn foo() {}
    |        ^^^
 
-error[E0107]: this method takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-89064.rs:31:16
    |
 LL |     let _ = 42.into::<Option<_>>();
diff --git a/tests/ui/suggestions/missing-lifetime-specifier.rs b/tests/ui/suggestions/missing-lifetime-specifier.rs
index 24f5f782f35..cb734e8ba85 100644
--- a/tests/ui/suggestions/missing-lifetime-specifier.rs
+++ b/tests/ui/suggestions/missing-lifetime-specifier.rs
@@ -37,19 +37,19 @@ thread_local! {
 
 thread_local! {
     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
-    //~^ ERROR this union takes 2 lifetime arguments but 1 lifetime argument
-    //~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-    //~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-    //~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-    //~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
+    //~^ ERROR union takes 2 lifetime arguments but 1 lifetime argument
+    //~| ERROR union takes 2 lifetime arguments but 1 lifetime argument was supplied
+    //~| ERROR union takes 2 lifetime arguments but 1 lifetime argument was supplied
+    //~| ERROR union takes 2 lifetime arguments but 1 lifetime argument was supplied
+    //~| ERROR union takes 2 lifetime arguments but 1 lifetime argument was supplied
 }
 thread_local! {
     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-    //~^ ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-    //~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-    //~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-    //~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-    //~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+    //~^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+    //~| ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+    //~| ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+    //~| ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+    //~| ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied
     //~| ERROR missing lifetime
     //~| ERROR missing lifetime
 }
diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr
index 997bbb5e9b5..21d2378382c 100644
--- a/tests/ui/suggestions/missing-lifetime-specifier.stderr
+++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr
@@ -133,7 +133,7 @@ LL | | }
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
 
-error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
@@ -151,7 +151,7 @@ help: add missing lifetime argument
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                       +++++++++
 
-error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
@@ -169,7 +169,7 @@ help: add missing lifetime argument
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                       +++++++++
 
-error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
@@ -187,7 +187,7 @@ help: add missing lifetime argument
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                       +++++++++
 
-error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
@@ -205,7 +205,7 @@ help: add missing lifetime argument
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                       +++++++++
 
-error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
@@ -223,7 +223,7 @@ help: add missing lifetime argument
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                       +++++++++
 
-error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
@@ -241,7 +241,7 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        +++++++++
 
-error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
@@ -259,7 +259,7 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        +++++++++
 
-error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
@@ -277,7 +277,7 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        +++++++++
 
-error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
@@ -295,7 +295,7 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        +++++++++
 
-error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
diff --git a/tests/ui/suggestions/missing-type-param-used-in-param.stderr b/tests/ui/suggestions/missing-type-param-used-in-param.stderr
index 4f7058a6492..3116c5a0a1c 100644
--- a/tests/ui/suggestions/missing-type-param-used-in-param.stderr
+++ b/tests/ui/suggestions/missing-type-param-used-in-param.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this function takes 2 generic arguments but 1 generic argument was supplied
+error[E0107]: function takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/missing-type-param-used-in-param.rs:6:5
    |
 LL |     two_type_params::<String>(100);
diff --git a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs
index 5e1f9361b39..4066cd3b11a 100644
--- a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs
+++ b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs
@@ -12,7 +12,7 @@ impl Foo<i32> for i32 {
 
 fn main() {
     1.bar::<i32>(0);
-    //~^ ERROR this method takes 0 generic arguments but 1 generic argument was supplied
+    //~^ ERROR method takes 0 generic arguments but 1 generic argument was supplied
     //~| HELP consider moving this generic argument to the `Foo` trait, which takes up to 1 argument
     //~| HELP remove these generics
 }
diff --git a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr
index 8ebff75c135..bfdb35947ef 100644
--- a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr
+++ b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this method takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/move-generic-to-trait-in-method-with-params.rs:14:7
    |
 LL |     1.bar::<i32>(0);
diff --git a/tests/ui/suggestions/type-ascription-instead-of-path-in-type.stderr b/tests/ui/suggestions/type-ascription-instead-of-path-in-type.stderr
index fcff02e09db..4e3180e84d2 100644
--- a/tests/ui/suggestions/type-ascription-instead-of-path-in-type.stderr
+++ b/tests/ui/suggestions/type-ascription-instead-of-path-in-type.stderr
@@ -18,7 +18,7 @@ LL |     let _: Vec<A:B> = A::B;
    = note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
-error[E0107]: this struct takes at least 1 generic argument but 0 generic arguments were supplied
+error[E0107]: struct takes at least 1 generic argument but 0 generic arguments were supplied
   --> $DIR/type-ascription-instead-of-path-in-type.rs:6:12
    |
 LL |     let _: Vec<A:B> = A::B;
diff --git a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs
index 8b6e8cfd720..ed262fd39a5 100644
--- a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs
+++ b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.rs
@@ -6,7 +6,7 @@ pub trait T<X, Y> {
 pub struct Foo {
     i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
     //~^ ERROR must be specified
-    //~| ERROR this trait takes 2 generic arguments but 4 generic arguments were supplied
+    //~| ERROR trait takes 2 generic arguments but 4 generic arguments were supplied
 }
 
 
diff --git a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr
index 75b91923284..175a5fbba61 100644
--- a/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr
+++ b/tests/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this trait takes 2 generic arguments but 4 generic arguments were supplied
+error[E0107]: trait takes 2 generic arguments but 4 generic arguments were supplied
   --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
    |
 LL |     i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs
index ad1b6e96be6..a04bb0afed5 100644
--- a/tests/ui/target-feature/invalid-attribute.rs
+++ b/tests/ui/target-feature/invalid-attribute.rs
@@ -26,12 +26,6 @@
 unsafe fn foo() {}
 
 #[target_feature(enable = "sse2")]
-//~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions
-//~| NOTE see issue #69098
-fn bar() {}
-//~^ NOTE not an `unsafe` function
-
-#[target_feature(enable = "sse2")]
 //~^ ERROR attribute should be applied to a function
 mod another {}
 //~^ NOTE not a function
@@ -75,8 +69,8 @@ trait Quux {
 
 impl Quux for Foo {
     #[target_feature(enable = "sse2")]
-    //~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions
-    //~| NOTE see issue #69098
+    //~^ ERROR `#[target_feature(..)]` cannot be applied to safe trait method
+    //~| NOTE cannot be applied to safe trait method
     fn foo() {}
     //~^ NOTE not an `unsafe` function
 }
@@ -86,9 +80,8 @@ fn main() {
     //~^ ERROR attribute should be applied to a function
     unsafe {
         foo();
-        bar();
     }
-    //~^^^^ NOTE not a function
+    //~^^^ NOTE not a function
 
     #[target_feature(enable = "sse2")]
     //~^ ERROR attribute should be applied to a function
diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr
index a2adfc67f08..22105bcca8d 100644
--- a/tests/ui/target-feature/invalid-attribute.stderr
+++ b/tests/ui/target-feature/invalid-attribute.stderr
@@ -5,7 +5,7 @@ LL | #[target_feature = "+sse2"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:34:1
+  --> $DIR/invalid-attribute.rs:28:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -14,7 +14,7 @@ LL | mod another {}
    | -------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:39:1
+  --> $DIR/invalid-attribute.rs:33:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | const FOO: usize = 7;
    | --------------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:44:1
+  --> $DIR/invalid-attribute.rs:38:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL | struct Foo;
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:49:1
+  --> $DIR/invalid-attribute.rs:43:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL | enum Bar {}
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:54:1
+  --> $DIR/invalid-attribute.rs:48:1
    |
 LL |   #[target_feature(enable = "sse2")]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -54,7 +54,7 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:62:1
+  --> $DIR/invalid-attribute.rs:56:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -63,19 +63,18 @@ LL | trait Baz {}
    | ------------ not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:85:5
+  --> $DIR/invalid-attribute.rs:79:5
    |
 LL |       #[target_feature(enable = "sse2")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL | /     unsafe {
 LL | |         foo();
-LL | |         bar();
 LL | |     }
    | |_____- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:93:5
+  --> $DIR/invalid-attribute.rs:86:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -101,36 +100,20 @@ error: malformed `target_feature` attribute input
 LL | #[target_feature(disable = "baz")]
    |                  ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
 
-error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
-  --> $DIR/invalid-attribute.rs:28:1
-   |
-LL | #[target_feature(enable = "sse2")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | fn bar() {}
-   | -------- not an `unsafe` function
-   |
-   = note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information
-   = help: add `#![feature(target_feature_11)]` to the crate attributes to enable
-
 error: cannot use `#[inline(always)]` with `#[target_feature]`
-  --> $DIR/invalid-attribute.rs:67:1
+  --> $DIR/invalid-attribute.rs:61:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
 
-error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
-  --> $DIR/invalid-attribute.rs:77:5
+error: `#[target_feature(..)]` cannot be applied to safe trait method
+  --> $DIR/invalid-attribute.rs:71:5
    |
 LL |     #[target_feature(enable = "sse2")]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
 ...
 LL |     fn foo() {}
    |     -------- not an `unsafe` function
-   |
-   = note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information
-   = help: add `#![feature(target_feature_11)]` to the crate attributes to enable
 
-error: aborting due to 15 previous errors
+error: aborting due to 14 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout
index c399fa66b6a..c31e6a218ce 100644
--- a/tests/ui/thir-print/thir-flat.stdout
+++ b/tests/ui/thir-print/thir-flat.stdout
@@ -1,5 +1,8 @@
 DefId(0:3 ~ thir_flat[45a6]::main):
 Thir {
+    body_type: Fn(
+        ([]; c_variadic: false)->(),
+    ),
     arms: [],
     blocks: [
         Block {
diff --git a/tests/ui/tool-attributes/auxiliary/p1.rs b/tests/ui/tool-attributes/auxiliary/p1.rs
new file mode 100644
index 00000000000..47195c7e9d6
--- /dev/null
+++ b/tests/ui/tool-attributes/auxiliary/p1.rs
@@ -0,0 +1,3 @@
+#![feature(rustc_attrs)]
+#[rustc_diagnostic_item = "Foo"]
+pub struct Foo {}
diff --git a/tests/ui/tool-attributes/auxiliary/p2.rs b/tests/ui/tool-attributes/auxiliary/p2.rs
new file mode 100644
index 00000000000..47195c7e9d6
--- /dev/null
+++ b/tests/ui/tool-attributes/auxiliary/p2.rs
@@ -0,0 +1,3 @@
+#![feature(rustc_attrs)]
+#[rustc_diagnostic_item = "Foo"]
+pub struct Foo {}
diff --git a/tests/ui/tool-attributes/duplicate-diagnostic.rs b/tests/ui/tool-attributes/duplicate-diagnostic.rs
new file mode 100644
index 00000000000..e2cf9508757
--- /dev/null
+++ b/tests/ui/tool-attributes/duplicate-diagnostic.rs
@@ -0,0 +1,13 @@
+// aux-build: p1.rs
+// aux-build: p2.rs
+
+// error-pattern: duplicate diagnostic item in crate `p2`
+// error-pattern: note: the diagnostic item is first defined in crate `p1`
+
+#![feature(rustc_attrs)]
+extern crate p1;
+extern crate p2;
+
+#[rustc_diagnostic_item = "Foo"]
+pub struct Foo {} //~ ERROR duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo`
+fn main() {}
diff --git a/tests/ui/tool-attributes/duplicate-diagnostic.stderr b/tests/ui/tool-attributes/duplicate-diagnostic.stderr
new file mode 100644
index 00000000000..26bd6a82e34
--- /dev/null
+++ b/tests/ui/tool-attributes/duplicate-diagnostic.stderr
@@ -0,0 +1,14 @@
+error: duplicate diagnostic item in crate `p2`: `Foo`.
+   |
+   = note: the diagnostic item is first defined in crate `p1`.
+
+error: duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo`.
+  --> $DIR/duplicate-diagnostic.rs:12:1
+   |
+LL | pub struct Foo {}
+   | ^^^^^^^^^^^^^^
+   |
+   = note: the diagnostic item is first defined in crate `p2`.
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr
index 3ec288d1382..dc967d51298 100644
--- a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr
+++ b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr
@@ -4,7 +4,7 @@ error[E0568]: auto traits cannot have super traits or lifetime bounds
 LL | auto trait Magic: Copy {}
    |            -----^^^^^^ help: remove the super traits or lifetime bounds
    |            |
-   |            auto trait cannot have super traits or lifetime bounds
+   |            auto traits cannot have super traits or lifetime bounds
 
 error[E0277]: the trait bound `NoClone: Copy` is not satisfied
   --> $DIR/supertrait-auto-trait.rs:16:23
diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr
index a397b0accc8..d4fea05fe4b 100644
--- a/tests/ui/traits/issue-77982.stderr
+++ b/tests/ui/traits/issue-77982.stderr
@@ -43,7 +43,7 @@ LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(
    |                                            |
    |                                            required by a bound introduced by this call
    |
-   = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
+   = note: multiple `impl`s satisfying `u32: From<_>` found in the `core` crate:
            - impl From<Ipv4Addr> for u32;
            - impl From<NonZeroU32> for u32;
            - impl From<bool> for u32;
diff --git a/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs
new file mode 100644
index 00000000000..c886aeeda3e
--- /dev/null
+++ b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs
@@ -0,0 +1,17 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+trait Trait<'a> {
+    type Item: for<'b> Trait2<'b>;
+}
+
+trait Trait2<'a> {}
+impl Trait2<'_> for () {}
+
+fn needs_trait(_: Box<impl for<'a> Trait<'a> + ?Sized>) {}
+
+fn foo(x: Box<dyn for<'a> Trait<'a, Item = ()>>) {
+    needs_trait(x);
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/more-object-bound.rs b/tests/ui/traits/new-solver/more-object-bound.rs
new file mode 100644
index 00000000000..712759ef0e6
--- /dev/null
+++ b/tests/ui/traits/new-solver/more-object-bound.rs
@@ -0,0 +1,27 @@
+// compile-flags: -Ztrait-solver=next
+// From #80800
+
+trait SuperTrait {
+    type A;
+    type B;
+}
+
+trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {}
+
+fn transmute<A, B>(x: A) -> B {
+    foo::<A, B, dyn Trait<A = A, B = B>>(x)
+    //~^ ERROR type annotations needed: cannot satisfy `dyn Trait<A = A, B = B>: Trait`
+}
+
+fn foo<A, B, T: ?Sized>(x: T::A) -> B
+where
+    T: Trait<B = B>,
+{
+    x
+}
+
+static X: u8 = 0;
+fn main() {
+    let x = transmute::<&u8, &[u8; 1_000_000]>(&X);
+    println!("{:?}", x[100_000]);
+}
diff --git a/tests/ui/traits/new-solver/more-object-bound.stderr b/tests/ui/traits/new-solver/more-object-bound.stderr
new file mode 100644
index 00000000000..208fdecb08f
--- /dev/null
+++ b/tests/ui/traits/new-solver/more-object-bound.stderr
@@ -0,0 +1,19 @@
+error[E0283]: type annotations needed: cannot satisfy `dyn Trait<A = A, B = B>: Trait`
+  --> $DIR/more-object-bound.rs:12:5
+   |
+LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: cannot satisfy `dyn Trait<A = A, B = B>: Trait`
+note: required by a bound in `foo`
+  --> $DIR/more-object-bound.rs:18:8
+   |
+LL | fn foo<A, B, T: ?Sized>(x: T::A) -> B
+   |    --- required by a bound in this function
+LL | where
+LL |     T: Trait<B = B>,
+   |        ^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/new-solver/object-unsafety.rs b/tests/ui/traits/new-solver/object-unsafety.rs
new file mode 100644
index 00000000000..7bdd863a762
--- /dev/null
+++ b/tests/ui/traits/new-solver/object-unsafety.rs
@@ -0,0 +1,20 @@
+// compile-flags: -Ztrait-solver=next
+
+trait Setup {
+    type From: Copy;
+}
+
+fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
+    *from
+}
+
+pub fn copy_any<T>(t: &T) -> T {
+    copy::<dyn Setup<From=T>>(t)
+    //~^ ERROR the trait bound `dyn Setup<From = T>: Setup` is not satisfied
+}
+
+fn main() {
+    let x = String::from("Hello, world");
+    let y = copy_any(&x);
+    println!("{y}");
+}
diff --git a/tests/ui/traits/new-solver/object-unsafety.stderr b/tests/ui/traits/new-solver/object-unsafety.stderr
new file mode 100644
index 00000000000..198ac623df8
--- /dev/null
+++ b/tests/ui/traits/new-solver/object-unsafety.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `dyn Setup<From = T>: Setup` is not satisfied
+  --> $DIR/object-unsafety.rs:12:12
+   |
+LL |     copy::<dyn Setup<From=T>>(t)
+   |            ^^^^^^^^^^^^^^^^^ the trait `Setup` is not implemented for `dyn Setup<From = T>`
+   |
+note: required by a bound in `copy`
+  --> $DIR/object-unsafety.rs:7:12
+   |
+LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
+   |            ^^^^^ required by this bound in `copy`
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | pub fn copy_any<T>(t: &T) -> T where dyn Setup<From = T>: Setup {
+   |                                ++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/try-example.rs b/tests/ui/traits/new-solver/try-example.rs
new file mode 100644
index 00000000000..e826f3a0059
--- /dev/null
+++ b/tests/ui/traits/new-solver/try-example.rs
@@ -0,0 +1,28 @@
+// check-pass
+// compile-flags: -Ztrait-solver=next
+
+use std::error::Error;
+
+fn main() -> Result<(), Box<dyn Error>> {
+    let x: i32 = parse()?;
+    Ok(())
+}
+
+trait Parse {}
+
+impl Parse for i32 {}
+
+#[derive(Debug)]
+struct ParseError;
+
+impl std::fmt::Display for ParseError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "ParseError")
+    }
+}
+
+impl Error for ParseError {}
+
+fn parse<T: Parse>() -> Result<T, ParseError> {
+    todo!()
+}
diff --git a/tests/ui/traits/object/vs-lifetime.rs b/tests/ui/traits/object/vs-lifetime.rs
index 14ae67cffd7..d3e6c0b217c 100644
--- a/tests/ui/traits/object/vs-lifetime.rs
+++ b/tests/ui/traits/object/vs-lifetime.rs
@@ -9,8 +9,8 @@ fn main() {
     let _: S<'static, dyn 'static +>;
     //~^ at least one trait is required for an object type
     let _: S<'static, 'static>;
-    //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
-    //~| ERROR this struct takes 1 generic argument but 0 generic arguments were supplied
+    //~^ ERROR struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+    //~| ERROR struct takes 1 generic argument but 0 generic arguments were supplied
     let _: S<dyn 'static +, 'static>;
     //~^ ERROR type provided when a lifetime was expected
     //~| ERROR at least one trait is required for an object type
diff --git a/tests/ui/traits/object/vs-lifetime.stderr b/tests/ui/traits/object/vs-lifetime.stderr
index 22446522852..a69cd140807 100644
--- a/tests/ui/traits/object/vs-lifetime.stderr
+++ b/tests/ui/traits/object/vs-lifetime.stderr
@@ -4,7 +4,7 @@ error[E0224]: at least one trait is required for an object type
 LL |     let _: S<'static, dyn 'static +>;
    |                       ^^^^^^^^^^^^^
 
-error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/vs-lifetime.rs:11:12
    |
 LL |     let _: S<'static, 'static>;
@@ -18,7 +18,7 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct S<'a, T>(&'a u8, T);
    |        ^ --
 
-error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/vs-lifetime.rs:11:12
    |
 LL |     let _: S<'static, 'static>;
diff --git a/tests/ui/traits/test-2.rs b/tests/ui/traits/test-2.rs
index 3fb0cec6a3b..ffb778a0141 100644
--- a/tests/ui/traits/test-2.rs
+++ b/tests/ui/traits/test-2.rs
@@ -7,9 +7,9 @@ impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
 
 fn main() {
     10.dup::<i32>();
-    //~^ ERROR this method takes 0 generic arguments but 1
+    //~^ ERROR method takes 0 generic arguments but 1
     10.blah::<i32, i32>();
-    //~^ ERROR this method takes 1 generic argument but 2
+    //~^ ERROR method takes 1 generic argument but 2
     (Box::new(10) as Box<dyn bar>).dup();
     //~^ ERROR E0038
     //~| ERROR E0038
diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr
index 2219ba9c333..6c0e8b8af4b 100644
--- a/tests/ui/traits/test-2.stderr
+++ b/tests/ui/traits/test-2.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this method takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/test-2.rs:9:8
    |
 LL |     10.dup::<i32>();
@@ -12,7 +12,7 @@ note: method defined here, with 0 generic parameters
 LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
    |                ^^^
 
-error[E0107]: this method takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: method takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/test-2.rs:11:8
    |
 LL |     10.blah::<i32, i32>();
diff --git a/tests/ui/transmutability/issue-101739-2.rs b/tests/ui/transmutability/issue-101739-2.rs
index 964a7e49ee6..e5a56ccc9e0 100644
--- a/tests/ui/transmutability/issue-101739-2.rs
+++ b/tests/ui/transmutability/issue-101739-2.rs
@@ -15,7 +15,7 @@ mod assert {
         const ASSUME_VISIBILITY: bool,
     >()
     where
-        Dst: BikeshedIntrinsicFrom< //~ ERROR this trait takes at most 3 generic arguments but 6 generic arguments were supplied
+        Dst: BikeshedIntrinsicFrom< //~ ERROR trait takes at most 3 generic arguments but 6 generic arguments were supplied
             Src,
             Context,
             ASSUME_ALIGNMENT,
diff --git a/tests/ui/transmutability/issue-101739-2.stderr b/tests/ui/transmutability/issue-101739-2.stderr
index 1b3d202590d..420a9f33008 100644
--- a/tests/ui/transmutability/issue-101739-2.stderr
+++ b/tests/ui/transmutability/issue-101739-2.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this trait takes at most 3 generic arguments but 6 generic arguments were supplied
+error[E0107]: trait takes at most 3 generic arguments but 6 generic arguments were supplied
   --> $DIR/issue-101739-2.rs:18:14
    |
 LL |           Dst: BikeshedIntrinsicFrom<
diff --git a/tests/ui/type-alias-enum-variants/enum-variant-generic-args.rs b/tests/ui/type-alias-enum-variants/enum-variant-generic-args.rs
index 0031a4665c8..759a7fd7e05 100644
--- a/tests/ui/type-alias-enum-variants/enum-variant-generic-args.rs
+++ b/tests/ui/type-alias-enum-variants/enum-variant-generic-args.rs
@@ -62,10 +62,10 @@ fn main() {
     AliasFixed::TSVariant::<()>(());
     //~^ ERROR type arguments are not allowed on this type [E0109]
     AliasFixed::<()>::TSVariant(());
-    //~^ ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
+    //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
     AliasFixed::<()>::TSVariant::<()>(());
     //~^ ERROR type arguments are not allowed on this type [E0109]
-    //~| ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
+    //~| ERROR type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
 
     // Struct variant
 
@@ -80,10 +80,10 @@ fn main() {
     AliasFixed::SVariant::<()> { v: () };
     //~^ ERROR type arguments are not allowed on this type [E0109]
     AliasFixed::<()>::SVariant { v: () };
-    //~^ ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
+    //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
     AliasFixed::<()>::SVariant::<()> { v: () };
     //~^ ERROR type arguments are not allowed on this type [E0109]
-    //~| ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
+    //~| ERROR type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
 
     // Unit variant
 
@@ -98,8 +98,8 @@ fn main() {
     AliasFixed::UVariant::<()>;
     //~^ ERROR type arguments are not allowed on this type [E0109]
     AliasFixed::<()>::UVariant;
-    //~^ ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
+    //~^ ERROR type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
     AliasFixed::<()>::UVariant::<()>;
     //~^ ERROR type arguments are not allowed on this type [E0109]
-    //~| ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
+    //~| ERROR type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
 }
diff --git a/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr b/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
index a922d7a5e41..758ff31ff70 100644
--- a/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
+++ b/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
@@ -304,7 +304,7 @@ LL |     AliasFixed::TSVariant::<()>(());
    |                 |
    |                 not allowed on this type
 
-error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/enum-variant-generic-args.rs:64:5
    |
 LL |     AliasFixed::<()>::TSVariant(());
@@ -318,7 +318,7 @@ note: type alias defined here, with 0 generic parameters
 LL | type AliasFixed = Enum<()>;
    |      ^^^^^^^^^^
 
-error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/enum-variant-generic-args.rs:66:5
    |
 LL |     AliasFixed::<()>::TSVariant::<()>(());
@@ -395,7 +395,7 @@ LL -     AliasFixed::SVariant::<()> { v: () };
 LL +     AliasFixed::<()>::SVariant { v: () };
    |
 
-error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/enum-variant-generic-args.rs:82:5
    |
 LL |     AliasFixed::<()>::SVariant { v: () };
@@ -409,7 +409,7 @@ note: type alias defined here, with 0 generic parameters
 LL | type AliasFixed = Enum<()>;
    |      ^^^^^^^^^^
 
-error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/enum-variant-generic-args.rs:84:5
    |
 LL |     AliasFixed::<()>::SVariant::<()> { v: () };
@@ -470,7 +470,7 @@ LL |     AliasFixed::UVariant::<()>;
    |                 |
    |                 not allowed on this type
 
-error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/enum-variant-generic-args.rs:100:5
    |
 LL |     AliasFixed::<()>::UVariant;
@@ -484,7 +484,7 @@ note: type alias defined here, with 0 generic parameters
 LL | type AliasFixed = Enum<()>;
    |      ^^^^^^^^^^
 
-error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/enum-variant-generic-args.rs:102:5
    |
 LL |     AliasFixed::<()>::UVariant::<()>;
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr
index a31cf1a51cc..ff375b2ff86 100644
--- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr
+++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr
@@ -1,4 +1,4 @@
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return types
   --> $DIR/type-alias-impl-trait-fn-type.rs:6:20
    |
 LL | type Foo = fn() -> impl Send;
diff --git a/tests/ui/typeck/issue-104513-ice.stderr b/tests/ui/typeck/issue-104513-ice.stderr
index 42cfe38aed8..09187d7863a 100644
--- a/tests/ui/typeck/issue-104513-ice.stderr
+++ b/tests/ui/typeck/issue-104513-ice.stderr
@@ -4,7 +4,7 @@ error[E0405]: cannot find trait `Oops` in this scope
 LL |     let _: S<impl Oops> = S;
    |                   ^^^^ not found in this scope
 
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable bindings
   --> $DIR/issue-104513-ice.rs:3:14
    |
 LL |     let _: S<impl Oops> = S;
diff --git a/tests/ui/typeck/issue-75883.rs b/tests/ui/typeck/issue-75883.rs
index 885acc48231..c50ea0a086b 100644
--- a/tests/ui/typeck/issue-75883.rs
+++ b/tests/ui/typeck/issue-75883.rs
@@ -4,7 +4,7 @@ pub struct UI {}
 
 impl UI {
     pub fn run() -> Result<_> {
-        //~^ ERROR: this enum takes 2 generic arguments but 1 generic argument was supplied
+        //~^ ERROR: enum takes 2 generic arguments but 1 generic argument was supplied
         //~| ERROR: the placeholder `_` is not allowed within types on item signatures for return types
         let mut ui = UI {};
         ui.interact();
@@ -13,7 +13,7 @@ impl UI {
     }
 
     pub fn interact(&mut self) -> Result<_> {
-        //~^ ERROR: this enum takes 2 generic arguments but 1 generic argument was supplied
+        //~^ ERROR: enum takes 2 generic arguments but 1 generic argument was supplied
         //~| ERROR: the placeholder `_` is not allowed within types on item signatures for return types
         unimplemented!();
     }
diff --git a/tests/ui/typeck/issue-75883.stderr b/tests/ui/typeck/issue-75883.stderr
index f5adcabe3e9..a1ed0840675 100644
--- a/tests/ui/typeck/issue-75883.stderr
+++ b/tests/ui/typeck/issue-75883.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
+error[E0107]: enum takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-75883.rs:6:21
    |
 LL |     pub fn run() -> Result<_> {
@@ -11,7 +11,7 @@ help: add missing generic argument
 LL |     pub fn run() -> Result<_, E> {
    |                             +++
 
-error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
+error[E0107]: enum takes 2 generic arguments but 1 generic argument was supplied
   --> $DIR/issue-75883.rs:15:35
    |
 LL |     pub fn interact(&mut self) -> Result<_> {
diff --git a/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.rs b/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.rs
new file mode 100644
index 00000000000..5ff567cd07c
--- /dev/null
+++ b/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.rs
@@ -0,0 +1,6 @@
+// compile-flags: -Ztrait-solver=next
+// known-bug: unknown
+
+fn main() {
+    (0u8 + 0u8) as char;
+}
diff --git a/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.stderr b/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.stderr
new file mode 100644
index 00000000000..6b09ccd5214
--- /dev/null
+++ b/tests/ui/typeck/lazy-norm/cast-checks-handling-projections.stderr
@@ -0,0 +1,9 @@
+error[E0271]: type mismatch resolving `char == <u8 as Add>::Output`
+  --> $DIR/cast-checks-handling-projections.rs:5:5
+   |
+LL |     (0u8 + 0u8) as char;
+   |     ^^^^^^^^^^^ types differ
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs b/tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs
new file mode 100644
index 00000000000..019c6e81c50
--- /dev/null
+++ b/tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs
@@ -0,0 +1,24 @@
+// compile-flags: -Ztrait-solver=next
+// known-bug: unknown
+
+trait Test {
+    type Assoc;
+}
+
+fn transform<T: Test>(x: T) -> T::Assoc {
+    todo!()
+}
+
+impl Test for i32 {
+    type Assoc = i32;
+}
+
+impl Test for String {
+    type Assoc = String;
+}
+
+fn main() {
+    let mut x = Default::default();
+    x = transform(x);
+    x = 1i32;
+}
diff --git a/tests/ui/typeck/lazy-norm/equating-projection-cyclically.stderr b/tests/ui/typeck/lazy-norm/equating-projection-cyclically.stderr
new file mode 100644
index 00000000000..57cbc65a17a
--- /dev/null
+++ b/tests/ui/typeck/lazy-norm/equating-projection-cyclically.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/equating-projection-cyclically.rs:22:19
+   |
+LL |     x = transform(x);
+   |                   ^ expected inferred type, found associated type
+   |
+   = note:         expected type `_`
+           found associated type `<_ as Test>::Assoc`
+   = help: consider constraining the associated type `<_ as Test>::Assoc` to `_`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/typeck-builtin-bound-type-parameters.rs b/tests/ui/typeck/typeck-builtin-bound-type-parameters.rs
index c463a8ad0c7..7ff9199f63c 100644
--- a/tests/ui/typeck/typeck-builtin-bound-type-parameters.rs
+++ b/tests/ui/typeck/typeck-builtin-bound-type-parameters.rs
@@ -1,17 +1,17 @@
 fn foo1<T:Copy<U>, U>(x: T) {}
-//~^ ERROR this trait takes 0 generic arguments but 1 generic argument was supplied
+//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
 
 trait Trait: Copy<dyn Send> {}
-//~^ ERROR this trait takes 0 generic arguments but 1 generic argument was supplied
+//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
 
 struct MyStruct1<T: Copy<T>>;
-//~^ ERROR this trait takes 0 generic arguments but 1 generic argument was supplied
+//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
 
 struct MyStruct2<'a, T: Copy<'a>>;
-//~^ ERROR this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
+//~^ ERROR trait takes 0 lifetime arguments but 1 lifetime argument was supplied
 
 fn foo2<'a, T:Copy<'a, U>, U>(x: T) {}
-//~^ ERROR this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
-//~| ERROR this trait takes 0 generic arguments but 1 generic argument was supplied
+//~^ ERROR trait takes 0 lifetime arguments but 1 lifetime argument was supplied
+//~| ERROR trait takes 0 generic arguments but 1 generic argument was supplied
 
 fn main() { }
diff --git a/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr b/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr
index 331540d1e42..a71fd953658 100644
--- a/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr
+++ b/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/typeck-builtin-bound-type-parameters.rs:1:11
    |
 LL | fn foo1<T:Copy<U>, U>(x: T) {}
@@ -6,7 +6,7 @@ LL | fn foo1<T:Copy<U>, U>(x: T) {}
    |           |
    |           expected 0 generic arguments
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/typeck-builtin-bound-type-parameters.rs:4:14
    |
 LL | trait Trait: Copy<dyn Send> {}
@@ -14,7 +14,7 @@ LL | trait Trait: Copy<dyn Send> {}
    |              |
    |              expected 0 generic arguments
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/typeck-builtin-bound-type-parameters.rs:7:21
    |
 LL | struct MyStruct1<T: Copy<T>>;
@@ -22,7 +22,7 @@ LL | struct MyStruct1<T: Copy<T>>;
    |                     |
    |                     expected 0 generic arguments
 
-error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/typeck-builtin-bound-type-parameters.rs:10:25
    |
 LL | struct MyStruct2<'a, T: Copy<'a>>;
@@ -30,7 +30,7 @@ LL | struct MyStruct2<'a, T: Copy<'a>>;
    |                         |
    |                         expected 0 lifetime arguments
 
-error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
+error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/typeck-builtin-bound-type-parameters.rs:13:15
    |
 LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {}
@@ -38,7 +38,7 @@ LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {}
    |               |
    |               expected 0 lifetime arguments
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/typeck-builtin-bound-type-parameters.rs:13:15
    |
 LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {}
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs
index b96c5271339..a450dbb82d1 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.rs
+++ b/tests/ui/typeck/typeck_type_placeholder_item.rs
@@ -227,4 +227,6 @@ fn evens_squared(n: usize) -> _ {
 }
 
 const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
-//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+//~^ ERROR the trait bound
+//~| ERROR the trait bound
+//~| ERROR the placeholder
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index bc02547c65e..bc6c9fd0779 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -437,17 +437,37 @@ LL | fn evens_squared(n: usize) -> _ {
    |                               not allowed in type signatures
    |                               help: replace with an appropriate return type: `impl Iterator<Item = usize>`
 
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
-  --> $DIR/typeck_type_placeholder_item.rs:229:10
+error[E0277]: the trait bound `std::ops::Range<{integer}>: Iterator` is not satisfied
+  --> $DIR/typeck_type_placeholder_item.rs:229:22
    |
 LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
-   |          ^ not allowed in type signatures
+   |                      ^^^^^^ `std::ops::Range<{integer}>` is not an iterator
+   |
+   = help: the trait `~const Iterator` is not implemented for `std::ops::Range<{integer}>`
+note: the trait `Iterator` is implemented for `std::ops::Range<{integer}>`, but that implementation is not `const`
+  --> $DIR/typeck_type_placeholder_item.rs:229:14
+   |
+LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+   |              ^^^^^^^
+
+error[E0277]: the trait bound `Filter<std::ops::Range<{integer}>, [closure@$DIR/typeck_type_placeholder_item.rs:229:29: 229:32]>: Iterator` is not satisfied
+  --> $DIR/typeck_type_placeholder_item.rs:229:45
    |
-note: however, the inferred type `Map<Filter<Range<i32>, [closure@typeck_type_placeholder_item.rs:229:29]>, [closure@typeck_type_placeholder_item.rs:229:49]>` cannot be named
+LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+   |                                             ^^^ `Filter<std::ops::Range<{integer}>, [closure@$DIR/typeck_type_placeholder_item.rs:229:29: 229:32]>` is not an iterator
+   |
+   = help: the trait `~const Iterator` is not implemented for `Filter<std::ops::Range<{integer}>, [closure@$DIR/typeck_type_placeholder_item.rs:229:29: 229:32]>`
+note: the trait `Iterator` is implemented for `Filter<std::ops::Range<{integer}>, [closure@$DIR/typeck_type_placeholder_item.rs:229:29: 229:32]>`, but that implementation is not `const`
   --> $DIR/typeck_type_placeholder_item.rs:229:14
    |
 LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/typeck_type_placeholder_item.rs:229:10
+   |
+LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+   |          ^ not allowed in type signatures
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:140:31
@@ -657,7 +677,7 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace with the correct type: `i32`
 
-error: aborting due to 71 previous errors
+error: aborting due to 73 previous errors
 
-Some errors have detailed explanations: E0121, E0282, E0403.
+Some errors have detailed explanations: E0121, E0277, E0282, E0403.
 For more information about an error, try `rustc --explain E0121`.
diff --git a/tests/ui/typeck/typeck_type_placeholder_lifetime_1.rs b/tests/ui/typeck/typeck_type_placeholder_lifetime_1.rs
index 43e46c5b6c3..90b12ffdf77 100644
--- a/tests/ui/typeck/typeck_type_placeholder_lifetime_1.rs
+++ b/tests/ui/typeck/typeck_type_placeholder_lifetime_1.rs
@@ -7,5 +7,5 @@ struct Foo<'a, T:'a> {
 
 pub fn main() {
     let c: Foo<_, _> = Foo { r: &5 };
-    //~^ ERROR this struct takes 1 generic argument but 2 generic arguments were supplied
+    //~^ ERROR struct takes 1 generic argument but 2 generic arguments were supplied
 }
diff --git a/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr b/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr
index a89c6b85c78..c4e4aed2067 100644
--- a/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/typeck_type_placeholder_lifetime_1.rs:9:12
    |
 LL |     let c: Foo<_, _> = Foo { r: &5 };
diff --git a/tests/ui/typeck/typeck_type_placeholder_lifetime_2.rs b/tests/ui/typeck/typeck_type_placeholder_lifetime_2.rs
index 178b8b1229a..e361312ddba 100644
--- a/tests/ui/typeck/typeck_type_placeholder_lifetime_2.rs
+++ b/tests/ui/typeck/typeck_type_placeholder_lifetime_2.rs
@@ -7,5 +7,5 @@ struct Foo<'a, T:'a> {
 
 pub fn main() {
     let c: Foo<_, usize> = Foo { r: &5 };
-    //~^ ERROR this struct takes 1 generic argument but 2 generic arguments were supplied
+    //~^ ERROR struct takes 1 generic argument but 2 generic arguments were supplied
 }
diff --git a/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr b/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr
index f30766bdf01..302231777bd 100644
--- a/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this struct takes 1 generic argument but 2 generic arguments were supplied
+error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/typeck_type_placeholder_lifetime_2.rs:9:12
    |
 LL |     let c: Foo<_, usize> = Foo { r: &5 };
diff --git a/tests/ui/ufcs/ufcs-qpath-missing-params.rs b/tests/ui/ufcs/ufcs-qpath-missing-params.rs
index a110bec4c0f..6ab6580c0e6 100644
--- a/tests/ui/ufcs/ufcs-qpath-missing-params.rs
+++ b/tests/ui/ufcs/ufcs-qpath-missing-params.rs
@@ -15,6 +15,6 @@ fn main() {
       //~^ ERROR missing generics for
 
     <String as IntoCow>::into_cow::<str>("foo".to_string());
-    //~^ ERROR this method takes 0 generic arguments but 1
+    //~^ ERROR method takes 0 generic arguments but 1
     //~| ERROR missing generics for
 }
diff --git a/tests/ui/ufcs/ufcs-qpath-missing-params.stderr b/tests/ui/ufcs/ufcs-qpath-missing-params.stderr
index ace1c36d674..2338871218b 100644
--- a/tests/ui/ufcs/ufcs-qpath-missing-params.stderr
+++ b/tests/ui/ufcs/ufcs-qpath-missing-params.stderr
@@ -30,7 +30,7 @@ help: add missing generic argument
 LL |     <String as IntoCow<B>>::into_cow::<str>("foo".to_string());
    |                       +++
 
-error[E0107]: this method takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/ufcs-qpath-missing-params.rs:17:26
    |
 LL |     <String as IntoCow>::into_cow::<str>("foo".to_string());
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs
index 65f40075bd8..c575f507704 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs
@@ -28,7 +28,7 @@ fn test<'a,'b>() {
 }
 
 fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) {
-    //~^ ERROR this trait takes 1 lifetime argument but 0 lifetime arguments were supplied
+    //~^ ERROR trait takes 1 lifetime argument but 0 lifetime arguments were supplied
     // Here, the omitted lifetimes are expanded to distinct things.
     same_type(x, y)
 }
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr
index 016fc4dfb24..8814617814c 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this trait takes 1 lifetime argument but 0 lifetime arguments were supplied
+error[E0107]: trait takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/unboxed-closure-sugar-region.rs:30:51
    |
 LL | fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) {
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs
index 462f6fb7b87..14d5646b508 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.rs
@@ -7,7 +7,7 @@ struct Bar<A> {
 fn bar() {
     let x: Box<Bar()> = panic!();
     //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
-    //~| ERROR this struct takes 1 generic argument but 0 generic arguments
+    //~| ERROR struct takes 1 generic argument but 0 generic arguments
 }
 
 fn main() { }
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr
index 29ea5735cad..27b22c2127b 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct-1.stderr
@@ -4,7 +4,7 @@ error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
 LL |     let x: Box<Bar()> = panic!();
    |                ^^^^^ only `Fn` traits may use parentheses
 
-error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/unboxed-closure-sugar-used-on-struct-1.rs:8:16
    |
 LL |     let x: Box<Bar()> = panic!();
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs
index bd61cbd8022..657b29204cd 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.rs
@@ -6,7 +6,7 @@ struct Bar<A> {
 
 fn foo(b: Box<Bar()>) {
     //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
-    //~| ERROR this struct takes 1 generic argument but 0 generic arguments
+    //~| ERROR struct takes 1 generic argument but 0 generic arguments
 }
 
 fn main() { }
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr
index 427ba3414f8..94e42a66c9e 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-used-on-struct.stderr
@@ -4,7 +4,7 @@ error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
 LL | fn foo(b: Box<Bar()>) {
    |               ^^^^^ only `Fn` traits may use parentheses
 
-error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
+error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/unboxed-closure-sugar-used-on-struct.rs:7:15
    |
 LL | fn foo(b: Box<Bar()>) {
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
index f26ad8e93a1..dd47ae73a38 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
@@ -3,7 +3,7 @@
 trait Three<A,B,C> { fn dummy(&self) -> (A,B,C); }
 
 fn foo(_: &dyn Three())
-//~^ ERROR this trait takes 3 generic arguments but 1 generic argument
+//~^ ERROR trait takes 3 generic arguments but 1 generic argument
 //~| ERROR associated type `Output` not found
 {}
 
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr
index ebaacf0a698..5d7fe3fa533 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this trait takes 3 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16
    |
 LL | fn foo(_: &dyn Three())
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
index 4465b43a757..2c7e12f3257 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
@@ -3,25 +3,25 @@
 trait Zero { fn dummy(&self); }
 
 fn foo1(_: dyn Zero()) {
-    //~^ ERROR this trait takes 0 generic arguments but 1 generic argument
+    //~^ ERROR trait takes 0 generic arguments but 1 generic argument
     //~| ERROR associated type `Output` not found for `Zero`
 }
 
 fn foo2(_: dyn Zero<usize>) {
-    //~^ ERROR this trait takes 0 generic arguments but 1 generic argument
+    //~^ ERROR trait takes 0 generic arguments but 1 generic argument
 }
 
 fn foo3(_: dyn Zero <   usize   >) {
-    //~^ ERROR this trait takes 0 generic arguments but 1 generic argument
+    //~^ ERROR trait takes 0 generic arguments but 1 generic argument
 }
 
 fn foo4(_: dyn Zero(usize)) {
-    //~^ ERROR this trait takes 0 generic arguments but 1 generic argument
+    //~^ ERROR trait takes 0 generic arguments but 1 generic argument
     //~| ERROR associated type `Output` not found for `Zero`
 }
 
 fn foo5(_: dyn Zero (   usize   )) {
-    //~^ ERROR this trait takes 0 generic arguments but 1 generic argument
+    //~^ ERROR trait takes 0 generic arguments but 1 generic argument
     //~| ERROR associated type `Output` not found for `Zero`
 }
 
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr
index 9601e64c189..50b90553aa7 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:16
    |
 LL | fn foo1(_: dyn Zero()) {
@@ -18,7 +18,7 @@ error[E0220]: associated type `Output` not found for `Zero`
 LL | fn foo1(_: dyn Zero()) {
    |                ^^^^^^ associated type `Output` not found
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:10:16
    |
 LL | fn foo2(_: dyn Zero<usize>) {
@@ -32,7 +32,7 @@ note: trait defined here, with 0 generic parameters
 LL | trait Zero { fn dummy(&self); }
    |       ^^^^
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:14:16
    |
 LL | fn foo3(_: dyn Zero <   usize   >) {
@@ -46,7 +46,7 @@ note: trait defined here, with 0 generic parameters
 LL | trait Zero { fn dummy(&self); }
    |       ^^^^
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:18:16
    |
 LL | fn foo4(_: dyn Zero(usize)) {
@@ -66,7 +66,7 @@ error[E0220]: associated type `Output` not found for `Zero`
 LL | fn foo4(_: dyn Zero(usize)) {
    |                ^^^^^^^^^^^ associated type `Output` not found
 
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:23:16
    |
 LL | fn foo5(_: dyn Zero (   usize   )) {
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.rs
index 4bcf90552f9..ad60b0a0c77 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.rs
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.rs
@@ -3,7 +3,7 @@
 trait Trait {}
 
 fn f<F:Trait(isize) -> isize>(x: F) {}
-//~^ ERROR this trait takes 0 generic arguments but 1 generic argument
+//~^ ERROR trait takes 0 generic arguments but 1 generic argument
 //~| ERROR associated type `Output` not found for `Trait`
 
 fn main() {}
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr
index 3ff05fb2331..130b193d69c 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr
@@ -1,4 +1,4 @@
-error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/unboxed-closure-sugar-wrong-trait.rs:5:8
    |
 LL | fn f<F:Trait(isize) -> isize>(x: F) {}
diff --git a/triagebot.toml b/triagebot.toml
index 7a26457ab04..f7607d522c1 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -482,7 +482,6 @@ compiler-team = [
     "@davidtwco",
     "@oli-obk",
     "@lcnr",
-    "@nagisa",
     "@wesleywiser",
     "@michaelwoerister",
 ]
@@ -552,7 +551,6 @@ mir = [
     "@oli-obk",
 ]
 mir-opt = [
-    "@nagisa",
     "@oli-obk",
     "@wesleywiser",
 ]