about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock18
-rw-r--r--Cargo.toml1
-rw-r--r--compiler/rustc_ast/src/util/literal.rs2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs104
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs7
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs6
-rw-r--r--compiler/rustc_attr/src/builtin.rs35
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs167
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs185
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs46
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs14
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/location.rs2
-rw-r--r--compiler/rustc_borrowck/src/nll.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs33
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs14
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/comments.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs8
-rw-r--r--compiler/rustc_codegen_gcc/src/type_of.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/glue.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs168
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs78
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs188
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs12
-rw-r--r--compiler/rustc_const_eval/src/util/alignment.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/call_kind.rs2
-rw-r--r--compiler/rustc_data_structures/src/intern.rs10
-rw-r--r--compiler/rustc_data_structures/src/transitive_relation.rs34
-rw-r--r--compiler/rustc_data_structures/src/transitive_relation/tests.rs106
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs13
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs1
-rw-r--r--compiler/rustc_errors/src/emitter.rs25
-rw-r--r--compiler/rustc_errors/src/lib.rs4
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/mbe.rs16
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs251
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs20
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs157
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs123
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs172
-rw-r--r--compiler/rustc_feature/src/accepted.rs6
-rw-r--r--compiler/rustc_feature/src/active.rs12
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs8
-rw-r--r--compiler/rustc_hir/src/hir_id.rs1
-rw-r--r--compiler/rustc_hir/src/lib.rs1
-rw-r--r--compiler/rustc_index/src/bit_set.rs12
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs16
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs4
-rw-r--r--compiler/rustc_infer/src/infer/free_regions.rs8
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs2
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs11
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs28
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs2
-rw-r--r--compiler/rustc_lint/src/builtin.rs34
-rw-r--r--compiler/rustc_lint/src/context.rs2
-rw-r--r--compiler/rustc_lint/src/internal.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs120
-rw-r--r--compiler/rustc_lint/src/methods.rs4
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs2
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs4
-rw-r--r--compiler/rustc_lint/src/types.rs49
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs25
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp1
-rw-r--r--compiler/rustc_macros/src/newtype.rs1
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs30
-rw-r--r--compiler/rustc_middle/src/arena.rs4
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/middle/region.rs8
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs6
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs75
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs22
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs12
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs3
-rw-r--r--compiler/rustc_middle/src/query/mod.rs7
-rw-r--r--compiler/rustc_middle/src/thir.rs10
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs2
-rw-r--r--compiler/rustc_middle/src/traits/chalk.rs2
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs175
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs6
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs20
-rw-r--r--compiler/rustc_middle/src/ty/context.rs62
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs2
-rw-r--r--compiler/rustc_middle/src/ty/error.rs2
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs2
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs182
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs10
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs2
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs6
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs75
-rw-r--r--compiler/rustc_middle/src/ty/util.rs22
-rw-r--r--compiler/rustc_mir_build/src/build/cfg.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs9
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/misc.rs2
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs6
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs25
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs245
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs32
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/util.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs37
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/mod.rs8
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs11
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs15
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs8
-rw-r--r--compiler/rustc_mir_transform/src/instcombine.rs73
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs2
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs4
-rw-r--r--compiler/rustc_mir_transform/src/simplify_try.rs12
-rw-r--r--compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs2
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs13
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs4
-rw-r--r--compiler/rustc_parse/src/parser/item.rs15
-rw-r--r--compiler/rustc_passes/src/check_attr.rs82
-rw-r--r--compiler/rustc_passes/src/dead.rs12
-rw-r--r--compiler/rustc_passes/src/intrinsicck.rs12
-rw-r--r--compiler/rustc_passes/src/stability.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs9
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_session/src/config.rs15
-rw-r--r--compiler/rustc_session/src/parse.rs21
-rw-r--r--compiler/rustc_span/src/def_id.rs5
-rw-r--r--compiler/rustc_span/src/hygiene.rs7
-rw-r--r--compiler/rustc_span/src/symbol.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs5
-rw-r--r--compiler/rustc_target/src/abi/mod.rs76
-rw-r--r--compiler/rustc_target/src/lib.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs88
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs42
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/on_unimplemented.rs46
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs90
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs2
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs18
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs2
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs23
-rw-r--r--compiler/rustc_ty_utils/src/representability.rs14
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs8
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs10
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs43
-rw-r--r--compiler/rustc_typeck/src/check/check.rs53
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs23
-rw-r--r--compiler/rustc_typeck/src/check/dropck.rs4
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs16
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs4
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs2
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs4
-rw-r--r--compiler/rustc_typeck/src/check/method/prelude2021.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs404
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs8
-rw-r--r--compiler/rustc_typeck/src/check/op.rs2
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs15
-rw-r--r--compiler/rustc_typeck/src/check/place_op.rs3
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs18
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_typeck/src/coherence/builtin.rs10
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls.rs2
-rw-r--r--compiler/rustc_typeck/src/coherence/orphan.rs10
-rw-r--r--compiler/rustc_typeck/src/collect.rs4
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs2
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs8
-rw-r--r--compiler/rustc_typeck/src/mem_categorization.rs2
-rw-r--r--compiler/rustc_typeck/src/outlives/implicit_infer.rs4
-rw-r--r--compiler/rustc_typeck/src/variance/constraints.rs2
-rw-r--r--library/alloc/src/alloc.rs2
-rw-r--r--library/alloc/src/borrow.rs2
-rw-r--r--library/alloc/src/boxed.rs15
-rw-r--r--library/alloc/src/collections/binary_heap.rs12
-rw-r--r--library/alloc/src/collections/btree/map.rs14
-rw-r--r--library/alloc/src/collections/btree/map/entry.rs6
-rw-r--r--library/alloc/src/collections/btree/map/tests.rs2
-rw-r--r--library/alloc/src/collections/btree/node.rs53
-rw-r--r--library/alloc/src/collections/btree/set.rs6
-rw-r--r--library/alloc/src/collections/btree/set/tests.rs6
-rw-r--r--library/alloc/src/collections/vec_deque/iter.rs69
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs60
-rw-r--r--library/alloc/src/fmt.rs6
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/alloc/src/rc/tests.rs6
-rw-r--r--library/alloc/src/slice.rs2
-rw-r--r--library/alloc/src/string.rs2
-rw-r--r--library/alloc/src/sync.rs4
-rw-r--r--library/alloc/src/sync/tests.rs8
-rw-r--r--library/alloc/src/tests.rs8
-rw-r--r--library/alloc/src/vec/mod.rs16
-rw-r--r--library/alloc/tests/boxed.rs2
-rw-r--r--library/alloc/tests/fmt.rs24
-rw-r--r--library/alloc/tests/linked_list.rs4
-rw-r--r--library/alloc/tests/slice.rs12
-rw-r--r--library/alloc/tests/str.rs10
-rw-r--r--library/alloc/tests/string.rs4
-rw-r--r--library/alloc/tests/vec.rs6
-rw-r--r--library/alloc/tests/vec_deque.rs4
-rw-r--r--library/core/benches/num/flt2dec/mod.rs2
-rw-r--r--library/core/benches/num/flt2dec/strategy/grisu.rs2
-rw-r--r--library/core/src/any.rs2
-rw-r--r--library/core/src/array/mod.rs10
-rw-r--r--library/core/src/ascii.rs14
-rw-r--r--library/core/src/cell.rs2
-rw-r--r--library/core/src/char/convert.rs7
-rw-r--r--library/core/src/char/methods.rs10
-rw-r--r--library/core/src/clone.rs21
-rw-r--r--library/core/src/convert/mod.rs6
-rw-r--r--library/core/src/fmt/mod.rs92
-rw-r--r--library/core/src/future/into_future.rs8
-rw-r--r--library/core/src/hint.rs123
-rw-r--r--library/core/src/iter/adapters/map.rs4
-rw-r--r--library/core/src/iter/mod.rs16
-rw-r--r--library/core/src/iter/sources/once.rs2
-rw-r--r--library/core/src/iter/sources/once_with.rs2
-rw-r--r--library/core/src/iter/traits/collect.rs23
-rw-r--r--library/core/src/iter/traits/double_ended.rs2
-rw-r--r--library/core/src/iter/traits/iterator.rs98
-rw-r--r--library/core/src/lib.rs12
-rw-r--r--library/core/src/macros/mod.rs14
-rw-r--r--library/core/src/marker.rs4
-rw-r--r--library/core/src/num/dec2flt/mod.rs15
-rw-r--r--library/core/src/num/error.rs2
-rw-r--r--library/core/src/num/int_macros.rs6
-rw-r--r--library/core/src/num/mod.rs2
-rw-r--r--library/core/src/num/nonzero.rs101
-rw-r--r--library/core/src/num/uint_macros.rs3
-rw-r--r--library/core/src/ops/index.rs4
-rw-r--r--library/core/src/ops/range.rs4
-rw-r--r--library/core/src/option.rs30
-rw-r--r--library/core/src/panic/panic_info.rs4
-rw-r--r--library/core/src/panicking.rs4
-rw-r--r--library/core/src/primitive_docs.rs20
-rw-r--r--library/core/src/ptr/const_ptr.rs9
-rw-r--r--library/core/src/ptr/mut_ptr.rs13
-rw-r--r--library/core/src/ptr/non_null.rs10
-rw-r--r--library/core/src/ptr/unique.rs3
-rw-r--r--library/core/src/result.rs106
-rw-r--r--library/core/src/slice/index.rs89
-rw-r--r--library/core/src/slice/iter.rs6
-rw-r--r--library/core/src/slice/mod.rs29
-rw-r--r--library/core/src/str/mod.rs44
-rw-r--r--library/core/src/str/traits.rs30
-rw-r--r--library/core/src/sync/atomic.rs10
-rw-r--r--library/core/src/time.rs2
-rw-r--r--library/core/src/unit.rs2
-rw-r--r--library/core/tests/any.rs16
-rw-r--r--library/core/tests/cell.rs8
-rw-r--r--library/core/tests/fmt/builders.rs126
-rw-r--r--library/core/tests/fmt/mod.rs8
-rw-r--r--library/core/tests/fmt/num.rs2
-rw-r--r--library/core/tests/iter/traits/iterator.rs8
-rw-r--r--library/core/tests/lazy.rs2
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/num/dec2flt/mod.rs8
-rw-r--r--library/core/tests/num/dec2flt/parse.rs2
-rw-r--r--library/core/tests/num/flt2dec/mod.rs2
-rw-r--r--library/core/tests/num/flt2dec/random.rs2
-rw-r--r--library/core/tests/ptr.rs2
-rw-r--r--library/core/tests/result.rs4
-rw-r--r--library/portable-simd/beginners-guide.md4
-rw-r--r--library/portable-simd/crates/core_simd/Cargo.toml2
-rw-r--r--library/portable-simd/crates/core_simd/examples/matrix_inversion.rs2
-rw-r--r--library/portable-simd/crates/core_simd/examples/nbody.rs12
-rw-r--r--library/portable-simd/crates/core_simd/examples/spectral_norm.rs4
-rw-r--r--library/portable-simd/crates/core_simd/src/comparisons.rs52
-rw-r--r--library/portable-simd/crates/core_simd/src/intrinsics.rs9
-rw-r--r--library/portable-simd/crates/core_simd/src/lib.rs3
-rw-r--r--library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs3
-rw-r--r--library/portable-simd/crates/core_simd/src/math.rs21
-rw-r--r--library/portable-simd/crates/core_simd/src/reduction.rs44
-rw-r--r--library/portable-simd/crates/core_simd/src/select.rs6
-rw-r--r--library/portable-simd/crates/core_simd/src/swizzle.rs12
-rw-r--r--library/portable-simd/crates/core_simd/src/vector.rs24
-rw-r--r--library/portable-simd/crates/core_simd/tests/i16_ops.rs27
-rw-r--r--library/portable-simd/crates/core_simd/tests/ops_macros.rs73
-rw-r--r--library/portable-simd/crates/core_simd/tests/round.rs1
-rw-r--r--library/portable-simd/crates/std_float/Cargo.toml2
-rw-r--r--library/portable-simd/crates/test_helpers/src/lib.rs20
-rw-r--r--library/proc_macro/src/lib.rs12
-rw-r--r--library/std/src/alloc.rs2
-rw-r--r--library/std/src/backtrace/tests.rs6
-rw-r--r--library/std/src/collections/hash/map.rs20
-rw-r--r--library/std/src/collections/hash/map/tests.rs6
-rw-r--r--library/std/src/collections/hash/set.rs20
-rw-r--r--library/std/src/collections/hash/set/tests.rs4
-rw-r--r--library/std/src/collections/mod.rs8
-rw-r--r--library/std/src/env.rs24
-rw-r--r--library/std/src/error.rs26
-rw-r--r--library/std/src/error/tests.rs6
-rw-r--r--library/std/src/ffi/c_str.rs4
-rw-r--r--library/std/src/ffi/c_str/tests.rs2
-rw-r--r--library/std/src/fs.rs6
-rw-r--r--library/std/src/fs/tests.rs20
-rw-r--r--library/std/src/io/buffered/bufreader.rs2
-rw-r--r--library/std/src/io/error.rs14
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs3
-rw-r--r--library/std/src/io/error/tests.rs8
-rw-r--r--library/std/src/io/mod.rs12
-rw-r--r--library/std/src/io/stdio.rs8
-rw-r--r--library/std/src/keyword_docs.rs48
-rw-r--r--library/std/src/lib.rs18
-rw-r--r--library/std/src/net/addr/tests.rs30
-rw-r--r--library/std/src/net/tcp.rs10
-rw-r--r--library/std/src/net/tcp/tests.rs13
-rw-r--r--library/std/src/net/udp.rs14
-rw-r--r--library/std/src/net/udp/tests.rs6
-rw-r--r--library/std/src/os/unix/fs.rs4
-rw-r--r--library/std/src/os/unix/net/addr.rs16
-rw-r--r--library/std/src/os/unix/net/ancillary.rs6
-rw-r--r--library/std/src/os/unix/net/datagram.rs24
-rw-r--r--library/std/src/os/unix/net/listener.rs10
-rw-r--r--library/std/src/os/unix/net/stream.rs14
-rw-r--r--library/std/src/os/unix/net/tests.rs12
-rw-r--r--library/std/src/panicking.rs6
-rw-r--r--library/std/src/path.rs2
-rw-r--r--library/std/src/path/tests.rs22
-rw-r--r--library/std/src/primitive_docs.rs20
-rw-r--r--library/std/src/process.rs18
-rw-r--r--library/std/src/process/tests.rs14
-rw-r--r--library/std/src/sync/mod.rs2
-rw-r--r--library/std/src/sync/mpsc/mod.rs20
-rw-r--r--library/std/src/sync/mpsc/shared.rs2
-rw-r--r--library/std/src/sync/mutex/tests.rs4
-rw-r--r--library/std/src/sync/poison.rs2
-rw-r--r--library/std/src/sync/rwlock/tests.rs4
-rw-r--r--library/std/src/sys/sgx/abi/mod.rs2
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/mod.rs4
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/raw.rs2
-rw-r--r--library/std/src/sys/sgx/net.rs2
-rw-r--r--library/std/src/sys/sgx/os.rs2
-rw-r--r--library/std/src/sys/sgx/stdio.rs2
-rw-r--r--library/std/src/sys/solid/mod.rs2
-rw-r--r--library/std/src/sys/solid/net.rs2
-rw-r--r--library/std/src/sys/solid/os.rs2
-rw-r--r--library/std/src/sys/unix/fs.rs76
-rw-r--r--library/std/src/sys/unix/net.rs2
-rw-r--r--library/std/src/sys/unix/os_str/tests.rs2
-rw-r--r--library/std/src/sys/unix/process/process_fuchsia.rs2
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs10
-rw-r--r--library/std/src/sys/unix/process/process_vxworks.rs4
-rw-r--r--library/std/src/sys/unix/rand.rs2
-rw-r--r--library/std/src/sys/unix/rwlock.rs6
-rw-r--r--library/std/src/sys/windows/mod.rs8
-rw-r--r--library/std/src/sys/windows/os.rs2
-rw-r--r--library/std/src/sys/windows/process/tests.rs4
-rw-r--r--library/std/src/sys/windows/thread_parker.rs2
-rw-r--r--library/std/src/sys_common/backtrace.rs2
-rw-r--r--library/std/src/sys_common/net/tests.rs2
-rw-r--r--library/std/src/sys_common/thread_parker/generic.rs2
-rw-r--r--library/std/src/sys_common/wtf8.rs2
-rw-r--r--library/std/src/sys_common/wtf8/tests.rs4
-rw-r--r--library/std/src/thread/mod.rs33
-rw-r--r--library/std/src/thread/scoped.rs62
-rw-r--r--library/std/src/thread/tests.rs27
-rw-r--r--library/std/src/time.rs4
-rw-r--r--library/std/src/time/tests.rs6
-rw-r--r--library/test/src/cli.rs4
-rw-r--r--library/test/src/console.rs16
-rw-r--r--library/test/src/formatters/junit.rs2
-rw-r--r--library/test/src/formatters/pretty.rs16
-rw-r--r--library/test/src/formatters/terse.rs14
-rw-r--r--library/test/src/helpers/concurrency.rs2
-rw-r--r--library/test/src/helpers/exit_code.rs2
-rw-r--r--library/test/src/lib.rs12
-rw-r--r--library/test/src/term/terminfo/parm.rs2
-rw-r--r--library/test/src/term/terminfo/parm/tests.rs6
-rw-r--r--library/test/src/term/terminfo/parser/compiled.rs2
-rw-r--r--library/test/src/test_result.rs2
-rw-r--r--library/unwind/src/libunwind.rs4
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/bootstrap.py17
-rw-r--r--src/bootstrap/builder.rs18
-rw-r--r--src/bootstrap/builder/tests.rs2
-rw-r--r--src/bootstrap/config.rs64
-rwxr-xr-xsrc/bootstrap/configure.py4
-rw-r--r--src/bootstrap/flags.rs4
-rw-r--r--src/bootstrap/lib.rs19
-rw-r--r--src/bootstrap/native.rs24
-rw-r--r--src/bootstrap/setup.rs30
-rw-r--r--src/bootstrap/test.rs4
-rw-r--r--src/bootstrap/tool.rs2
-rw-r--r--src/bootstrap/util.rs109
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile2
-rw-r--r--src/doc/rustdoc/book.toml4
-rw-r--r--src/doc/rustdoc/src/SUMMARY.md15
-rw-r--r--src/doc/rustdoc/src/advanced-features.md22
-rw-r--r--src/doc/rustdoc/src/command-line-arguments.md30
-rw-r--r--src/doc/rustdoc/src/deprecated-features.md (renamed from src/doc/rustdoc/src/passes.md)4
-rw-r--r--src/doc/rustdoc/src/how-to-read-rustdoc.md4
-rw-r--r--src/doc/rustdoc/src/how-to-write-documentation.md2
-rw-r--r--src/doc/rustdoc/src/lints.md24
-rw-r--r--src/doc/rustdoc/src/unstable-features.md51
-rw-r--r--src/doc/rustdoc/src/website-features.md25
-rw-r--r--src/doc/rustdoc/src/write-documentation/documentation-tests.md (renamed from src/doc/rustdoc/src/documentation-tests.md)2
-rw-r--r--src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md (renamed from src/doc/rustdoc/src/linking-to-items-by-name.md)2
-rw-r--r--src/doc/rustdoc/src/write-documentation/the-doc-attribute.md (renamed from src/doc/rustdoc/src/the-doc-attribute.md)4
-rw-r--r--src/doc/rustdoc/src/write-documentation/what-to-include.md (renamed from src/doc/rustdoc/src/what-to-include.md)2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md8
-rw-r--r--src/doc/unstable-book/src/language-features/box-patterns.md4
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/clean/inline.rs6
-rw-r--r--src/librustdoc/clean/mod.rs4
-rw-r--r--src/librustdoc/doctest.rs39
-rw-r--r--src/librustdoc/html/format.rs46
-rw-r--r--src/librustdoc/html/markdown.rs3
-rw-r--r--src/librustdoc/html/render/mod.rs32
-rw-r--r--src/librustdoc/html/render/print_item.rs12
-rw-r--r--src/librustdoc/html/sources.rs10
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css9
-rw-r--r--src/librustdoc/html/static/js/main.js2
-rw-r--r--src/librustdoc/json/conversions.rs3
-rw-r--r--src/librustdoc/markdown.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs12
m---------src/llvm-project0
-rw-r--r--src/rustdoc-json-types/lib.rs40
-rw-r--r--src/test/assembly/sparc-struct-abi.rs1
-rw-r--r--src/test/assembly/target-feature-multiple.rs1
-rw-r--r--src/test/codegen/abi-sysv64.rs1
-rw-r--r--src/test/codegen/abi-x86-interrupt.rs1
-rw-r--r--src/test/codegen/frame-pointer.rs2
-rw-r--r--src/test/codegen/inline-hint.rs4
-rw-r--r--src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs8
-rw-r--r--src/test/mir-opt/combine_clone_of_primitives.rs20
-rw-r--r--src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff80
-rw-r--r--src/test/mir-opt/inline/inline_generator.main.Inline.diff8
-rw-r--r--src/test/mir-opt/inline/issue_78442.bar.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff6
-rw-r--r--src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir2
-rw-r--r--src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir14
-rw-r--r--src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir14
-rw-r--r--src/test/rustdoc-gui/docblock-table-overflow.goml8
-rw-r--r--src/test/rustdoc-gui/hash-item-expansion.goml4
-rw-r--r--src/test/rustdoc-gui/impl-default-expansion.goml2
-rw-r--r--src/test/rustdoc-gui/mobile.goml5
-rw-r--r--src/test/rustdoc-gui/sidebar-source-code-display.goml22
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml3
-rw-r--r--src/test/rustdoc-gui/toggle-docs-mobile.goml2
-rw-r--r--src/test/rustdoc-gui/toggle-docs.goml11
-rw-r--r--src/test/rustdoc-json/fns/generics.rs26
-rw-r--r--src/test/rustdoc/duplicate_impls/issue-33054.rs4
-rw-r--r--src/test/ui/associated-consts/defaults-cyclic-fail.rs2
-rw-r--r--src/test/ui/associated-types/issue-59324.rs2
-rw-r--r--src/test/ui/associated-types/issue-59324.stderr11
-rw-r--r--src/test/ui/async-await/await-into-future.rs4
-rw-r--r--src/test/ui/async-await/edition-deny-async-fns-2015.stderr18
-rw-r--r--src/test/ui/async-await/suggest-switching-edition-on-await-cargo.rs47
-rw-r--r--src/test/ui/async-await/suggest-switching-edition-on-await-cargo.stderr43
-rw-r--r--src/test/ui/async-await/suggest-switching-edition-on-await.rs8
-rw-r--r--src/test/ui/async-await/suggest-switching-edition-on-await.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-move-by-capture.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr11
-rw-r--r--src/test/ui/borrowck/copy-suggestion-region-vid.rs17
-rw-r--r--src/test/ui/borrowck/copy-suggestion-region-vid.stderr14
-rw-r--r--src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr6
-rw-r--r--src/test/ui/borrowck/issue-88434-minimal-example.rs1
-rw-r--r--src/test/ui/borrowck/issue-88434-minimal-example.stderr8
-rw-r--r--src/test/ui/borrowck/issue-88434-removal-index-should-be-less.rs1
-rw-r--r--src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr8
-rw-r--r--src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr10
-rw-r--r--src/test/ui/box/large-allocator-ice.rs6
-rw-r--r--src/test/ui/cast/fat-ptr-cast.rs13
-rw-r--r--src/test/ui/cast/fat-ptr-cast.stderr34
-rw-r--r--src/test/ui/check-cfg/well-known-names.rs6
-rw-r--r--src/test/ui/check-cfg/well-known-values.rs14
-rw-r--r--src/test/ui/check-cfg/well-known-values.stderr22
-rw-r--r--src/test/ui/closures/2229_closure_analysis/match/issue-88331.stderr28
-rw-r--r--src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr38
-rw-r--r--src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr7
-rw-r--r--src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs1
-rw-r--r--src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs1
-rw-r--r--src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs1
-rw-r--r--src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs1
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs21
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-85848.rs2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-94287.rs10
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr14
-rw-r--r--src/test/ui/const-generics/issues/issue-79674.rs2
-rw-r--r--src/test/ui/consts/auxiliary/const_fn_lib.rs1
-rw-r--r--src/test/ui/consts/const-block-const-bound.rs2
-rw-r--r--src/test/ui/consts/const-eval/const-eval-query-stack.rs2
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr.stderr14
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr10
-rw-r--r--src/test/ui/consts/const-eval/issue-49296.rs2
-rw-r--r--src/test/ui/consts/const-eval/issue-49296.stderr2
-rw-r--r--src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs1
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs2
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr24
-rw-r--r--src/test/ui/consts/const-fn.rs1
-rw-r--r--src/test/ui/consts/const-match-check.eval1.stderr6
-rw-r--r--src/test/ui/consts/const-match-check.eval2.stderr6
-rw-r--r--src/test/ui/consts/const-match-check.matchck.stderr24
-rw-r--r--src/test/ui/consts/const_fn_trait_bound.gated.stderr8
-rw-r--r--src/test/ui/consts/const_fn_trait_bound.rs17
-rw-r--r--src/test/ui/consts/const_fn_trait_bound.stock.stderr30
-rw-r--r--src/test/ui/consts/drop_box.rs4
-rw-r--r--src/test/ui/consts/drop_box.stderr11
-rw-r--r--src/test/ui/consts/issue-37550-1.rs4
-rw-r--r--src/test/ui/consts/issue-37550-1.stderr12
-rw-r--r--src/test/ui/consts/issue-37550.rs2
-rw-r--r--src/test/ui/consts/issue-46553.rs1
-rw-r--r--src/test/ui/consts/issue-56164.rs2
-rw-r--r--src/test/ui/consts/issue-56164.stderr4
-rw-r--r--src/test/ui/consts/issue-88071.rs1
-rw-r--r--src/test/ui/consts/issue-94675.rs16
-rw-r--r--src/test/ui/consts/issue-94675.stderr38
-rw-r--r--src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs15
-rw-r--r--src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr17
-rw-r--r--src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/cast_errors.rs17
-rw-r--r--src/test/ui/consts/min_const_fn/cast_errors.stderr75
-rw-r--r--src/test/ui/consts/min_const_fn/cast_fn.rs11
-rw-r--r--src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr23
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.rs28
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.stderr170
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs4
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr25
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs19
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr21
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs10
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr21
-rw-r--r--src/test/ui/consts/miri_unleashed/abi-mismatch.stderr10
-rw-r--r--src/test/ui/consts/offset_from_ub.rs28
-rw-r--r--src/test/ui/consts/offset_from_ub.stderr26
-rw-r--r--src/test/ui/consts/offset_ub.stderr2
-rw-r--r--src/test/ui/consts/unstable-const-fn-in-libcore.rs1
-rw-r--r--src/test/ui/consts/unstable-const-fn-in-libcore.stderr6
-rw-r--r--src/test/ui/debuginfo/debuginfo-box-with-large-allocator.rs23
-rw-r--r--src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs2
-rw-r--r--src/test/ui/deprecation/deprecation-in-staged-api.rs4
-rw-r--r--src/test/ui/deprecation/deprecation-in-staged-api.stderr8
-rw-r--r--src/test/ui/deprecation/feature-gate-deprecated_suggestion.rs6
-rw-r--r--src/test/ui/deprecation/feature-gate-deprecated_suggestion.stderr11
-rw-r--r--src/test/ui/deprecation/staged-deprecation-in-future.rs (renamed from src/test/ui/deprecation/rustc_deprecation-in-future.rs)4
-rw-r--r--src/test/ui/deprecation/staged-deprecation-in-future.stderr (renamed from src/test/ui/deprecation/rustc_deprecation-in-future.stderr)6
-rw-r--r--src/test/ui/deprecation/suggestion.fixed9
-rw-r--r--src/test/ui/deprecation/suggestion.rs9
-rw-r--r--src/test/ui/deprecation/suggestion.stderr6
-rw-r--r--src/test/ui/editions/async-block-2015.rs6
-rw-r--r--src/test/ui/editions/async-block-2015.stderr6
-rw-r--r--src/test/ui/empty/empty-attributes.rs3
-rw-r--r--src/test/ui/empty/empty-attributes.stderr26
-rw-r--r--src/test/ui/empty/empty-never-array.stderr25
-rw-r--r--src/test/ui/error-codes/E0004-2.stderr27
-rw-r--r--src/test/ui/error-codes/E0004.stderr24
-rw-r--r--src/test/ui/error-codes/E0005.stderr26
-rw-r--r--src/test/ui/error-codes/E0297.stderr16
-rw-r--r--src/test/ui/error-codes/E0507.stderr11
-rw-r--r--src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr25
-rw-r--r--src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs23
-rw-r--r--src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr75
-rw-r--r--src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs9
-rw-r--r--src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr30
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.rs43
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.stderr94
-rw-r--r--src/test/ui/generic-associated-types/issue-90729.rs38
-rw-r--r--src/test/ui/generic-associated-types/issue-91139.migrate.stderr10
-rw-r--r--src/test/ui/generic-associated-types/issue-91139.rs12
-rw-r--r--src/test/ui/generic-associated-types/issue-93341.rs55
-rw-r--r--src/test/ui/generic-associated-types/issue-93342.rs57
-rw-r--r--src/test/ui/generics/single-colon-path-not-const-generics.rs13
-rw-r--r--src/test/ui/generics/single-colon-path-not-const-generics.stderr11
-rw-r--r--src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr408
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs4
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr52
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr78
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr81
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs15
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs3
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr13
-rw-r--r--src/test/ui/impl-trait/issues/issue-79099.stderr2
-rw-r--r--src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs5
-rw-r--r--src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr14
-rw-r--r--src/test/ui/issues/issue-17337.rs2
-rw-r--r--src/test/ui/issues/issue-21596.stderr4
-rw-r--r--src/test/ui/issues/issue-23036.rs1
-rw-r--r--src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr6
-rw-r--r--src/test/ui/issues/issue-61108.stderr9
-rw-r--r--src/test/ui/issues/issue-64559.stderr9
-rw-r--r--src/test/ui/issues/issue-87707.rs1
-rw-r--r--src/test/ui/issues/issue-87707.run.stderr4
-rw-r--r--src/test/ui/lint/auxiliary/inherited_stability.rs2
-rw-r--r--src/test/ui/lint/auxiliary/lint_output_format.rs2
-rw-r--r--src/test/ui/lint/auxiliary/lint_stability.rs46
-rw-r--r--src/test/ui/lint/auxiliary/lint_stability_fields.rs14
-rw-r--r--src/test/ui/lint/lint-stability-2.rs26
-rw-r--r--src/test/ui/lint/lint-stability-deprecated.rs26
-rw-r--r--src/test/ui/lint/lint-stability-fields-deprecated.rs12
-rw-r--r--src/test/ui/lint/lint-stability-fields.rs12
-rw-r--r--src/test/ui/lint/lint-stability.rs28
-rw-r--r--src/test/ui/lint/must_not_suspend/gated.rs11
-rw-r--r--src/test/ui/lint/must_not_suspend/gated.stderr43
-rw-r--r--src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs14
-rw-r--r--src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr47
-rw-r--r--src/test/ui/loops/issue-82916.stderr9
-rw-r--r--src/test/ui/macros/auxiliary/unstable-macros.rs2
-rw-r--r--src/test/ui/macros/macro-stability.rs6
-rw-r--r--src/test/ui/macros/macro-stability.stderr4
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs271
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs28
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs148
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs102
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs44
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr20
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs9
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr12
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs165
-rw-r--r--src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr385
-rw-r--r--src/test/ui/match/match_non_exhaustive.stderr38
-rw-r--r--src/test/ui/methods/issues/issue-84495.rs4
-rw-r--r--src/test/ui/methods/issues/issue-84495.stderr13
-rw-r--r--src/test/ui/methods/issues/issue-94581.rs7
-rw-r--r--src/test/ui/methods/issues/issue-94581.stderr15
-rw-r--r--src/test/ui/methods/method-call-err-msg.rs2
-rw-r--r--src/test/ui/methods/method-call-err-msg.stderr4
-rw-r--r--src/test/ui/mismatched_types/cast-rfc0401.rs2
-rw-r--r--src/test/ui/mismatched_types/cast-rfc0401.stderr8
-rw-r--r--src/test/ui/moves/issue-46099-move-in-macro.stderr5
-rw-r--r--src/test/ui/moves/move-fn-self-receiver.stderr10
-rw-r--r--src/test/ui/moves/move-in-guard-2.stderr5
-rw-r--r--src/test/ui/nll/issue-55825-const-fn.rs4
-rw-r--r--src/test/ui/nll/issue-55825-const-fn.stderr12
-rw-r--r--src/test/ui/nll/lint-no-err.rs28
-rw-r--r--src/test/ui/nll/lint-no-err.stderr17
-rw-r--r--src/test/ui/nll/match-guards-always-borrow.stderr6
-rw-r--r--src/test/ui/on-unimplemented/impl-substs.rs15
-rw-r--r--src/test/ui/on-unimplemented/impl-substs.stderr13
-rw-r--r--src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr18
-rw-r--r--src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr12
-rw-r--r--src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr28
-rw-r--r--src/test/ui/pattern/usefulness/auxiliary/hidden.rs10
-rw-r--r--src/test/ui/pattern/usefulness/auxiliary/unstable.rs13
-rw-r--r--src/test/ui/pattern/usefulness/doc-hidden-fields.rs26
-rw-r--r--src/test/ui/pattern/usefulness/doc-hidden-fields.stderr59
-rw-r--r--src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs33
-rw-r--r--src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr122
-rw-r--r--src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr262
-rw-r--r--src/test/ui/pattern/usefulness/empty-match.normal.stderr262
-rw-r--r--src/test/ui/pattern/usefulness/floats.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/guards.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr72
-rw-r--r--src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr7
-rw-r--r--src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr73
-rw-r--r--src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr12
-rw-r--r--src/test/ui/pattern/usefulness/issue-15129.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/issue-2111.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/issue-30240.stderr12
-rw-r--r--src/test/ui/pattern/usefulness/issue-3096-1.stderr7
-rw-r--r--src/test/ui/pattern/usefulness/issue-3096-2.stderr7
-rw-r--r--src/test/ui/pattern/usefulness/issue-31561.stderr31
-rw-r--r--src/test/ui/pattern/usefulness/issue-35609.stderr75
-rw-r--r--src/test/ui/pattern/usefulness/issue-3601.stderr14
-rw-r--r--src/test/ui/pattern/usefulness/issue-39362.stderr22
-rw-r--r--src/test/ui/pattern/usefulness/issue-40221.stderr23
-rw-r--r--src/test/ui/pattern/usefulness/issue-4321.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/issue-50900.stderr14
-rw-r--r--src/test/ui/pattern/usefulness/issue-56379.stderr31
-rw-r--r--src/test/ui/pattern/usefulness/issue-72377.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs1
-rw-r--r--src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr17
-rw-r--r--src/test/ui/pattern/usefulness/match-arm-statics-2.stderr54
-rw-r--r--src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr12
-rw-r--r--src/test/ui/pattern/usefulness/match-non-exhaustive.stderr10
-rw-r--r--src/test/ui/pattern/usefulness/match-privately-empty.stderr21
-rw-r--r--src/test/ui/pattern/usefulness/match-slice-patterns.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs63
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr304
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr23
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-match.stderr84
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr133
-rw-r--r--src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr120
-rw-r--r--src/test/ui/pattern/usefulness/stable-gated-fields.rs16
-rw-r--r--src/test/ui/pattern/usefulness/stable-gated-fields.stderr29
-rw-r--r--src/test/ui/pattern/usefulness/stable-gated-patterns.rs12
-rw-r--r--src/test/ui/pattern/usefulness/stable-gated-patterns.stderr49
-rw-r--r--src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr24
-rw-r--r--src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr14
-rw-r--r--src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr12
-rw-r--r--src/test/ui/pattern/usefulness/unstable-gated-fields.rs18
-rw-r--r--src/test/ui/pattern/usefulness/unstable-gated-fields.stderr33
-rw-r--r--src/test/ui/pattern/usefulness/unstable-gated-patterns.rs16
-rw-r--r--src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr25
-rw-r--r--src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr23
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/slice.stderr6
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs31
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum.stderr43
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr78
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs19
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr34
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs14
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr16
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr48
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr60
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr48
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr61
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr68
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr61
-rw-r--r--src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr19
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr165
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr6
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr6
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-closures.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr6
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr18
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr18
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr6
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr6
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/generic-bound.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr6
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr6
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-92111.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr20
-rw-r--r--src/test/ui/stability-attribute/auxiliary/lint-stability.rs46
-rw-r--r--src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs12
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.rs2
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.stderr17
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-non-staged.rs2
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-non-staged.stderr17
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity-4.rs6
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity-4.stderr24
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity.rs14
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity.stderr24
-rw-r--r--src/test/ui/str/str-idx.stderr8
-rw-r--r--src/test/ui/str/str-mut-idx.stderr8
-rw-r--r--src/test/ui/suggestions/borrow-for-loop-head.stderr9
-rw-r--r--src/test/ui/suggestions/constrain-suggest-ice.rs11
-rw-r--r--src/test/ui/suggestions/constrain-suggest-ice.stderr81
-rw-r--r--src/test/ui/suggestions/for-i-in-vec.stderr31
-rw-r--r--src/test/ui/suggestions/option-content-move2.stderr2
-rw-r--r--src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.rs30
-rw-r--r--src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr83
-rw-r--r--src/test/ui/suggestions/struct-field-type-including-single-colon.rs20
-rw-r--r--src/test/ui/suggestions/struct-field-type-including-single-colon.stderr36
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr9
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53096.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-89686.rs3
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-89686.stderr24
-rw-r--r--src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/structural-match.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/structural-match.stderr2
-rw-r--r--src/test/ui/unboxed-closures/issue-53448.rs3
-rw-r--r--src/test/ui/unboxed-closures/issue-53448.stderr20
-rw-r--r--src/test/ui/uninhabited/uninhabited-irrefutable.rs6
-rw-r--r--src/test/ui/uninhabited/uninhabited-irrefutable.stderr28
-rw-r--r--src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr100
-rw-r--r--src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs4
-rw-r--r--src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs5
-rw-r--r--src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs6
-rw-r--r--src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr18
-rw-r--r--src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs9
-rw-r--r--src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr34
-rw-r--r--src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs6
-rw-r--r--src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr18
-rw-r--r--src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs9
-rw-r--r--src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr34
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_enum.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eq_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_flatten.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_update.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/self_named_constructors.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/try_err.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs22
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs26
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs2
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr14
-rw-r--r--src/tools/linkchecker/main.rs20
m---------src/tools/miri19
m---------src/tools/rust-analyzer35
-rw-r--r--src/tools/rustdoc-gui/tester.js2
-rw-r--r--src/tools/tidy/src/bins.rs2
-rw-r--r--src/tools/tidy/src/deps.rs14
-rw-r--r--src/tools/tidy/src/error_codes_check.rs4
-rw-r--r--src/tools/tidy/src/features.rs8
-rw-r--r--src/tools/tidy/src/primitive_docs.rs6
-rw-r--r--src/tools/tidy/src/style.rs10
-rw-r--r--src/tools/tidy/src/target_specific_tests.rs4
-rw-r--r--src/tools/unicode-table-generator/src/main.rs10
-rw-r--r--src/tools/unicode-table-generator/src/unicode_download.rs5
-rw-r--r--src/tools/unstable-book-gen/src/main.rs2
-rw-r--r--src/tools/x/src/main.rs2
-rw-r--r--triagebot.toml7
897 files changed, 11837 insertions, 6140 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1af01a42afd..5d9edc5157d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -345,7 +345,6 @@ dependencies = [
  "libgit2-sys",
  "log",
  "memchr",
- "num_cpus",
  "opener",
  "openssl",
  "os_info",
@@ -1503,9 +1502,9 @@ dependencies = [
 
 [[package]]
 name = "git2"
-version = "0.13.23"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a8057932925d3a9d9e4434ea016570d37420ddb1ceed45a174d577f24ed6700"
+checksum = "6e7d3b96ec1fcaa8431cf04a4f1ef5caafe58d5cf7bcc31f09c1626adddb0ffe"
 dependencies = [
  "bitflags",
  "libc",
@@ -1518,9 +1517,9 @@ dependencies = [
 
 [[package]]
 name = "git2-curl"
-version = "0.14.1"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "883539cb0ea94bab3f8371a98cd8e937bbe9ee7c044499184aa4c17deb643a50"
+checksum = "1ee51709364c341fbb6fe2a385a290fb9196753bdde2fc45447d27cd31b11b13"
 dependencies = [
  "curl",
  "git2",
@@ -1975,9 +1974,9 @@ dependencies = [
 
 [[package]]
 name = "libgit2-sys"
-version = "0.12.24+1.3.0"
+version = "0.13.1+1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddbd6021eef06fb289a8f54b3c2acfdd85ff2a585dfbb24b8576325373d2152c"
+checksum = "43e598aa7a4faedf1ea1b4608f582b06f0f40211eec551b7ef36019ae3f62def"
 dependencies = [
  "cc",
  "libc",
@@ -2273,9 +2272,9 @@ dependencies = [
 
 [[package]]
 name = "minifier"
-version = "0.0.42"
+version = "0.0.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55a1388517eda8a68875243b650c26997e055a33d82571b5a0349129faef7d99"
+checksum = "d81352bda6f4d04af1720afaa762054f66e16caffd93c1f86461a1c0ac4e695e"
 dependencies = [
  "macro-utils",
 ]
@@ -2328,7 +2327,6 @@ dependencies = [
  "compiletest_rs",
  "env_logger 0.9.0",
  "getrandom 0.2.0",
- "hex 0.4.2",
  "libc",
  "log",
  "measureme 9.1.2",
diff --git a/Cargo.toml b/Cargo.toml
index cae48d79517..4e783996064 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,4 +1,5 @@
 [workspace]
+default-members = ["src/bootstrap"]
 members = [
   "src/bootstrap",
   "compiler/rustc",
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 231dd72af2c..9c18f55c03b 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -23,7 +23,7 @@ pub enum LitError {
 
 impl LitKind {
     /// Converts literal token into a semantic literal.
-    fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
+    pub fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
         let token::Lit { kind, symbol, suffix } = lit;
         if suffix.is_some() && !kind.may_have_suffix() {
             return Err(LitError::InvalidSuffix);
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 0cf73178d67..8f0b12cb4fe 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -64,8 +64,8 @@ struct AstValidator<'a> {
     /// certain positions.
     is_assoc_ty_bound_banned: bool,
 
-    /// Used to allow `let` expressions in certain syntactic locations.
-    is_let_allowed: bool,
+    /// See [ForbiddenLetReason]
+    forbidden_let_reason: Option<ForbiddenLetReason>,
 
     lint_buffer: &'a mut LintBuffer,
 }
@@ -103,20 +103,28 @@ impl<'a> AstValidator<'a> {
         self.is_tilde_const_allowed = old;
     }
 
-    fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
-        let old = mem::replace(&mut self.is_let_allowed, allowed);
+    fn with_let_management(
+        &mut self,
+        forbidden_let_reason: Option<ForbiddenLetReason>,
+        f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
+    ) {
+        let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
         f(self, old);
-        self.is_let_allowed = old;
+        self.forbidden_let_reason = old;
     }
 
     /// Emits an error banning the `let` expression provided in the given location.
-    fn ban_let_expr(&self, expr: &'a Expr) {
+    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.struct_span_err(expr.span, "`let` expressions are not supported here")
-                .note("only supported directly in conditions of `if`- and `while`-expressions")
-                .note("as well as when nested within `&&` and parentheses in those conditions")
-                .emit();
+            let err = "`let` expressions are not supported here";
+            let mut diag = sess.struct_span_err(expr.span, err);
+            diag.note("only supported directly in conditions of `if` and `while` expressions");
+            diag.note("as well as when nested within `&&` and parentheses in those conditions");
+            if let ForbiddenLetReason::ForbiddenWithOr(span) = forbidden_let_reason {
+                diag.span_note(span, "`||` operators are not allowed in let chain expressions");
+            }
+            diag.emit();
         } else {
             sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
                 .note("variable declaration using `let` is a statement")
@@ -988,39 +996,48 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     }
 
     fn visit_expr(&mut self, expr: &'a Expr) {
-        self.with_let_allowed(false, |this, let_allowed| match &expr.kind {
-            ExprKind::If(cond, then, opt_else) => {
-                this.visit_block(then);
-                walk_list!(this, visit_expr, opt_else);
-                this.with_let_allowed(true, |this, _| this.visit_expr(cond));
-                return;
-            }
-            ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
-            ExprKind::Match(expr, arms) => {
-                this.visit_expr(expr);
-                for arm in arms {
-                    this.visit_expr(&arm.body);
-                    this.visit_pat(&arm.pat);
-                    walk_list!(this, visit_attribute, &arm.attrs);
-                    if let Some(ref guard) = arm.guard {
-                        if let ExprKind::Let(_, ref expr, _) = guard.kind {
-                            this.with_let_allowed(true, |this, _| this.visit_expr(expr));
+        self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
+            match &expr.kind {
+                ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
+                    let forbidden_let_reason = Some(ForbiddenLetReason::ForbiddenWithOr(*span));
+                    this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(lhs));
+                    this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(rhs));
+                }
+                ExprKind::If(cond, then, opt_else) => {
+                    this.visit_block(then);
+                    walk_list!(this, visit_expr, opt_else);
+                    this.with_let_management(None, |this, _| this.visit_expr(cond));
+                    return;
+                }
+                ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
+                    this.ban_let_expr(expr, elem);
+                },
+                ExprKind::Match(scrutinee, arms) => {
+                    this.visit_expr(scrutinee);
+                    for arm in arms {
+                        this.visit_expr(&arm.body);
+                        this.visit_pat(&arm.pat);
+                        walk_list!(this, visit_attribute, &arm.attrs);
+                        if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
+                            this.with_let_management(None, |this, _| {
+                                this.visit_expr(guard_expr)
+                            });
                             return;
                         }
                     }
                 }
+                ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
+                    this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
+                    return;
+                }
+                ExprKind::While(cond, then, opt_label) => {
+                    walk_list!(this, visit_label, opt_label);
+                    this.visit_block(then);
+                    this.with_let_management(None, |this, _| this.visit_expr(cond));
+                    return;
+                }
+                _ => visit::walk_expr(this, expr),
             }
-            ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
-                this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
-                return;
-            }
-            ExprKind::While(cond, then, opt_label) => {
-                walk_list!(this, visit_label, opt_label);
-                this.visit_block(then);
-                this.with_let_allowed(true, |this, _| this.visit_expr(cond));
-                return;
-            }
-            _ => visit::walk_expr(this, expr),
         });
     }
 
@@ -1772,10 +1789,19 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
         is_tilde_const_allowed: false,
         is_impl_trait_banned: false,
         is_assoc_ty_bound_banned: false,
-        is_let_allowed: false,
+        forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
         lint_buffer: lints,
     };
     visit::walk_crate(&mut validator, krate);
 
     validator.has_proc_macro_decls
 }
+
+/// Used to forbid `let` expressions in certain syntactic locations.
+#[derive(Clone, Copy)]
+enum ForbiddenLetReason {
+    /// A let chain with the `||` operator
+    ForbiddenWithOr(Span),
+    /// `let` is not valid and the source environment is not important
+    GenericForbidden,
+}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 570ec45557d..097bd07c74c 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -437,13 +437,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 )
                 .emit();
             }
-        } else {
-            if attr.has_name(sym::deprecated) {
-                self.sess
-                    .struct_span_err(attr.span, "`#[deprecated]` cannot be used in staged API")
-                    .span_label(attr.span, "use `#[rustc_deprecated]` instead")
-                    .emit();
-            }
         }
     }
 
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 876dd7f757c..9d52c32885d 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -4,11 +4,13 @@
 //!
 //! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
 
-#![feature(iter_is_partitioned)]
+#![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
+#![feature(if_let_guard)]
+#![feature(iter_is_partitioned)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
 
 pub mod ast_validation;
 pub mod feature_gate;
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 061fee7f569..613320087d2 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -664,6 +664,7 @@ where
 {
     let mut depr: Option<(Deprecation, Span)> = None;
     let diagnostic = &sess.parse_sess.span_diagnostic;
+    let is_rustc = sess.features_untracked().staged_api;
 
     'outer: for attr in attrs_iter {
         if !(attr.has_name(sym::deprecated) || attr.has_name(sym::rustc_deprecated)) {
@@ -728,17 +729,31 @@ where
                                     continue 'outer;
                                 }
                             }
-                            sym::note if attr.has_name(sym::deprecated) => {
+                            sym::note => {
                                 if !get(mi, &mut note) {
                                     continue 'outer;
                                 }
                             }
+                            // FIXME(jhpratt) remove this after a bootstrap occurs. Emitting an
+                            // error specific to the renaming would be a good idea as well.
                             sym::reason if attr.has_name(sym::rustc_deprecated) => {
                                 if !get(mi, &mut note) {
                                     continue 'outer;
                                 }
                             }
-                            sym::suggestion if attr.has_name(sym::rustc_deprecated) => {
+                            sym::suggestion => {
+                                if !sess.features_untracked().deprecated_suggestion {
+                                    let mut diag = sess.struct_span_err(
+                                        mi.span,
+                                        "suggestions on deprecated items are unstable",
+                                    );
+                                    if sess.is_nightly_build() {
+                                        diag.help("add `#![feature(deprecated_suggestion)]` to the crate root");
+                                    }
+                                    // FIXME(jhpratt) change this to an actual tracking issue
+                                    diag.note("see #XXX for more details").emit();
+                                }
+
                                 if !get(mi, &mut suggestion) {
                                     continue 'outer;
                                 }
@@ -752,7 +767,7 @@ where
                                         if attr.has_name(sym::deprecated) {
                                             &["since", "note"]
                                         } else {
-                                            &["since", "reason", "suggestion"]
+                                            &["since", "note", "suggestion"]
                                         },
                                     ),
                                 );
@@ -775,24 +790,22 @@ where
             }
         }
 
-        if suggestion.is_some() && attr.has_name(sym::deprecated) {
-            unreachable!("only allowed on rustc_deprecated")
-        }
-
-        if attr.has_name(sym::rustc_deprecated) {
+        if is_rustc {
             if since.is_none() {
                 handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
                 continue;
             }
 
             if note.is_none() {
-                struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit();
+                struct_span_err!(diagnostic, attr.span, E0543, "missing 'note'").emit();
                 continue;
             }
         }
 
-        let is_since_rustc_version = attr.has_name(sym::rustc_deprecated);
-        depr = Some((Deprecation { since, note, suggestion, is_since_rustc_version }, attr.span));
+        depr = Some((
+            Deprecation { since, note, suggestion, is_since_rustc_version: is_rustc },
+            attr.span,
+        ));
     }
 
     depr
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 684a3ced5a0..1cbca58ca25 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1,5 +1,5 @@
 use either::Either;
-use rustc_const_eval::util::{CallDesugaringKind, CallKind};
+use rustc_const_eval::util::CallKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
@@ -17,7 +17,7 @@ use rustc_middle::ty::{
 };
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
 use rustc_span::symbol::sym;
-use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Span};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::TraitEngineExt as _;
 
@@ -195,144 +195,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     is_loop_move = true;
                 }
 
-                if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
-                    let place_name = self
-                        .describe_place(moved_place.as_ref())
-                        .map(|n| format!("`{}`", n))
-                        .unwrap_or_else(|| "value".to_owned());
-                    match kind {
-                        CallKind::FnCall { fn_trait_id, .. }
-                            if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
-                        {
-                            err.span_label(
-                                fn_call_span,
-                                &format!(
-                                    "{} {}moved due to this call{}",
-                                    place_name, partially_str, loop_message
-                                ),
-                            );
-                            err.span_note(
-                                var_span,
-                                "this value implements `FnOnce`, which causes it to be moved when called",
-                            );
-                        }
-                        CallKind::Operator { self_arg, .. } => {
-                            let self_arg = self_arg.unwrap();
-                            err.span_label(
-                                fn_call_span,
-                                &format!(
-                                    "{} {}moved due to usage in operator{}",
-                                    place_name, partially_str, loop_message
-                                ),
-                            );
-                            if self.fn_self_span_reported.insert(fn_span) {
-                                err.span_note(
-                                    // Check whether the source is accessible
-                                    if self
-                                        .infcx
-                                        .tcx
-                                        .sess
-                                        .source_map()
-                                        .span_to_snippet(self_arg.span)
-                                        .is_ok()
-                                    {
-                                        self_arg.span
-                                    } else {
-                                        fn_call_span
-                                    },
-                                    "calling this operator moves the left-hand side",
-                                );
-                            }
-                        }
-                        CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
-                            let self_arg = self_arg.unwrap();
-                            if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
-                                err.span_label(
-                                    fn_call_span,
-                                    &format!(
-                                        "{} {}moved due to this implicit call to `.into_iter()`{}",
-                                        place_name, partially_str, loop_message
-                                    ),
-                                );
-                                let sess = self.infcx.tcx.sess;
-                                let ty = used_place.ty(self.body, self.infcx.tcx).ty;
-                                // If we have a `&mut` ref, we need to reborrow.
-                                if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
-                                    // If we are in a loop this will be suggested later.
-                                    if !is_loop_move {
-                                        err.span_suggestion_verbose(
-                                            move_span.shrink_to_lo(),
-                                            &format!(
-                                                "consider creating a fresh reborrow of {} here",
-                                                self.describe_place(moved_place.as_ref())
-                                                    .map(|n| format!("`{}`", n))
-                                                    .unwrap_or_else(
-                                                        || "the mutable reference".to_string()
-                                                    ),
-                                            ),
-                                            "&mut *".to_string(),
-                                            Applicability::MachineApplicable,
-                                        );
-                                    }
-                                } else if let Ok(snippet) =
-                                    sess.source_map().span_to_snippet(move_span)
-                                {
-                                    err.span_suggestion(
-                                        move_span,
-                                        "consider borrowing to avoid moving into the for loop",
-                                        format!("&{}", snippet),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                            } else {
-                                err.span_label(
-                                    fn_call_span,
-                                    &format!(
-                                        "{} {}moved due to this method call{}",
-                                        place_name, partially_str, loop_message
-                                    ),
-                                );
-                            }
-                            if is_option_or_result && maybe_reinitialized_locations.is_empty() {
-                                err.span_suggestion_verbose(
-                                    fn_call_span.shrink_to_lo(),
-                                    "consider calling `.as_ref()` to borrow the type's contents",
-                                    "as_ref().".to_string(),
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                            // Avoid pointing to the same function in multiple different
-                            // error messages.
-                            if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span)
-                            {
-                                err.span_note(
-                                        self_arg.span,
-                                        &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
-                                    );
-                            }
-                        }
-                        // Other desugarings takes &self, which cannot cause a move
-                        _ => unreachable!(),
-                    }
-                } else {
-                    err.span_label(
-                        move_span,
-                        format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
-                    );
-                    // If the move error occurs due to a loop, don't show
-                    // another message for the same span
-                    if loop_message.is_empty() {
-                        move_spans.var_span_label(
-                            &mut err,
-                            format!(
-                                "variable {}moved due to use{}",
-                                partially_str,
-                                move_spans.describe()
-                            ),
-                            "moved",
-                        );
-                    }
-                }
+                self.explain_captures(
+                    &mut err,
+                    span,
+                    move_span,
+                    move_spans,
+                    *moved_place,
+                    Some(used_place),
+                    partially_str,
+                    loop_message,
+                    move_msg,
+                    is_loop_move,
+                    maybe_reinitialized_locations.is_empty(),
+                );
 
                 if let (UseSpans::PatUse(span), []) =
                     (move_spans, &maybe_reinitialized_locations[..])
@@ -448,8 +323,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 self.mir_hir_id(),
                                 rustc_infer::traits::ObligationCauseCode::MiscObligation,
                             );
-                            fulfill_cx.register_bound(&infcx, self.param_env, ty, copy_did, cause);
-                            let errors = fulfill_cx.select_where_possible(&infcx);
+                            fulfill_cx.register_bound(
+                                &infcx,
+                                self.param_env,
+                                // Erase any region vids from the type, which may not be resolved
+                                infcx.tcx.erase_regions(ty),
+                                copy_did,
+                                cause,
+                            );
+                            // Select all, including ambiguous predicates
+                            let errors = fulfill_cx.select_all_or_error(&infcx);
 
                             // Only emit suggestion if all required predicates are on generic
                             errors
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 2217c0e14b2..ffea15bdc33 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -138,7 +138,7 @@ impl BorrowExplanation {
                 let mut ty = local_decl.ty;
                 if local_decl.source_info.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
                     if let ty::Adt(adt, substs) = local_decl.ty.kind() {
-                        if tcx.is_diagnostic_item(sym::Option, adt.did) {
+                        if tcx.is_diagnostic_item(sym::Option, adt.did()) {
                             // in for loop desugaring, only look at the `Some(..)` inner type
                             ty = substs.type_at(0);
                         }
@@ -148,7 +148,7 @@ impl BorrowExplanation {
                     // If type is an ADT that implements Drop, then
                     // simplify output by reporting just the ADT name.
                     ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => {
-                        ("`Drop` code", format!("type `{}`", tcx.def_path_str(adt.did)))
+                        ("`Drop` code", format!("type `{}`", tcx.def_path_str(adt.did())))
                     }
 
                     // Otherwise, just report the whole type (and use
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 754856043b3..c2b5c16517a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1,11 +1,12 @@
 //! Borrow checker diagnostics.
 
-use rustc_const_eval::util::call_kind;
-use rustc_errors::Diagnostic;
+use rustc_const_eval::util::{call_kind, CallDesugaringKind};
+use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
 use rustc_hir::GeneratorKind;
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::{
     AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
     Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
@@ -13,8 +14,9 @@ use rustc_middle::mir::{
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
-use rustc_span::{symbol::sym, Span};
+use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
+use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
 
 use super::borrow_set::BorrowData;
 use super::MirBorrowckCtxt;
@@ -368,7 +370,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 ty::Adt(def, _) => {
                     let variant = if let Some(idx) = variant_index {
                         assert!(def.is_enum());
-                        &def.variants[idx]
+                        &def.variant(idx)
                     } else {
                         def.non_enum_variant()
                     };
@@ -482,9 +484,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             BorrowedContentSource::DerefSharedRef
         }
     }
-}
 
-impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
     /// name where required.
     pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
@@ -701,7 +701,7 @@ impl<'tcx> BorrowedContentSource<'tcx> {
             BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
             BorrowedContentSource::OverloadedDeref(ty) => ty
                 .ty_adt_def()
-                .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
+                .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
                     name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
                     _ => None,
                 })
@@ -731,7 +731,7 @@ impl<'tcx> BorrowedContentSource<'tcx> {
             }
             BorrowedContentSource::OverloadedDeref(ty) => ty
                 .ty_adt_def()
-                .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
+                .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
                     name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
                     _ => None,
                 })
@@ -995,4 +995,173 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let span = self.body.source_info(borrow.reserve_location).span;
         self.borrow_spans(span, borrow.reserve_location)
     }
+
+    fn explain_captures(
+        &mut self,
+        err: &mut Diagnostic,
+        span: Span,
+        move_span: Span,
+        move_spans: UseSpans<'tcx>,
+        moved_place: Place<'tcx>,
+        used_place: Option<PlaceRef<'tcx>>,
+        partially_str: &str,
+        loop_message: &str,
+        move_msg: &str,
+        is_loop_move: bool,
+        maybe_reinitialized_locations_is_empty: bool,
+    ) {
+        if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
+            let place_name = self
+                .describe_place(moved_place.as_ref())
+                .map(|n| format!("`{}`", n))
+                .unwrap_or_else(|| "value".to_owned());
+            match kind {
+                CallKind::FnCall { fn_trait_id, .. }
+                    if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
+                {
+                    err.span_label(
+                        fn_call_span,
+                        &format!(
+                            "{} {}moved due to this call{}",
+                            place_name, partially_str, loop_message
+                        ),
+                    );
+                    err.span_note(
+                        var_span,
+                        "this value implements `FnOnce`, which causes it to be moved when called",
+                    );
+                }
+                CallKind::Operator { self_arg, .. } => {
+                    let self_arg = self_arg.unwrap();
+                    err.span_label(
+                        fn_call_span,
+                        &format!(
+                            "{} {}moved due to usage in operator{}",
+                            place_name, partially_str, loop_message
+                        ),
+                    );
+                    if self.fn_self_span_reported.insert(fn_span) {
+                        err.span_note(
+                            // Check whether the source is accessible
+                            if self
+                                .infcx
+                                .tcx
+                                .sess
+                                .source_map()
+                                .span_to_snippet(self_arg.span)
+                                .is_ok()
+                            {
+                                self_arg.span
+                            } else {
+                                fn_call_span
+                            },
+                            "calling this operator moves the left-hand side",
+                        );
+                    }
+                }
+                CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
+                    let self_arg = self_arg.unwrap();
+                    if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
+                        let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
+                        let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
+                            Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
+                                type_known_to_meet_bound_modulo_regions(
+                                    &infcx,
+                                    self.param_env,
+                                    infcx.tcx.mk_imm_ref(
+                                        infcx.tcx.lifetimes.re_erased,
+                                        infcx.tcx.erase_regions(ty),
+                                    ),
+                                    def_id,
+                                    DUMMY_SP,
+                                )
+                            }),
+                            _ => false,
+                        };
+                        if suggest {
+                            err.span_suggestion_verbose(
+                                move_span.shrink_to_lo(),
+                                &format!(
+                                    "consider iterating over a slice of the `{}`'s content to \
+                                     avoid moving into the `for` loop",
+                                    ty,
+                                ),
+                                "&".to_string(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+
+                        err.span_label(
+                            fn_call_span,
+                            &format!(
+                                "{} {}moved due to this implicit call to `.into_iter()`{}",
+                                place_name, partially_str, loop_message
+                            ),
+                        );
+                        // If we have a `&mut` ref, we need to reborrow.
+                        if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place
+                            .map(|used_place| used_place.ty(self.body, self.infcx.tcx).ty.kind())
+                        {
+                            // If we are in a loop this will be suggested later.
+                            if !is_loop_move {
+                                err.span_suggestion_verbose(
+                                    move_span.shrink_to_lo(),
+                                    &format!(
+                                        "consider creating a fresh reborrow of {} here",
+                                        self.describe_place(moved_place.as_ref())
+                                            .map(|n| format!("`{}`", n))
+                                            .unwrap_or_else(|| "the mutable reference".to_string()),
+                                    ),
+                                    "&mut *".to_string(),
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
+                    } else {
+                        err.span_label(
+                            fn_call_span,
+                            &format!(
+                                "{} {}moved due to this method call{}",
+                                place_name, partially_str, loop_message
+                            ),
+                        );
+                    }
+                    if is_option_or_result && maybe_reinitialized_locations_is_empty {
+                        err.span_suggestion_verbose(
+                            fn_call_span.shrink_to_lo(),
+                            "consider calling `.as_ref()` to borrow the type's contents",
+                            "as_ref().".to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                    // Avoid pointing to the same function in multiple different
+                    // error messages.
+                    if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
+                        err.span_note(
+                            self_arg.span,
+                            &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
+                        );
+                    }
+                }
+                // Other desugarings takes &self, which cannot cause a move
+                _ => {}
+            }
+        } else {
+            if move_span != span || !loop_message.is_empty() {
+                err.span_label(
+                    move_span,
+                    format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
+                );
+            }
+            // If the move error occurs due to a loop, don't show
+            // another message for the same span
+            if loop_message.is_empty() {
+                move_spans.var_span_label(
+                    err,
+                    format!("variable {}moved due to use{}", partially_str, move_spans.describe()),
+                    "moved",
+                );
+            }
+        }
+    }
 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 19091569b4d..48a70abc0b6 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -1,15 +1,12 @@
-use rustc_const_eval::util::CallDesugaringKind;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::*;
 use rustc_middle::ty;
 use rustc_mir_dataflow::move_paths::{
     IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
 };
-use rustc_span::{sym, Span, DUMMY_SP};
-use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
+use rustc_span::{sym, Span};
 
-use crate::diagnostics::{CallKind, UseSpans};
+use crate::diagnostics::UseSpans;
 use crate::prefixes::PrefixSet;
 use crate::MirBorrowckCtxt;
 
@@ -391,7 +388,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         };
         let ty = move_place.ty(self.body, self.infcx.tcx).ty;
         let def_id = match *ty.kind() {
-            ty::Adt(self_def, _) => self_def.did,
+            ty::Adt(self_def, _) => self_def.did(),
             ty::Foreign(def_id)
             | ty::FnDef(def_id, _)
             | ty::Closure(def_id, _)
@@ -409,34 +406,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 ".as_ref()".to_string(),
                 Applicability::MaybeIncorrect,
             );
-        } else if let Some(UseSpans::FnSelfUse {
-            kind:
-                CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. },
-            ..
-        }) = use_spans
-        {
-            let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
-                Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
-                    type_known_to_meet_bound_modulo_regions(
-                        &infcx,
-                        self.param_env,
-                        infcx
-                            .tcx
-                            .mk_imm_ref(infcx.tcx.lifetimes.re_erased, infcx.tcx.erase_regions(ty)),
-                        def_id,
-                        DUMMY_SP,
-                    )
-                }),
-                _ => false,
-            };
-            if suggest {
-                err.span_suggestion_verbose(
-                    span.shrink_to_lo(),
-                    &format!("consider iterating over a slice of the `{}`'s content", ty),
-                    "&".to_string(),
-                    Applicability::MaybeIncorrect,
-                );
-            }
+        } else if let Some(use_spans) = use_spans {
+            self.explain_captures(
+                &mut err, span, span, use_spans, move_place, None, "", "", "", false, true,
+            );
         }
         err
     }
@@ -491,11 +464,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
 
                 use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
-                use_spans.var_span_label(
-                    err,
-                    format!("move occurs due to use{}", use_spans.describe()),
-                    "moved",
-                );
             }
         }
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 610798c7c05..c77bbeb86e5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -220,8 +220,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             PlaceRef {
                 local,
                 projection:
-                    [
-                        proj_base @ ..,
+                    &[
+                        ref proj_base @ ..,
                         ProjectionElem::Deref,
                         ProjectionElem::Field(field, _),
                         ProjectionElem::Deref,
@@ -342,7 +342,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     Applicability::MachineApplicable,
                 );
                 let tcx = self.infcx.tcx;
-                if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() {
+                if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
                     self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
                 }
             }
@@ -382,7 +382,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 let tcx = self.infcx.tcx;
                 if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
                 {
-                    if let ty::Closure(id, _) = ty.kind() {
+                    if let ty::Closure(id, _) = *ty.kind() {
                         self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
                     }
                 }
@@ -687,7 +687,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     fn show_mutating_upvar(
         &self,
         tcx: TyCtxt<'_>,
-        id: &hir::def_id::DefId,
+        id: hir::def_id::DefId,
         the_place_err: PlaceRef<'tcx>,
         err: &mut Diagnostic,
     ) {
@@ -701,7 +701,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
                 let root_hir_id = upvar_id.var_path.hir_id;
                 // we have an origin for this closure kind starting at this root variable so it's safe to unwrap here
-                let captured_places = tables.closure_min_captures[id].get(&root_hir_id).unwrap();
+                let captured_places = tables.closure_min_captures[&id].get(&root_hir_id).unwrap();
 
                 let origin_projection = closure_kind_origin
                     .projections
@@ -1083,7 +1083,7 @@ fn is_closure_or_generator(ty: Ty<'_>) -> bool {
 fn get_mut_span_in_struct_field<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
-    field: &mir::Field,
+    field: mir::Field,
 ) -> Option<Span> {
     // Expect our local to be a reference to a struct of some kind.
     if let ty::Ref(_, ty, _) = ty.kind()
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 38b16fedd3a..1df7e826343 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -345,8 +345,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     ty::Adt(adt, substs) => {
                         let generic_arg = substs[param_index as usize];
                         let identity_substs =
-                            InternalSubsts::identity_for_item(self.infcx.tcx, adt.did);
-                        let base_ty = self.infcx.tcx.mk_adt(adt, identity_substs);
+                            InternalSubsts::identity_for_item(self.infcx.tcx, adt.did());
+                        let base_ty = self.infcx.tcx.mk_adt(*adt, identity_substs);
                         let base_generic_arg = identity_substs[param_index as usize];
                         let adt_desc = adt.descr();
 
@@ -410,7 +410,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 "returns a closure that contains a reference to a captured variable, which then \
                  escapes the closure body"
             }
-            ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did) => {
+            ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => {
                 "returns an `async` block that contains a reference to a captured variable, which then \
                  escapes the closure body"
             }
diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs
index d378a2cbea3..c89da5514fd 100644
--- a/compiler/rustc_borrowck/src/location.rs
+++ b/compiler/rustc_borrowck/src/location.rs
@@ -100,7 +100,7 @@ impl LocationTable {
 }
 
 impl LocationIndex {
-    fn is_start(&self) -> bool {
+    fn is_start(self) -> bool {
         // even indices are start points; odd indices are mid points
         (self.index() % 2) == 0
     }
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 6fd9f4954a6..03b4a6ea983 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -85,7 +85,7 @@ fn populate_polonius_move_facts(
 ) {
     all_facts
         .path_is_var
-        .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(v, &m)| (m, v)));
+        .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
 
     for (child, move_path) in move_data.move_paths.iter_enumerated() {
         if let Some(parent) = move_path.parent {
@@ -135,7 +135,7 @@ fn populate_polonius_move_facts(
         }
     }
 
-    for (local, &path) in move_data.rev_lookup.iter_locals_enumerated() {
+    for (local, path) in move_data.rev_lookup.iter_locals_enumerated() {
         if body.local_kind(local) != LocalKind::Arg {
             // Non-arguments start out deinitialised; we simulate this with an
             // initial move:
@@ -226,7 +226,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
                      fr1={:?}, fr2={:?}",
                     fr1, fr2
                 );
-                all_facts.known_placeholder_subset.push((*fr1, *fr2));
+                all_facts.known_placeholder_subset.push((fr1, fr2));
             }
         }
     }
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index fa9fe905256..20f54d04777 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -942,14 +942,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             debug!("try_promote_type_test: ur={:?}", ur);
 
-            let non_local_ub = self.universal_region_relations.non_local_upper_bounds(&ur);
+            let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
             debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
 
             // This is slightly too conservative. To show T: '1, given `'2: '1`
             // and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to
             // avoid potential non-determinism we approximate this by requiring
             // T: '1 and T: '2.
-            for &upper_bound in non_local_ub {
+            for upper_bound in non_local_ub {
                 debug_assert!(self.universal_regions.is_universal_region(upper_bound));
                 debug_assert!(!self.universal_regions.is_local_free_region(upper_bound));
 
@@ -1588,12 +1588,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 // always will.)  We'll call them `shorter_fr+` -- they're ever
                 // so slightly larger than `shorter_fr`.
                 let shorter_fr_plus =
-                    self.universal_region_relations.non_local_upper_bounds(&shorter_fr);
+                    self.universal_region_relations.non_local_upper_bounds(shorter_fr);
                 debug!(
                     "try_propagate_universal_region_error: shorter_fr_plus={:?}",
                     shorter_fr_plus
                 );
-                for &&fr in &shorter_fr_plus {
+                for fr in shorter_fr_plus {
                     // Push the constraint `fr-: shorter_fr+`
                     propagated_outlives_requirements.push(ClosureOutlivesRequirement {
                         subject: ClosureOutlivesSubject::Region(fr_minus),
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 9a028147a4b..2e7798beb64 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -99,10 +99,9 @@ impl UniversalRegionRelations<'_> {
     crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
         assert!(self.universal_regions.is_universal_region(fr1));
         assert!(self.universal_regions.is_universal_region(fr2));
-        *self
-            .inverse_outlives
-            .postdom_upper_bound(&fr1, &fr2)
-            .unwrap_or(&self.universal_regions.fr_static)
+        self.inverse_outlives
+            .postdom_upper_bound(fr1, fr2)
+            .unwrap_or(self.universal_regions.fr_static)
     }
 
     /// Finds an "upper bound" for `fr` that is not local. In other
@@ -110,7 +109,7 @@ impl UniversalRegionRelations<'_> {
     /// outlives `fr` and (b) is not local.
     ///
     /// (*) If there are multiple competing choices, we return all of them.
-    crate fn non_local_upper_bounds<'a>(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> {
+    crate fn non_local_upper_bounds<'a>(&'a self, fr: RegionVid) -> Vec<RegionVid> {
         debug!("non_local_upper_bound(fr={:?})", fr);
         let res = self.non_local_bounds(&self.inverse_outlives, fr);
         assert!(!res.is_empty(), "can't find an upper bound!?");
@@ -120,7 +119,7 @@ impl UniversalRegionRelations<'_> {
     /// Returns the "postdominating" bound of the set of
     /// `non_local_upper_bounds` for the given region.
     crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
-        let upper_bounds = self.non_local_upper_bounds(&fr);
+        let upper_bounds = self.non_local_upper_bounds(fr);
 
         // In case we find more than one, reduce to one for
         // convenience.  This is to prevent us from generating more
@@ -130,7 +129,7 @@ impl UniversalRegionRelations<'_> {
         debug!("non_local_bound: post_dom={:?}", post_dom);
 
         post_dom
-            .and_then(|&post_dom| {
+            .and_then(|post_dom| {
                 // If the mutual immediate postdom is not local, then
                 // there is no non-local result we can return.
                 if !self.universal_regions.is_local_free_region(post_dom) {
@@ -150,7 +149,7 @@ impl UniversalRegionRelations<'_> {
     /// one. See `TransitiveRelation::postdom_upper_bound` for details.
     crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
         debug!("non_local_lower_bound(fr={:?})", fr);
-        let lower_bounds = self.non_local_bounds(&self.outlives, &fr);
+        let lower_bounds = self.non_local_bounds(&self.outlives, fr);
 
         // In case we find more than one, reduce to one for
         // convenience.  This is to prevent us from generating more
@@ -159,7 +158,7 @@ impl UniversalRegionRelations<'_> {
 
         debug!("non_local_bound: post_dom={:?}", post_dom);
 
-        post_dom.and_then(|&post_dom| {
+        post_dom.and_then(|post_dom| {
             // If the mutual immediate postdom is not local, then
             // there is no non-local result we can return.
             if !self.universal_regions.is_local_free_region(post_dom) {
@@ -176,11 +175,11 @@ impl UniversalRegionRelations<'_> {
     fn non_local_bounds<'a>(
         &self,
         relation: &'a TransitiveRelation<RegionVid>,
-        fr0: &'a RegionVid,
-    ) -> Vec<&'a RegionVid> {
+        fr0: RegionVid,
+    ) -> Vec<RegionVid> {
         // This method assumes that `fr0` is one of the universally
         // quantified region variables.
-        assert!(self.universal_regions.is_universal_region(*fr0));
+        assert!(self.universal_regions.is_universal_region(fr0));
 
         let mut external_parents = vec![];
         let mut queue = vec![fr0];
@@ -188,7 +187,7 @@ impl UniversalRegionRelations<'_> {
         // Keep expanding `fr` into its parents until we reach
         // non-local regions.
         while let Some(fr) = queue.pop() {
-            if !self.universal_regions.is_local_free_region(*fr) {
+            if !self.universal_regions.is_local_free_region(fr) {
                 external_parents.push(fr);
                 continue;
             }
@@ -205,17 +204,17 @@ impl UniversalRegionRelations<'_> {
     ///
     /// This will only ever be true for universally quantified regions.
     crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
-        self.outlives.contains(&fr1, &fr2)
+        self.outlives.contains(fr1, fr2)
     }
 
     /// Returns a vector of free regions `x` such that `fr1: x` is
     /// known to hold.
-    crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> {
-        self.outlives.reachable_from(&fr1)
+    crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> {
+        self.outlives.reachable_from(fr1)
     }
 
     /// Returns the _non-transitive_ set of known `outlives` constraints between free regions.
-    crate fn known_outlives(&self) -> impl Iterator<Item = (&RegionVid, &RegionVid)> {
+    crate fn known_outlives(&self) -> impl Iterator<Item = (RegionVid, RegionVid)> + '_ {
         self.outlives.base_edges()
     }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index fdbf95591c8..a7cf25d43d2 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -736,13 +736,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
             }
             ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind() {
                 ty::Adt(adt_def, _substs) if adt_def.is_enum() => {
-                    if index.as_usize() >= adt_def.variants.len() {
+                    if index.as_usize() >= adt_def.variants().len() {
                         PlaceTy::from_ty(span_mirbug_and_err!(
                             self,
                             place,
                             "cast to variant #{:?} but enum only has {:?}",
                             index,
-                            adt_def.variants.len()
+                            adt_def.variants().len()
                         ))
                     } else {
                         PlaceTy { ty: base_ty, variant_index: Some(index) }
@@ -816,7 +816,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
 
         let (variant, substs) = match base_ty {
             PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() {
-                ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs),
+                ty::Adt(adt_def, substs) => (adt_def.variant(variant_index), substs),
                 ty::Generator(def_id, substs, _) => {
                     let mut variants = substs.as_generator().state_tys(def_id, tcx);
                     let Some(mut variant) = variants.nth(variant_index.into()) else {
@@ -835,7 +835,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
             },
             PlaceTy { ty, variant_index: None } => match *ty.kind() {
                 ty::Adt(adt_def, substs) if !adt_def.is_enum() => {
-                    (&adt_def.variants[VariantIdx::new(0)], substs)
+                    (adt_def.variant(VariantIdx::new(0)), substs)
                 }
                 ty::Closure(_, substs) => {
                     return match substs
@@ -1198,7 +1198,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 tcx,
                 self.param_env,
                 proj,
-                |this, field, &()| {
+                |this, field, ()| {
                     let ty = this.field_ty(tcx, field);
                     self.normalize(ty, locations)
                 },
@@ -1449,7 +1449,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         );
                     }
                 };
-                if variant_index.as_usize() >= adt.variants.len() {
+                if variant_index.as_usize() >= adt.variants().len() {
                     span_bug!(
                         stmt.source_info.span,
                         "bad set discriminant ({:?} = {:?}): value of of range",
@@ -1928,7 +1928,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         match *ak {
             AggregateKind::Adt(adt_did, variant_index, substs, _, active_field_index) => {
                 let def = tcx.adt_def(adt_did);
-                let variant = &def.variants[variant_index];
+                let variant = &def.variant(variant_index);
                 let adj_field_index = active_field_index.unwrap_or(field_index);
                 if let Some(field) = variant.fields.get(adj_field_index) {
                     Ok(self.normalize(field.ty(tcx, substs), location))
diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
index 5fbaed7283a..37d2679c10d 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
@@ -82,8 +82,14 @@ pub(super) fn add_local_place_comments<'tcx>(
         return;
     }
     let TyAndLayout { ty, layout } = place.layout();
-    let rustc_target::abi::Layout { size, align, abi: _, variants: _, fields: _, largest_niche: _ } =
-        layout;
+    let rustc_target::abi::LayoutS {
+        size,
+        align,
+        abi: _,
+        variants: _,
+        fields: _,
+        largest_niche: _,
+    } = layout.0.0;
 
     let (kind, extra) = match *place.inner() {
         CPlaceInner::Var(place_local, var) => {
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index d3e36be3244..89fd0bfa8bb 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -67,7 +67,7 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Typ
                 pointer_ty(tcx)
             }
         }
-        ty::Adt(adt_def, _) if adt_def.repr.simd() => {
+        ty::Adt(adt_def, _) if adt_def.repr().simd() => {
             let (element, count) = match &tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().abi
             {
                 Abi::Vector { element, count } => (element.clone(), *count),
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 4dfb13476c2..6489b96be4b 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -1070,7 +1070,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
         };
 
         raw_eq, (v lhs_ref, v rhs_ref) {
-            let size = fx.layout_of(substs.type_at(0)).layout.size;
+            let size = fx.layout_of(substs.type_at(0)).layout.size();
             // FIXME add and use emit_small_memcmp
             let is_eq_value =
                 if size == Size::ZERO {
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 8cae506e0cb..fd63c3ecddb 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -127,7 +127,7 @@ pub(crate) fn coerce_unsized_into<'tcx>(
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
             assert_eq!(def_a, def_b);
 
-            for i in 0..def_a.variants[VariantIdx::new(0)].fields.len() {
+            for i in 0..def_a.variant(VariantIdx::new(0)).fields.len() {
                 let src_f = src.value_field(fx, mir::Field::new(i));
                 let dst_f = dst.place_field(fx, mir::Field::new(i));
 
@@ -200,7 +200,7 @@ pub(crate) fn size_and_align_of_dst<'tcx>(
 
             // Packed types ignore the alignment of their fields.
             if let ty::Adt(def, _) = layout.ty.kind() {
-                if def.repr.packed() {
+                if def.repr().packed() {
                     unsized_align = sized_align;
                 }
             }
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index b016af5174e..afe8797a030 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -24,7 +24,7 @@ fn codegen_field<'tcx>(
         }
         match field_layout.ty.kind() {
             ty::Slice(..) | ty::Str | ty::Foreign(..) => simple(fx),
-            ty::Adt(def, _) if def.repr.packed() => {
+            ty::Adt(def, _) if def.repr().packed() => {
                 assert_eq!(layout.align.abi.bytes(), 1);
                 simple(fx)
             }
@@ -816,7 +816,7 @@ pub(crate) fn assert_assignable<'tcx>(
             // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed
         }
         (&ty::Adt(adt_def_a, substs_a), &ty::Adt(adt_def_b, substs_b))
-            if adt_def_a.did == adt_def_b.did =>
+            if adt_def_a.did() == adt_def_b.did() =>
         {
             let mut types_a = substs_a.types();
             let mut types_b = substs_b.types();
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 572ac559d09..ef213f56369 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -272,20 +272,20 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                     use rustc_target::abi::Abi::*;
                     let tp_ty = substs.type_at(0);
                     let layout = self.layout_of(tp_ty).layout;
-                    let _use_integer_compare = match layout.abi {
+                    let _use_integer_compare = match layout.abi() {
                         Scalar(_) | ScalarPair(_, _) => true,
                         Uninhabited | Vector { .. } => false,
                         Aggregate { .. } => {
                             // For rusty ABIs, small aggregates are actually passed
                             // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
                             // so we re-use that same threshold here.
-                            layout.size <= self.data_layout().pointer_size * 2
+                            layout.size() <= self.data_layout().pointer_size * 2
                         }
                     };
 
                     let a = args[0].immediate();
                     let b = args[1].immediate();
-                    if layout.size.bytes() == 0 {
+                    if layout.size().bytes() == 0 {
                         self.const_bool(true)
                     }
                     /*else if use_integer_compare {
@@ -301,7 +301,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                         let void_ptr_type = self.context.new_type::<*const ()>();
                         let a_ptr = self.bitcast(a, void_ptr_type);
                         let b_ptr = self.bitcast(b, void_ptr_type);
-                        let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type);
+                        let n = self.context.new_cast(None, self.const_usize(layout.size().bytes()), self.sizet_type);
                         let builtin = self.context.get_builtin_function("memcmp");
                         let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]);
                         self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 0ada20cad2c..649ffc16249 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -56,8 +56,8 @@ pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLa
             if let (&ty::Adt(def, _), &Variants::Single { index }) =
                 (layout.ty.kind(), &layout.variants)
             {
-                if def.is_enum() && !def.variants.is_empty() {
-                    write!(&mut name, "::{}", def.variants[index].name).unwrap();
+                if def.is_enum() && !def.variants().is_empty() {
+                    write!(&mut name, "::{}", def.variant(index).name).unwrap();
                 }
             }
             if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index b2879ef4aea..98ba38356a4 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -90,7 +90,7 @@ impl<'ll, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     /// call. Since the function is never called, all other `CodeRegion`s can be
     /// added as `unreachable_region`s.
     fn define_unused_fn(&self, def_id: DefId) {
-        let instance = declare_unused_fn(self, &def_id);
+        let instance = declare_unused_fn(self, def_id);
         codegen_unused_fn_and_counter(self, instance);
         add_unused_function_coverage(self, instance, def_id);
     }
@@ -184,12 +184,12 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
     }
 }
 
-fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: &DefId) -> Instance<'tcx> {
+fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<'tcx> {
     let tcx = cx.tcx;
 
     let instance = Instance::new(
-        *def_id,
-        InternalSubsts::for_item(tcx, *def_id, |param, _| {
+        def_id,
+        InternalSubsts::for_item(tcx, def_id, |param, _| {
             if let ty::GenericParamDefKind::Lifetime = param.kind {
                 tcx.lifetimes.re_erased.into()
             } else {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 89fc8980037..f16a903ad2c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -617,7 +617,9 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
         ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
             pointer_or_reference_metadata(cx, t, pointee_type, unique_type_id)
         }
-        ty::Adt(def, _) if def.is_box() => {
+        // Box<T, A> may have a non-ZST allocator A. In that case, we
+        // cannot treat Box<T, A> as just an owned alias of `*mut T`.
+        ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => {
             pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id)
         }
         ty::FnDef(..) | ty::FnPtr(_) => subroutine_type_metadata(cx, unique_type_id),
@@ -639,7 +641,7 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
             AdtKind::Struct => prepare_struct_metadata(cx, t, unique_type_id).finalize(cx),
             AdtKind::Union => prepare_union_metadata(cx, t, unique_type_id).finalize(cx),
             AdtKind::Enum => {
-                prepare_enum_metadata(cx, t, def.did, unique_type_id, vec![]).finalize(cx)
+                prepare_enum_metadata(cx, t, def.did(), unique_type_id, vec![]).finalize(cx)
             }
         },
         ty::Tuple(tys) => {
@@ -1207,7 +1209,7 @@ fn prepare_struct_metadata<'ll, 'tcx>(
     let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false);
 
     let (struct_def_id, variant) = match struct_type.kind() {
-        ty::Adt(def, _) => (def.did, def.non_enum_variant()),
+        ty::Adt(def, _) => (def.did(), def.non_enum_variant()),
         _ => bug!("prepare_struct_metadata on a non-ADT"),
     };
 
@@ -1384,7 +1386,7 @@ fn prepare_union_metadata<'ll, 'tcx>(
     let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
 
     let (union_def_id, variant) = match union_type.kind() {
-        ty::Adt(def, _) => (def.did, def.non_enum_variant()),
+        ty::Adt(def, _) => (def.did(), def.non_enum_variant()),
         _ => bug!("prepare_union_metadata on a non-ADT"),
     };
 
@@ -1466,7 +1468,7 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
         };
 
         let variant_info_for = |index: VariantIdx| match *self.enum_type.kind() {
-            ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index], index),
+            ty::Adt(adt, _) => VariantInfo::Adt(&adt.variant(index), index),
             ty::Generator(def_id, _, _) => {
                 let (generator_layout, generator_saved_local_names) =
                     generator_variant_info_data.as_ref().unwrap();
@@ -1490,7 +1492,7 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
         match self.layout.variants {
             Variants::Single { index } => {
                 if let ty::Adt(adt, _) = self.enum_type.kind() {
-                    if adt.variants.is_empty() {
+                    if adt.variants().is_empty() {
                         return vec![];
                     }
                 }
@@ -1940,7 +1942,7 @@ fn prepare_enum_metadata<'ll, 'tcx>(
 
     let discriminant_type_metadata = |discr: Primitive| {
         let enumerators_metadata: Vec<_> = match enum_type.kind() {
-            ty::Adt(def, _) => iter::zip(def.discriminants(tcx), &def.variants)
+            ty::Adt(def, _) => iter::zip(def.discriminants(tcx), def.variants())
                 .map(|((_, discr), v)| {
                     let name = v.name.as_str();
                     let is_unsigned = match discr.ty.kind() {
@@ -2311,7 +2313,7 @@ fn set_members_of_composite_type<'ll, 'tcx>(
 fn compute_type_parameters<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> &'ll DIArray {
     if let ty::Adt(def, substs) = *ty.kind() {
         if substs.types().next().is_some() {
-            let generics = cx.tcx.generics_of(def.did);
+            let generics = cx.tcx.generics_of(def.did());
             let names = get_parameter_names(cx, generics);
             let template_params: Vec<_> = iter::zip(substs, names)
                 .filter_map(|(kind, name)| {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 1b4a193dbf1..34013b5f737 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -524,7 +524,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                             {
                                 Some(type_metadata(cx, impl_self_ty))
                             } else {
-                                Some(namespace::item_namespace(cx, def.did))
+                                Some(namespace::item_namespace(cx, def.did()))
                             }
                         }
                         _ => None,
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e7c13e793d9..7f804ab5e63 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -300,34 +300,34 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 use abi::Abi::*;
                 let tp_ty = substs.type_at(0);
                 let layout = self.layout_of(tp_ty).layout;
-                let use_integer_compare = match layout.abi {
+                let use_integer_compare = match layout.abi() {
                     Scalar(_) | ScalarPair(_, _) => true,
                     Uninhabited | Vector { .. } => false,
                     Aggregate { .. } => {
                         // For rusty ABIs, small aggregates are actually passed
                         // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
                         // so we re-use that same threshold here.
-                        layout.size <= self.data_layout().pointer_size * 2
+                        layout.size() <= self.data_layout().pointer_size * 2
                     }
                 };
 
                 let a = args[0].immediate();
                 let b = args[1].immediate();
-                if layout.size.bytes() == 0 {
+                if layout.size().bytes() == 0 {
                     self.const_bool(true)
                 } else if use_integer_compare {
-                    let integer_ty = self.type_ix(layout.size.bits());
+                    let integer_ty = self.type_ix(layout.size().bits());
                     let ptr_ty = self.type_ptr_to(integer_ty);
                     let a_ptr = self.bitcast(a, ptr_ty);
-                    let a_val = self.load(integer_ty, a_ptr, layout.align.abi);
+                    let a_val = self.load(integer_ty, a_ptr, layout.align().abi);
                     let b_ptr = self.bitcast(b, ptr_ty);
-                    let b_val = self.load(integer_ty, b_ptr, layout.align.abi);
+                    let b_val = self.load(integer_ty, b_ptr, layout.align().abi);
                     self.icmp(IntPredicate::IntEQ, a_val, b_val)
                 } else {
                     let i8p_ty = self.type_i8p();
                     let a_ptr = self.bitcast(a, i8p_ty);
                     let b_ptr = self.bitcast(b, i8p_ty);
-                    let n = self.const_usize(layout.size.bytes());
+                    let n = self.const_usize(layout.size().bytes());
                     let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]);
                     self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
                 }
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index e9d13a4ebaf..4b324740a1f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -527,8 +527,9 @@ pub(crate) fn should_use_new_llvm_pass_manager(user_opt: &Option<bool>, target_a
     // The new pass manager is enabled by default for LLVM >= 13.
     // This matches Clang, which also enables it since Clang 13.
 
-    // FIXME: There are some perf issues with the new pass manager
-    // when targeting s390x, so it is temporarily disabled for that
-    // arch, see https://github.com/rust-lang/rust/issues/89609
-    user_opt.unwrap_or_else(|| target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0))
+    // There are some perf issues with the new pass manager when targeting
+    // s390x with LLVM 13, so enable the new pass manager only with LLVM 14.
+    // See https://github.com/rust-lang/rust/issues/89609.
+    let min_version = if target_arch == "s390x" { 14 } else { 13 };
+    user_opt.unwrap_or_else(|| llvm_util::get_version() >= (min_version, 0, 0))
 }
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index da378dc6493..757aa9a1011 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -53,8 +53,8 @@ fn uncached_llvm_type<'a, 'tcx>(
             if let (&ty::Adt(def, _), &Variants::Single { index }) =
                 (layout.ty.kind(), &layout.variants)
             {
-                if def.is_enum() && !def.variants.is_empty() {
-                    write!(&mut name, "::{}", def.variants[index].name).unwrap();
+                if def.is_enum() && !def.variants().is_empty() {
+                    write!(&mut name, "::{}", def.variant(index).name).unwrap();
                 }
             }
             if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 11f32d92e44..0b31e4b5582 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -255,7 +255,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
             assert_eq!(def_a, def_b);
 
-            for i in 0..def_a.variants[VariantIdx::new(0)].fields.len() {
+            for i in 0..def_a.variant(VariantIdx::new(0)).fields.len() {
                 let src_f = src.project_field(bx, i);
                 let dst_f = dst.project_field(bx, i);
 
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 37e84046901..67df64e9b1b 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -74,7 +74,7 @@ fn push_debuginfo_type_name<'tcx>(
             if def.is_enum() && cpp_like_debuginfo {
                 msvc_enum_fallback(tcx, t, def, substs, output, visited);
             } else {
-                push_item_name(tcx, def.did, qualified, output);
+                push_item_name(tcx, def.did(), qualified, output);
                 push_generic_params_internal(tcx, substs, output, visited);
             }
         }
@@ -405,15 +405,15 @@ fn push_debuginfo_type_name<'tcx>(
     fn msvc_enum_fallback<'tcx>(
         tcx: TyCtxt<'tcx>,
         ty: Ty<'tcx>,
-        def: &AdtDef,
+        def: AdtDef<'tcx>,
         substs: SubstsRef<'tcx>,
         output: &mut String,
         visited: &mut FxHashSet<Ty<'tcx>>,
     ) {
-        let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error");
+        let layout = tcx.layout_of(tcx.param_env(def.did()).and(ty)).expect("layout error");
 
         output.push_str("enum$<");
-        push_item_name(tcx, def.did, true, output);
+        push_item_name(tcx, def.did(), true, output);
         push_generic_params_internal(tcx, substs, output, visited);
 
         if let Variants::Multiple {
@@ -427,7 +427,7 @@ fn push_debuginfo_type_name<'tcx>(
 
             // calculate the range of values for the dataful variant
             let dataful_discriminant_range =
-                dataful_variant_layout.largest_niche.unwrap().scalar.valid_range;
+                dataful_variant_layout.largest_niche().unwrap().scalar.valid_range;
 
             let min = dataful_discriminant_range.start;
             let min = tag.value.size(&tcx).truncate(min);
@@ -435,14 +435,14 @@ fn push_debuginfo_type_name<'tcx>(
             let max = dataful_discriminant_range.end;
             let max = tag.value.size(&tcx).truncate(max);
 
-            let dataful_variant_name = def.variants[*dataful_variant].name.as_str();
+            let dataful_variant_name = def.variant(*dataful_variant).name.as_str();
 
             output.push_str(&format!(", {}, {}, {}", min, max, dataful_variant_name));
         } else if let Variants::Single { index: variant_idx } = &layout.variants {
             // Uninhabited enums can't be constructed and should never need to be visualized so
             // skip this step for them.
-            if def.variants.len() != 0 {
-                let variant = def.variants[*variant_idx].name.as_str();
+            if def.variants().len() != 0 {
+                let variant = def.variant(*variant_idx).name.as_str();
 
                 output.push_str(&format!(", {}", variant));
             }
diff --git a/compiler/rustc_codegen_ssa/src/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs
index 2c4e6bbe9a5..694f5434e9a 100644
--- a/compiler/rustc_codegen_ssa/src/glue.rs
+++ b/compiler/rustc_codegen_ssa/src/glue.rs
@@ -74,7 +74,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
             // Packed types ignore the alignment of their fields.
             if let ty::Adt(def, _) = t.kind() {
-                if def.repr.packed() {
+                if def.repr().packed() {
                     unsized_align = sized_align;
                 }
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 66be58cf62c..858f71ebc39 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -126,7 +126,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
             .ty;
         let (llptr, llextra) = match self.val {
             OperandValue::Immediate(llptr) => (llptr, None),
-            OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
+            OperandValue::Pair(llptr, llextra) => {
+                // if the box's allocator isn't a ZST, then "llextra" is actually the allocator
+                if self.layout.ty.is_box() && !self.layout.field(cx, 1).is_zst() {
+                    (llptr, None)
+                } else {
+                    (llptr, Some(llextra))
+                }
+            }
             OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self),
         };
         let layout = cx.layout_of(projected_ty);
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 809d6447908..2b8fa3be56d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -149,7 +149,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
             _ if !field.is_unsized() => return simple(),
             ty::Slice(..) | ty::Str | ty::Foreign(..) => return simple(),
             ty::Adt(def, _) => {
-                if def.repr.packed() {
+                if def.repr().packed() {
                     // FIXME(eddyb) generalize the adjustment when we
                     // start supporting packing to larger alignments.
                     assert_eq!(self.layout.align.abi.bytes(), 1);
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index c49c5ecac26..6fd7f707e7e 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -105,13 +105,13 @@ fn const_to_valtree_inner<'tcx>(
         ty::Array(_, len) => branches(usize::try_from(len.eval_usize(ecx.tcx.tcx, ecx.param_env)).unwrap(), None),
 
         ty::Adt(def, _) => {
-            if def.variants.is_empty() {
+            if def.variants().is_empty() {
                 bug!("uninhabited types should have errored and never gotten converted to valtree")
             }
 
             let variant = ecx.read_discriminant(&place.into()).unwrap().1;
 
-            branches(def.variants[variant].fields.len(), def.is_enum().then_some(variant))
+            branches(def.variant(variant).fields.len(), def.is_enum().then_some(variant))
         }
 
         ty::Never
@@ -150,11 +150,11 @@ pub(crate) fn try_destructure_const<'tcx>(
         // Checks if we have any variants, to avoid downcasting to a non-existing variant (when
         // there are no variants `read_discriminant` successfully returns a non-existing variant
         // index).
-        ty::Adt(def, _) if def.variants.is_empty() => throw_ub!(Unreachable),
+        ty::Adt(def, _) if def.variants().is_empty() => throw_ub!(Unreachable),
         ty::Adt(def, _) => {
             let variant = ecx.read_discriminant(&op)?.1;
             let down = ecx.operand_downcast(&op, variant)?;
-            (def.variants[variant].fields.len(), Some(variant), down)
+            (def.variant(variant).fields.len(), Some(variant), down)
         }
         ty::Tuple(substs) => (substs.len(), None, op),
         _ => bug!("cannot destructure constant {:?}", val),
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 45ac3cd1f84..a8a57e6990f 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -164,7 +164,7 @@ pub enum StackPopCleanup {
 }
 
 /// State of a local variable including a memoized layout
-#[derive(Clone, PartialEq, Eq, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable)]
 pub struct LocalState<'tcx, Tag: Provenance = AllocId> {
     pub value: LocalValue<Tag>,
     /// Don't modify if `Some`, this is only used to prevent computing the layout twice
@@ -714,6 +714,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         self.size_and_align_of(&mplace.meta, &mplace.layout)
     }
 
+    #[instrument(skip(self, body, return_place, return_to_block), level = "debug")]
     pub fn push_stack_frame(
         &mut self,
         instance: ty::Instance<'tcx>,
@@ -721,6 +722,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
+        debug!("body: {:#?}", body);
         // first push a stack frame so we have access to the local substs
         let pre_frame = Frame {
             body,
@@ -824,6 +826,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// `Drop` impls for any locals that have been initialized at this point.
     /// The cleanup block ends with a special `Resume` terminator, which will
     /// cause us to continue unwinding.
+    #[instrument(skip(self), level = "debug")]
     pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> {
         info!(
             "popping stack frame ({})",
@@ -876,6 +879,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             return Ok(());
         }
 
+        debug!("locals: {:#?}", frame.locals);
+
         // Cleanup: deallocate all locals that are backed by an allocation.
         for local in &frame.locals {
             self.deallocate_local(local.value)?;
@@ -935,6 +940,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(())
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> {
         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
             // All locals have a backing allocation, even if the allocation is empty
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index bacb3f6ea7f..9f507bface2 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -174,7 +174,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
         }
 
         if let Some(def) = mplace.layout.ty.ty_adt_def() {
-            if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
+            if Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() {
                 // We are crossing over an `UnsafeCell`, we can mutate again. This means that
                 // References we encounter inside here are interned as pointing to mutable
                 // allocations.
@@ -359,6 +359,8 @@ pub fn intern_const_alloc_recursive<
     // pointers, ... So we can't intern them according to their type rules
 
     let mut todo: Vec<_> = leftover_allocations.iter().cloned().collect();
+    debug!(?todo);
+    debug!("dead_alloc_map: {:#?}", ecx.memory.dead_alloc_map);
     while let Some(alloc_id) = todo.pop() {
         if let Some((_, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) {
             // We can't call the `intern_shallow` method here, as its logic is tailored to safe
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 9b58e25d330..5eff7d693c5 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -73,7 +73,9 @@ crate fn eval_nullary_intrinsic<'tcx>(
         }
         sym::variant_count => match tp_ty.kind() {
             // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
-            ty::Adt(ref adt, _) => ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx),
+            ty::Adt(ref adt, _) => {
+                ConstValue::from_machine_usize(adt.variants().len() as u64, &tcx)
+            }
             ty::Projection(_)
             | ty::Opaque(_, _)
             | ty::Param(_)
@@ -219,48 +221,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             sym::saturating_add | sym::saturating_sub => {
                 let l = self.read_immediate(&args[0])?;
                 let r = self.read_immediate(&args[1])?;
-                let is_add = intrinsic_name == sym::saturating_add;
-                let (val, overflowed, _ty) = self.overflowing_binary_op(
-                    if is_add { BinOp::Add } else { BinOp::Sub },
+                let val = self.saturating_arith(
+                    if intrinsic_name == sym::saturating_add { BinOp::Add } else { BinOp::Sub },
                     &l,
                     &r,
                 )?;
-                let val = if overflowed {
-                    let size = l.layout.size;
-                    let num_bits = size.bits();
-                    if l.layout.abi.is_signed() {
-                        // For signed ints the saturated value depends on the sign of the first
-                        // term since the sign of the second term can be inferred from this and
-                        // the fact that the operation has overflowed (if either is 0 no
-                        // overflow can occur)
-                        let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
-                        let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
-                        if first_term_positive {
-                            // Negative overflow not possible since the positive first term
-                            // can only increase an (in range) negative term for addition
-                            // or corresponding negated positive term for subtraction
-                            Scalar::from_uint(
-                                (1u128 << (num_bits - 1)) - 1, // max positive
-                                Size::from_bits(num_bits),
-                            )
-                        } else {
-                            // Positive overflow not possible for similar reason
-                            // max negative
-                            Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
-                        }
-                    } else {
-                        // unsigned
-                        if is_add {
-                            // max unsigned
-                            Scalar::from_uint(size.unsigned_int_max(), Size::from_bits(num_bits))
-                        } else {
-                            // underflow to 0
-                            Scalar::from_uint(0u128, Size::from_bits(num_bits))
-                        }
-                    }
-                } else {
-                    val
-                };
                 self.write_scalar(val, dest)?;
             }
             sym::discriminant_value => {
@@ -344,53 +309,57 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_pointer(offset_ptr, dest)?;
             }
             sym::ptr_offset_from => {
-                let a = self.read_immediate(&args[0])?.to_scalar()?;
-                let b = self.read_immediate(&args[1])?.to_scalar()?;
+                let a = self.read_pointer(&args[0])?;
+                let b = self.read_pointer(&args[1])?;
 
                 // Special case: if both scalars are *equal integers*
                 // and not null, we pretend there is an allocation of size 0 right there,
                 // and their offset is 0. (There's never a valid object at null, making it an
                 // exception from the exception.)
                 // This is the dual to the special exception for offset-by-0
-                // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`).
-                //
-                // Control flow is weird because we cannot early-return (to reach the
-                // `go_to_block` at the end).
-                let done = if let (Ok(a), Ok(b)) = (a.try_to_int(), b.try_to_int()) {
-                    let a = a.try_to_machine_usize(*self.tcx).unwrap();
-                    let b = b.try_to_machine_usize(*self.tcx).unwrap();
-                    if a == b && a != 0 {
+                // in the inbounds pointer offset operation (see `ptr_offset_inbounds` below).
+                match (self.memory.ptr_try_get_alloc(a), self.memory.ptr_try_get_alloc(b)) {
+                    (Err(a), Err(b)) if a == b && a != 0 => {
+                        // Both are the same non-null integer.
                         self.write_scalar(Scalar::from_machine_isize(0, self), dest)?;
-                        true
-                    } else {
-                        false
                     }
-                } else {
-                    false
-                };
-
-                if !done {
-                    // General case: we need two pointers.
-                    let a = self.scalar_to_ptr(a);
-                    let b = self.scalar_to_ptr(b);
-                    let (a_alloc_id, a_offset, _) = self.memory.ptr_get_alloc(a)?;
-                    let (b_alloc_id, b_offset, _) = self.memory.ptr_get_alloc(b)?;
-                    if a_alloc_id != b_alloc_id {
-                        throw_ub_format!(
-                            "ptr_offset_from cannot compute offset of pointers into different \
-                            allocations.",
-                        );
+                    (Err(offset), _) | (_, Err(offset)) => {
+                        throw_ub!(DanglingIntPointer(offset, CheckInAllocMsg::OffsetFromTest));
+                    }
+                    (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => {
+                        // Both are pointers. They must be into the same allocation.
+                        if a_alloc_id != b_alloc_id {
+                            throw_ub_format!(
+                                "ptr_offset_from cannot compute offset of pointers into different \
+                                allocations.",
+                            );
+                        }
+                        // And they must both be valid for zero-sized accesses ("in-bounds or one past the end").
+                        self.memory.check_ptr_access_align(
+                            a,
+                            Size::ZERO,
+                            Align::ONE,
+                            CheckInAllocMsg::OffsetFromTest,
+                        )?;
+                        self.memory.check_ptr_access_align(
+                            b,
+                            Size::ZERO,
+                            Align::ONE,
+                            CheckInAllocMsg::OffsetFromTest,
+                        )?;
+
+                        // Compute offset.
+                        let usize_layout = self.layout_of(self.tcx.types.usize)?;
+                        let isize_layout = self.layout_of(self.tcx.types.isize)?;
+                        let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout);
+                        let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout);
+                        let (val, _overflowed, _ty) =
+                            self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
+                        let pointee_layout = self.layout_of(substs.type_at(0))?;
+                        let val = ImmTy::from_scalar(val, isize_layout);
+                        let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
+                        self.exact_div(&val, &size, dest)?;
                     }
-                    let usize_layout = self.layout_of(self.tcx.types.usize)?;
-                    let isize_layout = self.layout_of(self.tcx.types.isize)?;
-                    let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout);
-                    let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout);
-                    let (val, _overflowed, _ty) =
-                        self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
-                    let pointee_layout = self.layout_of(substs.type_at(0))?;
-                    let val = ImmTy::from_scalar(val, isize_layout);
-                    let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
-                    self.exact_div(&val, &size, dest)?;
                 }
             }
 
@@ -508,6 +477,49 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         self.binop_ignore_overflow(BinOp::Div, &a, &b, dest)
     }
 
+    pub fn saturating_arith(
+        &self,
+        mir_op: BinOp,
+        l: &ImmTy<'tcx, M::PointerTag>,
+        r: &ImmTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+        assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
+        let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?;
+        Ok(if overflowed {
+            let size = l.layout.size;
+            let num_bits = size.bits();
+            if l.layout.abi.is_signed() {
+                // For signed ints the saturated value depends on the sign of the first
+                // term since the sign of the second term can be inferred from this and
+                // the fact that the operation has overflowed (if either is 0 no
+                // overflow can occur)
+                let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
+                let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
+                if first_term_positive {
+                    // Negative overflow not possible since the positive first term
+                    // can only increase an (in range) negative term for addition
+                    // or corresponding negated positive term for subtraction
+                    Scalar::from_int(size.signed_int_max(), size)
+                } else {
+                    // Positive overflow not possible for similar reason
+                    // max negative
+                    Scalar::from_int(size.signed_int_min(), size)
+                }
+            } else {
+                // unsigned
+                if matches!(mir_op, BinOp::Add) {
+                    // max unsigned
+                    Scalar::from_uint(size.unsigned_int_max(), size)
+                } else {
+                    // underflow to 0
+                    Scalar::from_uint(0u128, size)
+                }
+            }
+        } else {
+            val
+        })
+    }
+
     /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
     /// allocation. For integer pointers, we consider each of them their own tiny allocation of size
     /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
index dfc1a6e4d38..447797f915c 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::DisambiguatedDefPathData;
 use rustc_middle::mir::interpret::{Allocation, ConstAllocation};
@@ -56,7 +57,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
             }
 
             // Types with identity (print the module path).
-            ty::Adt(&ty::AdtDef { did: def_id, .. }, substs)
+            ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
             | ty::FnDef(def_id, substs)
             | ty::Opaque(def_id, substs)
             | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index e100ebc4ccb..6397fcaaf8d 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -275,6 +275,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         Ok(new_ptr)
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub fn deallocate(
         &mut self,
         ptr: Pointer<Option<M::PointerTag>>,
@@ -305,6 +306,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             .into());
         };
 
+        debug!(?alloc);
+
         if alloc.mutability == Mutability::Not {
             throw_ub_format!("deallocating immutable allocation {}", alloc_id);
         }
@@ -385,9 +388,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
                 CheckInAllocMsg::DerefTest | CheckInAllocMsg::MemoryAccessTest => {
                     AllocCheck::Dereferenceable
                 }
-                CheckInAllocMsg::PointerArithmeticTest | CheckInAllocMsg::InboundsTest => {
-                    AllocCheck::Live
-                }
+                CheckInAllocMsg::PointerArithmeticTest
+                | CheckInAllocMsg::OffsetFromTest
+                | CheckInAllocMsg::InboundsTest => AllocCheck::Live,
             };
             let (size, align) = self.get_size_and_align(alloc_id, check)?;
             Ok((size, align, ()))
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index fb4fe41bdbc..2fae53bb9bd 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -759,7 +759,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                                 .ty
                                 .ty_adt_def()
                                 .expect("tagged layout for non adt")
-                                .variants
+                                .variants()
                                 .len();
                             assert!(usize::try_from(variant_index).unwrap() < variants_len);
                             VariantIdx::from_u32(variant_index)
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 5cacab82386..8fad5e63baf 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -267,7 +267,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 match layout.variants {
                     Variants::Single { index } => {
                         // Inside a variant
-                        PathElem::Field(def.variants[index].fields[field].name)
+                        PathElem::Field(def.variant(index).fields[field].name)
                     }
                     Variants::Multiple { .. } => bug!("we handled variants above"),
                 }
@@ -734,7 +734,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
         new_op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         let name = match old_op.layout.ty.kind() {
-            ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].name),
+            ty::Adt(adt, _) => PathElem::Variant(adt.variant(variant_id).name),
             // Generators also have variants
             ty::Generator(..) => PathElem::GeneratorState(variant_id),
             _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty),
@@ -771,7 +771,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
         // Special check preventing `UnsafeCell` in the inner part of constants
         if let Some(def) = op.layout.ty.ty_adt_def() {
             if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. }))
-                && Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type()
+                && Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type()
             {
                 throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
             }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index b78924490ca..7dc279cc840 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -230,8 +230,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                 }
             }
 
-            self.check_item_predicates();
-
             for (idx, local) in body.local_decls.iter_enumerated() {
                 // Handle the return place below.
                 if idx == RETURN_PLACE || local.internal {
@@ -358,83 +356,11 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
 
             match *ty.kind() {
                 ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)),
-                ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
-                ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)),
-
-                ty::Dynamic(preds, _) => {
-                    for pred in preds.iter() {
-                        match pred.skip_binder() {
-                            ty::ExistentialPredicate::AutoTrait(_)
-                            | ty::ExistentialPredicate::Projection(_) => {
-                                self.check_op(ops::ty::DynTrait(kind))
-                            }
-                            ty::ExistentialPredicate::Trait(trait_ref) => {
-                                if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
-                                    self.check_op(ops::ty::DynTrait(kind))
-                                }
-                            }
-                        }
-                    }
-                }
                 _ => {}
             }
         }
     }
 
-    fn check_item_predicates(&mut self) {
-        let ConstCx { tcx, .. } = *self.ccx;
-
-        let mut current = self.def_id().to_def_id();
-        loop {
-            let predicates = tcx.predicates_of(current);
-            for (predicate, _) in predicates.predicates {
-                match predicate.kind().skip_binder() {
-                    ty::PredicateKind::RegionOutlives(_)
-                    | ty::PredicateKind::TypeOutlives(_)
-                    | ty::PredicateKind::WellFormed(_)
-                    | ty::PredicateKind::Projection(_)
-                    | ty::PredicateKind::ConstEvaluatable(..)
-                    | ty::PredicateKind::ConstEquate(..)
-                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
-                    ty::PredicateKind::ObjectSafe(_) => {
-                        bug!("object safe predicate on function: {:#?}", predicate)
-                    }
-                    ty::PredicateKind::ClosureKind(..) => {
-                        bug!("closure kind predicate on function: {:#?}", predicate)
-                    }
-                    ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) => {
-                        bug!("subtype/coerce predicate on function: {:#?}", predicate)
-                    }
-                    ty::PredicateKind::Trait(pred) => {
-                        if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
-                            continue;
-                        }
-                        match pred.self_ty().kind() {
-                            ty::Param(p) => {
-                                let generics = tcx.generics_of(current);
-                                let def = generics.type_param(p, tcx);
-                                let span = tcx.def_span(def.def_id);
-
-                                // These are part of the function signature, so treat them like
-                                // arguments when determining importance.
-                                let kind = LocalKind::Arg;
-
-                                self.check_op_spanned(ops::ty::TraitBound(kind), span);
-                            }
-                            // other kinds of bounds are either tautologies
-                            // or cause errors in other passes
-                            _ => continue,
-                        }
-                    }
-                }
-            }
-            match predicates.parent {
-                Some(parent) => current = parent,
-                None => break,
-            }
-        }
-    }
-
     fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
         match self.const_kind() {
             // In a const fn all borrows are transient or point to the places given via
@@ -613,7 +539,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 ),
                 _,
                 _,
-            ) => self.check_op(ops::FnPtrCast),
+            ) => {
+                // Nothing to do here. Function pointer casts are allowed now.
+            }
 
             Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
                 // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index f6b92df92c0..ba248a3b6cb 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -356,31 +356,6 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
 }
 
 #[derive(Debug)]
-pub struct FnPtrCast;
-impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
-    fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
-        if ccx.const_kind() != hir::ConstContext::ConstFn {
-            Status::Allowed
-        } else {
-            Status::Unstable(sym::const_fn_fn_ptr_basics)
-        }
-    }
-
-    fn build_error(
-        &self,
-        ccx: &ConstCx<'_, 'tcx>,
-        span: Span,
-    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_fn_fn_ptr_basics,
-            span,
-            &format!("function pointer casts are not allowed in {}s", ccx.const_kind()),
-        )
-    }
-}
-
-#[derive(Debug)]
 pub struct Generator(pub hir::GeneratorKind);
 impl<'tcx> NonConstOp<'tcx> for Generator {
     fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
@@ -820,167 +795,4 @@ pub mod ty {
             )
         }
     }
-
-    #[derive(Debug)]
-    pub struct FnPtr(pub mir::LocalKind);
-    impl<'tcx> NonConstOp<'tcx> for FnPtr {
-        fn importance(&self) -> DiagnosticImportance {
-            match self.0 {
-                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
-                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
-                    DiagnosticImportance::Primary
-                }
-            }
-        }
-
-        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
-            if ccx.const_kind() != hir::ConstContext::ConstFn {
-                Status::Allowed
-            } else {
-                Status::Unstable(sym::const_fn_fn_ptr_basics)
-            }
-        }
-
-        fn build_error(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-            feature_err(
-                &ccx.tcx.sess.parse_sess,
-                sym::const_fn_fn_ptr_basics,
-                span,
-                &format!("function pointers cannot appear in {}s", ccx.const_kind()),
-            )
-        }
-    }
-
-    #[derive(Debug)]
-    pub struct ImplTrait;
-    impl<'tcx> NonConstOp<'tcx> for ImplTrait {
-        fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
-            Status::Unstable(sym::const_impl_trait)
-        }
-
-        fn build_error(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-            feature_err(
-                &ccx.tcx.sess.parse_sess,
-                sym::const_impl_trait,
-                span,
-                &format!("`impl Trait` is not allowed in {}s", ccx.const_kind()),
-            )
-        }
-    }
-
-    #[derive(Debug)]
-    pub struct TraitBound(pub mir::LocalKind);
-    impl<'tcx> NonConstOp<'tcx> for TraitBound {
-        fn importance(&self) -> DiagnosticImportance {
-            match self.0 {
-                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
-                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
-                    DiagnosticImportance::Primary
-                }
-            }
-        }
-
-        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
-            if ccx.const_kind() != hir::ConstContext::ConstFn {
-                Status::Allowed
-            } else {
-                Status::Unstable(sym::const_fn_trait_bound)
-            }
-        }
-
-        fn build_error(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-            let mut err = feature_err(
-                &ccx.tcx.sess.parse_sess,
-                sym::const_fn_trait_bound,
-                span,
-                "trait bounds other than `Sized` on const fn parameters are unstable",
-            );
-
-            match ccx.fn_sig() {
-                Some(fn_sig) if !fn_sig.span.contains(span) => {
-                    err.span_label(fn_sig.span, "function declared as const here");
-                }
-                _ => {}
-            }
-
-            err
-        }
-    }
-
-    #[derive(Debug)]
-    pub struct DynTrait(pub mir::LocalKind);
-    impl<'tcx> NonConstOp<'tcx> for DynTrait {
-        fn importance(&self) -> DiagnosticImportance {
-            match self.0 {
-                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
-                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
-                    DiagnosticImportance::Primary
-                }
-            }
-        }
-
-        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
-            if ccx.const_kind() != hir::ConstContext::ConstFn {
-                Status::Allowed
-            } else {
-                Status::Unstable(sym::const_fn_trait_bound)
-            }
-        }
-
-        fn build_error(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-            let mut err = feature_err(
-                &ccx.tcx.sess.parse_sess,
-                sym::const_fn_trait_bound,
-                span,
-                "trait objects in const fn are unstable",
-            );
-
-            match ccx.fn_sig() {
-                Some(fn_sig) if !fn_sig.span.contains(span) => {
-                    err.span_label(fn_sig.span, "function declared as const here");
-                }
-                _ => {}
-            }
-
-            err
-        }
-    }
-
-    /// A trait bound with the `?const Trait` opt-out
-    #[derive(Debug)]
-    pub struct TraitBoundNotConst;
-    impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
-        fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
-            Status::Unstable(sym::const_trait_bound_opt_out)
-        }
-
-        fn build_error(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-            feature_err(
-                &ccx.tcx.sess.parse_sess,
-                sym::const_trait_bound_opt_out,
-                span,
-                "`?const Trait` syntax is unstable",
-            )
-        }
-    }
 }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 6421ba9df0f..4ea21b4d06d 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -71,7 +71,7 @@ pub trait Qualif {
     /// Returning `true` for `in_adt_inherently` but `false` for `in_any_value_of_ty` is unsound.
     fn in_adt_inherently<'tcx>(
         cx: &ConstCx<'_, 'tcx>,
-        adt: &'tcx AdtDef,
+        adt: AdtDef<'tcx>,
         substs: SubstsRef<'tcx>,
     ) -> bool;
 }
@@ -96,12 +96,12 @@ impl Qualif for HasMutInterior {
 
     fn in_adt_inherently<'tcx>(
         cx: &ConstCx<'_, 'tcx>,
-        adt: &'tcx AdtDef,
+        adt: AdtDef<'tcx>,
         _: SubstsRef<'tcx>,
     ) -> bool {
         // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
         // It arises structurally for all other types.
-        Some(adt.did) == cx.tcx.lang_items().unsafe_cell_type()
+        Some(adt.did()) == cx.tcx.lang_items().unsafe_cell_type()
     }
 }
 
@@ -126,7 +126,7 @@ impl Qualif for NeedsDrop {
 
     fn in_adt_inherently<'tcx>(
         cx: &ConstCx<'_, 'tcx>,
-        adt: &'tcx AdtDef,
+        adt: AdtDef<'tcx>,
         _: SubstsRef<'tcx>,
     ) -> bool {
         adt.has_dtor(cx.tcx)
@@ -205,7 +205,7 @@ impl Qualif for NeedsNonConstDrop {
 
     fn in_adt_inherently<'tcx>(
         cx: &ConstCx<'_, 'tcx>,
-        adt: &'tcx AdtDef,
+        adt: AdtDef<'tcx>,
         _: SubstsRef<'tcx>,
     ) -> bool {
         adt.has_non_const_dtor(cx.tcx)
@@ -233,7 +233,7 @@ impl Qualif for CustomEq {
 
     fn in_adt_inherently<'tcx>(
         cx: &ConstCx<'_, 'tcx>,
-        adt: &'tcx AdtDef,
+        adt: AdtDef<'tcx>,
         substs: SubstsRef<'tcx>,
     ) -> bool {
         let ty = cx.tcx.mk_ty(ty::Adt(adt, substs));
diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs
index e4528b68907..fe4a726fe12 100644
--- a/compiler/rustc_const_eval/src/util/alignment.rs
+++ b/compiler/rustc_const_eval/src/util/alignment.rs
@@ -55,7 +55,7 @@ where
             ProjectionElem::Field(..) => {
                 let ty = place_base.ty(local_decls, tcx).ty;
                 match ty.kind() {
-                    ty::Adt(def, _) => return def.repr.pack,
+                    ty::Adt(def, _) => return def.repr().pack,
                     _ => {}
                 }
             }
diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs
index 11bb9508a1f..2165989b398 100644
--- a/compiler/rustc_const_eval/src/util/call_kind.rs
+++ b/compiler/rustc_const_eval/src/util/call_kind.rs
@@ -132,7 +132,7 @@ pub fn call_kind<'tcx>(
             .parent(method_did)
             .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
             .and_then(|did| match tcx.type_of(did).kind() {
-                ty::Adt(def, ..) => Some(def.did),
+                ty::Adt(def, ..) => Some(def.did()),
                 _ => None,
             });
         let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs
index f0e3f83e848..7a320b10b60 100644
--- a/compiler/rustc_data_structures/src/intern.rs
+++ b/compiler/rustc_data_structures/src/intern.rs
@@ -1,3 +1,4 @@
+use crate::stable_hasher::{HashStable, StableHasher};
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
 use std::ops::Deref;
@@ -98,5 +99,14 @@ impl<'a, T> Hash for Interned<'a, T> {
     }
 }
 
+impl<T, CTX> HashStable<CTX> for Interned<'_, T>
+where
+    T: HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.0.hash_stable(hcx, hasher);
+    }
+}
+
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs
index 0af571610fe..780753ed200 100644
--- a/compiler/rustc_data_structures/src/transitive_relation.rs
+++ b/compiler/rustc_data_structures/src/transitive_relation.rs
@@ -49,7 +49,7 @@ struct Edge {
     target: Index,
 }
 
-impl<T: Eq + Hash> TransitiveRelation<T> {
+impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
     pub fn is_empty(&self) -> bool {
         self.edges.is_empty()
     }
@@ -58,8 +58,8 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
         self.elements.iter()
     }
 
-    fn index(&self, a: &T) -> Option<Index> {
-        self.elements.get_index_of(a).map(Index)
+    fn index(&self, a: T) -> Option<Index> {
+        self.elements.get_index_of(&a).map(Index)
     }
 
     fn add_index(&mut self, a: T) -> Index {
@@ -76,12 +76,12 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
     /// `None`.
     pub fn maybe_map<F, U>(&self, mut f: F) -> Option<TransitiveRelation<U>>
     where
-        F: FnMut(&T) -> Option<U>,
-        U: Clone + Debug + Eq + Hash + Clone,
+        F: FnMut(T) -> Option<U>,
+        U: Clone + Debug + Eq + Hash + Copy,
     {
         let mut result = TransitiveRelation::default();
         for edge in &self.edges {
-            result.add(f(&self.elements[edge.source.0])?, f(&self.elements[edge.target.0])?);
+            result.add(f(self.elements[edge.source.0])?, f(self.elements[edge.target.0])?);
         }
         Some(result)
     }
@@ -100,7 +100,7 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
     }
 
     /// Checks whether `a < target` (transitively)
-    pub fn contains(&self, a: &T, b: &T) -> bool {
+    pub fn contains(&self, a: T, b: T) -> bool {
         match (self.index(a), self.index(b)) {
             (Some(a), Some(b)) => self.with_closure(|closure| closure.contains(a.0, b.0)),
             (None, _) | (_, None) => false,
@@ -113,10 +113,10 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
     /// Really this probably ought to be `impl Iterator<Item = &T>`, but
     /// I'm too lazy to make that work, and -- given the caching
     /// strategy -- it'd be a touch tricky anyhow.
-    pub fn reachable_from(&self, a: &T) -> Vec<&T> {
+    pub fn reachable_from(&self, a: T) -> Vec<T> {
         match self.index(a) {
             Some(a) => {
-                self.with_closure(|closure| closure.iter(a.0).map(|i| &self.elements[i]).collect())
+                self.with_closure(|closure| closure.iter(a.0).map(|i| self.elements[i]).collect())
             }
             None => vec![],
         }
@@ -157,7 +157,7 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
     /// a -> a1
     /// b -> b1
     /// ```
-    pub fn postdom_upper_bound(&self, a: &T, b: &T) -> Option<&T> {
+    pub fn postdom_upper_bound(&self, a: T, b: T) -> Option<T> {
         let mubs = self.minimal_upper_bounds(a, b);
         self.mutual_immediate_postdominator(mubs)
     }
@@ -165,7 +165,7 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
     /// Viewing the relation as a graph, computes the "mutual
     /// immediate postdominator" of a set of points (if one
     /// exists). See `postdom_upper_bound` for details.
-    pub fn mutual_immediate_postdominator<'a>(&'a self, mut mubs: Vec<&'a T>) -> Option<&'a T> {
+    pub fn mutual_immediate_postdominator<'a>(&'a self, mut mubs: Vec<T>) -> Option<T> {
         loop {
             match mubs.len() {
                 0 => return None,
@@ -189,7 +189,7 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
     ///     internal indices).
     ///
     /// Note that this set can, in principle, have any size.
-    pub fn minimal_upper_bounds(&self, a: &T, b: &T) -> Vec<&T> {
+    pub fn minimal_upper_bounds(&self, a: T, b: T) -> Vec<T> {
         let (Some(mut a), Some(mut b)) = (self.index(a), self.index(b)) else {
             return vec![];
         };
@@ -267,7 +267,7 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
         lub_indices
             .into_iter()
             .rev() // (4)
-            .map(|i| &self.elements[i])
+            .map(|i| self.elements[i])
             .collect()
     }
 
@@ -290,7 +290,7 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
     ///
     /// then `parents(a)` returns `[b, c]`. The `postdom_parent` function
     /// would further reduce this to just `f`.
-    pub fn parents(&self, a: &T) -> Vec<&T> {
+    pub fn parents(&self, a: T) -> Vec<T> {
         let Some(a) = self.index(a) else {
             return vec![];
         };
@@ -314,7 +314,7 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
         ancestors
             .into_iter()
             .rev() // (4)
-            .map(|i| &self.elements[i])
+            .map(|i| self.elements[i])
             .collect()
     }
 
@@ -350,10 +350,10 @@ impl<T: Eq + Hash> TransitiveRelation<T> {
 
     /// Lists all the base edges in the graph: the initial _non-transitive_ set of element
     /// relations, which will be later used as the basis for the transitive closure computation.
-    pub fn base_edges(&self) -> impl Iterator<Item = (&T, &T)> {
+    pub fn base_edges(&self) -> impl Iterator<Item = (T, T)> + '_ {
         self.edges
             .iter()
-            .map(move |edge| (&self.elements[edge.source.0], &self.elements[edge.target.0]))
+            .map(move |edge| (self.elements[edge.source.0], self.elements[edge.target.0]))
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/transitive_relation/tests.rs b/compiler/rustc_data_structures/src/transitive_relation/tests.rs
index 9fa7224376c..f63b1be1ddc 100644
--- a/compiler/rustc_data_structures/src/transitive_relation/tests.rs
+++ b/compiler/rustc_data_structures/src/transitive_relation/tests.rs
@@ -1,9 +1,9 @@
 use super::*;
 
-impl<T: Eq + Hash> TransitiveRelation<T> {
+impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
     /// A "best" parent in some sense. See `parents` and
     /// `postdom_upper_bound` for more details.
-    fn postdom_parent(&self, a: &T) -> Option<&T> {
+    fn postdom_parent(&self, a: T) -> Option<T> {
         self.mutual_immediate_postdominator(self.parents(a))
     }
 }
@@ -13,10 +13,10 @@ fn test_one_step() {
     let mut relation = TransitiveRelation::default();
     relation.add("a", "b");
     relation.add("a", "c");
-    assert!(relation.contains(&"a", &"c"));
-    assert!(relation.contains(&"a", &"b"));
-    assert!(!relation.contains(&"b", &"a"));
-    assert!(!relation.contains(&"a", &"d"));
+    assert!(relation.contains("a", "c"));
+    assert!(relation.contains("a", "b"));
+    assert!(!relation.contains("b", "a"));
+    assert!(!relation.contains("a", "d"));
 }
 
 #[test]
@@ -32,17 +32,17 @@ fn test_many_steps() {
 
     relation.add("e", "g");
 
-    assert!(relation.contains(&"a", &"b"));
-    assert!(relation.contains(&"a", &"c"));
-    assert!(relation.contains(&"a", &"d"));
-    assert!(relation.contains(&"a", &"e"));
-    assert!(relation.contains(&"a", &"f"));
-    assert!(relation.contains(&"a", &"g"));
+    assert!(relation.contains("a", "b"));
+    assert!(relation.contains("a", "c"));
+    assert!(relation.contains("a", "d"));
+    assert!(relation.contains("a", "e"));
+    assert!(relation.contains("a", "f"));
+    assert!(relation.contains("a", "g"));
 
-    assert!(relation.contains(&"b", &"g"));
+    assert!(relation.contains("b", "g"));
 
-    assert!(!relation.contains(&"a", &"x"));
-    assert!(!relation.contains(&"b", &"f"));
+    assert!(!relation.contains("a", "x"));
+    assert!(!relation.contains("b", "f"));
 }
 
 #[test]
@@ -54,9 +54,9 @@ fn mubs_triangle() {
     let mut relation = TransitiveRelation::default();
     relation.add("a", "tcx");
     relation.add("b", "tcx");
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"tcx"]);
-    assert_eq!(relation.parents(&"a"), vec![&"tcx"]);
-    assert_eq!(relation.parents(&"b"), vec![&"tcx"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["tcx"]);
+    assert_eq!(relation.parents("a"), vec!["tcx"]);
+    assert_eq!(relation.parents("b"), vec!["tcx"]);
 }
 
 #[test]
@@ -81,10 +81,10 @@ fn mubs_best_choice1() {
     relation.add("3", "1");
     relation.add("3", "2");
 
-    assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"2"]);
-    assert_eq!(relation.parents(&"0"), vec![&"2"]);
-    assert_eq!(relation.parents(&"2"), vec![&"1"]);
-    assert!(relation.parents(&"1").is_empty());
+    assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["2"]);
+    assert_eq!(relation.parents("0"), vec!["2"]);
+    assert_eq!(relation.parents("2"), vec!["1"]);
+    assert!(relation.parents("1").is_empty());
 }
 
 #[test]
@@ -108,10 +108,10 @@ fn mubs_best_choice2() {
     relation.add("3", "1");
     relation.add("3", "2");
 
-    assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1"]);
-    assert_eq!(relation.parents(&"0"), vec![&"1"]);
-    assert_eq!(relation.parents(&"1"), vec![&"2"]);
-    assert!(relation.parents(&"2").is_empty());
+    assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1"]);
+    assert_eq!(relation.parents("0"), vec!["1"]);
+    assert_eq!(relation.parents("1"), vec!["2"]);
+    assert!(relation.parents("2").is_empty());
 }
 
 #[test]
@@ -125,9 +125,9 @@ fn mubs_no_best_choice() {
     relation.add("3", "1");
     relation.add("3", "2");
 
-    assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1", &"2"]);
-    assert_eq!(relation.parents(&"0"), vec![&"1", &"2"]);
-    assert_eq!(relation.parents(&"3"), vec![&"1", &"2"]);
+    assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1", "2"]);
+    assert_eq!(relation.parents("0"), vec!["1", "2"]);
+    assert_eq!(relation.parents("3"), vec!["1", "2"]);
 }
 
 #[test]
@@ -145,8 +145,8 @@ fn mubs_best_choice_scc() {
     relation.add("3", "1");
     relation.add("3", "2");
 
-    assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1"]);
-    assert_eq!(relation.parents(&"0"), vec![&"1"]);
+    assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1"]);
+    assert_eq!(relation.parents("0"), vec!["1"]);
 }
 
 #[test]
@@ -165,10 +165,10 @@ fn pdub_crisscross() {
     relation.add("a1", "x");
     relation.add("b1", "x");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"a1", &"b1"]);
-    assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
-    assert_eq!(relation.postdom_parent(&"a"), Some(&"x"));
-    assert_eq!(relation.postdom_parent(&"b"), Some(&"x"));
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["a1", "b1"]);
+    assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x"));
+    assert_eq!(relation.postdom_parent("a"), Some("x"));
+    assert_eq!(relation.postdom_parent("b"), Some("x"));
 }
 
 #[test]
@@ -195,12 +195,12 @@ fn pdub_crisscross_more() {
     relation.add("a3", "x");
     relation.add("b2", "x");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"a1", &"b1"]);
-    assert_eq!(relation.minimal_upper_bounds(&"a1", &"b1"), vec![&"a2", &"b2"]);
-    assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["a1", "b1"]);
+    assert_eq!(relation.minimal_upper_bounds("a1", "b1"), vec!["a2", "b2"]);
+    assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x"));
 
-    assert_eq!(relation.postdom_parent(&"a"), Some(&"x"));
-    assert_eq!(relation.postdom_parent(&"b"), Some(&"x"));
+    assert_eq!(relation.postdom_parent("a"), Some("x"));
+    assert_eq!(relation.postdom_parent("b"), Some("x"));
 }
 
 #[test]
@@ -216,13 +216,13 @@ fn pdub_lub() {
     relation.add("a1", "x");
     relation.add("b1", "x");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"x"]);
-    assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["x"]);
+    assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x"));
 
-    assert_eq!(relation.postdom_parent(&"a"), Some(&"a1"));
-    assert_eq!(relation.postdom_parent(&"b"), Some(&"b1"));
-    assert_eq!(relation.postdom_parent(&"a1"), Some(&"x"));
-    assert_eq!(relation.postdom_parent(&"b1"), Some(&"x"));
+    assert_eq!(relation.postdom_parent("a"), Some("a1"));
+    assert_eq!(relation.postdom_parent("b"), Some("b1"));
+    assert_eq!(relation.postdom_parent("a1"), Some("x"));
+    assert_eq!(relation.postdom_parent("b1"), Some("x"));
 }
 
 #[test]
@@ -238,7 +238,7 @@ fn mubs_intermediate_node_on_one_side_only() {
     relation.add("c", "d");
     relation.add("b", "d");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"d"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["d"]);
 }
 
 #[test]
@@ -259,7 +259,7 @@ fn mubs_scc_1() {
     relation.add("a", "d");
     relation.add("b", "d");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
 }
 
 #[test]
@@ -279,7 +279,7 @@ fn mubs_scc_2() {
     relation.add("b", "d");
     relation.add("b", "c");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
 }
 
 #[test]
@@ -300,7 +300,7 @@ fn mubs_scc_3() {
     relation.add("b", "d");
     relation.add("b", "e");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
 }
 
 #[test]
@@ -322,7 +322,7 @@ fn mubs_scc_4() {
     relation.add("a", "d");
     relation.add("b", "e");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
 }
 
 #[test]
@@ -357,6 +357,6 @@ fn parent() {
         relation.add(a, b);
     }
 
-    let p = relation.postdom_parent(&3);
-    assert_eq!(p, Some(&0));
+    let p = relation.postdom_parent(3);
+    assert_eq!(p, Some(0));
 }
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index a59d91ea789..39ebd57b4b2 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -7,6 +7,7 @@ use crate::SuggestionStyle;
 use crate::ToolMetadata;
 use rustc_lint_defs::Applicability;
 use rustc_serialize::json::Json;
+use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
 use std::hash::{Hash, Hasher};
@@ -342,6 +343,18 @@ impl Diagnostic {
         self
     }
 
+    /// Help the user upgrade to the latest edition.
+    /// This is factored out to make sure it does the right thing with `Cargo.toml`.
+    pub fn help_use_latest_edition(&mut self) -> &mut Self {
+        if std::env::var_os("CARGO").is_some() {
+            self.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
+        } else {
+            self.help(&format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION));
+        }
+        self.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+        self
+    }
+
     /// Disallow attaching suggestions this diagnostic.
     /// Any suggestions attached e.g. with the `span_suggestion_*` methods
     /// (before and after the call to `disable_suggestions`) will be ignored.
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 5dc71f16200..98b8b2a569e 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -409,6 +409,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
         sp: impl Into<MultiSpan>,
         msg: &str,
     ) -> &mut Self);
+    forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self);
     forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
 
     forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 52c44231d8f..831d408195e 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1657,6 +1657,31 @@ impl EmitterWriter {
             let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
             draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
             let mut lines = complete.lines();
+            if lines.clone().next().is_none() {
+                // Account for a suggestion to completely remove a line(s) with whitespace (#94192).
+                let line_end = sm.lookup_char_pos(parts[0].span.hi()).line;
+                for line in line_start..=line_end {
+                    buffer.puts(
+                        row_num - 1 + line - line_start,
+                        0,
+                        &self.maybe_anonymized(line),
+                        Style::LineNumber,
+                    );
+                    buffer.puts(
+                        row_num - 1 + line - line_start,
+                        max_line_num_len + 1,
+                        "- ",
+                        Style::Removal,
+                    );
+                    buffer.puts(
+                        row_num - 1 + line - line_start,
+                        max_line_num_len + 3,
+                        &normalize_whitespace(&*file_lines.file.get_line(line - 1).unwrap()),
+                        Style::Removal,
+                    );
+                }
+                row_num += line_end - line_start;
+            }
             for (line_pos, (line, highlight_parts)) in
                 lines.by_ref().zip(highlights).take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
             {
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 217d3ec2c24..3641c38f9dc 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -1087,12 +1087,12 @@ impl HandlerInner {
         let warnings = match self.deduplicated_warn_count {
             0 => String::new(),
             1 => "1 warning emitted".to_string(),
-            count => format!("{} warnings emitted", count),
+            count => format!("{count} warnings emitted"),
         };
         let errors = match self.deduplicated_err_count {
             0 => String::new(),
             1 => "aborting due to previous error".to_string(),
-            count => format!("aborting due to {} previous errors", count),
+            count => format!("aborting due to {count} previous errors"),
         };
         if self.treat_err_as_bug() {
             return;
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index b024524aa29..8a9efe01368 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -3,6 +3,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(if_let_guard)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_internals)]
diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs
index 5244ac36bba..3d4c77aba73 100644
--- a/compiler/rustc_expand/src/mbe.rs
+++ b/compiler/rustc_expand/src/mbe.rs
@@ -6,17 +6,17 @@
 crate mod macro_check;
 crate mod macro_parser;
 crate mod macro_rules;
+crate mod metavar_expr;
 crate mod quoted;
 crate mod transcribe;
 
+use metavar_expr::MetaVarExpr;
 use rustc_ast::token::{self, NonterminalKind, Token, TokenKind};
 use rustc_ast::tokenstream::DelimSpan;
-
+use rustc_data_structures::sync::Lrc;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
-use rustc_data_structures::sync::Lrc;
-
 /// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
 /// that the delimiter itself might be `NoDelim`.
 #[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
@@ -73,8 +73,8 @@ enum KleeneOp {
     ZeroOrOne,
 }
 
-/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
-/// are "first-class" token trees. Useful for parsing macros.
+/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, `$(...)`,
+/// and `${...}` are "first-class" token trees. Useful for parsing macros.
 #[derive(Debug, Clone, PartialEq, Encodable, Decodable)]
 enum TokenTree {
     Token(Token),
@@ -85,6 +85,8 @@ enum TokenTree {
     MetaVar(Span, Ident),
     /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
     MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
+    /// A meta-variable expression inside `${...}`
+    MetaVarExpr(DelimSpan, MetaVarExpr),
 }
 
 impl TokenTree {
@@ -139,7 +141,9 @@ impl TokenTree {
             TokenTree::Token(Token { span, .. })
             | TokenTree::MetaVar(span, _)
             | TokenTree::MetaVarDecl(span, _, _) => span,
-            TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(),
+            TokenTree::Delimited(span, _)
+            | TokenTree::MetaVarExpr(span, _)
+            | TokenTree::Sequence(span, _) => span.entire(),
         }
     }
 
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 3497e5ad543..88e11693220 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -278,6 +278,8 @@ fn check_binders(
                 binders.insert(name, BinderInfo { span, ops: ops.into() });
             }
         }
+        // `MetaVarExpr` can not appear in the LHS of a macro arm
+        TokenTree::MetaVarExpr(..) => {}
         TokenTree::Delimited(_, ref del) => {
             for tt in &del.tts {
                 check_binders(sess, node_id, tt, macros, binders, ops, valid);
@@ -335,6 +337,8 @@ fn check_occurrences(
             let name = MacroRulesNormalizedIdent::new(name);
             check_ops_is_prefix(sess, node_id, macros, binders, ops, span, name);
         }
+        // FIXME(c410-f3r) Check token (https://github.com/rust-lang/rust/issues/93902)
+        TokenTree::MetaVarExpr(..) => {}
         TokenTree::Delimited(_, ref del) => {
             check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, valid);
         }
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index bb36dfd793d..dedfd779bb4 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -122,7 +122,7 @@ impl<'tt> TokenTreeOrTokenTreeSlice<'tt> {
 
 /// An unzipping of `TokenTree`s... see the `stack` field of `MatcherPos`.
 ///
-/// This is used by `inner_parse_loop` to keep track of delimited submatchers that we have
+/// This is used by `parse_tt_inner` to keep track of delimited submatchers that we have
 /// descended into.
 #[derive(Clone)]
 struct MatcherTtFrame<'tt> {
@@ -200,7 +200,7 @@ struct MatcherPos<'root, 'tt> {
 
 // This type is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MatcherPos<'_, '_>, 192);
+rustc_data_structures::static_assert_size!(MatcherPos<'_, '_>, 240);
 
 impl<'root, 'tt> MatcherPos<'root, 'tt> {
     /// Generates the top-level matcher position in which the "dot" is before the first token of
@@ -321,10 +321,13 @@ pub(super) fn count_names(ms: &[TokenTree]) -> usize {
     ms.iter().fold(0, |count, elt| {
         count
             + match *elt {
-                TokenTree::Sequence(_, ref seq) => seq.num_captures,
                 TokenTree::Delimited(_, ref delim) => count_names(&delim.tts),
                 TokenTree::MetaVar(..) => 0,
                 TokenTree::MetaVarDecl(..) => 1,
+                // FIXME(c410-f3r) MetaVarExpr should be handled instead of being ignored
+                // https://github.com/rust-lang/rust/issues/9390
+                TokenTree::MetaVarExpr(..) => 0,
+                TokenTree::Sequence(_, ref seq) => seq.num_captures,
                 TokenTree::Token(..) => 0,
             }
     })
@@ -436,7 +439,8 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
                 }
                 Occupied(..) => return Err((sp, format!("duplicated bind name: {}", bind_name))),
             },
-            TokenTree::MetaVar(..) | TokenTree::Token(..) => (),
+            TokenTree::Token(..) => (),
+            TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
         }
 
         Ok(())
@@ -476,21 +480,24 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool {
 ///   successful execution of this function.
 /// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in
 ///   the function `parse`.
-/// - `eof_items`: the set of items that would be valid if this was the EOF.
 /// - `bb_items`: the set of items that are waiting for the black-box parser.
 /// - `token`: the current token of the parser.
 ///
 /// # Returns
 ///
-/// A `ParseResult`. Note that matches are kept track of through the items generated.
-fn inner_parse_loop<'root, 'tt>(
+/// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept track of
+/// through the items generated.
+fn parse_tt_inner<'root, 'tt>(
     sess: &ParseSess,
+    ms: &[TokenTree],
     cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
-    next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>,
+    next_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
     bb_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
-    eof_items: &mut EofItems<'root, 'tt>,
     token: &Token,
-) -> Result<(), (rustc_span::Span, String)> {
+) -> Option<NamedParseResult> {
+    // Matcher positions that would be valid if the macro invocation was over now
+    let mut eof_items = EofItems::None;
+
     // Pop items from `cur_items` until it is empty.
     while let Some(mut item) = cur_items.pop() {
         // When unzipped trees end, remove them. This corresponds to backtracking out of a
@@ -517,6 +524,8 @@ fn inner_parse_loop<'root, 'tt>(
             // then we could be at the end of a sequence or at the beginning of the next
             // repetition.
             if let Some(repetition) = &item.repetition {
+                debug_assert!(matches!(item.top_elts, Tt(TokenTree::Sequence(..))));
+
                 // At this point, regardless of whether there is a separator, we should add all
                 // matches from the complete repetition of the sequence to the shared, top-level
                 // `matches` list (actually, `up.matches`, which could itself not be the top-level,
@@ -560,7 +569,7 @@ fn inner_parse_loop<'root, 'tt>(
             } else {
                 // If we are not in a repetition, then being at the end of a matcher means that we
                 // have reached the potential end of the input.
-                *eof_items = match eof_items {
+                eof_items = match eof_items {
                     EofItems::None => EofItems::One(item),
                     EofItems::One(_) | EofItems::Multiple => EofItems::Multiple,
                 }
@@ -608,7 +617,7 @@ fn inner_parse_loop<'root, 'tt>(
                 // We need to match a metavar (but the identifier is invalid)... this is an error
                 TokenTree::MetaVarDecl(span, _, None) => {
                     if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
-                        return Err((span, "missing fragment specifier".to_string()));
+                        return Some(Error(span, "missing fragment specifier".to_string()));
                     }
                 }
 
@@ -650,13 +659,36 @@ fn inner_parse_loop<'root, 'tt>(
                 // rules. NOTE that this is not necessarily an error unless _all_ items in
                 // `cur_items` end up doing this. There may still be some other matchers that do
                 // end up working out.
-                TokenTree::Token(..) | TokenTree::MetaVar(..) => {}
+                TokenTree::Token(..) => {}
+
+                TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
             }
         }
     }
 
-    // Yay a successful parse (so far)!
-    Ok(())
+    // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
+    // either the parse is ambiguous (which should never happen) or there is a syntax error.
+    if *token == token::Eof {
+        Some(match eof_items {
+            EofItems::One(mut eof_item) => {
+                let matches =
+                    eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap());
+                nameize(sess, ms, matches)
+            }
+            EofItems::Multiple => {
+                Error(token.span, "ambiguity: multiple successful parses".to_string())
+            }
+            EofItems::None => Failure(
+                Token::new(
+                    token::Eof,
+                    if token.span.is_dummy() { token.span } else { token.span.shrink_to_hi() },
+                ),
+                "missing tokens in macro arguments",
+            ),
+        })
+    } else {
+        None
+    }
 }
 
 /// Use the given sequence of token trees (`ms`) as a matcher. Match the token
@@ -667,7 +699,7 @@ pub(super) fn parse_tt(
     macro_name: Ident,
 ) -> NamedParseResult {
     // A queue of possible matcher positions. We initialize it with the matcher position in which
-    // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then
+    // the "dot" is before the first token of the first token tree in `ms`. `parse_tt_inner` then
     // processes all of these possible matcher positions and produces possible next positions into
     // `next_items`. After some post-processing, the contents of `next_items` replenish `cur_items`
     // and we start over again.
@@ -676,135 +708,118 @@ pub(super) fn parse_tt(
     // there are frequently *no* others! -- are allocated on the heap.
     let mut initial = MatcherPos::new(ms);
     let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)];
-    let mut next_items = Vec::new();
 
     loop {
-        assert!(next_items.is_empty());
+        let mut next_items = SmallVec::new();
 
         // Matcher positions black-box parsed by parser.rs (`parser`)
         let mut bb_items = SmallVec::new();
 
-        // Matcher positions that would be valid if the macro invocation was over now
-        let mut eof_items = EofItems::None;
-
         // Process `cur_items` until either we have finished the input or we need to get some
         // parsing from the black-box parser done. The result is that `next_items` will contain a
         // bunch of possible next matcher positions in `next_items`.
-        match inner_parse_loop(
+        if let Some(result) = parse_tt_inner(
             parser.sess,
+            ms,
             &mut cur_items,
             &mut next_items,
             &mut bb_items,
-            &mut eof_items,
             &parser.token,
         ) {
-            Ok(()) => {}
-            Err((sp, msg)) => return Error(sp, msg),
+            return result;
         }
 
-        // inner parse loop handled all cur_items, so it's empty
+        // `parse_tt_inner` handled all cur_items, so it's empty.
         assert!(cur_items.is_empty());
 
-        // We need to do some post processing after the `inner_parse_loop`.
+        // We need to do some post processing after the `parse_tt_inner`.
         //
         // Error messages here could be improved with links to original rules.
 
-        // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
-        // either the parse is ambiguous (which should never happen) or there is a syntax error.
-        if parser.token == token::Eof {
-            return match eof_items {
-                EofItems::One(mut eof_item) => {
-                    let matches =
-                        eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap());
-                    nameize(parser.sess, ms, matches)
-                }
-                EofItems::Multiple => {
-                    Error(parser.token.span, "ambiguity: multiple successful parses".to_string())
-                }
-                EofItems::None => Failure(
-                    Token::new(
-                        token::Eof,
-                        if parser.token.span.is_dummy() {
-                            parser.token.span
-                        } else {
-                            parser.token.span.shrink_to_hi()
-                        },
-                    ),
-                    "missing tokens in macro arguments",
-                ),
-            };
-        }
-        // Performance hack: `eof_items` may share matchers via `Rc` with other things that we want
-        // to modify. Dropping `eof_items` now may drop these refcounts to 1, preventing an
-        // unnecessary implicit clone later in `Rc::make_mut`.
-        drop(eof_items);
-
-        // If there are no possible next positions AND we aren't waiting for the black-box parser,
-        // then there is a syntax error.
-        if bb_items.is_empty() && next_items.is_empty() {
-            return Failure(parser.token.clone(), "no rules expected this token in macro call");
-        }
+        match (next_items.len(), bb_items.len()) {
+            (0, 0) => {
+                // There are no possible next positions AND we aren't waiting for the black-box
+                // parser: syntax error.
+                return Failure(parser.token.clone(), "no rules expected this token in macro call");
+            }
 
-        if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 {
-            // We need to call out to parse some rust nonterminal (black-box) parser. But something
-            // is wrong, because there is not EXACTLY ONE of these.
-            let nts = bb_items
-                .iter()
-                .map(|item| match item.top_elts.get_tt(item.idx) {
-                    TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind),
-                    _ => panic!(),
-                })
-                .collect::<Vec<String>>()
-                .join(" or ");
-
-            return Error(
-                parser.token.span,
-                format!(
-                    "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}",
-                    match next_items.len() {
-                        0 => format!("built-in NTs {}.", nts),
-                        1 => format!("built-in NTs {} or 1 other option.", nts),
-                        n => format!("built-in NTs {} or {} other options.", nts, n),
-                    }
-                ),
-            );
-        }
+            (_, 0) => {
+                // Dump all possible `next_items` into `cur_items` for the next iteration. Then
+                // process the next token.
+                cur_items.extend(next_items.drain(..));
+                parser.to_mut().bump();
+            }
 
-        if !next_items.is_empty() {
-            // Dump all possible `next_items` into `cur_items` for the next iteration. Then process
-            // the next token.
-            cur_items.extend(next_items.drain(..));
-            parser.to_mut().bump();
-        } else {
-            // Finally, we have the case where we need to call the black-box parser to get some
-            // nonterminal.
-            assert_eq!(bb_items.len(), 1);
-
-            let mut item = bb_items.pop().unwrap();
-            if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) {
-                let match_cur = item.match_cur;
-                // We use the span of the metavariable declaration to determine any
-                // edition-specific matching behavior for non-terminals.
-                let nt = match parser.to_mut().parse_nonterminal(kind) {
-                    Err(mut err) => {
-                        err.span_label(
-                            span,
-                            format!("while parsing argument for this `{}` macro fragment", kind),
-                        )
-                        .emit();
-                        return ErrorReported;
-                    }
-                    Ok(nt) => nt,
-                };
-                item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt)));
-                item.idx += 1;
-                item.match_cur += 1;
-            } else {
-                unreachable!()
+            (0, 1) => {
+                // We need to call the black-box parser to get some nonterminal.
+                let mut item = bb_items.pop().unwrap();
+                if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx)
+                {
+                    let match_cur = item.match_cur;
+                    // We use the span of the metavariable declaration to determine any
+                    // edition-specific matching behavior for non-terminals.
+                    let nt = match parser.to_mut().parse_nonterminal(kind) {
+                        Err(mut err) => {
+                            err.span_label(
+                                span,
+                                format!("while parsing argument for this `{kind}` macro fragment"),
+                            )
+                            .emit();
+                            return ErrorReported;
+                        }
+                        Ok(nt) => nt,
+                    };
+                    item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt)));
+                    item.idx += 1;
+                    item.match_cur += 1;
+                } else {
+                    unreachable!()
+                }
+                cur_items.push(item);
+            }
+
+            (_, _) => {
+                // We need to call the black-box parser to get some nonterminal, but something is
+                // wrong.
+                return bb_items_ambiguity_error(
+                    macro_name,
+                    next_items,
+                    bb_items,
+                    parser.token.span,
+                );
             }
-            cur_items.push(item);
         }
 
         assert!(!cur_items.is_empty());
     }
 }
+
+fn bb_items_ambiguity_error<'root, 'tt>(
+    macro_name: Ident,
+    next_items: SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
+    bb_items: SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
+    token_span: rustc_span::Span,
+) -> NamedParseResult {
+    let nts = bb_items
+        .iter()
+        .map(|item| match item.top_elts.get_tt(item.idx) {
+            TokenTree::MetaVarDecl(_, bind, Some(kind)) => {
+                format!("{} ('{}')", kind, bind)
+            }
+            _ => panic!(),
+        })
+        .collect::<Vec<String>>()
+        .join(" or ");
+
+    Error(
+        token_span,
+        format!(
+            "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}",
+            match next_items.len() {
+                0 => format!("built-in NTs {}.", nts),
+                1 => format!("built-in NTs {} or 1 other option.", nts),
+                n => format!("built-in NTs {} or {} other options.", nts, n),
+            }
+        ),
+    )
+}
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 62ea3aa76a4..c3b1b34aa29 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -580,7 +580,10 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
     use mbe::TokenTree;
     for tt in tts {
         match *tt {
-            TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (),
+            TokenTree::Token(..)
+            | TokenTree::MetaVar(..)
+            | TokenTree::MetaVarDecl(..)
+            | TokenTree::MetaVarExpr(..) => (),
             TokenTree::Delimited(_, ref del) => {
                 if !check_lhs_no_empty_seq(sess, &del.tts) {
                     return false;
@@ -669,7 +672,10 @@ impl FirstSets {
             let mut first = TokenSet::empty();
             for tt in tts.iter().rev() {
                 match *tt {
-                    TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
+                    TokenTree::Token(..)
+                    | TokenTree::MetaVar(..)
+                    | TokenTree::MetaVarDecl(..)
+                    | TokenTree::MetaVarExpr(..) => {
                         first.replace_with(tt.clone());
                     }
                     TokenTree::Delimited(span, ref delimited) => {
@@ -731,7 +737,10 @@ impl FirstSets {
         for tt in tts.iter() {
             assert!(first.maybe_empty);
             match *tt {
-                TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
+                TokenTree::Token(..)
+                | TokenTree::MetaVar(..)
+                | TokenTree::MetaVarDecl(..)
+                | TokenTree::MetaVarExpr(..) => {
                     first.add_one(tt.clone());
                     return first;
                 }
@@ -907,7 +916,10 @@ fn check_matcher_core(
         // First, update `last` so that it corresponds to the set
         // of NT tokens that might end the sequence `... token`.
         match *token {
-            TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
+            TokenTree::Token(..)
+            | TokenTree::MetaVar(..)
+            | TokenTree::MetaVarDecl(..)
+            | TokenTree::MetaVarExpr(..) => {
                 if token_can_be_followed_by_any(token) {
                     // don't need to track tokens that work with any,
                     last.replace_with_irrelevant();
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
new file mode 100644
index 00000000000..6c5a755da6f
--- /dev/null
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -0,0 +1,157 @@
+use rustc_ast::token;
+use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree};
+use rustc_ast::{LitIntType, LitKind};
+use rustc_ast_pretty::pprust;
+use rustc_errors::{Applicability, PResult};
+use rustc_session::parse::ParseSess;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+/// A meta-variable expression, for expansions based on properties of meta-variables.
+#[derive(Debug, Clone, PartialEq, Encodable, Decodable)]
+crate enum MetaVarExpr {
+    /// The number of repetitions of an identifier, optionally limited to a number
+    /// of outer-most repetition depths. If the depth limit is `None` then the depth is unlimited.
+    Count(Ident, Option<usize>),
+
+    /// Ignore a meta-variable for repetition without expansion.
+    Ignore(Ident),
+
+    /// The index of the repetition at a particular depth, where 0 is the inner-most
+    /// repetition. The `usize` is the depth.
+    Index(usize),
+
+    /// The length of the repetition at a particular depth, where 0 is the inner-most
+    /// repetition. The `usize` is the depth.
+    Length(usize),
+}
+
+impl MetaVarExpr {
+    /// Attempt to parse a meta-variable expression from a token stream.
+    crate fn parse<'sess>(
+        input: &TokenStream,
+        outer_span: Span,
+        sess: &'sess ParseSess,
+    ) -> PResult<'sess, MetaVarExpr> {
+        let mut tts = input.trees();
+        let ident = parse_ident(&mut tts, sess, outer_span)?;
+        let Some(TokenTree::Delimited(_, token::Paren, args)) = tts.next() else {
+            let msg = "meta-variable expression parameter must be wrapped in parentheses";
+            return Err(sess.span_diagnostic.struct_span_err(ident.span, msg));
+        };
+        check_trailing_token(&mut tts, sess)?;
+        let mut iter = args.trees();
+        let rslt = match &*ident.as_str() {
+            "count" => parse_count(&mut iter, sess, ident.span)?,
+            "ignore" => MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?),
+            "index" => MetaVarExpr::Index(parse_depth(&mut iter, sess, ident.span)?),
+            "length" => MetaVarExpr::Length(parse_depth(&mut iter, sess, ident.span)?),
+            _ => {
+                let err_msg = "unrecognized meta-variable expression";
+                let mut err = sess.span_diagnostic.struct_span_err(ident.span, err_msg);
+                err.span_suggestion(
+                    ident.span,
+                    "supported expressions are count, ignore, index and length",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+                return Err(err);
+            }
+        };
+        check_trailing_token(&mut iter, sess)?;
+        Ok(rslt)
+    }
+
+    crate fn ident(&self) -> Option<&Ident> {
+        match self {
+            MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(&ident),
+            MetaVarExpr::Index(..) | MetaVarExpr::Length(..) => None,
+        }
+    }
+}
+
+// Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}`
+fn check_trailing_token<'sess>(iter: &mut Cursor, sess: &'sess ParseSess) -> PResult<'sess, ()> {
+    if let Some(tt) = iter.next() {
+        let mut diag = sess.span_diagnostic.struct_span_err(
+            tt.span(),
+            &format!("unexpected token: {}", pprust::tt_to_string(&tt)),
+        );
+        diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens");
+        Err(diag)
+    } else {
+        Ok(())
+    }
+}
+
+/// Parse a meta-variable `count` expression: `count(ident[, depth])`
+fn parse_count<'sess>(
+    iter: &mut Cursor,
+    sess: &'sess ParseSess,
+    span: Span,
+) -> PResult<'sess, MetaVarExpr> {
+    let ident = parse_ident(iter, sess, span)?;
+    let depth = if try_eat_comma(iter) { Some(parse_depth(iter, sess, span)?) } else { None };
+    Ok(MetaVarExpr::Count(ident, depth))
+}
+
+/// Parses the depth used by index(depth) and length(depth).
+fn parse_depth<'sess>(
+    iter: &mut Cursor,
+    sess: &'sess ParseSess,
+    span: Span,
+) -> PResult<'sess, usize> {
+    let Some(tt) = iter.next() else { return Ok(0) };
+    let TokenTree::Token(token::Token {
+        kind: token::TokenKind::Literal(lit), ..
+    }) = tt else {
+        return Err(sess.span_diagnostic.struct_span_err(
+            span,
+            "meta-variable expression depth must be a literal"
+        ));
+    };
+    if let Ok(lit_kind) = LitKind::from_lit_token(lit)
+        && let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind
+        && let Ok(n_usize) = usize::try_from(n_u128)
+    {
+        Ok(n_usize)
+    }
+    else {
+        let msg = "only unsuffixes integer literals are supported in meta-variable expressions";
+        Err(sess.span_diagnostic.struct_span_err(span, msg))
+    }
+}
+
+/// Parses an generic ident
+fn parse_ident<'sess>(
+    iter: &mut Cursor,
+    sess: &'sess ParseSess,
+    span: Span,
+) -> PResult<'sess, Ident> {
+    let err_fn = |msg| sess.span_diagnostic.struct_span_err(span, msg);
+    if let Some(tt) = iter.next() && let TokenTree::Token(token) = tt {
+        if let Some((elem, false)) = token.ident() {
+            return Ok(elem);
+        }
+        let token_str = pprust::token_to_string(&token);
+        let mut err = err_fn(&format!("expected identifier, found `{}`", &token_str));
+        err.span_suggestion(
+            token.span,
+            &format!("try removing `{}`", &token_str),
+            String::new(),
+            Applicability::MaybeIncorrect,
+        );
+        return Err(err);
+    }
+    Err(err_fn("expected identifier"))
+}
+
+/// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
+/// iterator is not modified and the result is `false`.
+fn try_eat_comma(iter: &mut Cursor) -> bool {
+    if let Some(TokenTree::Token(token::Token { kind: token::Comma, .. })) = iter.look_ahead(0) {
+        let _ = iter.next();
+        return true;
+    }
+    false
+}
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index dedc6c618b9..12c5dac9e0b 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -1,13 +1,13 @@
 use crate::mbe::macro_parser;
-use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree};
+use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
 
 use rustc_ast::token::{self, Token};
 use rustc_ast::tokenstream;
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_feature::Features;
-use rustc_session::parse::ParseSess;
-use rustc_span::symbol::{kw, Ident};
+use rustc_session::parse::{feature_err, ParseSess};
+use rustc_span::symbol::{kw, sym, Ident};
 
 use rustc_span::edition::Edition;
 use rustc_span::{Span, SyntaxContext};
@@ -25,22 +25,22 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
 /// # Parameters
 ///
 /// - `input`: a token stream to read from, the contents of which we are parsing.
-/// - `expect_matchers`: `parse` can be used to parse either the "patterns" or the "body" of a
-///   macro. Both take roughly the same form _except_ that in a pattern, metavars are declared with
-///   their "matcher" type. For example `$var:expr` or `$id:ident`. In this example, `expr` and
-///   `ident` are "matchers". They are not present in the body of a macro rule -- just in the
-///   pattern, so we pass a parameter to indicate whether to expect them or not.
+/// - `parsing_patterns`: `parse` can be used to parse either the "patterns" or the "body" of a
+///   macro. Both take roughly the same form _except_ that:
+///   - In a pattern, metavars are declared with their "matcher" type. For example `$var:expr` or
+///     `$id:ident`. In this example, `expr` and `ident` are "matchers". They are not present in the
+///     body of a macro rule -- just in the pattern.
+///   - Metavariable expressions are only valid in the "body", not the "pattern".
 /// - `sess`: the parsing session. Any errors will be emitted to this session.
 /// - `node_id`: the NodeId of the macro we are parsing.
 /// - `features`: language features so we can do feature gating.
-/// - `edition`: the edition of the crate defining the macro
 ///
 /// # Returns
 ///
 /// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`.
 pub(super) fn parse(
     input: tokenstream::TokenStream,
-    expect_matchers: bool,
+    parsing_patterns: bool,
     sess: &ParseSess,
     node_id: NodeId,
     features: &Features,
@@ -55,9 +55,9 @@ pub(super) fn parse(
     while let Some(tree) = trees.next() {
         // Given the parsed tree, if there is a metavar and we are expecting matchers, actually
         // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
-        let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features, edition);
+        let tree = parse_tree(tree, &mut trees, parsing_patterns, sess, node_id, features, edition);
         match tree {
-            TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
+            TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
                 let span = match trees.next() {
                     Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) => {
                         match trees.next() {
@@ -118,6 +118,14 @@ pub(super) fn parse(
     result
 }
 
+/// Asks for the `macro_metavar_expr` feature if it is not already declared
+fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &ParseSess, span: Span) {
+    if !features.macro_metavar_expr {
+        let msg = "meta-variable expressions are unstable";
+        feature_err(&sess, sym::macro_metavar_expr, span, msg).emit();
+    }
+}
+
 /// Takes a `tokenstream::TokenTree` and returns a `self::TokenTree`. Specifically, this takes a
 /// generic `TokenTree`, such as is used in the rest of the compiler, and returns a `TokenTree`
 /// for use in parsing a macro.
@@ -129,14 +137,13 @@ pub(super) fn parse(
 /// - `tree`: the tree we wish to convert.
 /// - `outer_trees`: an iterator over trees. We may need to read more tokens from it in order to finish
 ///   converting `tree`
-/// - `expect_matchers`: same as for `parse` (see above).
+/// - `parsing_patterns`: same as [parse].
 /// - `sess`: the parsing session. Any errors will be emitted to this session.
 /// - `features`: language features so we can do feature gating.
-/// - `edition` - the edition of the crate defining the macro
 fn parse_tree(
     tree: tokenstream::TokenTree,
     outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
-    expect_matchers: bool,
+    parsing_patterns: bool,
     sess: &ParseSess,
     node_id: NodeId,
     features: &Features,
@@ -158,24 +165,57 @@ fn parse_tree(
             }
 
             match next {
-                // `tree` is followed by a delimited set of token trees. This indicates the beginning
-                // of a repetition sequence in the macro (e.g. `$(pat)*`).
-                Some(tokenstream::TokenTree::Delimited(span, delim, tts)) => {
-                    // Must have `(` not `{` or `[`
-                    if delim != token::Paren {
-                        let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
-                        let msg = format!("expected `(`, found `{}`", tok);
-                        sess.span_diagnostic.span_err(span.entire(), &msg);
+                // `tree` is followed by a delimited set of token trees.
+                Some(tokenstream::TokenTree::Delimited(delim_span, delim, tts)) => {
+                    if parsing_patterns {
+                        if delim != token::Paren {
+                            span_dollar_dollar_or_metavar_in_the_lhs_err(
+                                sess,
+                                &Token { kind: token::OpenDelim(delim), span: delim_span.entire() },
+                            );
+                        }
+                    } else {
+                        match delim {
+                            token::Brace => {
+                                // The delimiter is `{`.  This indicates the beginning
+                                // of a meta-variable expression (e.g. `${count(ident)}`).
+                                // Try to parse the meta-variable expression.
+                                match MetaVarExpr::parse(&tts, delim_span.entire(), sess) {
+                                    Err(mut err) => {
+                                        err.emit();
+                                        // Returns early the same read `$` to avoid spanning
+                                        // unrelated diagnostics that could be performed afterwards
+                                        return TokenTree::token(token::Dollar, span);
+                                    }
+                                    Ok(elem) => {
+                                        maybe_emit_macro_metavar_expr_feature(
+                                            features,
+                                            sess,
+                                            delim_span.entire(),
+                                        );
+                                        return TokenTree::MetaVarExpr(delim_span, elem);
+                                    }
+                                }
+                            }
+                            token::Paren => {}
+                            _ => {
+                                let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
+                                let msg = format!("expected `(` or `{{`, found `{}`", tok);
+                                sess.span_diagnostic.span_err(delim_span.entire(), &msg);
+                            }
+                        }
                     }
-                    // Parse the contents of the sequence itself
-                    let sequence = parse(tts, expect_matchers, sess, node_id, features, edition);
+                    // If we didn't find a metavar expression above, then we must have a
+                    // repetition sequence in the macro (e.g. `$(pat)*`).  Parse the
+                    // contents of the sequence itself
+                    let sequence = parse(tts, parsing_patterns, sess, node_id, features, edition);
                     // Get the Kleene operator and optional separator
                     let (separator, kleene) =
-                        parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
+                        parse_sep_and_kleene_op(&mut trees, delim_span.entire(), sess);
                     // Count the number of captured "names" (i.e., named metavars)
                     let name_captures = macro_parser::count_names(&sequence);
                     TokenTree::Sequence(
-                        span,
+                        delim_span,
                         Lrc::new(SequenceRepetition {
                             tts: sequence,
                             separator,
@@ -197,7 +237,20 @@ fn parse_tree(
                     }
                 }
 
-                // `tree` is followed by a random token. This is an error.
+                // `tree` is followed by another `$`. This is an escaped `$`.
+                Some(tokenstream::TokenTree::Token(Token { kind: token::Dollar, span })) => {
+                    if parsing_patterns {
+                        span_dollar_dollar_or_metavar_in_the_lhs_err(
+                            sess,
+                            &Token { kind: token::Dollar, span },
+                        );
+                    } else {
+                        maybe_emit_macro_metavar_expr_feature(features, sess, span);
+                    }
+                    TokenTree::token(token::Dollar, span)
+                }
+
+                // `tree` is followed by some other token. This is an error.
                 Some(tokenstream::TokenTree::Token(token)) => {
                     let msg = format!(
                         "expected identifier, found `{}`",
@@ -221,7 +274,7 @@ fn parse_tree(
             span,
             Lrc::new(Delimited {
                 delim,
-                tts: parse(tts, expect_matchers, sess, node_id, features, edition),
+                tts: parse(tts, parsing_patterns, sess, node_id, features, edition),
             }),
         ),
     }
@@ -309,3 +362,15 @@ fn parse_sep_and_kleene_op(
     // Return a dummy
     (None, KleeneToken::new(KleeneOp::ZeroOrMore, span))
 }
+
+// `$$` or a meta-variable is the lhs of a macro but shouldn't.
+//
+// For example, `macro_rules! foo { ( ${length()} ) => {} }`
+fn span_dollar_dollar_or_metavar_in_the_lhs_err<'sess>(sess: &'sess ParseSess, token: &Token) {
+    sess.span_diagnostic
+        .span_err(token.span, &format!("unexpected token: {}", pprust::token_to_string(token)));
+    sess.span_diagnostic.span_note_without_error(
+        token.span,
+        "`$$` and meta-variable expressions are not allowed inside macro parameter definitions",
+    );
+}
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 760dea77f9c..387d5895e24 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -1,15 +1,15 @@
 use crate::base::ExtCtxt;
-use crate::mbe;
 use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
-
+use crate::mbe::{self, MetaVarExpr};
 use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::token::{self, NtTT, Token};
+use rustc_ast::token::{self, NtTT, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{pluralize, PResult};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use rustc_span::hygiene::{LocalExpnId, Transparency};
-use rustc_span::symbol::MacroRulesNormalizedIdent;
+use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
 use rustc_span::Span;
 
 use smallvec::{smallvec, SmallVec};
@@ -255,6 +255,11 @@ pub(super) fn transcribe<'a>(
                 }
             }
 
+            // Replace meta-variable expressions with the result of their expansion.
+            mbe::TokenTree::MetaVarExpr(sp, expr) => {
+                transcribe_metavar_expr(cx, expr, interp, &repeats, &mut result, &sp)?;
+            }
+
             // If we are entering a new delimiter, we push its contents to the `stack` to be
             // processed, and we push all of the currently produced results to the `result_stack`.
             // We will produce all of the results of the inside of the `Delimited` and then we will
@@ -391,6 +396,165 @@ fn lockstep_iter_size(
                 _ => LockstepIterSize::Unconstrained,
             }
         }
+        TokenTree::MetaVarExpr(_, ref expr) => {
+            let default_rslt = LockstepIterSize::Unconstrained;
+            let Some(ident) = expr.ident() else { return default_rslt; };
+            let name = MacroRulesNormalizedIdent::new(ident.clone());
+            match lookup_cur_matched(name, interpolations, repeats) {
+                Some(MatchedSeq(ref ads)) => {
+                    default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
+                }
+                _ => default_rslt,
+            }
+        }
         TokenTree::Token(..) => LockstepIterSize::Unconstrained,
     }
 }
+
+/// Used solely by the `count` meta-variable expression, counts the outer-most repetitions at a
+/// given optional nested depth.
+///
+/// For example, a macro parameter of `$( { $( $foo:ident ),* } )*` called with `{ a, b } { c }`:
+///
+/// * `[ $( ${count(foo)} ),* ]` will return [2, 1] with a, b = 2 and c = 1
+/// * `[ $( ${count(foo, 0)} ),* ]` will be the same as `[ $( ${count(foo)} ),* ]`
+/// * `[ $( ${count(foo, 1)} ),* ]` will return an error because `${count(foo, 1)}` is
+///   declared inside a single repetition and the index `1` implies two nested repetitions.
+fn count_repetitions<'a>(
+    cx: &ExtCtxt<'a>,
+    depth_opt: Option<usize>,
+    mut matched: &NamedMatch,
+    repeats: &[(usize, usize)],
+    sp: &DelimSpan,
+) -> PResult<'a, usize> {
+    // Recursively count the number of matches in `matched` at given depth
+    // (or at the top-level of `matched` if no depth is given).
+    fn count<'a>(
+        cx: &ExtCtxt<'a>,
+        declared_lhs_depth: usize,
+        depth_opt: Option<usize>,
+        matched: &NamedMatch,
+        sp: &DelimSpan,
+    ) -> PResult<'a, usize> {
+        match matched {
+            MatchedNonterminal(_) => {
+                if declared_lhs_depth == 0 {
+                    return Err(cx.struct_span_err(
+                        sp.entire(),
+                        "`count` can not be placed inside the inner-most repetition",
+                    ));
+                }
+                match depth_opt {
+                    None => Ok(1),
+                    Some(_) => Err(out_of_bounds_err(cx, declared_lhs_depth, sp.entire(), "count")),
+                }
+            }
+            MatchedSeq(ref named_matches) => {
+                let new_declared_lhs_depth = declared_lhs_depth + 1;
+                match depth_opt {
+                    None => named_matches
+                        .iter()
+                        .map(|elem| count(cx, new_declared_lhs_depth, None, elem, sp))
+                        .sum(),
+                    Some(0) => Ok(named_matches.len()),
+                    Some(depth) => named_matches
+                        .iter()
+                        .map(|elem| count(cx, new_declared_lhs_depth, Some(depth - 1), elem, sp))
+                        .sum(),
+                }
+            }
+        }
+    }
+    // `repeats` records all of the nested levels at which we are currently
+    // matching meta-variables. The meta-var-expr `count($x)` only counts
+    // matches that occur in this "subtree" of the `NamedMatch` where we
+    // are currently transcribing, so we need to descend to that subtree
+    // before we start counting. `matched` contains the various levels of the
+    // tree as we descend, and its final value is the subtree we are currently at.
+    for &(idx, _) in repeats {
+        if let MatchedSeq(ref ads) = matched {
+            matched = &ads[idx];
+        }
+    }
+    count(cx, 0, depth_opt, matched, sp)
+}
+
+/// Returns a `NamedMatch` item declared on the RHS given an arbitrary [Ident]
+fn matched_from_ident<'ctx, 'interp, 'rslt>(
+    cx: &ExtCtxt<'ctx>,
+    ident: Ident,
+    interp: &'interp FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
+) -> PResult<'ctx, &'rslt NamedMatch>
+where
+    'interp: 'rslt,
+{
+    let span = ident.span;
+    let key = MacroRulesNormalizedIdent::new(ident);
+    interp.get(&key).ok_or_else(|| {
+        cx.struct_span_err(
+            span,
+            &format!("variable `{}` is not recognized in meta-variable expression", key),
+        )
+    })
+}
+
+/// Used by meta-variable expressions when an user input is out of the actual declared bounds. For
+/// example, index(999999) in an repetition of only three elements.
+fn out_of_bounds_err<'a>(
+    cx: &ExtCtxt<'a>,
+    max: usize,
+    span: Span,
+    ty: &str,
+) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+    cx.struct_span_err(span, &format!("{ty} depth must be less than {max}"))
+}
+
+fn transcribe_metavar_expr<'a>(
+    cx: &ExtCtxt<'a>,
+    expr: MetaVarExpr,
+    interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
+    repeats: &[(usize, usize)],
+    result: &mut Vec<TreeAndSpacing>,
+    sp: &DelimSpan,
+) -> PResult<'a, ()> {
+    match expr {
+        MetaVarExpr::Count(original_ident, depth_opt) => {
+            let matched = matched_from_ident(cx, original_ident, interp)?;
+            let count = count_repetitions(cx, depth_opt, matched, &repeats, sp)?;
+            let tt = TokenTree::token(
+                TokenKind::lit(token::Integer, sym::integer(count), None),
+                sp.entire(),
+            );
+            result.push(tt.into());
+        }
+        MetaVarExpr::Ignore(original_ident) => {
+            // Used to ensure that `original_ident` is present in the LHS
+            let _ = matched_from_ident(cx, original_ident, interp)?;
+        }
+        MetaVarExpr::Index(depth) => match repeats.iter().nth_back(depth) {
+            Some((index, _)) => {
+                result.push(
+                    TokenTree::token(
+                        TokenKind::lit(token::Integer, sym::integer(*index), None),
+                        sp.entire(),
+                    )
+                    .into(),
+                );
+            }
+            None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")),
+        },
+        MetaVarExpr::Length(depth) => match repeats.iter().nth_back(depth) {
+            Some((_, length)) => {
+                result.push(
+                    TokenTree::token(
+                        TokenKind::lit(token::Integer, sym::integer(*length), None),
+                        sp.entire(),
+                    )
+                    .into(),
+                );
+            }
+            None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "length")),
+        },
+    }
+    Ok(())
+}
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index d43f926d0a5..fc2ac75d609 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -86,6 +86,10 @@ declare_features! (
     (accepted, conservative_impl_trait, "1.26.0", Some(34511), None),
     /// Allows calling constructor functions in `const fn`.
     (accepted, const_constructor, "1.40.0", Some(61456), None),
+    /// Allows using and casting function pointers in a `const fn`.
+    (accepted, const_fn_fn_ptr_basics, "1.61.0", Some(57563), None),
+    /// Allows trait bounds in `const fn`.
+    (accepted, const_fn_trait_bound, "1.61.0", Some(93706), None),
     /// Allows calling `transmute` in const fn
     (accepted, const_fn_transmute, "1.56.0", Some(53605), None),
     /// Allows accessing fields of unions inside `const` functions.
@@ -96,6 +100,8 @@ declare_features! (
     (accepted, const_generics_defaults, "1.59.0", Some(44580), None),
     /// Allows the use of `if` and `match` in constants.
     (accepted, const_if_match, "1.46.0", Some(49146), None),
+    /// Allows argument and return position `impl Trait` in a `const fn`.
+    (accepted, const_impl_trait, "1.61.0", Some(77463), None),
     /// Allows indexing into constant arrays.
     (accepted, const_indexing, "1.26.0", Some(29947), None),
     /// Allows let bindings, assignments and destructuring in `const` functions and constants.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 1f7dc769512..ccd296c3da1 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -169,6 +169,8 @@ declare_features! (
     (active, staged_api, "1.0.0", None, None),
     /// Added for testing E0705; perma-unstable.
     (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
+    /// Added for testing unstable lints; perma-unstable.
+    (active, test_unstable_lint, "1.60.0", None, None),
     /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions.
     /// Marked `incomplete` since perma-unstable and unsound.
     (incomplete, unsafe_pin_internals, "1.60.0", None, None),
@@ -338,14 +340,8 @@ declare_features! (
     (active, const_extern_fn, "1.40.0", Some(64926), None),
     /// Allows basic arithmetic on floating point types in a `const fn`.
     (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
-    /// Allows using and casting function pointers in a `const fn`.
-    (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
-    /// Allows trait bounds in `const fn`.
-    (active, const_fn_trait_bound, "1.53.0", Some(93706), None),
     /// Allows `for _ in _` loops in const contexts.
     (active, const_for, "1.56.0", Some(87575), None),
-    /// Allows argument and return position `impl Trait` in a `const fn`.
-    (active, const_impl_trait, "1.48.0", Some(77463), None),
     /// Allows using `&mut` in constant functions.
     (active, const_mut_refs, "1.41.0", Some(57349), None),
     /// Be more precise when looking for live drops in a const context.
@@ -368,6 +364,8 @@ declare_features! (
     (active, default_alloc_error_handler, "1.48.0", Some(66741), None),
     /// Allows default type parameters to influence type inference.
     (active, default_type_parameter_fallback, "1.3.0", Some(27336), None),
+    /// Allows having using `suggestion` in the `#[deprecated]` attribute.
+    (active, deprecated_suggestion, "1.61.0", Some(94785), None),
     /// Allows `#[derive(Default)]` and `#[default]` on enums.
     (active, derive_default_enum, "1.56.0", Some(86985), None),
     /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
@@ -432,6 +430,8 @@ declare_features! (
     (active, link_cfg, "1.14.0", Some(37406), None),
     /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
     (active, lint_reasons, "1.31.0", Some(54503), None),
+    /// Give access to additional metadata about declarative macro meta-variables.
+    (active, macro_metavar_expr, "1.61.0", Some(83527), None),
     /// Allows `#[marker]` on certain traits allowing overlapping implementations.
     (active, marker_trait_attr, "1.30.0", Some(29864), None),
     /// A minimal, sound subset of specialization intended to be used by the
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 4b9cf784495..9c7b8f80324 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -461,7 +461,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // DuplicatesOk since it has its own validation
     ungated!(
         rustc_deprecated, Normal,
-        template!(List: r#"since = "version", reason = "...""#), DuplicatesOk // See E0550
+        template!(List: r#"since = "version", note = "...""#), DuplicatesOk // See E0550
     ),
     // DuplicatesOk since it has its own validation
     ungated!(
@@ -606,17 +606,17 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(
         rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
         "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
-        niche optimizations in libcore and will never be stable",
+        niche optimizations in libcore and libstd and will never be stable",
     ),
     rustc_attr!(
         rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
         "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
-        niche optimizations in libcore and will never be stable",
+        niche optimizations in libcore and libstd and will never be stable",
     ),
     rustc_attr!(
         rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \
-        niche optimizations in libcore and will never be stable",
+        niche optimizations in libcore and libstd and will never be stable",
     ),
 
     // ==========================================================================
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index dee391b9cce..f23e3ce1901 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -13,6 +13,7 @@ use std::fmt;
 /// the code base.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[derive(Encodable, Decodable)]
+#[rustc_pass_by_value]
 pub struct HirId {
     pub owner: LocalDefId,
     pub local_id: ItemLocalId,
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index ba3eeb91fe9..d56230e1dc5 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -9,6 +9,7 @@
 #![feature(once_cell)]
 #![feature(min_specialization)]
 #![feature(never_type)]
+#![feature(rustc_attrs)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 12bde029494..d7e5c2b6056 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -654,15 +654,19 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
 
 impl<T: Idx> BitRelations<HybridBitSet<T>> for ChunkedBitSet<T> {
     fn union(&mut self, other: &HybridBitSet<T>) -> bool {
-        // FIXME: this is slow if `other` is dense, and could easily be
-        // improved, but it hasn't been a problem in practice so far.
+        // FIXME: This is slow if `other` is dense, but it hasn't been a problem
+        // in practice so far.
+        // If a a faster implementation of this operation is required, consider
+        // reopening https://github.com/rust-lang/rust/pull/94625
         assert_eq!(self.domain_size, other.domain_size());
         sequential_update(|elem| self.insert(elem), other.iter())
     }
 
     fn subtract(&mut self, other: &HybridBitSet<T>) -> bool {
-        // FIXME: this is slow if `other` is dense, and could easily be
-        // improved, but it hasn't been a problem in practice so far.
+        // FIXME: This is slow if `other` is dense, but it hasn't been a problem
+        // in practice so far.
+        // If a a faster implementation of this operation is required, consider
+        // reopening https://github.com/rust-lang/rust/pull/94625
         assert_eq!(self.domain_size, other.domain_size());
         sequential_update(|elem| self.remove(elem), other.iter())
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index bf4882d4595..abc25d51776 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -582,7 +582,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) =
                     (exp_found.expected.kind(), exp_found.found.kind())
                 {
-                    report_path_match(err, exp_adt.did, found_adt.did);
+                    report_path_match(err, exp_adt.did(), found_adt.did());
                 }
             }
             TypeError::Traits(ref exp_found) => {
@@ -914,7 +914,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 return Some(());
             }
             if let ty::Adt(def, _) = ta.kind() {
-                let path_ = self.tcx.def_path_str(def.did);
+                let path_ = self.tcx.def_path_str(def.did());
                 if path_ == other_path {
                     self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, other_ty);
                     return Some(());
@@ -1126,12 +1126,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         // process starts here
         match (t1.kind(), t2.kind()) {
             (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => {
-                let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1);
-                let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2);
+                let did1 = def1.did();
+                let did2 = def2.did();
+                let sub_no_defaults_1 = self.strip_generic_default_params(did1, sub1);
+                let sub_no_defaults_2 = self.strip_generic_default_params(did2, sub2);
                 let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
-                let path1 = self.tcx.def_path_str(def1.did);
-                let path2 = self.tcx.def_path_str(def2.did);
-                if def1.did == def2.did {
+                let path1 = self.tcx.def_path_str(did1);
+                let path2 = self.tcx.def_path_str(did2);
+                if did1 == did2 {
                     // Easy case. Replace same types with `_` to shorten the output and highlight
                     // the differing ones.
                     //     let x: Foo<Bar, Qux> = y::<Foo<Quz, Qux>>();
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 16f7504cbbe..a9a92fdbd64 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -958,7 +958,7 @@ impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> {
         let t = match t.kind() {
             // We'll hide this type only if all its type params are hidden as well.
             ty::Adt(def, substs) => {
-                let generics = self.tcx().generics_of(def.did);
+                let generics = self.tcx().generics_of(def.did());
                 // Account for params with default values, like `Vec`, where we
                 // want to show `Vec<T>`, not `Vec<T, _>`. If we replaced that
                 // subst, then we'd get the incorrect output, so we passthrough.
@@ -985,7 +985,7 @@ impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> {
                 };
                 if self.level == 1 || substs.iter().any(should_keep) {
                     let substs = self.tcx().intern_substs(&substs[..]);
-                    self.tcx().mk_ty(ty::Adt(def, substs))
+                    self.tcx().mk_ty(ty::Adt(*def, substs))
                 } else {
                     self.tcx().ty_error()
                 }
diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs
index 187c67df3eb..082eb1bf111 100644
--- a/compiler/rustc_infer/src/infer/free_regions.rs
+++ b/compiler/rustc_infer/src/infer/free_regions.rs
@@ -86,7 +86,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
 
     /// Check whether `r_a <= r_b` is found in the relation.
     fn check_relation(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
-        r_a == r_b || self.relation.contains(&r_a, &r_b)
+        r_a == r_b || self.relation.contains(r_a, r_b)
     }
 
     /// True for free regions other than `'static`.
@@ -119,9 +119,9 @@ impl<'tcx> FreeRegionMap<'tcx> {
         let result = if r_a == r_b {
             r_a
         } else {
-            match self.relation.postdom_upper_bound(&r_a, &r_b) {
+            match self.relation.postdom_upper_bound(r_a, r_b) {
                 None => tcx.lifetimes.re_static,
-                Some(r) => *r,
+                Some(r) => r,
             }
         };
         debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
@@ -132,6 +132,6 @@ impl<'tcx> FreeRegionMap<'tcx> {
 impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
     type Lifted = FreeRegionMap<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
-        self.relation.maybe_map(|&fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation })
+        self.relation.maybe_map(|fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation })
     }
 }
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 381097344ec..e98f33ea86e 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -1,3 +1,5 @@
+//! Greatest lower bound. See [`lattice`].
+
 use super::combine::CombineFields;
 use super::lattice::{self, LatticeDir};
 use super::InferCtxt;
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index 652f5abab15..73cc411e533 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -58,14 +58,11 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    /// Replaces all regions (resp. types) bound by `binder` with placeholder
-    /// regions (resp. types) and return a map indicating which bound-region
-    /// placeholder region. This is the first step of checking subtyping
-    /// when higher-ranked things are involved.
+    /// Replaces all bound variables (lifetimes, types, and constants) bound by
+    /// `binder` with placeholder variables.
     ///
-    /// **Important:** You have to be careful to not leak these placeholders,
-    /// for more information about how placeholders and HRTBs work, see
-    /// the [rustc dev guide].
+    /// This is the first step of checking subtyping when higher-ranked things are involved.
+    /// For more details visit the relevant sections of the [rustc dev guide].
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
     pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index c47d4769637..32affd6a14e 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -1,23 +1,21 @@
-//! # Lattice Variables
+//! # Lattice variables
 //!
-//! This file contains generic code for operating on inference variables
-//! that are characterized by an upper- and lower-bound. The logic and
-//! reasoning is explained in detail in the large comment in `infer.rs`.
+//! Generic code for operating on [lattices] of inference variables
+//! that are characterized by an upper- and lower-bound.
 //!
-//! The code in here is defined quite generically so that it can be
+//! The code is defined quite generically so that it can be
 //! applied both to type variables, which represent types being inferred,
 //! and fn variables, which represent function types being inferred.
-//! It may eventually be applied to their types as well, who knows.
+//! (It may eventually be applied to their types as well.)
 //! In some cases, the functions are also generic with respect to the
 //! operation on the lattice (GLB vs LUB).
 //!
-//! Although all the functions are generic, we generally write the
-//! comments in a way that is specific to type variables and the LUB
-//! operation. It's just easier that way.
+//! ## Note
 //!
-//! In general all of the functions are defined parametrically
-//! over a `LatticeValue`, which is a value defined with respect to
-//! a lattice.
+//! Although all the functions are generic, for simplicity, comments in the source code
+//! generally refer to type variables and the LUB operation.
+//!
+//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
 
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::InferCtxt;
@@ -27,6 +25,11 @@ use rustc_middle::ty::relate::{RelateResult, TypeRelation};
 use rustc_middle::ty::TyVar;
 use rustc_middle::ty::{self, Ty};
 
+/// Trait for returning data about a lattice, and for abstracting
+/// over the "direction" of the lattice operation (LUB/GLB).
+///
+/// GLB moves "down" the lattice (to smaller values); LUB moves
+/// "up" the lattice (to bigger values).
 pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
     fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
 
@@ -41,6 +44,7 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
 }
 
+/// Relates two types using a given lattice.
 pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
     this: &mut L,
     a: Ty<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index 57cbe2c54f7..bc85a4ac609 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -1,3 +1,5 @@
+//! Least upper bound. See [`lattice`].
+
 use super::combine::CombineFields;
 use super::lattice::{self, LatticeDir};
 use super::InferCtxt;
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 72b8d8bb297..53ad8374349 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -658,7 +658,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
             let impl_ty = cx.tcx.type_of(parent);
             let outerdef = match impl_ty.kind() {
-                ty::Adt(def, _) => Some(def.did),
+                ty::Adt(def, _) => Some(def.did()),
                 ty::Foreign(def_id) => Some(*def_id),
                 _ => None,
             };
@@ -841,7 +841,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
             let mut impls = LocalDefIdSet::default();
             cx.tcx.for_each_impl(debug, |d| {
                 if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
-                    if let Some(def_id) = ty_def.did.as_local() {
+                    if let Some(def_id) = ty_def.did().as_local() {
                         impls.insert(def_id);
                     }
                 }
@@ -2535,9 +2535,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
 
         /// Test if this enum has several actually "existing" variants.
         /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
-        fn is_multi_variant(adt: &ty::AdtDef) -> bool {
+        fn is_multi_variant<'tcx>(adt: ty::AdtDef<'tcx>) -> bool {
             // As an approximation, we only count dataless variants. Those are definitely inhabited.
-            let existing_variants = adt.variants.iter().filter(|v| v.fields.is_empty()).count();
+            let existing_variants = adt.variants().iter().filter(|v| v.fields.is_empty()).count();
             existing_variants > 1
         }
 
@@ -2571,7 +2571,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                 Adt(adt_def, substs) if !adt_def.is_union() => {
                     // First check if this ADT has a layout attribute (like `NonNull` and friends).
                     use std::ops::Bound;
-                    match tcx.layout_scalar_valid_range(adt_def.did) {
+                    match tcx.layout_scalar_valid_range(adt_def.did()) {
                         // We exploit here that `layout_scalar_valid_range` will never
                         // return `Bound::Excluded`.  (And we have tests checking that we
                         // handle the attribute correctly.)
@@ -2592,12 +2592,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                         _ => {}
                     }
                     // Now, recurse.
-                    match adt_def.variants.len() {
+                    match adt_def.variants().len() {
                         0 => Some(("enums with no variants have no valid value".to_string(), None)),
                         1 => {
                             // Struct, or enum with exactly one variant.
                             // Proceed recursively, check all fields.
-                            let variant = &adt_def.variants[VariantIdx::from_u32(0)];
+                            let variant = &adt_def.variant(VariantIdx::from_u32(0));
                             variant.fields.iter().find_map(|field| {
                                 ty_find_init_error(tcx, field.ty(tcx, substs), init).map(
                                     |(mut msg, span)| {
@@ -2622,8 +2622,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                         }
                         // Multi-variant enum.
                         _ => {
-                            if init == InitKind::Uninit && is_multi_variant(adt_def) {
-                                let span = tcx.def_span(adt_def.did);
+                            if init == InitKind::Uninit && is_multi_variant(*adt_def) {
+                                let span = tcx.def_span(adt_def.did());
                                 Some((
                                     "enums have to be initialized to a variant".to_string(),
                                     Some(span),
@@ -2819,15 +2819,15 @@ impl ClashingExternDeclarations {
                 let mut ty = ty;
                 loop {
                     if let ty::Adt(def, substs) = *ty.kind() {
-                        let is_transparent = def.subst(tcx, substs).repr.transparent();
-                        let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, &def);
+                        let is_transparent = def.subst(tcx, substs).repr().transparent();
+                        let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, def);
                         debug!(
                             "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
                             ty, is_transparent, is_non_null
                         );
                         if is_transparent && !is_non_null {
-                            debug_assert!(def.variants.len() == 1);
-                            let v = &def.variants[VariantIdx::new(0)];
+                            debug_assert!(def.variants().len() == 1);
+                            let v = &def.variant(VariantIdx::new(0));
                             ty = transparent_newtype_field(tcx, v)
                                 .expect(
                                     "single-variant transparent structure with zero-sized field",
@@ -2861,8 +2861,8 @@ impl ClashingExternDeclarations {
 
                 let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
                     debug!("compare_layouts({:?}, {:?})", a, b);
-                    let a_layout = &cx.layout_of(a)?.layout.abi;
-                    let b_layout = &cx.layout_of(b)?.layout.abi;
+                    let a_layout = &cx.layout_of(a)?.layout.abi();
+                    let b_layout = &cx.layout_of(b)?.layout.abi();
                     debug!(
                         "comparing layouts: {:?} == {:?} = {}",
                         a_layout,
@@ -2892,8 +2892,8 @@ impl ClashingExternDeclarations {
                             }
 
                             // Grab a flattened representation of all fields.
-                            let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
-                            let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
+                            let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter());
+                            let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter());
 
                             // Perform a structural comparison for each field.
                             a_fields.eq_by(
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index b892e520d3b..d3c019ad70e 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -1050,7 +1050,7 @@ impl<'tcx> LateContext<'tcx> {
             ) -> Result<Self::Path, Self::Error> {
                 if trait_ref.is_none() {
                     if let ty::Adt(def, substs) = self_ty.kind() {
-                        return self.print_def_path(def.did, substs);
+                        return self.print_def_path(def.did(), substs);
                     }
                 }
 
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 5078c240ec7..27d44da6dfc 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -202,7 +202,7 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
             Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
                 if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
                     if let Some(name @ (sym::Ty | sym::TyCtxt)) =
-                        cx.tcx.get_diagnostic_name(adt.did)
+                        cx.tcx.get_diagnostic_name(adt.did())
                     {
                         // NOTE: This path is currently unreachable as `Ty<'tcx>` is
                         // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index f46f74fa45f..7b018e7f75f 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -17,7 +17,7 @@ use rustc_session::lint::{
     builtin::{self, FORBIDDEN_LINT_GROUPS},
     Level, Lint, LintExpectationId, LintId,
 };
-use rustc_session::parse::feature_err;
+use rustc_session::parse::{add_feature_diagnostics, feature_err};
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP};
@@ -93,10 +93,19 @@ impl<'s> LintLevelsBuilder<'s> {
         self.store
     }
 
+    fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
+        &self.sets.list[self.cur].specs
+    }
+
+    fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
+        &mut self.sets.list[self.cur].specs
+    }
+
     fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
-        let mut specs = FxHashMap::default();
         self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
 
+        self.cur =
+            self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE });
         for &(ref lint_name, level) in &sess.opts.lint_opts {
             store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
             let orig_level = level;
@@ -108,30 +117,24 @@ impl<'s> LintLevelsBuilder<'s> {
             };
             for id in ids {
                 // ForceWarn and Forbid cannot be overriden
-                if let Some((Level::ForceWarn | Level::Forbid, _)) = specs.get(&id) {
+                if let Some((Level::ForceWarn | Level::Forbid, _)) = self.current_specs().get(&id) {
                     continue;
                 }
 
-                self.check_gated_lint(id, DUMMY_SP);
-                let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
-                specs.insert(id, (level, src));
+                if self.check_gated_lint(id, DUMMY_SP) {
+                    let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
+                    self.current_specs_mut().insert(id, (level, src));
+                }
             }
         }
-
-        self.cur = self.sets.list.push(LintSet { specs, parent: COMMAND_LINE });
     }
 
     /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
     /// (e.g. if a forbid was already inserted on the same scope), then emits a
     /// diagnostic with no change to `specs`.
-    fn insert_spec(
-        &mut self,
-        specs: &mut FxHashMap<LintId, LevelAndSource>,
-        id: LintId,
-        (level, src): LevelAndSource,
-    ) {
+    fn insert_spec(&mut self, id: LintId, (level, src): LevelAndSource) {
         let (old_level, old_src) =
-            self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess);
+            self.sets.get_lint_level(id.lint, self.cur, Some(self.current_specs()), &self.sess);
         // Setting to a non-forbid level is an error if the lint previously had
         // a forbid level. Note that this is not necessarily true even with a
         // `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`.
@@ -154,7 +157,10 @@ impl<'s> LintLevelsBuilder<'s> {
                 };
                 debug!(
                     "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
-                    fcw_warning, specs, old_src, id_name
+                    fcw_warning,
+                    self.current_specs(),
+                    old_src,
+                    id_name
                 );
 
                 let decorate_diag = |diag: &mut Diagnostic| {
@@ -213,9 +219,9 @@ impl<'s> LintLevelsBuilder<'s> {
             }
         }
         if let Level::ForceWarn = old_level {
-            specs.insert(id, (old_level, old_src));
+            self.current_specs_mut().insert(id, (old_level, old_src));
         } else {
-            specs.insert(id, (level, src));
+            self.current_specs_mut().insert(id, (level, src));
         }
     }
 
@@ -239,7 +245,9 @@ impl<'s> LintLevelsBuilder<'s> {
         is_crate_node: bool,
         source_hir_id: Option<HirId>,
     ) -> BuilderPush {
-        let mut specs = FxHashMap::default();
+        let prev = self.cur;
+        self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev });
+
         let sess = self.sess;
         let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
         for (attr_index, attr) in attrs.iter().enumerate() {
@@ -258,7 +266,7 @@ impl<'s> LintLevelsBuilder<'s> {
             };
 
             if metas.is_empty() {
-                // FIXME (#55112): issue unused-attributes lint for `#[level()]`
+                // This emits the unused_attributes lint for `#[level()]`
                 continue;
             }
 
@@ -271,8 +279,6 @@ impl<'s> LintLevelsBuilder<'s> {
                     ast::MetaItemKind::Word => {} // actual lint names handled later
                     ast::MetaItemKind::NameValue(ref name_value) => {
                         if item.path == sym::reason {
-                            // FIXME (#55112): issue unused-attributes lint if we thereby
-                            // don't have any lint names (`#[level(reason = "foo")]`)
                             if let ast::LitKind::Str(rationale, _) = name_value.kind {
                                 if !self.sess.features_untracked().lint_reasons {
                                     feature_err(
@@ -350,8 +356,9 @@ impl<'s> LintLevelsBuilder<'s> {
                             reason,
                         );
                         for &id in *ids {
-                            self.check_gated_lint(id, attr.span);
-                            self.insert_spec(&mut specs, id, (level, src));
+                            if self.check_gated_lint(id, attr.span) {
+                                self.insert_spec(id, (level, src));
+                            }
                         }
                         if let Level::Expect(expect_id) = level {
                             self.lint_expectations
@@ -370,7 +377,7 @@ impl<'s> LintLevelsBuilder<'s> {
                                     reason,
                                 );
                                 for id in ids {
-                                    self.insert_spec(&mut specs, *id, (level, src));
+                                    self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations
@@ -379,8 +386,12 @@ impl<'s> LintLevelsBuilder<'s> {
                             }
                             Err((Some(ids), ref new_lint_name)) => {
                                 let lint = builtin::RENAMED_AND_REMOVED_LINTS;
-                                let (lvl, src) =
-                                    self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+                                let (lvl, src) = self.sets.get_lint_level(
+                                    lint,
+                                    self.cur,
+                                    Some(self.current_specs()),
+                                    &sess,
+                                );
                                 struct_lint_level(
                                     self.sess,
                                     lint,
@@ -410,7 +421,7 @@ impl<'s> LintLevelsBuilder<'s> {
                                     reason,
                                 );
                                 for id in ids {
-                                    self.insert_spec(&mut specs, *id, (level, src));
+                                    self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations
@@ -450,8 +461,12 @@ impl<'s> LintLevelsBuilder<'s> {
 
                     CheckLintNameResult::Warning(msg, renamed) => {
                         let lint = builtin::RENAMED_AND_REMOVED_LINTS;
-                        let (renamed_lint_level, src) =
-                            self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+                        let (renamed_lint_level, src) = self.sets.get_lint_level(
+                            lint,
+                            self.cur,
+                            Some(self.current_specs()),
+                            &sess,
+                        );
                         struct_lint_level(
                             self.sess,
                             lint,
@@ -474,8 +489,12 @@ impl<'s> LintLevelsBuilder<'s> {
                     }
                     CheckLintNameResult::NoLint(suggestion) => {
                         let lint = builtin::UNKNOWN_LINTS;
-                        let (level, src) =
-                            self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+                        let (level, src) = self.sets.get_lint_level(
+                            lint,
+                            self.cur,
+                            Some(self.current_specs()),
+                            self.sess,
+                        );
                         struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| {
                             let name = if let Some(tool_ident) = tool_ident {
                                 format!("{}::{}", tool_ident.name, name)
@@ -506,8 +525,9 @@ impl<'s> LintLevelsBuilder<'s> {
                     {
                         let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
                         for &id in ids {
-                            self.check_gated_lint(id, attr.span);
-                            self.insert_spec(&mut specs, id, (level, src));
+                            if self.check_gated_lint(id, attr.span) {
+                                self.insert_spec(id, (level, src));
+                            }
                         }
                         if let Level::Expect(expect_id) = level {
                             self.lint_expectations
@@ -521,7 +541,7 @@ impl<'s> LintLevelsBuilder<'s> {
         }
 
         if !is_crate_node {
-            for (id, &(level, ref src)) in specs.iter() {
+            for (id, &(level, ref src)) in self.current_specs().iter() {
                 if !id.lint.crate_level_only {
                     continue;
                 }
@@ -532,7 +552,7 @@ impl<'s> LintLevelsBuilder<'s> {
 
                 let lint = builtin::UNUSED_ATTRIBUTES;
                 let (lint_level, lint_src) =
-                    self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+                    self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), self.sess);
                 struct_lint_level(
                     self.sess,
                     lint,
@@ -553,9 +573,9 @@ impl<'s> LintLevelsBuilder<'s> {
             }
         }
 
-        let prev = self.cur;
-        if !specs.is_empty() {
-            self.cur = self.sets.list.push(LintSet { specs, parent: prev });
+        if self.current_specs().is_empty() {
+            self.sets.list.pop();
+            self.cur = prev;
         }
 
         BuilderPush { prev, changed: prev != self.cur }
@@ -576,18 +596,24 @@ impl<'s> LintLevelsBuilder<'s> {
     }
 
     /// Checks if the lint is gated on a feature that is not enabled.
-    fn check_gated_lint(&self, lint_id: LintId, span: Span) {
+    ///
+    /// Returns `true` if the lint's feature is enabled.
+    fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
         if let Some(feature) = lint_id.lint.feature_gate {
             if !self.sess.features_untracked().enabled(feature) {
-                feature_err(
-                    &self.sess.parse_sess,
-                    feature,
-                    span,
-                    &format!("the `{}` lint is unstable", lint_id.lint.name_lower()),
-                )
-                .emit();
+                let lint = builtin::UNKNOWN_LINTS;
+                let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
+                struct_lint_level(self.sess, lint, level, src, Some(span.into()), |lint_db| {
+                    let mut db =
+                        lint_db.build(&format!("unknown lint: `{}`", lint_id.lint.name_lower()));
+                    db.note(&format!("the `{}` lint is unstable", lint_id.lint.name_lower(),));
+                    add_feature_diagnostics(&mut db, &self.sess.parse_sess, feature);
+                    db.emit();
+                });
+                return false;
             }
         }
+        true
     }
 
     /// Called after `push` when the scope of a set of attributes are exited.
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
index ae936834754..b6a45676a30 100644
--- a/compiler/rustc_lint/src/methods.rs
+++ b/compiler/rustc_lint/src/methods.rs
@@ -84,9 +84,9 @@ fn lint_cstring_as_ptr(
 ) {
     let source_type = cx.typeck_results().expr_ty(source);
     if let ty::Adt(def, substs) = source_type.kind() {
-        if cx.tcx.is_diagnostic_item(sym::Result, def.did) {
+        if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
             if let ty::Adt(adt, _) = substs.type_at(0).kind() {
-                if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did) {
+                if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
                     cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| {
                         let mut diag = diag
                             .build("getting the inner pointer of a temporary `CString`");
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 3130d57c2a9..f21f25c3584 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -149,7 +149,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 ty::Ref(_, r, _) if *r.kind() == ty::Str,
             ) || matches!(
                 ty.ty_adt_def(),
-                Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did),
+                Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did()),
             );
 
             let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index c47fdc063a9..2c8b41d7214 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -57,8 +57,8 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<Stri
             }
             Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
                 if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
-                    if cx.tcx.has_attr(adt.did, sym::rustc_pass_by_value) {
-                        return Some(cx.tcx.def_path_str_with_substs(adt.did, substs));
+                    if cx.tcx.has_attr(adt.did(), sym::rustc_pass_by_value) {
+                        return Some(cx.tcx.def_path_str_with_substs(adt.did(), substs));
                     }
                 }
             }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index c0bf64387ff..ed5578c754d 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -667,8 +667,8 @@ enum FfiResult<'tcx> {
     FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
 }
 
-crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtDef) -> bool {
-    tcx.get_attrs(def.did).iter().any(|a| a.has_name(sym::rustc_nonnull_optimization_guaranteed))
+crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
+    tcx.get_attrs(def.did()).iter().any(|a| a.has_name(sym::rustc_nonnull_optimization_guaranteed))
 }
 
 /// `repr(transparent)` structs can have a single non-ZST field, this function returns that
@@ -692,8 +692,8 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
         ty::FnPtr(_) => true,
         ty::Ref(..) => true,
         ty::Adt(def, _) if def.is_box() && matches!(mode, CItemKind::Definition) => true,
-        ty::Adt(def, substs) if def.repr.transparent() && !def.is_union() => {
-            let marked_non_null = nonnull_optimization_guaranteed(tcx, &def);
+        ty::Adt(def, substs) if def.repr().transparent() && !def.is_union() => {
+            let marked_non_null = nonnull_optimization_guaranteed(tcx, *def);
 
             if marked_non_null {
                 return true;
@@ -701,11 +701,11 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
 
             // Types with a `#[repr(no_niche)]` attribute have their niche hidden.
             // The attribute is used by the UnsafeCell for example (the only use so far).
-            if def.repr.hide_niche() {
+            if def.repr().hide_niche() {
                 return false;
             }
 
-            def.variants
+            def.variants()
                 .iter()
                 .filter_map(|variant| transparent_newtype_field(cx.tcx, variant))
                 .any(|field| ty_is_known_nonnull(cx, field.ty(tcx, substs), mode))
@@ -721,8 +721,10 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
     Some(match *ty.kind() {
         ty::Adt(field_def, field_substs) => {
             let inner_field_ty = {
-                let first_non_zst_ty =
-                    field_def.variants.iter().filter_map(|v| transparent_newtype_field(cx.tcx, v));
+                let first_non_zst_ty = field_def
+                    .variants()
+                    .iter()
+                    .filter_map(|v| transparent_newtype_field(cx.tcx, v));
                 debug_assert_eq!(
                     first_non_zst_ty.clone().count(),
                     1,
@@ -771,7 +773,7 @@ crate fn repr_nullable_ptr<'tcx>(
 ) -> Option<Ty<'tcx>> {
     debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty);
     if let ty::Adt(ty_def, substs) = ty.kind() {
-        let field_ty = match &ty_def.variants.raw[..] {
+        let field_ty = match &ty_def.variants().raw[..] {
             [var_one, var_two] => match (&var_one.fields[..], &var_two.fields[..]) {
                 ([], [field]) | ([field], []) => field.ty(cx.tcx, substs),
                 _ => return None,
@@ -795,7 +797,9 @@ crate fn repr_nullable_ptr<'tcx>(
         let field_ty_abi = &cx.layout_of(field_ty).unwrap().abi;
         if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
             match (field_ty_scalar.valid_range.start, field_ty_scalar.valid_range.end) {
-                (0, _) => unreachable!("Non-null optimisation extended to a non-zero value."),
+                (0, x) if x == field_ty_scalar.value.size(&cx.tcx).unsigned_int_max() - 1 => {
+                    return Some(get_nullable_type(cx, field_ty).unwrap());
+                }
                 (1, _) => {
                     return Some(get_nullable_type(cx, field_ty).unwrap());
                 }
@@ -843,13 +847,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         &self,
         cache: &mut FxHashSet<Ty<'tcx>>,
         ty: Ty<'tcx>,
-        def: &ty::AdtDef,
+        def: ty::AdtDef<'tcx>,
         variant: &ty::VariantDef,
         substs: SubstsRef<'tcx>,
     ) -> FfiResult<'tcx> {
         use FfiResult::*;
 
-        if def.repr.transparent() {
+        if def.repr().transparent() {
             // Can assume that at most one field is not a ZST, so only check
             // that field's type for FFI-safety.
             if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
@@ -923,7 +927,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     AdtKind::Struct | AdtKind::Union => {
                         let kind = if def.is_struct() { "struct" } else { "union" };
 
-                        if !def.repr.c() && !def.repr.transparent() {
+                        if !def.repr().c() && !def.repr().transparent() {
                             return FfiUnsafe {
                                 ty,
                                 reason: format!("this {} has unspecified layout", kind),
@@ -937,7 +941,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
                         let is_non_exhaustive =
                             def.non_enum_variant().is_field_list_non_exhaustive();
-                        if is_non_exhaustive && !def.did.is_local() {
+                        if is_non_exhaustive && !def.did().is_local() {
                             return FfiUnsafe {
                                 ty,
                                 reason: format!("this {} is non-exhaustive", kind),
@@ -956,14 +960,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         self.check_variant_for_ffi(cache, ty, def, def.non_enum_variant(), substs)
                     }
                     AdtKind::Enum => {
-                        if def.variants.is_empty() {
+                        if def.variants().is_empty() {
                             // Empty enums are okay... although sort of useless.
                             return FfiSafe;
                         }
 
                         // Check for a repr() attribute to specify the size of the
                         // discriminant.
-                        if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() {
+                        if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
+                        {
                             // Special-case types like `Option<extern fn()>`.
                             if repr_nullable_ptr(self.cx, ty, self.mode).is_none() {
                                 return FfiUnsafe {
@@ -979,7 +984,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             }
                         }
 
-                        if def.is_variant_list_non_exhaustive() && !def.did.is_local() {
+                        if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
                             return FfiUnsafe {
                                 ty,
                                 reason: "this enum is non-exhaustive".into(),
@@ -988,7 +993,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         }
 
                         // Check the contained variants.
-                        for variant in &def.variants {
+                        for variant in def.variants() {
                             let is_non_exhaustive = variant.is_field_list_non_exhaustive();
                             if is_non_exhaustive && !variant.def_id.is_local() {
                                 return FfiUnsafe {
@@ -1159,7 +1164,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             }
             diag.note(note);
             if let ty::Adt(def, _) = ty.kind() {
-                if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did) {
+                if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
                     diag.span_note(sp, "the type is defined here");
                 }
             }
@@ -1349,7 +1354,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
             let (largest, slargest, largest_index) = iter::zip(enum_definition.variants, variants)
                 .map(|(variant, variant_layout)| {
                     // Subtract the size of the enum tag.
-                    let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
+                    let bytes = variant_layout.size().bytes().saturating_sub(tag_size);
 
                     debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
                     bytes
@@ -1462,9 +1467,9 @@ impl InvalidAtomicOrdering {
             && let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def()
             // skip extension traits, only lint functions from the standard library
             && cx.tcx.trait_id_of_impl(impl_did).is_none()
-            && let Some(parent) = cx.tcx.parent(adt.did)
+            && let Some(parent) = cx.tcx.parent(adt.did())
             && cx.tcx.is_diagnostic_item(sym::atomic_mod, parent)
-            && ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did))
+            && ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did()))
         {
             return Some((method_path.ident.name, args));
         }
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 16d222f68a3..abe34a8a39f 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -202,7 +202,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                     let descr_pre = &format!("{}boxed ", descr_pre);
                     check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural_len)
                 }
-                ty::Adt(def, _) => check_must_use_def(cx, def.did, span, descr_pre, descr_post),
+                ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post),
                 ty::Opaque(def, _) => {
                     let mut has_emitted = false;
                     for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 04a339f3c95..8539e8868e2 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3128,6 +3128,7 @@ declare_lint_pass! {
         SUSPICIOUS_AUTO_TRAIT_IMPLS,
         UNEXPECTED_CFGS,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
+        TEST_UNSTABLE_LINT,
     ]
 }
 
@@ -3399,7 +3400,7 @@ declare_lint! {
     ///     //                  ^^^^^^^^
     ///     // This call to try_into matches both Foo:try_into and TryInto::try_into as
     ///     // `TryInto` has been added to the Rust prelude in 2021 edition.
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     ///
@@ -3771,3 +3772,25 @@ declare_lint! {
     Warn,
     "deprecated where clause location"
 }
+
+declare_lint! {
+    /// The `test_unstable_lint` lint tests unstable lints and is perma-unstable.
+    ///
+    /// ### Example
+    ///
+    /// ```
+    /// #![allow(test_unstable_lint)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In order to test the behavior of unstable lints, a permanently-unstable
+    /// lint is required. This lint can be used to trigger warnings and errors
+    /// from the compiler related to unstable lints.
+    pub TEST_UNSTABLE_LINT,
+    Deny,
+    "this unstable lint is only for testing",
+    @feature_gate = sym::test_unstable_lint;
+}
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index ef6c9ef6627..51739df067f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -9,6 +9,7 @@
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/COFFImportFile.h"
 #include "llvm/Object/ObjectFile.h"
+#include "llvm/Pass.h"
 #include "llvm/Bitcode/BitcodeWriterPass.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/ADT/Optional.h"
diff --git a/compiler/rustc_macros/src/newtype.rs b/compiler/rustc_macros/src/newtype.rs
index f5968a8a7ea..c8b31cd0c4d 100644
--- a/compiler/rustc_macros/src/newtype.rs
+++ b/compiler/rustc_macros/src/newtype.rs
@@ -197,6 +197,7 @@ impl Parse for Newtype {
             #(#attrs)*
             #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
             #[rustc_layout_scalar_valid_range_end(#max)]
+            #[rustc_pass_by_value]
             #vis struct #name {
                 private: u32,
             }
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 7cdcb6a4ab3..f4bc28f4da1 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -392,7 +392,7 @@ impl Collector<'_> {
                     .layout;
                 // In both stdcall and fastcall, we always round up the argument size to the
                 // nearest multiple of 4 bytes.
-                (layout.size.bytes_usize() + 3) & !3
+                (layout.size().bytes_usize() + 3) & !3
             })
             .sum()
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index e5e0cce198f..2e6ce7b7040 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -979,7 +979,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         )
     }
 
-    fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
+    fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> {
         let kind = self.kind(item_id);
         let did = self.local_def_id(item_id);
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 06f73c1c916..924e5f92103 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1029,9 +1029,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
     }
 
-    fn encode_enum_variant_info(&mut self, def: &ty::AdtDef, index: VariantIdx) {
+    fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) {
         let tcx = self.tcx;
-        let variant = &def.variants[index];
+        let variant = &def.variant(index);
         let def_id = variant.def_id;
         debug!("EncodeContext::encode_enum_variant_info({:?})", def_id);
 
@@ -1057,9 +1057,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
-    fn encode_enum_variant_ctor(&mut self, def: &ty::AdtDef, index: VariantIdx) {
+    fn encode_enum_variant_ctor(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) {
         let tcx = self.tcx;
-        let variant = &def.variants[index];
+        let variant = &def.variant(index);
         let def_id = variant.ctor_def_id.unwrap();
         debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id);
 
@@ -1122,11 +1122,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
     fn encode_field(
         &mut self,
-        adt_def: &ty::AdtDef,
+        adt_def: ty::AdtDef<'tcx>,
         variant_index: VariantIdx,
         field_index: usize,
     ) {
-        let variant = &adt_def.variants[variant_index];
+        let variant = &adt_def.variant(variant_index);
         let field = &variant.fields[field_index];
 
         let def_id = field.did;
@@ -1137,7 +1137,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.encode_item_type(def_id);
     }
 
-    fn encode_struct_ctor(&mut self, adt_def: &ty::AdtDef, def_id: DefId) {
+    fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>, def_id: DefId) {
         debug!("EncodeContext::encode_struct_ctor({:?})", def_id);
         let tcx = self.tcx;
         let variant = adt_def.non_enum_variant();
@@ -1149,7 +1149,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             is_non_exhaustive: variant.is_field_list_non_exhaustive(),
         };
 
-        record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data), adt_def.repr));
+        record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data), adt_def.repr()));
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -1414,7 +1414,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 self.encode_explicit_item_bounds(def_id);
                 EntryKind::OpaqueTy
             }
-            hir::ItemKind::Enum(..) => EntryKind::Enum(self.tcx.adt_def(def_id).repr),
+            hir::ItemKind::Enum(..) => EntryKind::Enum(self.tcx.adt_def(def_id).repr()),
             hir::ItemKind::Struct(ref struct_def, _) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 let variant = adt_def.non_enum_variant();
@@ -1433,7 +1433,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                         ctor,
                         is_non_exhaustive: variant.is_field_list_non_exhaustive(),
                     }),
-                    adt_def.repr,
+                    adt_def.repr(),
                 )
             }
             hir::ItemKind::Union(..) => {
@@ -1447,7 +1447,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                         ctor: None,
                         is_non_exhaustive: variant.is_field_list_non_exhaustive(),
                     }),
-                    adt_def.repr,
+                    adt_def.repr(),
                 )
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
@@ -1500,7 +1500,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
             hir::ItemKind::Enum(..) => record!(self.tables.children[def_id] <-
-                self.tcx.adt_def(def_id).variants.iter().map(|v| {
+                self.tcx.adt_def(def_id).variants().iter().map(|v| {
                     assert!(v.def_id.is_local());
                     v.def_id.index
                 })
@@ -1926,8 +1926,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
-    fn encode_fields(&mut self, adt_def: &ty::AdtDef) {
-        for (variant_index, variant) in adt_def.variants.iter_enumerated() {
+    fn encode_fields(&mut self, adt_def: ty::AdtDef<'tcx>) {
+        for (variant_index, variant) in adt_def.variants().iter_enumerated() {
             for (field_index, _field) in variant.fields.iter().enumerate() {
                 self.encode_field(adt_def, variant_index, field_index);
             }
@@ -1991,7 +1991,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 let def = self.tcx.adt_def(item.def_id.to_def_id());
                 self.encode_fields(def);
 
-                for (i, variant) in def.variants.iter_enumerated() {
+                for (i, variant) in def.variants().iter_enumerated() {
                     self.encode_enum_variant_info(def, i);
 
                     if let Some(_ctor_def_id) = variant.ctor_def_id {
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index c4e6734aa0f..f6d8fc5b81f 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -6,10 +6,10 @@
 macro_rules! arena_types {
     ($macro:path) => (
         $macro!([
-            [] layout: rustc_target::abi::Layout,
+            [] layout: rustc_target::abi::LayoutS<'tcx>,
             [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
             // AdtDef are interned and compared by address
-            [decode] adt_def: rustc_middle::ty::AdtDef,
+            [decode] adt_def: rustc_middle::ty::AdtDefData,
             [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<'tcx>>,
             [] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<'tcx>>,
             [decode] mir: rustc_middle::mir::Body<'tcx>,
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index f977b0fffeb..a575f27ad38 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -44,6 +44,7 @@
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
+#![feature(type_alias_impl_trait)]
 #![feature(crate_visibility_modifier)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 6124d140702..12fa5a13de8 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -7,7 +7,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
 
 use crate::ty::TyCtxt;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
 use rustc_hir::Node;
@@ -214,14 +214,14 @@ pub struct ScopeTree {
     /// conditional expression or repeating block. (Note that the
     /// enclosing scope ID for the block associated with a closure is
     /// the closure itself.)
-    pub parent_map: FxHashMap<Scope, (Scope, ScopeDepth)>,
+    pub parent_map: FxIndexMap<Scope, (Scope, ScopeDepth)>,
 
     /// Maps from a variable or binding ID to the block in which that
     /// variable is declared.
-    var_map: FxHashMap<hir::ItemLocalId, Scope>,
+    var_map: FxIndexMap<hir::ItemLocalId, Scope>,
 
     /// Maps from a `NodeId` to the associated destruction scope (if any).
-    destruction_scopes: FxHashMap<hir::ItemLocalId, Scope>,
+    destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>,
 
     /// `rvalue_scopes` includes entries for those expressions whose
     /// cleanup scope is larger than the default. The map goes from the
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 640d3a5a02b..2336d460407 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -46,7 +46,7 @@ impl CounterValueReference {
 
     /// Returns explicitly-requested zero-based version of the counter id, used
     /// during codegen. LLVM expects zero-based indexes.
-    pub fn zero_based_index(&self) -> u32 {
+    pub fn zero_based_index(self) -> u32 {
         let one_based_index = self.as_u32();
         debug_assert!(one_based_index > 0);
         one_based_index - 1
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index e524625f966..c9786590476 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -184,6 +184,8 @@ pub enum CheckInAllocMsg {
     MemoryAccessTest,
     /// We are doing pointer arithmetic.
     PointerArithmeticTest,
+    /// We are doing pointer offset_from.
+    OffsetFromTest,
     /// None of the above -- generic/unspecific inbounds test.
     InboundsTest,
 }
@@ -199,6 +201,7 @@ impl fmt::Display for CheckInAllocMsg {
                 CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ",
                 CheckInAllocMsg::MemoryAccessTest => "memory access failed: ",
                 CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic failed: ",
+                CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ",
                 CheckInAllocMsg::InboundsTest => "",
             }
         )
@@ -358,6 +361,9 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
             DanglingIntPointer(0, CheckInAllocMsg::InboundsTest) => {
                 write!(f, "null pointer is not a valid pointer for this operation")
             }
+            DanglingIntPointer(0, msg) => {
+                write!(f, "{}null pointer is not a valid pointer", msg)
+            }
             DanglingIntPointer(i, msg) => {
                 write!(f, "{}0x{:x} is not a valid pointer", msg, i)
             }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 62be33b16cc..a5468b3f4f2 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1292,6 +1292,8 @@ pub enum InlineAsmOperand<'tcx> {
 /// Type for MIR `Assert` terminator error messages.
 pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
 
+// FIXME: Change `Successors` to `impl Iterator<Item = BasicBlock>`.
+#[allow(rustc::pass_by_value)]
 pub type Successors<'a> =
     iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>;
 pub type SuccessorsMut<'a> =
@@ -1832,7 +1834,8 @@ impl<V, T> ProjectionElem<V, T> {
 /// and the index is a local.
 pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
 
-// At least on 64 bit systems, `PlaceElem` should not be larger than two pointers.
+// This type is fairly frequently used, so we shouldn't unintentionally increase
+// its size.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(PlaceElem<'_>, 24);
 
@@ -1912,6 +1915,27 @@ impl<'tcx> Place<'tcx> {
             (base, proj)
         })
     }
+
+    /// Generates a new place by appending `more_projections` to the existing ones
+    /// and interning the result.
+    pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self {
+        if more_projections.is_empty() {
+            return self;
+        }
+
+        let mut v: Vec<PlaceElem<'tcx>>;
+
+        let new_projections = if self.projection.is_empty() {
+            more_projections
+        } else {
+            v = Vec::with_capacity(self.projection.len() + more_projections.len());
+            v.extend(self.projection);
+            v.extend(more_projections);
+            &v
+        };
+
+        Place { local: self.local, projection: tcx.intern_place_elems(new_projections) }
+    }
 }
 
 impl From<Local> for Place<'_> {
@@ -2184,6 +2208,15 @@ impl<'tcx> Operand<'tcx> {
             Operand::Copy(_) | Operand::Move(_) => None,
         }
     }
+
+    /// Gets the `ty::FnDef` from an operand if it's a constant function item.
+    ///
+    /// While this is unlikely in general, it's the normal case of what you'll
+    /// find as the `func` in a [`TerminatorKind::Call`].
+    pub fn const_fn_def(&self) -> Option<(DefId, SubstsRef<'tcx>)> {
+        let const_ty = self.constant()?.literal.ty();
+        if let ty::FnDef(def_id, substs) = *const_ty.kind() { Some((def_id, substs)) } else { None }
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -2422,7 +2455,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 
                     AggregateKind::Adt(adt_did, variant, substs, _user_ty, _) => {
                         ty::tls::with(|tcx| {
-                            let variant_def = &tcx.adt_def(adt_did).variants[variant];
+                            let variant_def = &tcx.adt_def(adt_did).variant(variant);
                             let substs = tcx.lift(substs).expect("could not lift for printing");
                             let name = FmtPrinter::new(tcx, Namespace::ValueNS)
                                 .print_def_path(variant_def.def_id, substs)?
@@ -2534,7 +2567,7 @@ pub enum ConstantKind<'tcx> {
 
 impl<'tcx> Constant<'tcx> {
     pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
-        match self.literal.const_for_ty()?.val().try_to_scalar() {
+        match self.literal.try_to_scalar() {
             Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
                 GlobalAlloc::Static(def_id) => {
                     assert!(!tcx.is_thread_local_static(def_id));
@@ -2554,7 +2587,14 @@ impl<'tcx> Constant<'tcx> {
 impl<'tcx> From<ty::Const<'tcx>> for ConstantKind<'tcx> {
     #[inline]
     fn from(ct: ty::Const<'tcx>) -> Self {
-        Self::Ty(ct)
+        match ct.val() {
+            ty::ConstKind::Value(cv) => {
+                // FIXME Once valtrees are introduced we need to convert those
+                // into `ConstValue` instances here
+                Self::Val(cv, ct.ty())
+            }
+            _ => Self::Ty(ct),
+        }
     }
 }
 
@@ -2635,6 +2675,27 @@ impl<'tcx> ConstantKind<'tcx> {
             Self::Val(val, _) => val.try_to_machine_usize(tcx),
         }
     }
+
+    pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
+        let cv = ConstValue::from_bool(v);
+        Self::Val(cv, tcx.types.bool)
+    }
+
+    pub fn from_zero_sized(ty: Ty<'tcx>) -> Self {
+        let cv = ConstValue::Scalar(Scalar::ZST);
+        Self::Val(cv, ty)
+    }
+
+    pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
+        let ty = tcx.types.usize;
+        let size = tcx
+            .layout_of(ty::ParamEnv::empty().and(ty))
+            .unwrap_or_else(|e| bug!("could not compute layout for {:?}: {:?}", ty, e))
+            .size;
+        let cv = ConstValue::Scalar(Scalar::from_uint(n as u128, size));
+
+        Self::Val(cv, ty)
+    }
 }
 
 /// A collection of projections into user types.
@@ -2722,7 +2783,7 @@ impl<'tcx> UserTypeProjections {
         self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field))
     }
 
-    pub fn variant(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx, field: Field) -> Self {
+    pub fn variant(self, adt_def: AdtDef<'tcx>, variant_index: VariantIdx, field: Field) -> Self {
         self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field))
     }
 }
@@ -2773,12 +2834,12 @@ impl UserTypeProjection {
 
     pub(crate) fn variant(
         mut self,
-        adt_def: &AdtDef,
+        adt_def: AdtDef<'_>,
         variant_index: VariantIdx,
         field: Field,
     ) -> Self {
         self.projs.push(ProjectionElem::Downcast(
-            Some(adt_def.variants[variant_index].name),
+            Some(adt_def.variant(variant_index).name),
             variant_index,
         ));
         self.projs.push(ProjectionElem::Field(field, ()));
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index dab1da78d4c..50d9c8e98b9 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -18,9 +18,8 @@ use rustc_middle::mir::interpret::{
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::MirSource;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_target::abi::Size;
-use std::ops::ControlFlow;
 
 const INDENT: &str = "    ";
 /// Alignment for lining up comments following MIR statements
@@ -672,16 +671,27 @@ pub fn write_allocations<'tcx>(
         }
     }
     struct CollectAllocIds(BTreeSet<AllocId>);
-    impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
-        fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+
+    impl<'tcx> Visitor<'tcx> for CollectAllocIds {
+        fn visit_const(&mut self, c: ty::Const<'tcx>, _loc: Location) {
             if let ty::ConstKind::Value(val) = c.val() {
                 self.0.extend(alloc_ids_from_const(val));
             }
-            c.super_visit_with(self)
+        }
+
+        fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) {
+            match c.literal {
+                ConstantKind::Ty(c) => self.visit_const(c, loc),
+                ConstantKind::Val(val, _) => {
+                    self.0.extend(alloc_ids_from_const(val));
+                }
+            }
         }
     }
+
     let mut visitor = CollectAllocIds(Default::default());
-    body.visit_with(&mut visitor);
+    visitor.visit_body(body);
+
     // `seen` contains all seen allocations, including the ones we have *not* printed yet.
     // The protocol is to first `insert` into `seen`, and only if that returns `true`
     // then push to `todo`.
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 23f9849e831..51d8113840a 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -33,14 +33,14 @@ impl<'tcx> PlaceTy<'tcx> {
     /// not carry a `Ty` for `T`.)
     ///
     /// Note that the resulting type has not been normalized.
-    pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> {
+    pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> {
         let answer = match self.ty.kind() {
             ty::Adt(adt_def, substs) => {
                 let variant_def = match self.variant_index {
                     None => adt_def.non_enum_variant(),
                     Some(variant_index) => {
                         assert!(adt_def.is_enum());
-                        &adt_def.variants[variant_index]
+                        &adt_def.variant(variant_index)
                     }
                 };
                 let field_def = &variant_def.fields[f.index()];
@@ -57,7 +57,7 @@ impl<'tcx> PlaceTy<'tcx> {
     /// `PlaceElem`, where we can just use the `Ty` that is already
     /// stored inline on field projection elems.
     pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
-        self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, &ty| ty)
+        self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty)
     }
 
     /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -70,11 +70,11 @@ impl<'tcx> PlaceTy<'tcx> {
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         elem: &ProjectionElem<V, T>,
-        mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>,
+        mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>,
     ) -> PlaceTy<'tcx>
     where
         V: ::std::fmt::Debug,
-        T: ::std::fmt::Debug,
+        T: ::std::fmt::Debug + Copy,
     {
         let answer = match *elem {
             ProjectionElem::Deref => {
@@ -105,7 +105,7 @@ impl<'tcx> PlaceTy<'tcx> {
             ProjectionElem::Downcast(_name, index) => {
                 PlaceTy { ty: self.ty, variant_index: Some(index) }
             }
-            ProjectionElem::Field(ref f, ref fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
+            ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
         };
         debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
         answer
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 7320a569069..aeb0f956eb4 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -225,12 +225,14 @@ macro_rules! make_mir_visitor {
                 self.super_var_debug_info(var_debug_info);
             }
 
+            #[allow(rustc::pass_by_value)]
             fn visit_local(&mut self,
                             _local: & $($mutability)? Local,
                             _context: PlaceContext,
                             _location: Location) {
             }
 
+            #[allow(rustc::pass_by_value)]
             fn visit_source_scope(&mut self,
                                       scope: & $($mutability)? SourceScope) {
                 self.super_source_scope(scope);
@@ -851,6 +853,7 @@ macro_rules! make_mir_visitor {
                 }
             }
 
+            #[allow(rustc::pass_by_value)]
             fn super_source_scope(&mut self,
                                       _scope: & $($mutability)? SourceScope) {
             }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 6b572690e21..44b622c1e3d 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -523,7 +523,7 @@ rustc_queries! {
         storage(ArenaCacheSelector<'tcx>)
         separate_provide_extern
     }
-    query adt_def(key: DefId) -> &'tcx ty::AdtDef {
+    query adt_def(key: DefId) -> ty::AdtDef<'tcx> {
         desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
@@ -1035,6 +1035,11 @@ rustc_queries! {
         separate_provide_extern
     }
 
+    /// Determines whether an item is annotated with `doc(hidden)`.
+    query is_doc_hidden(def_id: DefId) -> bool {
+        desc { |tcx| "checking whether `{}` is `doc(hidden)`", tcx.def_path_str(def_id) }
+    }
+
     query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] {
         desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 40dce281c82..785d3ee7709 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -17,6 +17,7 @@ use rustc_index::newtype_index;
 use rustc_index::vec::IndexVec;
 use rustc_middle::infer::canonical::Canonical;
 use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::mir::{
     BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
 };
@@ -127,7 +128,7 @@ pub struct Block {
 #[derive(Debug, HashStable)]
 pub struct Adt<'tcx> {
     /// The ADT we're constructing.
-    pub adt_def: &'tcx AdtDef,
+    pub adt_def: AdtDef<'tcx>,
     /// The variant of the ADT.
     pub variant_index: VariantIdx,
     pub substs: SubstsRef<'tcx>,
@@ -419,7 +420,8 @@ pub enum ExprKind<'tcx> {
     /// This is only distinguished from `Literal` so that we can register some
     /// info for diagnostics.
     StaticRef {
-        literal: Const<'tcx>,
+        alloc_id: AllocId,
+        ty: Ty<'tcx>,
         def_id: DefId,
     },
     /// Inline assembly, i.e. `asm!()`.
@@ -615,7 +617,7 @@ pub enum PatKind<'tcx> {
     /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
     /// multiple variants.
     Variant {
-        adt_def: &'tcx AdtDef,
+        adt_def: AdtDef<'tcx>,
         substs: SubstsRef<'tcx>,
         variant_index: VariantIdx,
         subpatterns: Vec<FieldPat<'tcx>>,
@@ -712,7 +714,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
             PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
                 let variant = match *self.kind {
                     PatKind::Variant { adt_def, variant_index, .. } => {
-                        Some(&adt_def.variants[variant_index])
+                        Some(adt_def.variant(variant_index))
                     }
                     _ => self.ty.ty_adt_def().and_then(|adt| {
                         if !adt.is_enum() { Some(adt.non_enum_variant()) } else { None }
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 95489ac3ab2..1c472f38184 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -123,7 +123,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
         }
         Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
         Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
-        StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
+        StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
         InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
             for op in &**operands {
                 use InlineAsmOperand::*;
diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs
index 09a28249cce..015bdb5783f 100644
--- a/compiler/rustc_middle/src/traits/chalk.rs
+++ b/compiler/rustc_middle/src/traits/chalk.rs
@@ -75,7 +75,7 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> {
     type InternedVariances = Vec<chalk_ir::Variance>;
     type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>;
     type DefId = DefId;
-    type InternedAdtId = &'tcx AdtDef;
+    type InternedAdtId = AdtDef<'tcx>;
     type Identifier = ();
     type FnAbi = Abi;
 
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index d5a8f586361..cad77f6436e 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -4,6 +4,7 @@ use crate::ty::util::{Discr, IntTypeExt};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::HashingControls;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::ErrorGuaranteed;
@@ -89,62 +90,62 @@ bitflags! {
 /// where `x` here represents the `DefId` of `S.x`. Then, the `DefId`
 /// can be used with [`TyCtxt::type_of()`] to get the type of the field.
 #[derive(TyEncodable, TyDecodable)]
-pub struct AdtDef {
+pub struct AdtDefData {
     /// The `DefId` of the struct, enum or union item.
     pub did: DefId,
     /// Variants of the ADT. If this is a struct or union, then there will be a single variant.
-    pub variants: IndexVec<VariantIdx, VariantDef>,
+    variants: IndexVec<VariantIdx, VariantDef>,
     /// Flags of the ADT (e.g., is this a struct? is this non-exhaustive?).
     flags: AdtFlags,
     /// Repr options provided by the user.
-    pub repr: ReprOptions,
+    repr: ReprOptions,
 }
 
-impl PartialOrd for AdtDef {
-    fn partial_cmp(&self, other: &AdtDef) -> Option<Ordering> {
+impl PartialOrd for AdtDefData {
+    fn partial_cmp(&self, other: &AdtDefData) -> Option<Ordering> {
         Some(self.cmp(&other))
     }
 }
 
 /// There should be only one AdtDef for each `did`, therefore
 /// it is fine to implement `Ord` only based on `did`.
-impl Ord for AdtDef {
-    fn cmp(&self, other: &AdtDef) -> Ordering {
+impl Ord for AdtDefData {
+    fn cmp(&self, other: &AdtDefData) -> Ordering {
         self.did.cmp(&other.did)
     }
 }
 
 /// There should be only one AdtDef for each `did`, therefore
 /// it is fine to implement `PartialEq` only based on `did`.
-impl PartialEq for AdtDef {
+impl PartialEq for AdtDefData {
     #[inline]
     fn eq(&self, other: &Self) -> bool {
         self.did == other.did
     }
 }
 
-impl Eq for AdtDef {}
+impl Eq for AdtDefData {}
 
 /// There should be only one AdtDef for each `did`, therefore
 /// it is fine to implement `Hash` only based on `did`.
-impl Hash for AdtDef {
+impl Hash for AdtDefData {
     #[inline]
     fn hash<H: Hasher>(&self, s: &mut H) {
         self.did.hash(s)
     }
 }
 
-impl<'a> HashStable<StableHashingContext<'a>> for AdtDef {
+impl<'a> HashStable<StableHashingContext<'a>> for AdtDefData {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         thread_local! {
             static CACHE: RefCell<FxHashMap<(usize, HashingControls), Fingerprint>> = Default::default();
         }
 
         let hash: Fingerprint = CACHE.with(|cache| {
-            let addr = self as *const AdtDef as usize;
+            let addr = self as *const AdtDefData as usize;
             let hashing_controls = hcx.hashing_controls();
             *cache.borrow_mut().entry((addr, hashing_controls)).or_insert_with(|| {
-                let ty::AdtDef { did, ref variants, ref flags, ref repr } = *self;
+                let ty::AdtDefData { did, ref variants, ref flags, ref repr } = *self;
 
                 let mut hasher = StableHasher::new();
                 did.hash_stable(hcx, &mut hasher);
@@ -160,6 +161,32 @@ impl<'a> HashStable<StableHashingContext<'a>> for AdtDef {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct AdtDef<'tcx>(pub Interned<'tcx, AdtDefData>);
+
+impl<'tcx> AdtDef<'tcx> {
+    pub fn did(self) -> DefId {
+        self.0.0.did
+    }
+
+    pub fn variants(self) -> &'tcx IndexVec<VariantIdx, VariantDef> {
+        &self.0.0.variants
+    }
+
+    pub fn variant(self, idx: VariantIdx) -> &'tcx VariantDef {
+        &self.0.0.variants[idx]
+    }
+
+    pub fn flags(self) -> AdtFlags {
+        self.0.0.flags
+    }
+
+    pub fn repr(self) -> ReprOptions {
+        self.0.0.repr
+    }
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
 pub enum AdtKind {
     Struct,
@@ -177,8 +204,8 @@ impl Into<DataTypeKind> for AdtKind {
     }
 }
 
-impl<'tcx> AdtDef {
-    /// Creates a new `AdtDef`.
+impl AdtDefData {
+    /// Creates a new `AdtDefData`.
     pub(super) fn new(
         tcx: TyCtxt<'_>,
         did: DefId,
@@ -218,36 +245,38 @@ impl<'tcx> AdtDef {
             flags |= AdtFlags::IS_MANUALLY_DROP;
         }
 
-        AdtDef { did, variants, flags, repr }
+        AdtDefData { did, variants, flags, repr }
     }
+}
 
+impl<'tcx> AdtDef<'tcx> {
     /// Returns `true` if this is a struct.
     #[inline]
-    pub fn is_struct(&self) -> bool {
-        self.flags.contains(AdtFlags::IS_STRUCT)
+    pub fn is_struct(self) -> bool {
+        self.flags().contains(AdtFlags::IS_STRUCT)
     }
 
     /// Returns `true` if this is a union.
     #[inline]
-    pub fn is_union(&self) -> bool {
-        self.flags.contains(AdtFlags::IS_UNION)
+    pub fn is_union(self) -> bool {
+        self.flags().contains(AdtFlags::IS_UNION)
     }
 
     /// Returns `true` if this is an enum.
     #[inline]
-    pub fn is_enum(&self) -> bool {
-        self.flags.contains(AdtFlags::IS_ENUM)
+    pub fn is_enum(self) -> bool {
+        self.flags().contains(AdtFlags::IS_ENUM)
     }
 
     /// Returns `true` if the variant list of this ADT is `#[non_exhaustive]`.
     #[inline]
-    pub fn is_variant_list_non_exhaustive(&self) -> bool {
-        self.flags.contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
+    pub fn is_variant_list_non_exhaustive(self) -> bool {
+        self.flags().contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
     }
 
     /// Returns the kind of the ADT.
     #[inline]
-    pub fn adt_kind(&self) -> AdtKind {
+    pub fn adt_kind(self) -> AdtKind {
         if self.is_enum() {
             AdtKind::Enum
         } else if self.is_union() {
@@ -258,7 +287,7 @@ impl<'tcx> AdtDef {
     }
 
     /// Returns a description of this abstract data type.
-    pub fn descr(&self) -> &'static str {
+    pub fn descr(self) -> &'static str {
         match self.adt_kind() {
             AdtKind::Struct => "struct",
             AdtKind::Union => "union",
@@ -268,7 +297,7 @@ impl<'tcx> AdtDef {
 
     /// Returns a description of a variant of this abstract data type.
     #[inline]
-    pub fn variant_descr(&self) -> &'static str {
+    pub fn variant_descr(self) -> &'static str {
         match self.adt_kind() {
             AdtKind::Struct => "struct",
             AdtKind::Union => "union",
@@ -278,65 +307,65 @@ impl<'tcx> AdtDef {
 
     /// If this function returns `true`, it implies that `is_struct` must return `true`.
     #[inline]
-    pub fn has_ctor(&self) -> bool {
-        self.flags.contains(AdtFlags::HAS_CTOR)
+    pub fn has_ctor(self) -> bool {
+        self.flags().contains(AdtFlags::HAS_CTOR)
     }
 
     /// Returns `true` if this type is `#[fundamental]` for the purposes
     /// of coherence checking.
     #[inline]
-    pub fn is_fundamental(&self) -> bool {
-        self.flags.contains(AdtFlags::IS_FUNDAMENTAL)
+    pub fn is_fundamental(self) -> bool {
+        self.flags().contains(AdtFlags::IS_FUNDAMENTAL)
     }
 
     /// Returns `true` if this is `PhantomData<T>`.
     #[inline]
-    pub fn is_phantom_data(&self) -> bool {
-        self.flags.contains(AdtFlags::IS_PHANTOM_DATA)
+    pub fn is_phantom_data(self) -> bool {
+        self.flags().contains(AdtFlags::IS_PHANTOM_DATA)
     }
 
     /// Returns `true` if this is Box<T>.
     #[inline]
-    pub fn is_box(&self) -> bool {
-        self.flags.contains(AdtFlags::IS_BOX)
+    pub fn is_box(self) -> bool {
+        self.flags().contains(AdtFlags::IS_BOX)
     }
 
     /// Returns `true` if this is `ManuallyDrop<T>`.
     #[inline]
-    pub fn is_manually_drop(&self) -> bool {
-        self.flags.contains(AdtFlags::IS_MANUALLY_DROP)
+    pub fn is_manually_drop(self) -> bool {
+        self.flags().contains(AdtFlags::IS_MANUALLY_DROP)
     }
 
     /// Returns `true` if this type has a destructor.
-    pub fn has_dtor(&self, tcx: TyCtxt<'tcx>) -> bool {
+    pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
         self.destructor(tcx).is_some()
     }
 
-    pub fn has_non_const_dtor(&self, tcx: TyCtxt<'tcx>) -> bool {
+    pub fn has_non_const_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
         matches!(self.destructor(tcx), Some(Destructor { constness: hir::Constness::NotConst, .. }))
     }
 
     /// Asserts this is a struct or union and returns its unique variant.
-    pub fn non_enum_variant(&self) -> &VariantDef {
+    pub fn non_enum_variant(self) -> &'tcx VariantDef {
         assert!(self.is_struct() || self.is_union());
-        &self.variants[VariantIdx::new(0)]
+        &self.variant(VariantIdx::new(0))
     }
 
     #[inline]
-    pub fn predicates(&self, tcx: TyCtxt<'tcx>) -> GenericPredicates<'tcx> {
-        tcx.predicates_of(self.did)
+    pub fn predicates(self, tcx: TyCtxt<'tcx>) -> GenericPredicates<'tcx> {
+        tcx.predicates_of(self.did())
     }
 
     /// Returns an iterator over all fields contained
     /// by this ADT.
     #[inline]
-    pub fn all_fields(&self) -> impl Iterator<Item = &FieldDef> + Clone {
-        self.variants.iter().flat_map(|v| v.fields.iter())
+    pub fn all_fields(self) -> impl Iterator<Item = &'tcx FieldDef> + Clone {
+        self.variants().iter().flat_map(|v| v.fields.iter())
     }
 
     /// Whether the ADT lacks fields. Note that this includes uninhabited enums,
     /// e.g., `enum Void {}` is considered payload free as well.
-    pub fn is_payloadfree(&self) -> bool {
+    pub fn is_payloadfree(self) -> bool {
         // Treat the ADT as not payload-free if arbitrary_enum_discriminant is used (#88621).
         // This would disallow the following kind of enum from being casted into integer.
         // ```
@@ -347,31 +376,31 @@ impl<'tcx> AdtDef {
         // }
         // ```
         if self
-            .variants
+            .variants()
             .iter()
             .any(|v| matches!(v.discr, VariantDiscr::Explicit(_)) && v.ctor_kind != CtorKind::Const)
         {
             return false;
         }
-        self.variants.iter().all(|v| v.fields.is_empty())
+        self.variants().iter().all(|v| v.fields.is_empty())
     }
 
     /// Return a `VariantDef` given a variant id.
-    pub fn variant_with_id(&self, vid: DefId) -> &VariantDef {
-        self.variants.iter().find(|v| v.def_id == vid).expect("variant_with_id: unknown variant")
+    pub fn variant_with_id(self, vid: DefId) -> &'tcx VariantDef {
+        self.variants().iter().find(|v| v.def_id == vid).expect("variant_with_id: unknown variant")
     }
 
     /// Return a `VariantDef` given a constructor id.
-    pub fn variant_with_ctor_id(&self, cid: DefId) -> &VariantDef {
-        self.variants
+    pub fn variant_with_ctor_id(self, cid: DefId) -> &'tcx VariantDef {
+        self.variants()
             .iter()
             .find(|v| v.ctor_def_id == Some(cid))
             .expect("variant_with_ctor_id: unknown variant")
     }
 
     /// Return the index of `VariantDef` given a variant id.
-    pub fn variant_index_with_id(&self, vid: DefId) -> VariantIdx {
-        self.variants
+    pub fn variant_index_with_id(self, vid: DefId) -> VariantIdx {
+        self.variants()
             .iter_enumerated()
             .find(|(_, v)| v.def_id == vid)
             .expect("variant_index_with_id: unknown variant")
@@ -379,15 +408,15 @@ impl<'tcx> AdtDef {
     }
 
     /// Return the index of `VariantDef` given a constructor id.
-    pub fn variant_index_with_ctor_id(&self, cid: DefId) -> VariantIdx {
-        self.variants
+    pub fn variant_index_with_ctor_id(self, cid: DefId) -> VariantIdx {
+        self.variants()
             .iter_enumerated()
             .find(|(_, v)| v.ctor_def_id == Some(cid))
             .expect("variant_index_with_ctor_id: unknown variant")
             .0
     }
 
-    pub fn variant_of_res(&self, res: Res) -> &VariantDef {
+    pub fn variant_of_res(self, res: Res) -> &'tcx VariantDef {
         match res {
             Res::Def(DefKind::Variant, vid) => self.variant_with_id(vid),
             Res::Def(DefKind::Ctor(..), cid) => self.variant_with_ctor_id(cid),
@@ -402,10 +431,10 @@ impl<'tcx> AdtDef {
     }
 
     #[inline]
-    pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option<Discr<'tcx>> {
+    pub fn eval_explicit_discr(self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option<Discr<'tcx>> {
         assert!(self.is_enum());
         let param_env = tcx.param_env(expr_did);
-        let repr_type = self.repr.discr_type();
+        let repr_type = self.repr().discr_type();
         match tcx.const_eval_poly(expr_did) {
             Ok(val) => {
                 let ty = repr_type.to_ty(tcx);
@@ -437,14 +466,14 @@ impl<'tcx> AdtDef {
 
     #[inline]
     pub fn discriminants(
-        &'tcx self,
+        self,
         tcx: TyCtxt<'tcx>,
     ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'tcx> {
         assert!(self.is_enum());
-        let repr_type = self.repr.discr_type();
+        let repr_type = self.repr().discr_type();
         let initial = repr_type.initial_discriminant(tcx);
         let mut prev_discr = None::<Discr<'tcx>>;
-        self.variants.iter_enumerated().map(move |(i, v)| {
+        self.variants().iter_enumerated().map(move |(i, v)| {
             let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
             if let VariantDiscr::Explicit(expr_did) = v.discr {
                 if let Some(new_discr) = self.eval_explicit_discr(tcx, expr_did) {
@@ -458,8 +487,8 @@ impl<'tcx> AdtDef {
     }
 
     #[inline]
-    pub fn variant_range(&self) -> Range<VariantIdx> {
-        VariantIdx::new(0)..VariantIdx::new(self.variants.len())
+    pub fn variant_range(self) -> Range<VariantIdx> {
+        VariantIdx::new(0)..VariantIdx::new(self.variants().len())
     }
 
     /// Computes the discriminant value used by a specific variant.
@@ -469,7 +498,7 @@ impl<'tcx> AdtDef {
     /// assuming there are no constant-evaluation errors there.
     #[inline]
     pub fn discriminant_for_variant(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         variant_index: VariantIdx,
     ) -> Discr<'tcx> {
@@ -477,19 +506,19 @@ impl<'tcx> AdtDef {
         let (val, offset) = self.discriminant_def_for_variant(variant_index);
         let explicit_value = val
             .and_then(|expr_did| self.eval_explicit_discr(tcx, expr_did))
-            .unwrap_or_else(|| self.repr.discr_type().initial_discriminant(tcx));
+            .unwrap_or_else(|| self.repr().discr_type().initial_discriminant(tcx));
         explicit_value.checked_add(tcx, offset as u128).0
     }
 
     /// Yields a `DefId` for the discriminant and an offset to add to it
     /// Alternatively, if there is no explicit discriminant, returns the
     /// inferred discriminant directly.
-    pub fn discriminant_def_for_variant(&self, variant_index: VariantIdx) -> (Option<DefId>, u32) {
-        assert!(!self.variants.is_empty());
+    pub fn discriminant_def_for_variant(self, variant_index: VariantIdx) -> (Option<DefId>, u32) {
+        assert!(!self.variants().is_empty());
         let mut explicit_index = variant_index.as_u32();
         let expr_did;
         loop {
-            match self.variants[VariantIdx::from_u32(explicit_index)].discr {
+            match self.variant(VariantIdx::from_u32(explicit_index)).discr {
                 ty::VariantDiscr::Relative(0) => {
                     expr_did = None;
                     break;
@@ -506,8 +535,8 @@ impl<'tcx> AdtDef {
         (expr_did, variant_index.as_u32() - explicit_index)
     }
 
-    pub fn destructor(&self, tcx: TyCtxt<'tcx>) -> Option<Destructor> {
-        tcx.adt_destructor(self.did)
+    pub fn destructor(self, tcx: TyCtxt<'tcx>) -> Option<Destructor> {
+        tcx.adt_destructor(self.did())
     }
 
     /// Returns a list of types such that `Self: Sized` if and only
@@ -520,7 +549,7 @@ impl<'tcx> AdtDef {
     ///
     /// Due to normalization being eager, this applies even if
     /// the associated type is behind a pointer (e.g., issue #31299).
-    pub fn sized_constraint(&self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] {
-        tcx.adt_sized_constraint(self.did).0
+    pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] {
+        tcx.adt_sized_constraint(self.did()).0
     }
 }
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 8ba6c1f67c9..1446f7dac36 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -164,7 +164,7 @@ impl<'tcx> CapturedPlace<'tcx> {
                         write!(
                             &mut symbol,
                             "__{}",
-                            def.variants[variant].fields[idx as usize].name.as_str(),
+                            def.variant(variant).fields[idx as usize].name.as_str(),
                         )
                         .unwrap();
                     }
@@ -281,7 +281,7 @@ pub struct CaptureInfo {
     /// let mut t = (0,1);
     ///
     /// let c = || {
-    ///     println!("{}",t); // L1
+    ///     println!("{t}"); // L1
     ///     t.1 = 4; // L2
     /// };
     /// ```
@@ -330,7 +330,7 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc
                     curr_string = format!(
                         "{}.{}",
                         curr_string,
-                        def.variants[variant].fields[idx as usize].name.as_str()
+                        def.variant(variant).fields[idx as usize].name.as_str()
                     );
                 }
                 ty::Tuple(_) => {
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 69455951c57..7fcc46cc7c2 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -15,7 +15,7 @@ use crate::mir::{
 use crate::thir;
 use crate::traits;
 use crate::ty::subst::SubstsRef;
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::Span;
@@ -156,6 +156,12 @@ impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ConstAllocation<'tcx> {
     }
 }
 
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AdtDef<'tcx> {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+        self.0.0.encode(e)
+    }
+}
+
 impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         e.encode_alloc_id(self)
@@ -178,8 +184,7 @@ encodable_via_deref! {
     &'tcx mir::Body<'tcx>,
     &'tcx mir::UnsafetyCheckResult,
     &'tcx mir::BorrowCheckResult<'tcx>,
-    &'tcx mir::coverage::CodeRegion,
-    &'tcx ty::AdtDef
+    &'tcx mir::coverage::CodeRegion
 }
 
 pub trait TyDecoder<'tcx>: Decoder {
@@ -367,6 +372,12 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ConstAllocation<'tcx> {
     }
 }
 
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for AdtDef<'tcx> {
+    fn decode(decoder: &mut D) -> Self {
+        decoder.tcx().intern_adt_def(Decodable::decode(decoder))
+    }
+}
+
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, Span)] {
     fn decode(decoder: &mut D) -> &'tcx Self {
         decoder.tcx().arena.alloc_from_iter(
@@ -409,8 +420,7 @@ impl_decodable_via_ref! {
     &'tcx mir::UnsafetyCheckResult,
     &'tcx mir::BorrowCheckResult<'tcx>,
     &'tcx mir::coverage::CodeRegion,
-    &'tcx ty::List<ty::BoundVariableKind>,
-    &'tcx ty::AdtDef
+    &'tcx ty::List<ty::BoundVariableKind>
 }
 
 #[macro_export]
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index b48b6e3a820..494535f3d59 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -17,7 +17,7 @@ use crate::ty::query::{self, TyCtxtAt};
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
 use crate::ty::TyKind::*;
 use crate::ty::{
-    self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
+    self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
     ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy,
     FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
     ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region,
@@ -56,7 +56,7 @@ use rustc_span::def_id::{DefPathHash, StableCrateId};
 use rustc_span::source_map::{MultiSpan, SourceMap};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
+use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
 use rustc_target::spec::abi;
 
 use rustc_type_ir::TypeFlags;
@@ -114,8 +114,8 @@ pub struct CtxtInterners<'tcx> {
     const_: InternedSet<'tcx, ConstS<'tcx>>,
     const_allocation: InternedSet<'tcx, Allocation>,
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
-    layout: InternedSet<'tcx, Layout>,
-    adt_def: InternedSet<'tcx, AdtDef>,
+    layout: InternedSet<'tcx, LayoutS<'tcx>>,
+    adt_def: InternedSet<'tcx, AdtDefData>,
 }
 
 impl<'tcx> CtxtInterners<'tcx> {
@@ -1123,8 +1123,8 @@ impl<'tcx> TyCtxt<'tcx> {
         kind: AdtKind,
         variants: IndexVec<VariantIdx, ty::VariantDef>,
         repr: ReprOptions,
-    ) -> &'tcx ty::AdtDef {
-        self.intern_adt_def(ty::AdtDef::new(self, did, kind, variants, repr))
+    ) -> ty::AdtDef<'tcx> {
+        self.intern_adt_def(ty::AdtDefData::new(self, did, kind, variants, repr))
     }
 
     /// Allocates a read-only byte or string literal for `mir::interpret`.
@@ -2146,48 +2146,8 @@ direct_interners! {
     region: mk_region(RegionKind): Region -> Region<'tcx>,
     const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>,
     const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
-}
-
-macro_rules! direct_interners_old {
-    ($($name:ident: $method:ident($ty:ty),)+) => {
-        $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
-            fn borrow<'a>(&'a self) -> &'a $ty {
-                &self.0
-            }
-        }
-
-        impl<'tcx> PartialEq for InternedInSet<'tcx, $ty> {
-            fn eq(&self, other: &Self) -> bool {
-                // The `Borrow` trait requires that `x.borrow() == y.borrow()`
-                // equals `x == y`.
-                self.0 == other.0
-            }
-        }
-
-        impl<'tcx> Eq for InternedInSet<'tcx, $ty> {}
-
-        impl<'tcx> Hash for InternedInSet<'tcx, $ty> {
-            fn hash<H: Hasher>(&self, s: &mut H) {
-                // The `Borrow` trait requires that `x.borrow().hash(s) ==
-                // x.hash(s)`.
-                self.0.hash(s)
-            }
-        }
-
-        impl<'tcx> TyCtxt<'tcx> {
-            pub fn $method(self, v: $ty) -> &'tcx $ty {
-                self.interners.$name.intern(v, |v| {
-                    InternedInSet(self.interners.arena.alloc(v))
-                }).0
-            }
-        })+
-    }
-}
-
-// FIXME: eventually these should all be converted to `direct_interners`.
-direct_interners_old! {
-    layout: intern_layout(Layout),
-    adt_def: intern_adt_def(AdtDef),
+    layout: intern_layout(LayoutS<'tcx>): Layout -> Layout<'tcx>,
+    adt_def: intern_adt_def(AdtDefData): AdtDef -> AdtDef<'tcx>,
 }
 
 macro_rules! slice_interners {
@@ -2341,7 +2301,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     #[inline]
-    pub fn mk_adt(self, def: &'tcx AdtDef, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
+    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))
     }
@@ -2563,12 +2523,12 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn mk_place_downcast(
         self,
         place: Place<'tcx>,
-        adt_def: &'tcx AdtDef,
+        adt_def: AdtDef<'tcx>,
         variant_index: VariantIdx,
     ) -> Place<'tcx> {
         self.mk_place_elem(
             place,
-            PlaceElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index),
+            PlaceElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index),
         )
     }
 
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 99a3d4c7fe4..7d950b79cdd 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -512,7 +512,7 @@ pub fn suggest_constraining_type_params<'a>(
         };
 
         err.span_suggestion_verbose(span, msg, suggestion, applicability);
-    } else {
+    } else if suggestions.len() > 1 {
         err.multipart_suggestion_verbose(
             "consider restricting type parameters",
             suggestions.into_iter().map(|(span, suggestion, _)| (span, suggestion)).collect(),
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 708bd64578c..599845bae79 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -247,7 +247,7 @@ impl<'tcx> Ty<'tcx> {
             }
             ty::Tuple(ref tys) if tys.is_empty() => format!("`{}`", self).into(),
 
-            ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
+            ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did())).into(),
             ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
             ty::Array(t, n) => {
                 if t.is_simple_ty() {
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index c0dd4db2945..9c018dc685c 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -86,7 +86,7 @@ pub fn simplify_type<'tcx>(
         ty::Int(int_type) => Some(IntSimplifiedType(int_type)),
         ty::Uint(uint_type) => Some(UintSimplifiedType(uint_type)),
         ty::Float(float_type) => Some(FloatSimplifiedType(float_type)),
-        ty::Adt(def, _) => Some(AdtSimplifiedType(def.did)),
+        ty::Adt(def, _) => Some(AdtSimplifiedType(def.did())),
         ty::Str => Some(StrSimplifiedType),
         ty::Array(..) => Some(ArraySimplifiedType),
         ty::Slice(..) => Some(SliceSimplifiedType),
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index e2289b44b5c..2c78c1f63d8 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -105,21 +105,21 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-impl<'tcx> AdtDef {
+impl<'tcx> AdtDef<'tcx> {
     /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited.
     fn uninhabited_from(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         substs: SubstsRef<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> DefIdForest<'tcx> {
         // Non-exhaustive ADTs from other crates are always considered inhabited.
-        if self.is_variant_list_non_exhaustive() && !self.did.is_local() {
+        if self.is_variant_list_non_exhaustive() && !self.did().is_local() {
             DefIdForest::empty()
         } else {
             DefIdForest::intersection(
                 tcx,
-                self.variants
+                self.variants()
                     .iter()
                     .map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)),
             )
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 7495449da4c..5b92b33f6d4 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -5,6 +5,7 @@ use crate::ty::subst::Subst;
 use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
 use rustc_ast as ast;
 use rustc_attr as attr;
+use rustc_data_structures::intern::Interned;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::BitSet;
@@ -302,7 +303,7 @@ fn invert_mapping(map: &[u32]) -> Vec<u32> {
 }
 
 impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
-    fn scalar_pair(&self, a: Scalar, b: Scalar) -> Layout {
+    fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS<'tcx> {
         let dl = self.data_layout();
         let b_align = b.value.align(dl);
         let align = a.value.align(dl).max(b_align).max(dl.aggregate_align);
@@ -316,7 +317,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             .chain(Niche::from_scalar(dl, Size::ZERO, a))
             .max_by_key(|niche| niche.available(dl));
 
-        Layout {
+        LayoutS {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary {
                 offsets: vec![Size::ZERO, b_offset],
@@ -335,7 +336,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
         fields: &[TyAndLayout<'_>],
         repr: &ReprOptions,
         kind: StructKind,
-    ) -> Result<Layout, LayoutError<'tcx>> {
+    ) -> Result<LayoutS<'tcx>, LayoutError<'tcx>> {
         let dl = self.data_layout();
         let pack = repr.pack;
         if pack.is_some() && repr.align.is_some() {
@@ -503,8 +504,20 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                 // Two non-ZST fields, and they're both scalars.
                 (
-                    Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(a), .. }, .. })),
-                    Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(b), .. }, .. })),
+                    Some((
+                        i,
+                        &TyAndLayout {
+                            layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(a), .. }, _)),
+                            ..
+                        },
+                    )),
+                    Some((
+                        j,
+                        &TyAndLayout {
+                            layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(b), .. }, _)),
+                            ..
+                        },
+                    )),
                     None,
                 ) => {
                     // Order by the memory placement, not source order.
@@ -537,7 +550,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             abi = Abi::Uninhabited;
         }
 
-        Ok(Layout {
+        Ok(LayoutS {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary { offsets, memory_index },
             abi,
@@ -547,7 +560,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
         })
     }
 
-    fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> {
+    fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
         let tcx = self.tcx;
         let param_env = self.param_env;
         let dl = self.data_layout();
@@ -556,7 +569,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             assert!(size.bits() <= 128);
             Scalar { value, valid_range: WrappingRange { start: 0, end: size.unsigned_int_max() } }
         };
-        let scalar = |value: Primitive| tcx.intern_layout(Layout::scalar(self, scalar_unit(value)));
+        let scalar =
+            |value: Primitive| tcx.intern_layout(LayoutS::scalar(self, scalar_unit(value)));
 
         let univariant = |fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind| {
             Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?))
@@ -565,11 +579,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
         Ok(match *ty.kind() {
             // Basic scalars.
-            ty::Bool => tcx.intern_layout(Layout::scalar(
+            ty::Bool => tcx.intern_layout(LayoutS::scalar(
                 self,
                 Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } },
             )),
-            ty::Char => tcx.intern_layout(Layout::scalar(
+            ty::Char => tcx.intern_layout(LayoutS::scalar(
                 self,
                 Scalar {
                     value: Int(I32, false),
@@ -585,11 +599,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             ty::FnPtr(_) => {
                 let mut ptr = scalar_unit(Pointer);
                 ptr.valid_range = ptr.valid_range.with_start(1);
-                tcx.intern_layout(Layout::scalar(self, ptr))
+                tcx.intern_layout(LayoutS::scalar(self, ptr))
             }
 
             // The never type.
-            ty::Never => tcx.intern_layout(Layout {
+            ty::Never => tcx.intern_layout(LayoutS {
                 variants: Variants::Single { index: VariantIdx::new(0) },
                 fields: FieldsShape::Primitive,
                 abi: Abi::Uninhabited,
@@ -607,13 +621,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                 let pointee = tcx.normalize_erasing_regions(param_env, pointee);
                 if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
-                    return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr)));
+                    return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
                 }
 
                 let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
                 let metadata = match unsized_part.kind() {
                     ty::Foreign(..) => {
-                        return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr)));
+                        return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
                     }
                     ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
                     ty::Dynamic(..) => {
@@ -651,7 +665,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                 let largest_niche = if count != 0 { element.largest_niche } else { None };
 
-                tcx.intern_layout(Layout {
+                tcx.intern_layout(LayoutS {
                     variants: Variants::Single { index: VariantIdx::new(0) },
                     fields: FieldsShape::Array { stride: element.size, count },
                     abi,
@@ -662,7 +676,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             }
             ty::Slice(element) => {
                 let element = self.layout_of(element)?;
-                tcx.intern_layout(Layout {
+                tcx.intern_layout(LayoutS {
                     variants: Variants::Single { index: VariantIdx::new(0) },
                     fields: FieldsShape::Array { stride: element.size, count: 0 },
                     abi: Abi::Aggregate { sized: false },
@@ -671,7 +685,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     size: Size::ZERO,
                 })
             }
-            ty::Str => tcx.intern_layout(Layout {
+            ty::Str => tcx.intern_layout(LayoutS {
                 variants: Variants::Single { index: VariantIdx::new(0) },
                 fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
                 abi: Abi::Aggregate { sized: false },
@@ -719,7 +733,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             }
 
             // SIMD vector types.
-            ty::Adt(def, substs) if def.repr.simd() => {
+            ty::Adt(def, substs) if def.repr().simd() => {
                 if !def.is_struct() {
                     // Should have yielded E0517 by now.
                     tcx.sess.delay_span_bug(
@@ -775,7 +789,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                     // Extract the number of elements from the layout of the array field:
                     let Ok(TyAndLayout {
-                        layout: Layout { fields: FieldsShape::Array { count, .. }, .. },
+                        layout: Layout(Interned(LayoutS { fields: FieldsShape::Array { count, .. }, .. }, _)),
                         ..
                     }) = self.layout_of(f0_ty) else {
                         return Err(LayoutError::Unknown(ty));
@@ -825,7 +839,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     FieldsShape::Array { stride: e_ly.size, count: e_len }
                 };
 
-                tcx.intern_layout(Layout {
+                tcx.intern_layout(LayoutS {
                     variants: Variants::Single { index: VariantIdx::new(0) },
                     fields,
                     abi: Abi::Vector { element: e_abi, count: e_len },
@@ -839,7 +853,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             ty::Adt(def, substs) => {
                 // Cache the field layouts.
                 let variants = def
-                    .variants
+                    .variants()
                     .iter()
                     .map(|v| {
                         v.fields
@@ -850,22 +864,22 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
 
                 if def.is_union() {
-                    if def.repr.pack.is_some() && def.repr.align.is_some() {
+                    if def.repr().pack.is_some() && def.repr().align.is_some() {
                         self.tcx.sess.delay_span_bug(
-                            tcx.def_span(def.did),
+                            tcx.def_span(def.did()),
                             "union cannot be packed and aligned",
                         );
                         return Err(LayoutError::Unknown(ty));
                     }
 
                     let mut align =
-                        if def.repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
+                        if def.repr().pack.is_some() { dl.i8_align } else { dl.aggregate_align };
 
-                    if let Some(repr_align) = def.repr.align {
+                    if let Some(repr_align) = def.repr().align {
                         align = align.max(AbiAndPrefAlign::new(repr_align));
                     }
 
-                    let optimize = !def.repr.inhibit_union_abi_opt();
+                    let optimize = !def.repr().inhibit_union_abi_opt();
                     let mut size = Size::ZERO;
                     let mut abi = Abi::Aggregate { sized: true };
                     let index = VariantIdx::new(0);
@@ -901,11 +915,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                         size = cmp::max(size, field.size);
                     }
 
-                    if let Some(pack) = def.repr.pack {
+                    if let Some(pack) = def.repr().pack {
                         align = align.min(AbiAndPrefAlign::new(pack));
                     }
 
-                    return Ok(tcx.intern_layout(Layout {
+                    return Ok(tcx.intern_layout(LayoutS {
                         variants: Variants::Single { index },
                         fields: FieldsShape::Union(
                             NonZeroUsize::new(variants[index].len())
@@ -949,7 +963,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     // Only one variant is present.
                     (present_second.is_none() &&
                     // Representation optimizations are allowed.
-                    !def.repr.inhibit_enum_layout_opt());
+                    !def.repr().inhibit_enum_layout_opt());
                 if is_struct {
                     // Struct, or univariant enum equivalent to a struct.
                     // (Typechecking will reject discriminant-sizing attrs.)
@@ -958,8 +972,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     let kind = if def.is_enum() || variants[v].is_empty() {
                         StructKind::AlwaysSized
                     } else {
-                        let param_env = tcx.param_env(def.did);
-                        let last_field = def.variants[v].fields.last().unwrap();
+                        let param_env = tcx.param_env(def.did());
+                        let last_field = def.variant(v).fields.last().unwrap();
                         let always_sized =
                             tcx.type_of(last_field.did).is_sized(tcx.at(DUMMY_SP), param_env);
                         if !always_sized {
@@ -969,9 +983,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                         }
                     };
 
-                    let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr, kind)?;
+                    let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr(), kind)?;
                     st.variants = Variants::Single { index: v };
-                    let (start, end) = self.tcx.layout_scalar_valid_range(def.did);
+                    let (start, end) = self.tcx.layout_scalar_valid_range(def.did());
                     match st.abi {
                         Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => {
                             // the asserts ensure that we are not using the
@@ -997,7 +1011,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                             }
 
                             // Update `largest_niche` if we have introduced a larger niche.
-                            let niche = if def.repr.hide_niche() {
+                            let niche = if def.repr().hide_niche() {
                                 None
                             } else {
                                 Niche::from_scalar(dl, Size::ZERO, *scalar)
@@ -1035,14 +1049,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 // instead of actual discriminants, so dataful enums with
                 // explicit discriminants (RFC #2363) would misbehave.
                 let no_explicit_discriminants = def
-                    .variants
+                    .variants()
                     .iter_enumerated()
                     .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32()));
 
                 let mut niche_filling_layout = None;
 
                 // Niche-filling enum optimization.
-                if !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants {
+                if !def.repr().inhibit_enum_layout_opt() && no_explicit_discriminants {
                     let mut dataful_variant = None;
                     let mut niche_variants = VariantIdx::MAX..=VariantIdx::new(0);
 
@@ -1093,24 +1107,24 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                                     let mut st = self.univariant_uninterned(
                                         ty,
                                         v,
-                                        &def.repr,
+                                        &def.repr(),
                                         StructKind::AlwaysSized,
                                     )?;
                                     st.variants = Variants::Single { index: j };
 
                                     align = align.max(st.align);
 
-                                    Ok(st)
+                                    Ok(tcx.intern_layout(st))
                                 })
                                 .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
 
-                            let offset = st[i].fields.offset(field_index) + niche.offset;
-                            let size = st[i].size;
+                            let offset = st[i].fields().offset(field_index) + niche.offset;
+                            let size = st[i].size();
 
-                            let abi = if st.iter().all(|v| v.abi.is_uninhabited()) {
+                            let abi = if st.iter().all(|v| v.abi().is_uninhabited()) {
                                 Abi::Uninhabited
                             } else {
-                                match st[i].abi {
+                                match st[i].abi() {
                                     Abi::Scalar(_) => Abi::Scalar(niche_scalar),
                                     Abi::ScalarPair(first, second) => {
                                         // We need to use scalar_unit to reset the
@@ -1130,7 +1144,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                             let largest_niche = Niche::from_scalar(dl, offset, niche_scalar);
 
-                            niche_filling_layout = Some(Layout {
+                            niche_filling_layout = Some(LayoutS {
                                 variants: Variants::Multiple {
                                     tag: niche_scalar,
                                     tag_encoding: TagEncoding::Niche {
@@ -1155,7 +1169,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 }
 
                 let (mut min, mut max) = (i128::MAX, i128::MIN);
-                let discr_type = def.repr.discr_type();
+                let discr_type = def.repr().discr_type();
                 let bits = Integer::from_attr(self, discr_type).size().bits();
                 for (i, discr) in def.discriminants(tcx) {
                     if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
@@ -1179,7 +1193,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     max = 0;
                 }
                 assert!(min <= max, "discriminant range is {}...{}", min, max);
-                let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max);
+                let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr(), min, max);
 
                 let mut align = dl.aggregate_align;
                 let mut size = Size::ZERO;
@@ -1194,7 +1208,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 // determining the alignment of the overall enum, and the
                 // determining the alignment of the payload after the tag.)
                 let mut prefix_align = min_ity.align(dl).abi;
-                if def.repr.c() {
+                if def.repr().c() {
                     for fields in &variants {
                         for field in fields {
                             prefix_align = prefix_align.max(field.align.abi);
@@ -1209,7 +1223,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                         let mut st = self.univariant_uninterned(
                             ty,
                             &field_layouts,
-                            &def.repr,
+                            &def.repr(),
                             StructKind::Prefixed(min_ity.size(), prefix_align),
                         )?;
                         st.variants = Variants::Single { index: i };
@@ -1236,7 +1250,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     return Err(LayoutError::SizeOverflow(ty));
                 }
 
-                let typeck_ity = Integer::from_attr(dl, def.repr.discr_type());
+                let typeck_ity = Integer::from_attr(dl, def.repr().discr_type());
                 if typeck_ity < min_ity {
                     // It is a bug if Layout decided on a greater discriminant size than typeck for
                     // some reason at this point (based on values discriminant can take on). Mostly
@@ -1266,7 +1280,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 // won't be so conservative.
 
                 // Use the initial field alignment
-                let mut ity = if def.repr.c() || def.repr.int.is_some() {
+                let mut ity = if def.repr().c() || def.repr().int.is_some() {
                     min_ity
                 } else {
                     Integer::for_align(dl, start_align).unwrap_or(min_ity)
@@ -1377,7 +1391,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                 let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
 
-                let tagged_layout = Layout {
+                let layout_variants =
+                    layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect();
+
+                let tagged_layout = LayoutS {
                     variants: Variants::Multiple {
                         tag,
                         tag_encoding: TagEncoding::Direct,
@@ -1563,7 +1580,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
         ty: Ty<'tcx>,
         def_id: hir::def_id::DefId,
         substs: SubstsRef<'tcx>,
-    ) -> Result<&'tcx Layout, LayoutError<'tcx>> {
+    ) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
         use SavedLocalEligibility::*;
         let tcx = self.tcx;
         let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs);
@@ -1586,7 +1603,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             value: Primitive::Int(discr_int, false),
             valid_range: WrappingRange { start: 0, end: max_discr },
         };
-        let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag));
+        let tag_layout = self.tcx.intern_layout(LayoutS::scalar(self, tag));
         let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
 
         let promoted_layouts = ineligible_locals
@@ -1722,20 +1739,20 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                 size = size.max(variant.size);
                 align = align.max(variant.align);
-                Ok(variant)
+                Ok(tcx.intern_layout(variant))
             })
             .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
 
         size = size.align_to(align.abi);
 
-        let abi = if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi.is_uninhabited())
-        {
-            Abi::Uninhabited
-        } else {
-            Abi::Aggregate { sized: true }
-        };
+        let abi =
+            if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi().is_uninhabited()) {
+                Abi::Uninhabited
+            } else {
+                Abi::Aggregate { sized: true }
+            };
 
-        let layout = tcx.intern_layout(Layout {
+        let layout = tcx.intern_layout(LayoutS {
             variants: Variants::Multiple {
                 tag,
                 tag_encoding: TagEncoding::Direct,
@@ -1804,7 +1821,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
         };
 
         let adt_kind = adt_def.adt_kind();
-        let adt_packed = adt_def.repr.pack.is_some();
+        let adt_packed = adt_def.repr().pack.is_some();
 
         let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
             let mut min_size = Size::ZERO;
@@ -1838,12 +1855,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
         match layout.variants {
             Variants::Single { index } => {
-                if !adt_def.variants.is_empty() && layout.fields != FieldsShape::Primitive {
+                if !adt_def.variants().is_empty() && layout.fields != FieldsShape::Primitive {
                     debug!(
                         "print-type-size `{:#?}` variant {}",
-                        layout, adt_def.variants[index].name
+                        layout,
+                        adt_def.variant(index).name
                     );
-                    let variant_def = &adt_def.variants[index];
+                    let variant_def = &adt_def.variant(index);
                     let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
                     record(
                         adt_kind.into(),
@@ -1862,10 +1880,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 debug!(
                     "print-type-size `{:#?}` adt general variants def {}",
                     layout.ty,
-                    adt_def.variants.len()
+                    adt_def.variants().len()
                 );
                 let variant_infos: Vec<_> = adt_def
-                    .variants
+                    .variants()
                     .iter_enumerated()
                     .map(|(i, variant_def)| {
                         let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
@@ -1947,17 +1965,17 @@ impl<'tcx> SizeSkeleton<'tcx> {
 
             ty::Adt(def, substs) => {
                 // Only newtypes and enums w/ nullable pointer optimization.
-                if def.is_union() || def.variants.is_empty() || def.variants.len() > 2 {
+                if def.is_union() || def.variants().is_empty() || def.variants().len() > 2 {
                     return Err(err);
                 }
 
                 // Get a zero-sized variant or a pointer newtype.
                 let zero_or_ptr_variant = |i| {
                     let i = VariantIdx::new(i);
-                    let fields = def.variants[i]
-                        .fields
-                        .iter()
-                        .map(|field| SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env));
+                    let fields =
+                        def.variant(i).fields.iter().map(|field| {
+                            SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env)
+                        });
                     let mut ptr = None;
                     for field in fields {
                         let field = field?;
@@ -1980,11 +1998,11 @@ impl<'tcx> SizeSkeleton<'tcx> {
 
                 let v0 = zero_or_ptr_variant(0)?;
                 // Newtype.
-                if def.variants.len() == 1 {
+                if def.variants().len() == 1 {
                     if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
                         return Ok(SizeSkeleton::Pointer {
                             non_zero: non_zero
-                                || match tcx.layout_scalar_valid_range(def.did) {
+                                || match tcx.layout_scalar_valid_range(def.did()) {
                                     (Bound::Included(start), Bound::Unbounded) => start > 0,
                                     (Bound::Included(start), Bound::Included(end)) => {
                                         0 < start && start < end
@@ -2245,12 +2263,12 @@ where
                 }
 
                 let fields = match this.ty.kind() {
-                    ty::Adt(def, _) if def.variants.is_empty() =>
+                    ty::Adt(def, _) if def.variants().is_empty() =>
                         bug!("for_variant called on zero-variant enum"),
-                    ty::Adt(def, _) => def.variants[variant_index].fields.len(),
+                    ty::Adt(def, _) => def.variant(variant_index).fields.len(),
                     _ => bug!(),
                 };
-                tcx.intern_layout(Layout {
+                tcx.intern_layout(LayoutS {
                     variants: Variants::Single { index: variant_index },
                     fields: match NonZeroUsize::new(fields) {
                         Some(fields) => FieldsShape::Union(fields),
@@ -2263,10 +2281,10 @@ where
                 })
             }
 
-            Variants::Multiple { ref variants, .. } => &variants[variant_index],
+            Variants::Multiple { ref variants, .. } => variants[variant_index],
         };
 
-        assert_eq!(layout.variants, Variants::Single { index: variant_index });
+        assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
 
         TyAndLayout { ty: this.ty, layout }
     }
@@ -2284,8 +2302,10 @@ where
         ) -> TyMaybeWithLayout<'tcx> {
             let tcx = cx.tcx();
             let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
-                let layout = Layout::scalar(cx, tag);
-                TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) }
+                TyAndLayout {
+                    layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
+                    ty: tag.value.to_ty(tcx),
+                }
             };
 
             match *this.ty.kind() {
@@ -2386,7 +2406,7 @@ where
                 ty::Adt(def, substs) => {
                     match this.variants {
                         Variants::Single { index } => {
-                            TyMaybeWithLayout::Ty(def.variants[index].fields[i].ty(tcx, substs))
+                            TyMaybeWithLayout::Ty(def.variant(index).fields[i].ty(tcx, substs))
                         }
 
                         // Discriminant field for enums (where applicable).
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6edcfbcdc6c..e7cef9e198b 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -41,7 +41,7 @@ use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::cstore::CrateStoreDyn;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{sym, Span};
+use rustc_span::Span;
 use rustc_target::abi::Align;
 
 use std::hash::Hash;
@@ -2125,14 +2125,6 @@ impl<'tcx> TyCtxt<'tcx> {
         self.sess.contains_name(&self.get_attrs(did), attr)
     }
 
-    /// Determines whether an item is annotated with `doc(hidden)`.
-    pub fn is_doc_hidden(self, did: DefId) -> bool {
-        self.get_attrs(did)
-            .iter()
-            .filter_map(|attr| if attr.has_name(sym::doc) { attr.meta_item_list() } else { None })
-            .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
-    }
-
     /// Returns `true` if this is an `auto trait`.
     pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
         self.trait_def(trait_def_id).has_auto_impl
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 8d7f6d84c7c..c74b3e9d0fc 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -274,7 +274,7 @@ fn characteristic_def_id_of_type_cached<'a>(
     visited: &mut SsoHashSet<Ty<'a>>,
 ) -> Option<DefId> {
     match *ty.kind() {
-        ty::Adt(adt_def, _) => Some(adt_def.did),
+        ty::Adt(adt_def, _) => Some(adt_def.did()),
 
         ty::Dynamic(data, ..) => data.principal_def_id(),
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 0927dc2d266..00cb9907d95 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -618,7 +618,7 @@ pub trait PrettyPrinter<'tcx>:
                 ty::BoundTyKind::Param(p) => p!(write("{}", p)),
             },
             ty::Adt(def, substs) => {
-                p!(print_def_path(def.did, substs));
+                p!(print_def_path(def.did(), substs));
             }
             ty::Dynamic(data, r) => {
                 let print_r = self.should_print_region(r);
@@ -1487,7 +1487,7 @@ pub trait PrettyPrinter<'tcx>:
                         }
                         p!(")");
                     }
-                    ty::Adt(def, _) if def.variants.is_empty() => {
+                    ty::Adt(def, _) if def.variants().is_empty() => {
                         self = self.typed_value(
                             |mut this| {
                                 write!(this, "unreachable()")?;
@@ -1500,7 +1500,7 @@ pub trait PrettyPrinter<'tcx>:
                     ty::Adt(def, substs) => {
                         let variant_idx =
                             contents.variant.expect("destructed const of adt without variant idx");
-                        let variant_def = &def.variants[variant_idx];
+                        let variant_def = &def.variant(variant_idx);
                         p!(print_value_path(variant_def.def_id, substs));
 
                         match variant_def.ctor_kind {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 42ddbcc1e2f..81ee7942c4d 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -406,7 +406,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
         (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
 
         (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def => {
-            let substs = relation.relate_item_substs(a_def.did, a_substs, b_substs)?;
+            let substs = relation.relate_item_substs(a_def.did(), a_substs, b_substs)?;
             Ok(tcx.mk_adt(a_def, substs))
         }
 
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 2d51462221c..5c7910db362 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -33,13 +33,13 @@ impl fmt::Debug for ty::TraitDef {
     }
 }
 
-impl fmt::Debug for ty::AdtDef {
+impl<'tcx> fmt::Debug for ty::AdtDef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         ty::tls::with(|tcx| {
             with_no_trimmed_paths!({
                 f.write_str(
                     &FmtPrinter::new(tcx, Namespace::TypeNS)
-                        .print_def_path(self.did, &[])?
+                        .print_def_path(self.did(), &[])?
                         .into_buffer(),
                 )
             })
@@ -672,7 +672,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
 // TypeFoldable implementations.
 
 /// AdtDefs are basically the same as a DefId.
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
+impl<'tcx> TypeFoldable<'tcx> for ty::AdtDef<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         _folder: &mut F,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index a1e906140e0..a49189ae92a 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -109,7 +109,7 @@ pub enum TyKind<'tcx> {
     ///
     /// Note that generic parameters in fields only get lazily substituted
     /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, substs))`.
-    Adt(&'tcx AdtDef, SubstsRef<'tcx>),
+    Adt(AdtDef<'tcx>, SubstsRef<'tcx>),
 
     /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
     Foreign(DefId),
@@ -977,7 +977,6 @@ impl<'tcx> TraitRef<'tcx> {
         substs: SubstsRef<'tcx>,
     ) -> ty::TraitRef<'tcx> {
         let defs = tcx.generics_of(trait_id);
-
         ty::TraitRef { def_id: trait_id, substs: tcx.intern_substs(&substs[..defs.params.len()]) }
     }
 }
@@ -1888,6 +1887,15 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
+    pub fn is_array_slice(self) -> bool {
+        match self.kind() {
+            Slice(_) => true,
+            RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_)),
+            _ => false,
+        }
+    }
+
+    #[inline]
     pub fn is_array(self) -> bool {
         matches!(self.kind(), Array(..))
     }
@@ -1895,7 +1903,7 @@ impl<'tcx> Ty<'tcx> {
     #[inline]
     pub fn is_simd(self) -> bool {
         match self.kind() {
-            Adt(def, _) => def.repr.simd(),
+            Adt(def, _) => def.repr().simd(),
             _ => false,
         }
     }
@@ -1911,7 +1919,7 @@ impl<'tcx> Ty<'tcx> {
     pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
         match self.kind() {
             Adt(def, substs) => {
-                assert!(def.repr.simd(), "`simd_size_and_type` called on non-SIMD type");
+                assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type");
                 let variant = def.non_enum_variant();
                 let f0_ty = variant.fields[0].ty(tcx, substs);
 
@@ -2145,9 +2153,9 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
-    pub fn ty_adt_def(self) -> Option<&'tcx AdtDef> {
+    pub fn ty_adt_def(self) -> Option<AdtDef<'tcx>> {
         match self.kind() {
-            Adt(adt, _) => Some(adt),
+            Adt(adt, _) => Some(*adt),
             _ => None,
         }
     }
@@ -2186,7 +2194,7 @@ impl<'tcx> Ty<'tcx> {
         variant_index: VariantIdx,
     ) -> Option<Discr<'tcx>> {
         match self.kind() {
-            TyKind::Adt(adt, _) if adt.variants.is_empty() => {
+            TyKind::Adt(adt, _) if adt.variants().is_empty() => {
                 // This can actually happen during CTFE, see
                 // https://github.com/rust-lang/rust/issues/89765.
                 None
@@ -2204,7 +2212,7 @@ impl<'tcx> Ty<'tcx> {
     /// Returns the type of the discriminant of this type.
     pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self.kind() {
-            ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx),
+            ty::Adt(adt, _) if adt.is_enum() => adt.repr().discr_type().to_ty(tcx),
             ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
 
             ty::Param(_) | ty::Projection(_) | ty::Opaque(..) | ty::Infer(ty::TyVar(_)) => {
@@ -2372,6 +2380,57 @@ impl<'tcx> Ty<'tcx> {
             }
         }
     }
+
+    /// Fast path helper for primitives which are always `Copy` and which
+    /// have a side-effect-free `Clone` impl.
+    ///
+    /// Returning true means the type is known to be pure and `Copy+Clone`.
+    /// Returning `false` means nothing -- could be `Copy`, might not be.
+    ///
+    /// This is mostly useful for optimizations, as there are the types
+    /// on which we can replace cloning with dereferencing.
+    pub fn is_trivially_pure_clone_copy(self) -> bool {
+        match self.kind() {
+            ty::Bool | ty::Char | ty::Never => true,
+
+            // These aren't even `Clone`
+            ty::Str | ty::Slice(..) | ty::Foreign(..) | ty::Dynamic(..) => false,
+
+            ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
+
+            // The voldemort ZSTs are fine.
+            ty::FnDef(..) => true,
+
+            ty::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(),
+
+            // A 100-tuple isn't "trivial", so doing this only for reasonable sizes.
+            ty::Tuple(field_tys) => {
+                field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy)
+            }
+
+            // Sometimes traits aren't implemented for every ABI or arity,
+            // because we can't be generic over everything yet.
+            ty::FnPtr(..) => false,
+
+            // Definitely absolutely not copy.
+            ty::Ref(_, _, hir::Mutability::Mut) => false,
+
+            // Thin pointers & thin shared references are pure-clone-copy, but for
+            // anything with custom metadata it might be more complicated.
+            ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false,
+
+            ty::Generator(..) | ty::GeneratorWitness(..) => false,
+
+            // Might be, but not "trivial" so just giving the safe answer.
+            ty::Adt(..) | ty::Closure(..) | ty::Opaque(..) => false,
+
+            ty::Projection(..) | ty::Param(..) | ty::Infer(..) | ty::Error(..) => false,
+
+            ty::Bound(..) | ty::Placeholder(..) => {
+                bug!("`is_trivially_pure_clone_copy` applied to unexpected type: {:?}", self);
+            }
+        }
+    }
 }
 
 /// Extra information about why we ended up with a particular variance.
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 04e766d16cc..984f5d99852 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -21,7 +21,7 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::NodeIdHashingMode;
-use rustc_span::DUMMY_SP;
+use rustc_span::{sym, DUMMY_SP};
 use rustc_target::abi::{Integer, Size, TargetDataLayout};
 use smallvec::SmallVec;
 use std::{fmt, iter};
@@ -377,10 +377,10 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Note that this returns only the constraints for the
     /// destructor of `def` itself. For the destructors of the
     /// contents, you need `adt_dtorck_constraint`.
-    pub fn destructor_constraints(self, def: &'tcx ty::AdtDef) -> Vec<ty::subst::GenericArg<'tcx>> {
+    pub fn destructor_constraints(self, def: ty::AdtDef<'tcx>) -> Vec<ty::subst::GenericArg<'tcx>> {
         let dtor = match def.destructor(self) {
             None => {
-                debug!("destructor_constraints({:?}) - no dtor", def.did);
+                debug!("destructor_constraints({:?}) - no dtor", def.did());
                 return vec![];
             }
             Some(dtor) => dtor.did,
@@ -415,7 +415,7 @@ impl<'tcx> TyCtxt<'tcx> {
             _ => bug!(),
         };
 
-        let item_substs = match *self.type_of(def.did).kind() {
+        let item_substs = match *self.type_of(def.did()).kind() {
             ty::Adt(def_, substs) if def_ == def => substs,
             _ => bug!(),
         };
@@ -445,7 +445,7 @@ impl<'tcx> TyCtxt<'tcx> {
             })
             .map(|(item_param, _)| item_param)
             .collect();
-        debug!("destructor_constraint({:?}) = {:?}", def.did, result);
+        debug!("destructor_constraint({:?}) = {:?}", def.did(), result);
         result
     }
 
@@ -704,7 +704,7 @@ impl<'tcx> Ty<'tcx> {
         tcx_at: TyCtxtAt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> bool {
-        tcx_at.is_copy_raw(param_env.and(self))
+        self.is_trivially_pure_clone_copy() || tcx_at.is_copy_raw(param_env.and(self))
     }
 
     /// Checks whether values of this type `T` have a size known at
@@ -1154,6 +1154,14 @@ pub fn normalize_opaque_types<'tcx>(
     val.fold_with(&mut visitor)
 }
 
+/// Determines whether an item is annotated with `doc(hidden)`.
+pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    tcx.get_attrs(def_id)
+        .iter()
+        .filter_map(|attr| if attr.has_name(sym::doc) { attr.meta_item_list() } else { None })
+        .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
+}
+
 pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { normalize_opaque_types, ..*providers }
+    *providers = ty::query::Providers { normalize_opaque_types, is_doc_hidden, ..*providers }
 }
diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs
index f08c6405af1..dca9a63120c 100644
--- a/compiler/rustc_mir_build/src/build/cfg.rs
+++ b/compiler/rustc_mir_build/src/build/cfg.rs
@@ -2,7 +2,7 @@
 
 use crate::build::CFG;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 
 impl<'tcx> CFG<'tcx> {
     crate fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
@@ -73,7 +73,7 @@ impl<'tcx> CFG<'tcx> {
             Rvalue::Use(Operand::Constant(Box::new(Constant {
                 span: source_info.span,
                 user_ty: None,
-                literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(),
+                literal: ConstantKind::from_zero_sized(tcx.types.unit),
             }))),
         );
     }
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 79ac09d523d..0c0b0f2bd05 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -1,6 +1,7 @@
 //! See docs in build/expr/mod.rs
 
 use crate::build::Builder;
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
@@ -26,8 +27,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 assert_eq!(literal.ty(), ty);
                 Constant { span, user_ty, literal: literal.into() }
             }
-            ExprKind::StaticRef { literal, .. } => {
-                Constant { span, user_ty: None, literal: literal.into() }
+            ExprKind::StaticRef { alloc_id, ty, .. } => {
+                let const_val =
+                    ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &this.tcx));
+                let literal = ConstantKind::Val(const_val, ty);
+
+                Constant { span, user_ty: None, literal }
             }
             ExprKind::ConstBlock { value } => {
                 Constant { span: span, user_ty: None, literal: value.into() }
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 389f711099b..3b93d127d2c 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -334,8 +334,8 @@ impl<'tcx> PlaceBuilder<'tcx> {
         self.project(PlaceElem::Deref)
     }
 
-    crate fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Self {
-        self.project(PlaceElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index))
+    crate fn downcast(self, adt_def: AdtDef<'tcx>, variant_index: VariantIdx) -> Self {
+        self.project(PlaceElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index))
     }
 
     fn index(self, index: Local) -> Self {
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index c706e6ef1d4..8092f999311 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -9,7 +9,7 @@ use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
-use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
+use rustc_middle::ty::CanonicalUserTypeAnnotation;
 use std::iter;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -107,7 +107,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     Constant {
                         span: expr_span,
                         user_ty: None,
-                        literal: ty::Const::from_bool(this.tcx, true).into(),
+                        literal: ConstantKind::from_bool(this.tcx, true),
                     },
                 );
 
@@ -118,7 +118,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     Constant {
                         span: expr_span,
                         user_ty: None,
-                        literal: ty::Const::from_bool(this.tcx, false).into(),
+                        literal: ConstantKind::from_bool(this.tcx, false),
                     },
                 );
 
@@ -183,8 +183,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         span: expr_span,
                         user_ty: None,
                         literal: match op {
-                            LogicalOp::And => ty::Const::from_bool(this.tcx, false).into(),
-                            LogicalOp::Or => ty::Const::from_bool(this.tcx, true).into(),
+                            LogicalOp::And => ConstantKind::from_bool(this.tcx, false),
+                            LogicalOp::Or => ConstantKind::from_bool(this.tcx, true),
                         },
                     },
                 );
@@ -332,7 +332,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     .collect();
 
                 let field_names: Vec<_> =
-                    (0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect();
+                    (0..adt_def.variant(variant_index).fields.len()).map(Field::new).collect();
 
                 let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
                     let place_builder =
@@ -367,7 +367,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     })
                 });
                 let adt = Box::new(AggregateKind::Adt(
-                    adt_def.did,
+                    adt_def.did(),
                     variant_index,
                     substs,
                     user_ty,
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 44fe93ba363..c724e3e1b8f 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -946,7 +946,7 @@ enum TestKind<'tcx> {
     /// Test what enum variant a value is.
     Switch {
         /// The enum type being tested.
-        adt_def: &'tcx ty::AdtDef,
+        adt_def: ty::AdtDef<'tcx>,
         /// The set of variants that we should create a branch for. We also
         /// create an additional "otherwise" case.
         variants: BitSet<VariantIdx>,
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 4f9a2c0ce77..7f53d9dd705 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
-                let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
+                let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
                     i == variant_index || {
                         self.tcx.features().exhaustive_patterns
                             && !v
@@ -276,7 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 )
                                 .is_empty()
                     }
-                }) && (adt_def.did.is_local()
+                }) && (adt_def.did().is_local()
                     || !adt_def.is_variant_list_non_exhaustive());
                 if irrefutable {
                     let place_builder = match_pair.place.downcast(adt_def, variant_index);
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index da9c4b930df..96069f05b40 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -30,11 +30,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// It is a bug to call this with a not-fully-simplified pattern.
     pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
         match *match_pair.pattern.kind {
-            PatKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => Test {
+            PatKind::Variant { adt_def, substs: _, variant_index: _, subpatterns: _ } => Test {
                 span: match_pair.pattern.span,
                 kind: TestKind::Switch {
                     adt_def,
-                    variants: BitSet::new_empty(adt_def.variants.len()),
+                    variants: BitSet::new_empty(adt_def.variants().len()),
                 },
             },
 
@@ -174,7 +174,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             TestKind::Switch { adt_def, ref variants } => {
                 let target_blocks = make_target_blocks(self);
                 // Variants is a BitVec of indexes into adt_def.variants.
-                let num_enum_variants = adt_def.variants.len();
+                let num_enum_variants = adt_def.variants().len();
                 debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
                 let otherwise_block = *target_blocks.last().unwrap();
                 let tcx = self.tcx;
@@ -201,7 +201,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     otherwise_block,
                 );
                 debug!("num_enum_variants: {}, variants: {:?}", num_enum_variants, variants);
-                let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
+                let discr_ty = adt_def.repr().discr_type().to_ty(tcx);
                 let discr = self.temp(discr_ty, test.span);
                 self.cfg.push_assign(
                     block,
@@ -733,7 +733,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn candidate_after_variant_switch<'pat>(
         &mut self,
         match_pair_index: usize,
-        adt_def: &'tcx ty::AdtDef,
+        adt_def: ty::AdtDef<'tcx>,
         variant_index: VariantIdx,
         subpatterns: &'pat [FieldPat<'tcx>],
         candidate: &mut Candidate<'pat, 'tcx>,
@@ -744,7 +744,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // we want to create a set of derived match-patterns like
         // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
         let elem =
-            ProjectionElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index);
+            ProjectionElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index);
         let downcast_place = match_pair.place.project(elem); // `(x as Variant)`
         let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
             // e.g., `(x as Variant).0`
@@ -798,7 +798,7 @@ impl Test<'_> {
                 // variants, we have a target for each variant and the
                 // otherwise case, and we make sure that all of the cases not
                 // specified have the same block.
-                adt_def.variants.len() + 1
+                adt_def.variants().len() + 1
             }
             TestKind::SwitchInt { switch_ty, ref options, .. } => {
                 if switch_ty.is_bool() {
diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs
index fd591446014..3516eca1c14 100644
--- a/compiler/rustc_mir_build/src/build/misc.rs
+++ b/compiler/rustc_mir_build/src/build/misc.rs
@@ -54,7 +54,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             Constant {
                 span: source_info.span,
                 user_ty: None,
-                literal: ty::Const::from_usize(self.tcx, value).into(),
+                literal: ConstantKind::from_usize(self.tcx, value),
             },
         );
         temp
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index b40d3e453e9..2d1198edbc3 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -162,7 +162,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for LayoutConstrainedPlaceVisitor<'a, 'tcx> {
             ExprKind::Field { lhs, .. } => {
                 if let ty::Adt(adt_def, _) = self.thir[lhs].ty.kind() {
                     if (Bound::Unbounded, Bound::Unbounded)
-                        != self.tcx.layout_scalar_valid_range(adt_def.did)
+                        != self.tcx.layout_scalar_valid_range(adt_def.did())
                     {
                         self.found = true;
                     }
@@ -242,7 +242,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                         visit::walk_pat(self, pat);
                         self.in_union_destructure = old_in_union_destructure;
                     } else if (Bound::Unbounded, Bound::Unbounded)
-                        != self.tcx.layout_scalar_valid_range(adt_def.did)
+                        != self.tcx.layout_scalar_valid_range(adt_def.did())
                     {
                         let old_inside_adt = std::mem::replace(&mut self.inside_adt, true);
                         visit::walk_pat(self, pat);
@@ -386,7 +386,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 user_ty: _,
                 fields: _,
                 base: _,
-            }) => match self.tcx.layout_scalar_valid_range(adt_def.did) {
+            }) => match self.tcx.layout_scalar_valid_range(adt_def.did()) {
                 (Bound::Unbounded, Bound::Unbounded) => {}
                 _ => self.requires_unsafe(expr.span, InitializingTypeWith),
             },
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 651edc827c3..23ee982489d 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -8,7 +8,6 @@ use rustc_middle::hir::place::Place as HirPlace;
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
-use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
 use rustc_middle::thir::*;
 use rustc_middle::ty::adjustment::{
@@ -229,7 +228,7 @@ impl<'tcx> Cx<'tcx> {
                         let user_ty =
                             user_provided_types.get(fun.hir_id).copied().map(|mut u_ty| {
                                 if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value {
-                                    *did = adt_def.did;
+                                    *did = adt_def.did();
                                 }
                                 u_ty
                             });
@@ -377,7 +376,7 @@ impl<'tcx> Cx<'tcx> {
                         let user_ty = user_provided_types.get(expr.hir_id).copied();
                         debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
                         ExprKind::Adt(Box::new(Adt {
-                            adt_def: adt,
+                            adt_def: *adt,
                             variant_index: VariantIdx::new(0),
                             substs,
                             user_ty,
@@ -403,7 +402,7 @@ impl<'tcx> Cx<'tcx> {
                                 let user_ty = user_provided_types.get(expr.hir_id).copied();
                                 debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
                                 ExprKind::Adt(Box::new(Adt {
-                                    adt_def: adt,
+                                    adt_def: *adt,
                                     variant_index: index,
                                     substs,
                                     user_ty,
@@ -570,6 +569,9 @@ impl<'tcx> Cx<'tcx> {
 
             hir::ExprKind::ConstBlock(ref anon_const) => {
                 let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
+
+                // FIXME Do we want to use `from_inline_const` once valtrees
+                // are introduced? This would create `ValTree`s that will never be used...
                 let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
 
                 ExprKind::ConstBlock { value }
@@ -678,7 +680,7 @@ impl<'tcx> Cx<'tcx> {
                                     let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
                                     let (d, o) = adt_def.discriminant_def_for_variant(idx);
                                     use rustc_middle::ty::util::IntTypeExt;
-                                    let ty = adt_def.repr.discr_type();
+                                    let ty = adt_def.repr().discr_type();
                                     let ty = ty.to_ty(self.tcx());
                                     Some((d, o, ty))
                                 }
@@ -922,7 +924,7 @@ impl<'tcx> Cx<'tcx> {
                     // A unit struct/variant which is used as a value.
                     // We return a completely different ExprKind here to account for this special case.
                     ty::Adt(adt_def, substs) => ExprKind::Adt(Box::new(Adt {
-                        adt_def,
+                        adt_def: *adt_def,
                         variant_index: adt_def.variant_index_with_ctor_id(def_id),
                         substs,
                         user_ty: user_provided_type,
@@ -941,15 +943,8 @@ impl<'tcx> Cx<'tcx> {
                 let kind = if self.tcx.is_thread_local_static(id) {
                     ExprKind::ThreadLocalRef(id)
                 } else {
-                    let ptr = self.tcx.create_static_alloc(id);
-                    ExprKind::StaticRef {
-                        literal: ty::Const::from_scalar(
-                            self.tcx,
-                            Scalar::from_pointer(ptr.into(), &self.tcx),
-                            ty,
-                        ),
-                        def_id: id,
-                    }
+                    let alloc_id = self.tcx.create_static_alloc(id);
+                    ExprKind::StaticRef { alloc_id, ty, def_id: id }
                 };
                 ExprKind::Deref {
                     arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }),
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 27a6b5beb62..e2c56df6014 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -7,7 +7,8 @@ use super::{PatCtxt, PatternError};
 use rustc_arena::TypedArena;
 use rustc_ast::Mutability;
 use rustc_errors::{
-    error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
+    ErrorGuaranteed,
 };
 use rustc_hir as hir;
 use rustc_hir::def::*;
@@ -20,7 +21,7 @@ use rustc_session::lint::builtin::{
 };
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
-use rustc_span::{DesugaringKind, ExpnKind, Span};
+use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span};
 
 crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
     let body_id = match def_id.as_local() {
@@ -64,7 +65,9 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         intravisit::walk_expr(self, ex);
         match &ex.kind {
-            hir::ExprKind::Match(scrut, arms, source) => self.check_match(scrut, arms, *source),
+            hir::ExprKind::Match(scrut, arms, source) => {
+                self.check_match(scrut, arms, *source, ex.span)
+            }
             hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => {
                 self.check_let(pat, init, *span)
             }
@@ -163,6 +166,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         scrut: &hir::Expr<'_>,
         hir_arms: &'tcx [hir::Arm<'tcx>],
         source: hir::MatchSource,
+        expr_span: Span,
     ) {
         let mut cx = self.new_cx(scrut.hir_id);
 
@@ -208,7 +212,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         }
 
         // Check if the match is exhaustive.
-        let is_empty_match = arms.is_empty();
         let witnesses = report.non_exhaustiveness_witnesses;
         if !witnesses.is_empty() {
             if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 {
@@ -216,7 +219,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
                 let pat = hir_arms[1].pat.for_loop_some().unwrap();
                 self.check_irrefutable(pat, "`for` loop binding", None);
             } else {
-                non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+                non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, hir_arms, expr_span);
             }
         }
     }
@@ -239,6 +242,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         }
 
         let joined_patterns = joined_uncovered_patterns(&cx, &witnesses);
+
+        let mut bindings = vec![];
+
         let mut err = struct_span_err!(
             self.tcx.sess,
             pat.span,
@@ -255,6 +261,16 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
                 false
             }
             _ => {
+                pat.walk(&mut |pat: &hir::Pat<'_>| {
+                    match pat.kind {
+                        hir::PatKind::Binding(_, _, ident, _) => {
+                            bindings.push(ident);
+                        }
+                        _ => {}
+                    }
+                    true
+                });
+
                 err.span_label(pat.span, pattern_not_covered_label(&witnesses, &joined_patterns));
                 true
             }
@@ -265,13 +281,71 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
                 "`let` bindings require an \"irrefutable pattern\", like a `struct` or \
                  an `enum` with only one variant",
             );
-            if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                err.span_suggestion(
-                    span,
-                    "you might want to use `if let` to ignore the variant that isn't matched",
-                    format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]),
+            if self.tcx.sess.source_map().span_to_snippet(span).is_ok() {
+                let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1));
+                let start_span = span.shrink_to_lo();
+                let end_span = semi_span.shrink_to_lo();
+                err.multipart_suggestion(
+                    &format!(
+                        "you might want to use `if let` to ignore the variant{} that {} matched",
+                        pluralize!(witnesses.len()),
+                        match witnesses.len() {
+                            1 => "isn't",
+                            _ => "aren't",
+                        },
+                    ),
+                    vec![
+                        match &bindings[..] {
+                            [] => (start_span, "if ".to_string()),
+                            [binding] => (start_span, format!("let {} = if ", binding)),
+                            bindings => (
+                                start_span,
+                                format!(
+                                    "let ({}) = if ",
+                                    bindings
+                                        .iter()
+                                        .map(|ident| ident.to_string())
+                                        .collect::<Vec<_>>()
+                                        .join(", ")
+                                ),
+                            ),
+                        },
+                        match &bindings[..] {
+                            [] => (semi_span, " { todo!() }".to_string()),
+                            [binding] => {
+                                (end_span, format!(" {{ {} }} else {{ todo!() }}", binding))
+                            }
+                            bindings => (
+                                end_span,
+                                format!(
+                                    " {{ ({}) }} else {{ todo!() }}",
+                                    bindings
+                                        .iter()
+                                        .map(|ident| ident.to_string())
+                                        .collect::<Vec<_>>()
+                                        .join(", ")
+                                ),
+                            ),
+                        },
+                    ],
                     Applicability::HasPlaceholders,
                 );
+                if !bindings.is_empty() && cx.tcx.sess.is_nightly_build() {
+                    err.span_suggestion_verbose(
+                        semi_span.shrink_to_lo(),
+                        &format!(
+                            "alternatively, on nightly, you might want to use \
+                             `#![feature(let_else)]` to handle the variant{} that {} matched",
+                            pluralize!(witnesses.len()),
+                            match witnesses.len() {
+                                1 => "isn't",
+                                _ => "aren't",
+                            },
+                        ),
+                        " else { todo!() }".to_string(),
+                        Applicability::HasPlaceholders,
+                    );
+                }
             }
             err.note(
                 "for more information, visit \
@@ -321,20 +395,20 @@ fn check_for_bindings_named_same_as_variants(
             && let pat_ty = cx.typeck_results.pat_ty(p).peel_refs()
             && let ty::Adt(edef, _) = pat_ty.kind()
             && edef.is_enum()
-            && edef.variants.iter().any(|variant| {
+            && edef.variants().iter().any(|variant| {
                 variant.ident(cx.tcx) == ident && variant.ctor_kind == CtorKind::Const
             })
         {
-            let variant_count = edef.variants.len();
+            let variant_count = edef.variants().len();
             cx.tcx.struct_span_lint_hir(
                 BINDINGS_WITH_VARIANT_NAME,
                 p.hir_id,
                 p.span,
                 |lint| {
-                    let ty_path = cx.tcx.def_path_str(edef.did);
+                    let ty_path = cx.tcx.def_path_str(edef.did());
                     let mut err = lint.build(&format!(
                         "pattern binding `{}` is named the same as one \
-                                        of the variants of the type `{}`",
+                         of the variants of the type `{}`",
                         ident, ty_path
                     ));
                     err.code(error_code!(E0170));
@@ -494,21 +568,26 @@ fn non_exhaustive_match<'p, 'tcx>(
     scrut_ty: Ty<'tcx>,
     sp: Span,
     witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
-    is_empty_match: bool,
+    arms: &[hir::Arm<'tcx>],
+    expr_span: Span,
 ) {
+    let is_empty_match = arms.is_empty();
     let non_empty_enum = match scrut_ty.kind() {
-        ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
+        ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(),
         _ => false,
     };
     // In the case of an empty match, replace the '`_` not covered' diagnostic with something more
     // informative.
     let mut err;
+    let pattern;
+    let mut patterns_len = 0;
     if is_empty_match && !non_empty_enum {
         err = create_e0004(
             cx.tcx.sess,
             sp,
             format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
         );
+        pattern = "_".to_string();
     } else {
         let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
         err = create_e0004(
@@ -517,18 +596,24 @@ fn non_exhaustive_match<'p, 'tcx>(
             format!("non-exhaustive patterns: {} not covered", joined_patterns),
         );
         err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+        patterns_len = witnesses.len();
+        pattern = if witnesses.len() < 4 {
+            witnesses
+                .iter()
+                .map(|witness| witness.to_pat(cx).to_string())
+                .collect::<Vec<String>>()
+                .join(" | ")
+        } else {
+            "_".to_string()
+        };
     };
 
     let is_variant_list_non_exhaustive = match scrut_ty.kind() {
-        ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did.is_local() => true,
+        ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => true,
         _ => false,
     };
 
     adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
-    err.help(
-        "ensure that all possible cases are being handled, \
-              possibly by adding wildcards or more match arms",
-    );
     err.note(&format!(
         "the matched value is of type `{}`{}",
         scrut_ty,
@@ -540,14 +625,14 @@ fn non_exhaustive_match<'p, 'tcx>(
         && matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
     {
         err.note(&format!(
-            "`{}` does not have a fixed maximum value, \
-                so a wildcard `_` is necessary to match exhaustively",
+            "`{}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
+             exhaustively",
             scrut_ty,
         ));
         if cx.tcx.sess.is_nightly_build() {
             err.help(&format!(
-                "add `#![feature(precise_pointer_size_matching)]` \
-                    to the crate attributes to enable precise `{}` matching",
+                "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
+                 enable precise `{}` matching",
                 scrut_ty,
             ));
         }
@@ -557,6 +642,84 @@ fn non_exhaustive_match<'p, 'tcx>(
             err.note("references are always considered inhabited");
         }
     }
+
+    let mut suggestion = None;
+    let sm = cx.tcx.sess.source_map();
+    match arms {
+        [] if sp.ctxt() == expr_span.ctxt() => {
+            // Get the span for the empty match body `{}`.
+            let (indentation, more) = if let Some(snippet) = sm.indentation_before(sp) {
+                (format!("\n{}", snippet), "    ")
+            } else {
+                (" ".to_string(), "")
+            };
+            suggestion = Some((
+                sp.shrink_to_hi().with_hi(expr_span.hi()),
+                format!(
+                    " {{{indentation}{more}{pattern} => todo!(),{indentation}}}",
+                    indentation = indentation,
+                    more = more,
+                    pattern = pattern,
+                ),
+            ));
+        }
+        [only] => {
+            let pre_indentation = if let (Some(snippet), true) = (
+                sm.indentation_before(only.span),
+                sm.is_multiline(sp.shrink_to_hi().with_hi(only.span.lo())),
+            ) {
+                format!("\n{}", snippet)
+            } else {
+                " ".to_string()
+            };
+            let comma = if matches!(only.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
+            suggestion = Some((
+                only.span.shrink_to_hi(),
+                format!("{}{}{} => todo!()", comma, pre_indentation, pattern),
+            ));
+        }
+        [.., prev, last] if prev.span.ctxt() == last.span.ctxt() => {
+            if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) {
+                let comma =
+                    if matches!(last.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
+                suggestion = Some((
+                    last.span.shrink_to_hi(),
+                    format!(
+                        "{}{}{} => todo!()",
+                        comma,
+                        snippet.strip_prefix(",").unwrap_or(&snippet),
+                        pattern
+                    ),
+                ));
+            }
+        }
+        _ => {}
+    }
+
+    let msg = format!(
+        "ensure that all possible cases are being handled by adding a match arm with a wildcard \
+         pattern{}{}",
+        if patterns_len > 1 && patterns_len < 4 && suggestion.is_some() {
+            ", a match arm with multiple or-patterns"
+        } else {
+            // we are either not suggesting anything, or suggesting `_`
+            ""
+        },
+        match patterns_len {
+            // non-exhaustive enum case
+            0 if suggestion.is_some() => " as shown",
+            0 => "",
+            1 if suggestion.is_some() => " or an explicit pattern as shown",
+            1 => " or an explicit pattern",
+            _ if suggestion.is_some() => " as shown, or multiple match arms",
+            _ => " or multiple match arms",
+        },
+    );
+    if let Some((span, sugg)) = suggestion {
+        err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+    } else {
+        err.help(&msg);
+    }
     err.emit();
 }
 
@@ -597,31 +760,43 @@ fn adt_defined_here<'p, 'tcx>(
 ) {
     let ty = ty.peel_refs();
     if let ty::Adt(def, _) = ty.kind() {
-        if let Some(sp) = cx.tcx.hir().span_if_local(def.did) {
-            err.span_label(sp, format!("`{}` defined here", ty));
-        }
-
-        if witnesses.len() < 4 {
-            for sp in maybe_point_at_variant(cx, def, witnesses.iter()) {
-                err.span_label(sp, "not covered");
+        let mut spans = vec![];
+        if witnesses.len() < 5 {
+            for sp in maybe_point_at_variant(cx, *def, witnesses.iter()) {
+                spans.push(sp);
             }
         }
+        let def_span = cx
+            .tcx
+            .hir()
+            .get_if_local(def.did())
+            .and_then(|node| node.ident())
+            .map(|ident| ident.span)
+            .unwrap_or_else(|| cx.tcx.def_span(def.did()));
+        let mut span: MultiSpan =
+            if spans.is_empty() { def_span.into() } else { spans.clone().into() };
+
+        span.push_span_label(def_span, String::new());
+        for pat in spans {
+            span.push_span_label(pat, "not covered".to_string());
+        }
+        err.span_note(span, &format!("`{}` defined here", ty));
     }
 }
 
 fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
-    def: &AdtDef,
+    def: AdtDef<'tcx>,
     patterns: impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>>,
 ) -> Vec<Span> {
     use Constructor::*;
     let mut covered = vec![];
     for pattern in patterns {
         if let Variant(variant_index) = pattern.ctor() {
-            if let ty::Adt(this_def, _) = pattern.ty().kind() && this_def.did != def.did {
+            if let ty::Adt(this_def, _) = pattern.ty().kind() && this_def.did() != def.did() {
                 continue;
             }
-            let sp = def.variants[*variant_index].ident(cx.tcx).span;
+            let sp = def.variant(*variant_index).ident(cx.tcx).span;
             if covered.contains(&sp) {
                 // Don't point at variants that have already been covered due to other patterns to avoid
                 // visual clutter.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index b83cbb753df..ae9b44cee4b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -110,8 +110,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    fn adt_derive_msg(&self, adt_def: &AdtDef) -> String {
-        let path = self.tcx().def_path_str(adt_def.did);
+    fn adt_derive_msg(&self, adt_def: AdtDef<'tcx>) -> String {
+        let path = self.tcx().def_path_str(adt_def.did());
         format!(
             "to use a constant of type `{}` in a pattern, \
             `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
@@ -346,7 +346,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                     adt_def,
                     cv.ty()
                 );
-                let path = tcx.def_path_str(adt_def.did);
+                let path = tcx.def_path_str(adt_def.did());
                 let msg = format!(
                     "to use a constant of type `{}` in a pattern, \
                      `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
@@ -363,7 +363,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
             ty::Adt(adt_def, substs) if adt_def.is_enum() => {
                 let destructured = tcx.destructure_const(param_env.and(cv));
                 PatKind::Variant {
-                    adt_def,
+                    adt_def: *adt_def,
                     substs,
                     variant_index: destructured
                         .variant
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 002c0b5f7d8..612bed639bf 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -681,7 +681,7 @@ impl<'tcx> Constructor<'tcx> {
     /// This means that the variant has a stdlib unstable feature marking it.
     pub(super) fn is_unstable_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
         if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() {
-            let variant_def_id = adt.variants[*idx].def_id;
+            let variant_def_id = adt.variant(*idx).def_id;
             // Filter variants that depend on a disabled unstable feature.
             return matches!(
                 pcx.cx.tcx.eval_stability(variant_def_id, None, DUMMY_SP, None),
@@ -692,16 +692,16 @@ impl<'tcx> Constructor<'tcx> {
     }
 
     /// Checks if the `Constructor` is a `Constructor::Variant` with a `#[doc(hidden)]`
-    /// attribute.
+    /// attribute from a type not local to the current crate.
     pub(super) fn is_doc_hidden_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
         if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() {
-            let variant_def_id = adt.variants[*idx].def_id;
-            return pcx.cx.tcx.is_doc_hidden(variant_def_id);
+            let variant_def_id = adt.variants()[*idx].def_id;
+            return pcx.cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local();
         }
         false
     }
 
-    fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
+    fn variant_index_for_adt(&self, adt: ty::AdtDef<'tcx>) -> VariantIdx {
         match *self {
             Variant(idx) => idx,
             Single => {
@@ -725,7 +725,7 @@ impl<'tcx> Constructor<'tcx> {
                         // patterns. If we're here we can assume this is a box pattern.
                         1
                     } else {
-                        let variant = &adt.variants[self.variant_index_for_adt(adt)];
+                        let variant = &adt.variant(self.variant_index_for_adt(*adt));
                         Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant).count()
                     }
                 }
@@ -973,10 +973,10 @@ impl<'tcx> SplitWildcard<'tcx> {
                 // exception is if the pattern is at the top level, because we want empty matches to be
                 // considered exhaustive.
                 let is_secretly_empty =
-                    def.variants.is_empty() && !is_exhaustive_pat_feature && !pcx.is_top_level;
+                    def.variants().is_empty() && !is_exhaustive_pat_feature && !pcx.is_top_level;
 
                 let mut ctors: SmallVec<[_; 1]> = def
-                    .variants
+                    .variants()
                     .iter_enumerated()
                     .filter(|(_, v)| {
                         // If `exhaustive_patterns` is enabled, we exclude variants known to be
@@ -1179,7 +1179,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
     ) -> impl Iterator<Item = (Field, Ty<'tcx>)> + Captures<'a> + Captures<'p> {
         let ty::Adt(adt, substs) = ty.kind() else { bug!() };
         // Whether we must not match the fields of this variant exhaustively.
-        let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local();
+        let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did().is_local();
 
         variant.fields.iter().enumerate().filter_map(move |(i, field)| {
             let ty = field.ty(cx.tcx, substs);
@@ -1213,7 +1213,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
                         // patterns. If we're here we can assume this is a box pattern.
                         Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
                     } else {
-                        let variant = &adt.variants[constructor.variant_index_for_adt(adt)];
+                        let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
                         let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
                             .map(|(_, ty)| ty);
                         Fields::wildcards_from_tys(cx, tys)
@@ -1346,7 +1346,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
                             PatKind::Variant { variant_index, .. } => Variant(*variant_index),
                             _ => bug!(),
                         };
-                        let variant = &adt.variants[ctor.variant_index_for_adt(adt)];
+                        let variant = &adt.variant(ctor.variant_index_for_adt(*adt));
                         // For each field in the variant, we store the relevant index into `self.fields` if any.
                         let mut field_id_to_id: Vec<Option<usize>> =
                             (0..variant.fields.len()).map(|_| None).collect();
@@ -1459,15 +1459,15 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
                     PatKind::Deref { subpattern: subpatterns.next().unwrap() }
                 }
                 ty::Adt(adt_def, substs) => {
-                    let variant_index = self.ctor.variant_index_for_adt(adt_def);
-                    let variant = &adt_def.variants[variant_index];
+                    let variant_index = self.ctor.variant_index_for_adt(*adt_def);
+                    let variant = &adt_def.variant(variant_index);
                     let subpatterns = Fields::list_variant_nonhidden_fields(cx, self.ty, variant)
                         .zip(subpatterns)
                         .map(|((field, _ty), pattern)| FieldPat { field, pattern })
                         .collect();
 
                     if adt_def.is_enum() {
-                        PatKind::Variant { adt_def, substs, variant_index, subpatterns }
+                        PatKind::Variant { adt_def: *adt_def, substs, variant_index, subpatterns }
                     } else {
                         PatKind::Leaf { subpatterns }
                     }
@@ -1640,9 +1640,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
                 }
                 ty::Adt(..) | ty::Tuple(..) => {
                     let variant = match self.ty.kind() {
-                        ty::Adt(adt, _) => {
-                            Some(&adt.variants[self.ctor.variant_index_for_adt(adt)])
-                        }
+                        ty::Adt(adt, _) => Some(adt.variant(self.ctor.variant_index_for_adt(*adt))),
                         ty::Tuple(_) => None,
                         _ => unreachable!(),
                     };
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 6282b07e6f0..d21fbb9edff 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -653,7 +653,7 @@ macro_rules! CloneImpls {
 
 CloneImpls! { <'tcx>
     Span, Field, Mutability, Symbol, hir::HirId, usize, ty::Const<'tcx>,
-    Region<'tcx>, Ty<'tcx>, BindingMode, &'tcx AdtDef,
+    Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>,
     SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
     UserTypeProjection, PatTyProj<'tcx>
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 286473c38e3..176723ab28b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -325,7 +325,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
     pub(super) fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
         match ty.kind() {
             ty::Adt(def, ..) => {
-                def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local()
+                def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did().is_local()
             }
             _ => false,
         }
diff --git a/compiler/rustc_mir_build/src/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs
index aea8667314f..82f97f22cce 100644
--- a/compiler/rustc_mir_build/src/thir/util.rs
+++ b/compiler/rustc_mir_build/src/thir/util.rs
@@ -20,7 +20,7 @@ crate trait UserAnnotatedTyHelpers<'tcx> {
         match ty.kind() {
             ty::Adt(adt_def, ..) => {
                 if let UserType::TypeOf(ref mut did, _) = &mut user_ty.value {
-                    *did = adt_def.did;
+                    *did = adt_def.did();
                 }
                 Some(user_ty)
             }
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 774df752113..84491d0c2ad 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -407,7 +407,7 @@ where
         self.drop_ladder(fields, succ, unwind).0
     }
 
-    fn open_drop_for_box(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock {
+    fn open_drop_for_box(&mut self, adt: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> BasicBlock {
         debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs);
 
         let interior = self.tcx().mk_place_deref(self.place);
@@ -420,9 +420,9 @@ where
         self.drop_subpath(interior, interior_path, succ, unwind_succ)
     }
 
-    fn open_drop_for_adt(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock {
+    fn open_drop_for_adt(&mut self, adt: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> BasicBlock {
         debug!("open_drop_for_adt({:?}, {:?}, {:?})", self, adt, substs);
-        if adt.variants.is_empty() {
+        if adt.variants().is_empty() {
             return self.elaborator.patch().new_block(BasicBlockData {
                 statements: vec![],
                 terminator: Some(Terminator {
@@ -434,7 +434,7 @@ where
         }
 
         let skip_contents =
-            adt.is_union() || Some(adt.did) == self.tcx().lang_items().manually_drop();
+            adt.is_union() || Some(adt.did()) == self.tcx().lang_items().manually_drop();
         let contents_drop = if skip_contents {
             (self.succ, self.unwind)
         } else {
@@ -450,7 +450,7 @@ where
 
     fn open_drop_for_adt_contents(
         &mut self,
-        adt: &'tcx ty::AdtDef,
+        adt: ty::AdtDef<'tcx>,
         substs: SubstsRef<'tcx>,
     ) -> (BasicBlock, Unwind) {
         let (succ, unwind) = self.drop_ladder_bottom();
@@ -458,7 +458,7 @@ where
             let fields = self.move_paths_for_fields(
                 self.place,
                 self.path,
-                &adt.variants[VariantIdx::new(0)],
+                &adt.variant(VariantIdx::new(0)),
                 substs,
             );
             self.drop_ladder(fields, succ, unwind)
@@ -469,22 +469,22 @@ where
 
     fn open_drop_for_multivariant(
         &mut self,
-        adt: &'tcx ty::AdtDef,
+        adt: ty::AdtDef<'tcx>,
         substs: SubstsRef<'tcx>,
         succ: BasicBlock,
         unwind: Unwind,
     ) -> (BasicBlock, Unwind) {
-        let mut values = Vec::with_capacity(adt.variants.len());
-        let mut normal_blocks = Vec::with_capacity(adt.variants.len());
+        let mut values = Vec::with_capacity(adt.variants().len());
+        let mut normal_blocks = Vec::with_capacity(adt.variants().len());
         let mut unwind_blocks =
-            if unwind.is_cleanup() { None } else { Some(Vec::with_capacity(adt.variants.len())) };
+            if unwind.is_cleanup() { None } else { Some(Vec::with_capacity(adt.variants().len())) };
 
         let mut have_otherwise_with_drop_glue = false;
         let mut have_otherwise = false;
         let tcx = self.tcx();
 
         for (variant_index, discr) in adt.discriminants(tcx) {
-            let variant = &adt.variants[variant_index];
+            let variant = &adt.variant(variant_index);
             let subpath = self.elaborator.downcast_subpath(self.path, variant_index);
 
             if let Some(variant_path) = subpath {
@@ -564,7 +564,7 @@ where
 
     fn adt_switch_block(
         &mut self,
-        adt: &'tcx ty::AdtDef,
+        adt: ty::AdtDef<'tcx>,
         blocks: Vec<BasicBlock>,
         values: &[u128],
         succ: BasicBlock,
@@ -577,7 +577,7 @@ where
         // Additionally, we do not want to switch on the
         // discriminant after it is free-ed, because that
         // way lies only trouble.
-        let discr_ty = adt.repr.discr_type().to_ty(self.tcx());
+        let discr_ty = adt.repr().discr_type().to_ty(self.tcx());
         let discr = Place::from(self.new_temp(discr_ty));
         let discr_rv = Rvalue::Discriminant(self.place);
         let switch_block = BasicBlockData {
@@ -869,9 +869,9 @@ where
             ty::Tuple(fields) => self.open_drop_for_tuple(fields),
             ty::Adt(def, substs) => {
                 if def.is_box() {
-                    self.open_drop_for_box(def, substs)
+                    self.open_drop_for_box(*def, substs)
                 } else {
-                    self.open_drop_for_adt(def, substs)
+                    self.open_drop_for_adt(*def, substs)
                 }
             }
             ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
@@ -927,7 +927,7 @@ where
     /// The contained value will not be dropped.
     fn box_free_block(
         &mut self,
-        adt: &'tcx ty::AdtDef,
+        adt: ty::AdtDef<'tcx>,
         substs: SubstsRef<'tcx>,
         target: BasicBlock,
         unwind: Unwind,
@@ -940,7 +940,7 @@ where
     /// value).
     fn unelaborated_free_block(
         &mut self,
-        adt: &'tcx ty::AdtDef,
+        adt: ty::AdtDef<'tcx>,
         substs: SubstsRef<'tcx>,
         target: BasicBlock,
         unwind: Unwind,
@@ -948,7 +948,8 @@ where
         let tcx = self.tcx();
         let unit_temp = Place::from(self.new_temp(tcx.mk_unit()));
         let free_func = tcx.require_lang_item(LangItem::BoxFree, Some(self.source_info.span));
-        let args = adt.variants[VariantIdx::new(0)]
+        let args = adt
+            .variant(VariantIdx::new(0))
             .fields
             .iter()
             .enumerate()
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 7d6a08d47da..87c1060f552 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -705,14 +705,14 @@ fn switch_on_enum_discriminant<'mir, 'tcx>(
     body: &'mir mir::Body<'tcx>,
     block: &'mir mir::BasicBlockData<'tcx>,
     switch_on: mir::Place<'tcx>,
-) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> {
+) -> Option<(mir::Place<'tcx>, ty::AdtDef<'tcx>)> {
     for statement in block.statements.iter().rev() {
         match &statement.kind {
             mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated)))
                 if *lhs == switch_on =>
             {
-                match &discriminated.ty(body, tcx).ty.kind() {
-                    ty::Adt(def, _) => return Some((*discriminated, def)),
+                match discriminated.ty(body, tcx).ty.kind() {
+                    ty::Adt(def, _) => return Some((*discriminated, *def)),
 
                     // `Rvalue::Discriminant` is also used to get the active yield point for a
                     // generator, but we do not need edge-specific effects in that case. This may
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
index f2b34159382..1af789b4885 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
@@ -37,8 +37,8 @@ rustc_index::newtype_index! {
 }
 
 impl MoveOutIndex {
-    pub fn move_path_index(&self, move_data: &MoveData<'_>) -> MovePathIndex {
-        move_data.moves[*self].path
+    pub fn move_path_index(self, move_data: &MoveData<'_>) -> MovePathIndex {
+        move_data.moves[self].path
     }
 }
 
@@ -338,8 +338,8 @@ impl MovePathLookup {
     /// `MovePathIndex`es.
     pub fn iter_locals_enumerated(
         &self,
-    ) -> impl DoubleEndedIterator<Item = (Local, &MovePathIndex)> + ExactSizeIterator {
-        self.locals.iter_enumerated()
+    ) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ {
+        self.locals.iter_enumerated().map(|(l, &idx)| (l, idx))
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index eaf3f19bff1..9d198ef2f7a 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -127,7 +127,10 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
                 &AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => {
                     let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
                         self.tcx.unsafety_check_result(def_id.expect_local());
-                    self.register_violations(violations, used_unsafe_blocks);
+                    self.register_violations(
+                        violations,
+                        used_unsafe_blocks.iter().map(|(&h, &d)| (h, d)),
+                    );
                 }
             },
             _ => {}
@@ -261,7 +264,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
     fn register_violations<'a>(
         &mut self,
         violations: impl IntoIterator<Item = &'a UnsafetyViolation>,
-        new_used_unsafe_blocks: impl IntoIterator<Item = (&'a HirId, &'a UsedUnsafeBlockData)>,
+        new_used_unsafe_blocks: impl IntoIterator<Item = (HirId, UsedUnsafeBlockData)>,
     ) {
         use UsedUnsafeBlockData::{AllAllowedInUnsafeFn, SomeDisallowedInUnsafeFn};
 
@@ -318,7 +321,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
 
         new_used_unsafe_blocks
             .into_iter()
-            .for_each(|(&hir_id, &usage_data)| update_entry(self, hir_id, usage_data));
+            .for_each(|(hir_id, usage_data)| update_entry(self, hir_id, usage_data));
     }
     fn check_mut_borrowing_layout_constrained_field(
         &mut self,
@@ -333,7 +336,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
                 ProjectionElem::Field(..) => {
                     let ty = place_base.ty(&self.body.local_decls, self.tcx).ty;
                     if let ty::Adt(def, _) = ty.kind() {
-                        if self.tcx.layout_scalar_valid_range(def.did)
+                        if self.tcx.layout_scalar_valid_range(def.did())
                             != (Bound::Unbounded, Bound::Unbounded)
                         {
                             let details = if is_mut_use {
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 55f7e70db8f..6bb7e676e85 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -48,7 +48,7 @@ impl CoverageGraph {
                 let mut bcb_successors = Vec::new();
                 for successor in
                     bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind)
-                        .filter_map(|&successor_bb| bb_to_bcb[successor_bb])
+                        .filter_map(|successor_bb| bb_to_bcb[successor_bb])
                 {
                     if !seen[successor] {
                         seen[successor] = true;
@@ -483,7 +483,7 @@ impl std::fmt::Debug for BcbBranch {
 fn bcb_filtered_successors<'a, 'tcx>(
     body: &'tcx &'a mir::Body<'tcx>,
     term_kind: &'tcx TerminatorKind<'tcx>,
-) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a> {
+) -> Box<dyn Iterator<Item = BasicBlock> + 'a> {
     let mut successors = term_kind.successors();
     Box::new(
         match &term_kind {
@@ -494,9 +494,8 @@ fn bcb_filtered_successors<'a, 'tcx>(
             // `next().into_iter()`) into the `mir::Successors` aliased type.
             _ => successors.next().into_iter().chain(&[]),
         }
-        .filter(move |&&successor| {
-            body[successor].terminator().kind != TerminatorKind::Unreachable
-        }),
+        .copied()
+        .filter(move |&successor| body[successor].terminator().kind != TerminatorKind::Unreachable),
     )
 }
 
@@ -695,7 +694,7 @@ pub struct ShortCircuitPreorder<
     F: Fn(
         &'tcx &'a mir::Body<'tcx>,
         &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
+    ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
 > {
     body: &'tcx &'a mir::Body<'tcx>,
     visited: BitSet<BasicBlock>,
@@ -709,7 +708,7 @@ impl<
     F: Fn(
         &'tcx &'a mir::Body<'tcx>,
         &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
+    ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
 > ShortCircuitPreorder<'a, 'tcx, F>
 {
     pub fn new(
@@ -733,7 +732,7 @@ impl<
     F: Fn(
         &'tcx &'a mir::Body<'tcx>,
         &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
+    ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
 > Iterator for ShortCircuitPreorder<'a, 'tcx, F>
 {
     type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index d9a66cace52..8bc7f5e9ce2 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -210,7 +210,7 @@ struct SuspensionPoint<'tcx> {
 
 struct TransformVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    state_adt_ref: &'tcx AdtDef,
+    state_adt_ref: AdtDef<'tcx>,
     state_substs: SubstsRef<'tcx>,
 
     // The type of the discriminant in the generator struct
@@ -243,11 +243,11 @@ impl<'tcx> TransformVisitor<'tcx> {
         val: Operand<'tcx>,
         source_info: SourceInfo,
     ) -> impl Iterator<Item = Statement<'tcx>> {
-        let kind = AggregateKind::Adt(self.state_adt_ref.did, idx, self.state_substs, None, None);
-        assert_eq!(self.state_adt_ref.variants[idx].fields.len(), 1);
+        let kind = AggregateKind::Adt(self.state_adt_ref.did(), idx, self.state_substs, None, None);
+        assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 1);
         let ty = self
             .tcx
-            .type_of(self.state_adt_ref.variants[idx].fields[0].did)
+            .type_of(self.state_adt_ref.variant(idx).fields[0].did)
             .subst(self.tcx, self.state_substs);
         expand_aggregate(
             Place::return_place(),
diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs
index 385fcc43496..d1c4a4b21d0 100644
--- a/compiler/rustc_mir_transform/src/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instcombine.rs
@@ -4,7 +4,7 @@ use crate::MirPass;
 use rustc_hir::Mutability;
 use rustc_middle::mir::{
     BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
-    StatementKind, UnOp,
+    Statement, StatementKind, Terminator, TerminatorKind, UnOp,
 };
 use rustc_middle::ty::{self, TyCtxt};
 
@@ -29,6 +29,11 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
                     _ => {}
                 }
             }
+
+            ctx.combine_primitive_clone(
+                &mut block.terminator.as_mut().unwrap(),
+                &mut block.statements,
+            );
         }
     }
 }
@@ -130,4 +135,70 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
             }
         }
     }
+
+    fn combine_primitive_clone(
+        &self,
+        terminator: &mut Terminator<'tcx>,
+        statements: &mut Vec<Statement<'tcx>>,
+    ) {
+        let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind
+        else { return };
+
+        // It's definitely not a clone if there are multiple arguments
+        if args.len() != 1 {
+            return;
+        }
+
+        let Some((destination_place, destination_block)) = *destination
+        else { return };
+
+        // Only bother looking more if it's easy to know what we're calling
+        let Some((fn_def_id, fn_substs)) = func.const_fn_def()
+        else { return };
+
+        // Clone needs one subst, so we can cheaply rule out other stuff
+        if fn_substs.len() != 1 {
+            return;
+        }
+
+        // These types are easily available from locals, so check that before
+        // doing DefId lookups to figure out what we're actually calling.
+        let arg_ty = args[0].ty(self.local_decls, self.tcx);
+
+        let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind()
+        else { return };
+
+        if !inner_ty.is_trivially_pure_clone_copy() {
+            return;
+        }
+
+        let trait_def_id = self.tcx.trait_of_item(fn_def_id);
+        if trait_def_id.is_none() || trait_def_id != self.tcx.lang_items().clone_trait() {
+            return;
+        }
+
+        if !self.tcx.consider_optimizing(|| {
+            format!(
+                "InstCombine - Call: {:?} SourceInfo: {:?}",
+                (fn_def_id, fn_substs),
+                terminator.source_info
+            )
+        }) {
+            return;
+        }
+
+        let Some(arg_place) = args.pop().unwrap().place()
+        else { return };
+
+        statements.push(Statement {
+            source_info: terminator.source_info,
+            kind: StatementKind::Assign(box (
+                destination_place,
+                Rvalue::Use(Operand::Copy(
+                    arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx),
+                )),
+            )),
+        });
+        terminator.kind = TerminatorKind::Goto { target: destination_block };
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index 4167f8df11c..d7fb7063114 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -124,7 +124,7 @@ fn is_needs_drop_and_init<'tcx>(
             //
             // If its projection *is* present in `MoveData`, then the field may have been moved
             // from separate from its parent. Recurse.
-            adt.variants.iter_enumerated().any(|(vid, variant)| {
+            adt.variants().iter_enumerated().any(|(vid, variant)| {
                 // Enums have multiple variants, which are discriminated with a `Downcast` projection.
                 // Structs have a single variant, and don't use a `Downcast` projection.
                 let mpi = if adt.is_enum() {
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 9533e869bc5..bf031b423c2 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -760,10 +760,10 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
 
     let statements = expand_aggregate(
         Place::return_place(),
-        adt_def.variants[variant_index].fields.iter().enumerate().map(|(idx, field_def)| {
+        adt_def.variant(variant_index).fields.iter().enumerate().map(|(idx, field_def)| {
             (Operand::Move(Place::from(Local::new(idx + 1))), field_def.ty(tcx, substs))
         }),
-        AggregateKind::Adt(adt_def.did, variant_index, substs, None, None),
+        AggregateKind::Adt(adt_def.did(), variant_index, substs, None, None),
         source_info,
         tcx,
     )
diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs
index d5507fcc78c..884c5fb765f 100644
--- a/compiler/rustc_mir_transform/src/simplify_try.rs
+++ b/compiler/rustc_mir_transform/src/simplify_try.rs
@@ -707,7 +707,7 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
     ) -> StatementEquality {
         let helper = |rhs: &Rvalue<'tcx>,
                       place: &Place<'tcx>,
-                      variant_index: &VariantIdx,
+                      variant_index: VariantIdx,
                       switch_value: u128,
                       side_to_choose| {
             let place_type = place.ty(self.body, self.tcx).ty;
@@ -717,7 +717,7 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
             };
             // We need to make sure that the switch value that targets the bb with
             // SetDiscriminant is the same as the variant discriminant.
-            let variant_discr = adt.discriminant_for_variant(self.tcx, *variant_index).val;
+            let variant_discr = adt.discriminant_for_variant(self.tcx, variant_index).val;
             if variant_discr != switch_value {
                 trace!(
                     "NO: variant discriminant {} does not equal switch value {}",
@@ -726,7 +726,7 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
                 );
                 return StatementEquality::NotEqual;
             }
-            let variant_is_fieldless = adt.variants[*variant_index].fields.is_empty();
+            let variant_is_fieldless = adt.variant(variant_index).fields.is_empty();
             if !variant_is_fieldless {
                 trace!("NO: variant {:?} was not fieldless", variant_index);
                 return StatementEquality::NotEqual;
@@ -753,7 +753,7 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
             // check for case A
             (
                 StatementKind::Assign(box (_, rhs)),
-                StatementKind::SetDiscriminant { place, variant_index },
+                &StatementKind::SetDiscriminant { ref place, variant_index },
             ) if y_target_and_value.value.is_some() => {
                 // choose basic block of x, as that has the assign
                 helper(
@@ -765,8 +765,8 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
                 )
             }
             (
-                StatementKind::SetDiscriminant { place, variant_index },
-                StatementKind::Assign(box (_, rhs)),
+                &StatementKind::SetDiscriminant { ref place, variant_index },
+                &StatementKind::Assign(box (_, ref rhs)),
             ) if x_target_and_value.value.is_some() => {
                 // choose basic block of y, as that has the assign
                 helper(
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index 7133724d07d..bd196f11879 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -65,7 +65,7 @@ fn variant_discriminants<'tcx>(
         Variants::Multiple { variants, .. } => variants
             .iter_enumerated()
             .filter_map(|(idx, layout)| {
-                (layout.abi != Abi::Uninhabited)
+                (layout.abi() != Abi::Uninhabited)
                     .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
             })
             .collect(),
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 40daf4eb28f..21d5bec65f0 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2073,6 +2073,19 @@ impl<'a> Parser<'a> {
                     let value = self.mk_expr_err(start.to(expr.span));
                     err.emit();
                     return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
+                } else if token::Colon == snapshot.token.kind
+                    && expr.span.lo() == snapshot.token.span.hi()
+                    && matches!(expr.kind, ExprKind::Path(..))
+                {
+                    // Find a mistake like "foo::var:A".
+                    err.span_suggestion(
+                        snapshot.token.span,
+                        "write a path separator here",
+                        "::".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                    err.emit();
+                    return Ok(GenericArg::Type(self.mk_ty(start.to(expr.span), TyKind::Err)));
                 } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg()
                 {
                     // Avoid the following output by checking that we consumed a full const arg:
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index df865d77b9b..b993d48c995 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -20,7 +20,6 @@ use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult};
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
 use rustc_session::lint::BuiltinLintDiagnostics;
-use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Pos};
@@ -2712,8 +2711,7 @@ impl<'a> Parser<'a> {
         let mut async_block_err = |e: &mut Diagnostic, span: Span| {
             recover_async = true;
             e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
-            e.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
-            e.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+            e.help_use_latest_edition();
         };
 
         while self.token != token::CloseDelim(close_delim) {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 5db1e4e0523..122fe10e80f 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -14,7 +14,7 @@ use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, Visibility
 use rustc_ast::{MacArgs, MacCall, MacDelimiter};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
-use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
+use rustc_span::edition::Edition;
 use rustc_span::lev_distance::lev_distance;
 use rustc_span::source_map::{self, Span};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -1534,6 +1534,16 @@ impl<'a> Parser<'a> {
         let name = self.parse_field_ident(adt_ty, lo)?;
         self.expect_field_ty_separator()?;
         let ty = self.parse_ty()?;
+        if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
+            self.struct_span_err(self.token.span, "found single colon in a struct field type path")
+                .span_suggestion_verbose(
+                    self.token.span,
+                    "write a path separator here",
+                    "::".to_string(),
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
+        }
         if self.token.kind == token::Eq {
             self.bump();
             let const_expr = self.parse_anon_const_expr()?;
@@ -2102,8 +2112,7 @@ impl<'a> Parser<'a> {
             let diag = self.diagnostic();
             struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015")
                 .span_label(span, "to use `async fn`, switch to Rust 2018 or later")
-                .help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION))
-                .note("for more on editions, read https://doc.rust-lang.org/edition-guide")
+                .help_use_latest_edition()
                 .emit();
         }
     }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index d94ad7ba71a..01b12eec628 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -4,7 +4,7 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
+use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, struct_span_err, Applicability};
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@@ -178,34 +178,7 @@ impl CheckAttrVisitor<'_> {
                 check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
             }
 
-            // Warn on useless empty attributes.
-            if matches!(
-                attr.name_or_empty(),
-                sym::macro_use
-                    | sym::allow
-                    | sym::warn
-                    | sym::deny
-                    | sym::forbid
-                    | sym::feature
-                    | sym::repr
-                    | sym::target_feature
-            ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
-            {
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    lint.build("unused attribute")
-                        .span_suggestion(
-                            attr.span,
-                            "remove this attribute",
-                            String::new(),
-                            Applicability::MachineApplicable,
-                        )
-                        .note(&format!(
-                            "attribute `{}` with an empty list has no effect",
-                            attr.name_or_empty()
-                        ))
-                        .emit();
-                });
-            }
+            self.check_unused_attribute(hir_id, attr)
         }
 
         if !is_valid {
@@ -1372,7 +1345,7 @@ impl CheckAttrVisitor<'_> {
         target: Target,
         item: Option<ItemLike<'_>>,
     ) -> bool {
-        let is_function = matches!(target, Target::Fn | Target::Method(..));
+        let is_function = matches!(target, Target::Fn);
         if !is_function {
             self.tcx
                 .sess
@@ -1969,6 +1942,55 @@ impl CheckAttrVisitor<'_> {
             });
         }
     }
+
+    fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
+        // Warn on useless empty attributes.
+        let note = if matches!(
+            attr.name_or_empty(),
+            sym::macro_use
+                | sym::allow
+                | sym::expect
+                | sym::warn
+                | sym::deny
+                | sym::forbid
+                | sym::feature
+                | sym::repr
+                | sym::target_feature
+        ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
+        {
+            format!(
+                "attribute `{}` with an empty list has no effect",
+                attr.name_or_empty()
+            )
+        } else if matches!(
+                attr.name_or_empty(),
+                sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
+            ) && let Some(meta) = attr.meta_item_list()
+            && meta.len() == 1
+            && let Some(item) = meta[0].meta_item()
+            && let MetaItemKind::NameValue(_) = &item.kind
+            && item.path == sym::reason
+        {
+            format!(
+                "attribute `{}` without any lints has no effect",
+                attr.name_or_empty()
+            )
+        } else {
+            return;
+        };
+
+        self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+            lint.build("unused attribute")
+                .span_suggestion(
+                    attr.span,
+                    "remove this attribute",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+                .note(&note)
+                .emit();
+        });
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index e438b521a95..c777074df46 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -259,7 +259,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                 if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) {
                     let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
                     if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
-                        if let Some(adt_def_id) = adt_def.did.as_local() {
+                        if let Some(adt_def_id) = adt_def.did().as_local() {
                             self.ignored_derived_traits
                                 .entry(adt_def_id)
                                 .or_default()
@@ -297,7 +297,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                 match item.kind {
                     hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
                         let def = self.tcx.adt_def(item.def_id);
-                        self.repr_has_repr_c = def.repr.c();
+                        self.repr_has_repr_c = def.repr().c();
 
                         intravisit::walk_item(self, &item);
                     }
@@ -328,8 +328,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         self.repr_has_repr_c = had_repr_c;
     }
 
-    fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &[hir::ExprField<'_>]) {
-        if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did.is_local() {
+    fn mark_as_used_if_union(&mut self, adt: ty::AdtDef<'tcx>, fields: &[hir::ExprField<'_>]) {
+        if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did().is_local() {
             for field in fields {
                 let index = self.tcx.field_index(field.hir_id, self.typeck_results());
                 self.insert_def_id(adt.non_enum_variant().fields[index].did);
@@ -382,8 +382,8 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
             hir::ExprKind::Struct(ref qpath, ref fields, _) => {
                 let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
                 self.handle_res(res);
-                if let ty::Adt(ref adt, _) = self.typeck_results().expr_ty(expr).kind() {
-                    self.mark_as_used_if_union(adt, fields);
+                if let ty::Adt(adt, _) = self.typeck_results().expr_ty(expr).kind() {
+                    self.mark_as_used_if_union(*adt, fields);
                 }
             }
             _ => (),
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index b2129ce9f24..6316f3b8459 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -38,22 +38,22 @@ struct ExprVisitor<'tcx> {
 fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
     let ty::Adt(def, substs) = *ty.kind() else { return ty };
 
-    if def.variants.len() == 2 && !def.repr.c() && def.repr.int.is_none() {
+    if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
         let data_idx;
 
         let one = VariantIdx::new(1);
         let zero = VariantIdx::new(0);
 
-        if def.variants[zero].fields.is_empty() {
+        if def.variant(zero).fields.is_empty() {
             data_idx = one;
-        } else if def.variants[one].fields.is_empty() {
+        } else if def.variant(one).fields.is_empty() {
             data_idx = zero;
         } else {
             return ty;
         }
 
-        if def.variants[data_idx].fields.len() == 1 {
-            return def.variants[data_idx].fields[0].ty(tcx, substs);
+        if def.variant(data_idx).fields.len() == 1 {
+            return def.variant(data_idx).fields[0].ty(tcx, substs);
         }
     }
 
@@ -165,7 +165,7 @@ impl<'tcx> ExprVisitor<'tcx> {
             ty::RawPtr(ty::TypeAndMut { ty, mutbl: _ }) if self.is_thin_ptr_ty(ty) => {
                 Some(asm_ty_isize)
             }
-            ty::Adt(adt, substs) if adt.repr.simd() => {
+            ty::Adt(adt, substs) if adt.repr().simd() => {
                 let fields = &adt.non_enum_variant().fields;
                 let elem_ty = fields[0].ty(self.tcx, substs);
                 match elem_ty.kind() {
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 37a9f0ecd8c..f36a1f61aac 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -202,7 +202,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                     self.tcx.sess,
                     *span,
                     E0549,
-                    "rustc_deprecated attribute must be paired with \
+                    "deprecated attribute must be paired with \
                     either stable or unstable attribute"
                 )
                 .emit();
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index fd1c0239b59..fdda77d01b3 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -9,6 +9,7 @@
 use rustc_ast::MacroDef;
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::intern::Interned;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -182,7 +183,7 @@ where
         let tcx = self.def_id_visitor.tcx();
         // InternalSubsts are not visited here because they are visited below in `super_visit_with`.
         match *ty.kind() {
-            ty::Adt(&ty::AdtDef { did: def_id, .. }, ..)
+            ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), ..)
             | ty::Foreign(def_id)
             | ty::FnDef(def_id, ..)
             | ty::Closure(def_id, ..)
@@ -930,7 +931,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         &mut self,
         use_ctxt: Span,        // syntax context of the field name at the use site
         span: Span,            // span of the field pattern, e.g., `x: 0`
-        def: &'tcx ty::AdtDef, // definition of the struct or enum
+        def: ty::AdtDef<'tcx>, // definition of the struct or enum
         field: &'tcx ty::FieldDef,
         in_update_syntax: bool,
     ) {
@@ -941,7 +942,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         // definition of the field
         let ident = Ident::new(kw::Empty, use_ctxt);
         let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.current_item);
-        let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, hir_id).1;
+        let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1;
         if !field.vis.is_accessible_from(def_id, self.tcx) {
             let label = if in_update_syntax {
                 format!("field `{}` is private", field.name)
@@ -956,7 +957,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
                 "field `{}` of {} `{}` is private",
                 field.name,
                 def.variant_descr(),
-                self.tcx.def_path_str(def.did)
+                self.tcx.def_path_str(def.did())
             )
             .span_label(span, label)
             .emit();
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index cf71f9b3fc5..d071d66ffa6 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -554,7 +554,7 @@ impl<'tcx> SaveContext<'tcx> {
                     Some(Data::RefData(Ref {
                         kind: RefKind::Type,
                         span,
-                        ref_id: id_from_def_id(def.did),
+                        ref_id: id_from_def_id(def.did()),
                     }))
                 }
                 _ => {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 221dc86c1d4..1d36ff059de 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1072,6 +1072,7 @@ impl CrateCheckConfig {
         // NOTE: This should be kept in sync with `default_configuration` and
         // `fill_well_known_values`
         const WELL_KNOWN_NAMES: &[Symbol] = &[
+            // rustc
             sym::unix,
             sym::windows,
             sym::target_os,
@@ -1091,9 +1092,12 @@ impl CrateCheckConfig {
             sym::debug_assertions,
             sym::proc_macro,
             sym::test,
+            sym::feature,
+            // rustdoc
             sym::doc,
             sym::doctest,
-            sym::feature,
+            // miri
+            sym::miri,
         ];
 
         // We only insert well-known names if `names()` was activated
@@ -1128,13 +1132,14 @@ impl CrateCheckConfig {
 
         // No-values
         for name in [
+            sym::doc,
+            sym::miri,
             sym::unix,
-            sym::windows,
-            sym::debug_assertions,
-            sym::proc_macro,
             sym::test,
-            sym::doc,
             sym::doctest,
+            sym::windows,
+            sym::proc_macro,
+            sym::debug_assertions,
             sym::target_thread_local,
         ] {
             self.values_valid.entry(name).or_default();
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 38ddb841d96..d34a3360a83 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -98,7 +98,26 @@ pub fn feature_err_issue<'a>(
     explain: &str,
 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
     let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
+    add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
+    err
+}
+
+/// Adds the diagnostics for a feature to an existing error.
+pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) {
+    add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language);
+}
 
+/// Adds the diagnostics for a feature to an existing error.
+///
+/// This variant allows you to control whether it is a library or language feature.
+/// Almost always, you want to use this for a language feature. If so, prefer
+/// `add_feature_diagnostics`.
+pub fn add_feature_diagnostics_for_issue<'a>(
+    err: &mut Diagnostic,
+    sess: &'a ParseSess,
+    feature: Symbol,
+    issue: GateIssue,
+) {
     if let Some(n) = find_feature_issue(feature, issue) {
         err.note(&format!(
             "see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
@@ -110,8 +129,6 @@ pub fn feature_err_issue<'a>(
     if sess.unstable_features.is_nightly_build() {
         err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
     }
-
-    err
 }
 
 /// Info about a parsing session.
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 56da7c43728..6d1b36796d8 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -27,8 +27,8 @@ impl CrateNum {
     }
 
     #[inline]
-    pub fn as_def_id(&self) -> DefId {
-        DefId { krate: *self, index: CRATE_DEF_INDEX }
+    pub fn as_def_id(self) -> DefId {
+        DefId { krate: self, index: CRATE_DEF_INDEX }
     }
 }
 
@@ -222,6 +222,7 @@ impl<D: Decoder> Decodable<D> for DefIndex {
 // On below-64 bit systems we can simply use the derived `Hash` impl
 #[cfg_attr(not(target_pointer_width = "64"), derive(Hash))]
 #[repr(C)]
+#[rustc_pass_by_value]
 // We guarantee field order. Note that the order is essential here, see below why.
 pub struct DefId {
     // cfg-ing the order of fields so that the `DefIndex` which is high entropy always ends up in
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 5fae46d5fd8..86adfa7a18c 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -85,10 +85,17 @@ rustc_index::newtype_index! {
     /// A unique ID associated with a macro invocation and expansion.
     pub struct LocalExpnId {
         ENCODABLE = custom
+        ORD_IMPL = custom
         DEBUG_FORMAT = "expn{}"
     }
 }
 
+// To ensure correctness of incremental compilation,
+// `LocalExpnId` must not implement `Ord` or `PartialOrd`.
+// See https://github.com/rust-lang/rust/issues/90317.
+impl !Ord for LocalExpnId {}
+impl !PartialOrd for LocalExpnId {}
+
 /// Assert that the provided `HashStableContext` is configured with the 'default'
 /// `HashingControls`. We should always have bailed out before getting to here
 /// with a non-default mode. With this check in place, we can avoid the need
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 3f44292e034..967eb3cc22a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -562,6 +562,7 @@ symbols! {
         delay_span_bug_from_inside_query,
         deny,
         deprecated,
+        deprecated_suggestion,
         deref,
         deref_method,
         deref_mut,
@@ -845,6 +846,7 @@ symbols! {
         macro_export,
         macro_lifetime_matcher,
         macro_literal_matcher,
+        macro_metavar_expr,
         macro_reexport,
         macro_use,
         macro_vis_matcher,
@@ -891,6 +893,7 @@ symbols! {
         minnumf32,
         minnumf64,
         mips_target_feature,
+        miri,
         misc,
         mmx_reg,
         modifiers,
@@ -1383,6 +1386,7 @@ symbols! {
         test_case,
         test_removed_feature,
         test_runner,
+        test_unstable_lint,
         then_with,
         thread,
         thread_local,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index a9c41ce0c4e..c8fdf363f05 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::base_n;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::intern::Interned;
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{CrateNum, DefId};
@@ -453,7 +454,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
             }
 
             // Mangle all nominal types as paths.
-            ty::Adt(&ty::AdtDef { did: def_id, .. }, substs)
+            ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
             | ty::FnDef(def_id, substs)
             | ty::Opaque(def_id, substs)
             | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
@@ -684,7 +685,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
                     ty::Adt(def, substs) => {
                         let variant_idx =
                             contents.variant.expect("destructed const of adt without variant idx");
-                        let variant_def = &def.variants[variant_idx];
+                        let variant_def = &def.variant(variant_idx);
 
                         self.push("V");
                         self = self.print_def_path(variant_def.def_id, substs)?;
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 4ef86371298..fb5e0272cc3 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -10,6 +10,7 @@ use std::num::NonZeroUsize;
 use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
 use std::str::FromStr;
 
+use rustc_data_structures::intern::Interned;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::json::{Json, ToJson};
@@ -1024,7 +1025,7 @@ rustc_index::newtype_index! {
 }
 
 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum Variants {
+pub enum Variants<'a> {
     /// Single enum variants, structs/tuples, unions, and all non-ADTs.
     Single { index: VariantIdx },
 
@@ -1038,7 +1039,7 @@ pub enum Variants {
         tag: Scalar,
         tag_encoding: TagEncoding,
         tag_field: usize,
-        variants: IndexVec<VariantIdx, Layout>,
+        variants: IndexVec<VariantIdx, Layout<'a>>,
     },
 }
 
@@ -1146,8 +1147,8 @@ impl Niche {
     }
 }
 
-#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub struct Layout {
+#[derive(PartialEq, Eq, Hash, HashStable_Generic)]
+pub struct LayoutS<'a> {
     /// Says where the fields are located within the layout.
     pub fields: FieldsShape,
 
@@ -1158,7 +1159,7 @@ pub struct Layout {
     ///
     /// To access all fields of this layout, both `fields` and the fields of the active variant
     /// must be taken into account.
-    pub variants: Variants,
+    pub variants: Variants<'a>,
 
     /// The `abi` defines how this data is passed between functions, and it defines
     /// value restrictions via `valid_range`.
@@ -1177,12 +1178,12 @@ pub struct Layout {
     pub size: Size,
 }
 
-impl Layout {
+impl<'a> LayoutS<'a> {
     pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
         let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
         let size = scalar.value.size(cx);
         let align = scalar.value.align(cx);
-        Layout {
+        LayoutS {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Primitive,
             abi: Abi::Scalar(scalar),
@@ -1193,6 +1194,59 @@ impl Layout {
     }
 }
 
+impl<'a> fmt::Debug for LayoutS<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // This is how `Layout` used to print before it become
+        // `Interned<LayoutS>`. We print it like this to avoid having to update
+        // expected output in a lot of tests.
+        f.debug_struct("Layout")
+            .field("fields", &self.fields)
+            .field("variants", &self.variants)
+            .field("abi", &self.abi)
+            .field("largest_niche", &self.largest_niche)
+            .field("align", &self.align)
+            .field("size", &self.size)
+            .finish()
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Layout<'a>(pub Interned<'a, LayoutS<'a>>);
+
+impl<'a> fmt::Debug for Layout<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // See comment on `<LayoutS as Debug>::fmt` above.
+        self.0.0.fmt(f)
+    }
+}
+
+impl<'a> Layout<'a> {
+    pub fn fields(self) -> &'a FieldsShape {
+        &self.0.0.fields
+    }
+
+    pub fn variants(self) -> &'a Variants<'a> {
+        &self.0.0.variants
+    }
+
+    pub fn abi(self) -> Abi {
+        self.0.0.abi
+    }
+
+    pub fn largest_niche(self) -> Option<Niche> {
+        self.0.0.largest_niche
+    }
+
+    pub fn align(self) -> AbiAndPrefAlign {
+        self.0.0.align
+    }
+
+    pub fn size(self) -> Size {
+        self.0.0.size
+    }
+}
+
 /// The layout of a type, alongside the type itself.
 /// Provides various type traversal APIs (e.g., recursing into fields).
 ///
@@ -1203,13 +1257,13 @@ impl Layout {
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
 pub struct TyAndLayout<'a, Ty> {
     pub ty: Ty,
-    pub layout: &'a Layout,
+    pub layout: Layout<'a>,
 }
 
 impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
-    type Target = &'a Layout;
-    fn deref(&self) -> &&'a Layout {
-        &self.layout
+    type Target = &'a LayoutS<'a>;
+    fn deref(&self) -> &&'a LayoutS<'a> {
+        &self.layout.0.0
     }
 }
 
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index 2919743e499..e9ef71ede51 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -8,13 +8,14 @@
 //! LLVM.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(bool_to_option)]
-#![feature(let_else)]
-#![feature(nll)]
-#![feature(never_type)]
 #![feature(associated_type_bounds)]
+#![feature(bool_to_option)]
 #![feature(exhaustive_patterns)]
+#![feature(let_else)]
 #![feature(min_specialization)]
+#![feature(never_type)]
+#![feature(nll)]
+#![feature(rustc_attrs)]
 #![feature(step_trait)]
 
 use std::iter::FromIterator;
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 63efa951f96..a3d32acc6fb 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -676,7 +676,7 @@ fn fundamental_ty_inner_tys<'tcx>(
             match types.next() {
                 None => {
                     tcx.sess.span_err(
-                        tcx.def_span(def.did),
+                        tcx.def_span(def.did()),
                         "`#[fundamental]` requires at least one type parameter",
                     );
 
@@ -729,7 +729,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
             InCrate::Remote => true,
         },
 
-        ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
+        ty::Adt(def, _) => def_id_is_local(def.did(), in_crate),
         ty::Foreign(did) => def_id_is_local(did, in_crate),
         ty::Opaque(..) => {
             // This merits some explanation.
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 6655541461d..f880b28b3c8 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -35,34 +35,14 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
     span: Span,
 ) -> Result<(), NotConstEvaluatable> {
     debug!("is_const_evaluatable({:?})", uv);
-    if infcx.tcx.features().generic_const_exprs {
-        let tcx = infcx.tcx;
+    let tcx = infcx.tcx;
+
+    if tcx.features().generic_const_exprs {
         match AbstractConst::new(tcx, uv)? {
             // We are looking at a generic abstract constant.
             Some(ct) => {
-                for pred in param_env.caller_bounds() {
-                    match pred.kind().skip_binder() {
-                        ty::PredicateKind::ConstEvaluatable(uv) => {
-                            if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
-                                // Try to unify with each subtree in the AbstractConst to allow for
-                                // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
-                                // predicate for `(N + 1) * 2`
-                                let result =
-                                    walk_abstract_const(tcx, b_ct, |b_ct| {
-                                        match try_unify(tcx, ct, b_ct) {
-                                            true => ControlFlow::BREAK,
-                                            false => ControlFlow::CONTINUE,
-                                        }
-                                    });
-
-                                if let ControlFlow::Break(()) = result {
-                                    debug!("is_const_evaluatable: abstract_const ~~> ok");
-                                    return Ok(());
-                                }
-                            }
-                        }
-                        _ => {} // don't care
-                    }
+                if satisfied_from_param_env(tcx, ct, param_env)? {
+                    return Ok(());
                 }
 
                 // We were unable to unify the abstract constant with
@@ -163,6 +143,33 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
         }
     }
 
+    // If we're evaluating a foreign constant, under a nightly compiler without generic
+    // const exprs, AND it would've passed if that expression had been evaluated with
+    // generic const exprs, then suggest using generic const exprs.
+    if concrete.is_err()
+        && tcx.sess.is_nightly_build()
+        && !uv.def.did.is_local()
+        && !tcx.features().generic_const_exprs
+        && let Ok(Some(ct)) = AbstractConst::new(tcx, uv)
+        && satisfied_from_param_env(tcx, ct, param_env) == Ok(true)
+    {
+        tcx.sess
+            .struct_span_fatal(
+                // Slightly better span than just using `span` alone
+                if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
+                "failed to evaluate generic const expression",
+            )
+            .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
+            .span_suggestion_verbose(
+                rustc_span::DUMMY_SP,
+                "consider enabling this feature",
+                "#![feature(generic_const_exprs)]\n".to_string(),
+                rustc_errors::Applicability::MaybeIncorrect,
+            )
+            .emit();
+        rustc_errors::FatalError.raise();
+    }
+
     debug!(?concrete, "is_const_evaluatable");
     match concrete {
         Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() {
@@ -178,6 +185,37 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
     }
 }
 
+fn satisfied_from_param_env<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ct: AbstractConst<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> Result<bool, NotConstEvaluatable> {
+    for pred in param_env.caller_bounds() {
+        match pred.kind().skip_binder() {
+            ty::PredicateKind::ConstEvaluatable(uv) => {
+                if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
+                    // Try to unify with each subtree in the AbstractConst to allow for
+                    // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
+                    // predicate for `(N + 1) * 2`
+                    let result =
+                        walk_abstract_const(tcx, b_ct, |b_ct| match try_unify(tcx, ct, b_ct) {
+                            true => ControlFlow::BREAK,
+                            false => ControlFlow::CONTINUE,
+                        });
+
+                    if let ControlFlow::Break(()) = result {
+                        debug!("is_const_evaluatable: abstract_const ~~> ok");
+                        return Ok(true);
+                    }
+                }
+            }
+            _ => {} // don't care
+        }
+    }
+
+    Ok(false)
+}
+
 /// A tree representing an anonymous constant.
 ///
 /// This is only able to represent a subset of `MIR`,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index ccbd2dedfea..28c596c4e53 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -813,7 +813,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     | ty::Foreign(did)
                     | ty::FnDef(did, _)
                     | ty::Generator(did, ..) => Some(did),
-                    ty::Adt(def, _) => Some(def.did),
+                    ty::Adt(def, _) => Some(def.did()),
                     _ => None,
                 };
 
@@ -1467,7 +1467,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                 ty::Bool => Some(0),
                 ty::Char => Some(1),
                 ty::Str => Some(2),
-                ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did) => Some(2),
+                ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did()) => Some(2),
                 ty::Int(..)
                 | ty::Uint(..)
                 | ty::Float(..)
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index a277f74f7a4..d2b1fe2e0df 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -4,20 +4,20 @@ use super::{
 use crate::infer::InferCtxt;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, GenericParamDefKind};
 use rustc_span::symbol::sym;
 use std::iter;
 
 use super::InferCtxtPrivExt;
 
-crate trait InferCtxtExt<'tcx> {
+pub trait InferCtxtExt<'tcx> {
     /*private*/
     fn impl_similar_to(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
         obligation: &PredicateObligation<'tcx>,
-    ) -> Option<DefId>;
+    ) -> Option<(DefId, SubstsRef<'tcx>)>;
 
     /*private*/
     fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>;
@@ -34,7 +34,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
         obligation: &PredicateObligation<'tcx>,
-    ) -> Option<DefId> {
+    ) -> Option<(DefId, SubstsRef<'tcx>)> {
         let tcx = self.tcx;
         let param_env = obligation.param_env;
         let trait_ref = tcx.erase_late_bound_regions(trait_ref);
@@ -50,7 +50,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             let impl_self_ty = impl_trait_ref.self_ty();
 
             if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
-                self_match_impls.push(def_id);
+                self_match_impls.push((def_id, impl_substs));
 
                 if iter::zip(
                     trait_ref.substs.types().skip(1),
@@ -58,12 +58,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 )
                 .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
                 {
-                    fuzzy_match_impls.push(def_id);
+                    fuzzy_match_impls.push((def_id, impl_substs));
                 }
             }
         });
 
-        let impl_def_id = if self_match_impls.len() == 1 {
+        let impl_def_id_and_substs = if self_match_impls.len() == 1 {
             self_match_impls[0]
         } else if fuzzy_match_impls.len() == 1 {
             fuzzy_match_impls[0]
@@ -71,7 +71,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             return None;
         };
 
-        tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
+        tcx.has_attr(impl_def_id_and_substs.0, sym::rustc_on_unimplemented)
+            .then_some(impl_def_id_and_substs)
     }
 
     /// Used to set on_unimplemented's `ItemContext`
@@ -120,8 +121,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         trait_ref: ty::PolyTraitRef<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     ) -> OnUnimplementedNote {
-        let def_id =
-            self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
+        let (def_id, substs) = self
+            .impl_similar_to(trait_ref, obligation)
+            .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
         let trait_ref = trait_ref.skip_binder();
 
         let mut flags = vec![(
@@ -170,13 +172,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             if let Some(def) = self_ty.ty_adt_def() {
                 // We also want to be able to select self's original
                 // signature with no type arguments resolved
-                flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
+                flags.push((sym::_Self, Some(self.tcx.type_of(def.did()).to_string())));
             }
 
             for param in generics.params.iter() {
                 let value = match param.kind {
                     GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
-                        trait_ref.substs[param.index as usize].to_string()
+                        substs[param.index as usize].to_string()
                     }
                     GenericParamDefKind::Lifetime => continue,
                 };
@@ -184,16 +186,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 flags.push((name, Some(value)));
 
                 if let GenericParamDefKind::Type { .. } = param.kind {
-                    let param_ty = trait_ref.substs[param.index as usize].expect_ty();
+                    let param_ty = substs[param.index as usize].expect_ty();
                     if let Some(def) = param_ty.ty_adt_def() {
                         // We also want to be able to select the parameter's
                         // original signature with no type arguments resolved
-                        flags.push((name, Some(self.tcx.type_of(def.did).to_string())));
+                        flags.push((name, Some(self.tcx.type_of(def.did()).to_string())));
                     }
                 }
             }
 
-            if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
+            if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
                 flags.push((sym::crate_local, None));
             }
 
@@ -202,13 +204,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 flags.push((sym::_Self, Some("{integral}".to_owned())));
             }
 
+            if self_ty.is_array_slice() {
+                flags.push((sym::_Self, Some("&[]".to_owned())));
+            }
+
             if let ty::Array(aty, len) = self_ty.kind() {
                 flags.push((sym::_Self, Some("[]".to_owned())));
                 flags.push((sym::_Self, Some(format!("[{}]", aty))));
                 if let Some(def) = aty.ty_adt_def() {
                     // We also want to be able to select the array's type's original
                     // signature with no type arguments resolved
-                    let type_string = self.tcx.type_of(def.did).to_string();
+                    let type_string = self.tcx.type_of(def.did()).to_string();
                     flags.push((sym::_Self, Some(format!("[{}]", type_string))));
 
                     let len =
@@ -229,9 +235,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             }
         });
 
-        if let Ok(Some(command)) =
-            OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
-        {
+        if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
             command.evaluate(self.tcx, trait_ref, &flags)
         } else {
             OnUnimplementedNote::default()
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 f2ddc3ea7fa..b617067e66d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2129,7 +2129,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if !is_upvar_tys_infer_tuple {
                     let msg = format!("required because it appears within the type `{}`", ty);
                     match ty.kind() {
-                        ty::Adt(def, _) => match self.tcx.opt_item_name(def.did) {
+                        ty::Adt(def, _) => match self.tcx.opt_item_name(def.did()) {
                             Some(ident) => err.span_note(ident.span, &msg),
                             None => err.note(&msg),
                         },
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index b4b2e4cd042..62c6c845479 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -346,6 +346,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
 
         let obligation = &mut pending_obligation.obligation;
 
+        debug!(?obligation, "process_obligation pre-resolve");
+
         if obligation.predicate.has_infer_types_or_consts() {
             obligation.predicate =
                 self.selcx.infcx().resolve_vars_if_possible(obligation.predicate);
@@ -355,6 +357,21 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
 
         let infcx = self.selcx.infcx();
 
+        if obligation.predicate.has_projections() {
+            let mut obligations = Vec::new();
+            let predicate = crate::traits::project::try_normalize_with_depth_to(
+                self.selcx,
+                obligation.param_env,
+                obligation.cause.clone(),
+                obligation.recursion_depth + 1,
+                obligation.predicate,
+                &mut obligations,
+            );
+            if predicate != obligation.predicate {
+                obligations.push(obligation.with(predicate));
+                return ProcessResult::Changed(mk_pending(obligations));
+            }
+        }
         let binder = obligation.predicate.kind();
         match binder.no_bound_vars() {
             None => match binder.skip_binder() {
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index c293708dcc9..08308253ced 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -43,7 +43,7 @@ pub fn can_type_implement_copy<'tcx>(
         };
 
         let mut infringing = Vec::new();
-        for variant in &adt.variants {
+        for variant in adt.variants() {
             for field in &variant.fields {
                 let ty = field.ty(tcx, substs);
                 if ty.references_error() {
@@ -56,7 +56,7 @@ pub fn can_type_implement_copy<'tcx>(
                 // If it does not, then this field probably doesn't normalize
                 // to begin with, and point to the bad field's span instead.
                 let cause = if field
-                    .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did))
+                    .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
                     .has_param_types_or_consts()
                 {
                     cause.clone()
diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
index 9752ff45323..2f697c1fa27 100644
--- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
@@ -54,7 +54,7 @@ fn parse_error(
 impl<'tcx> OnUnimplementedDirective {
     fn parse(
         tcx: TyCtxt<'tcx>,
-        trait_def_id: DefId,
+        item_def_id: DefId,
         items: &[NestedMetaItem],
         span: Span,
         is_root: bool,
@@ -63,7 +63,7 @@ impl<'tcx> OnUnimplementedDirective {
         let mut item_iter = items.iter();
 
         let parse_value = |value_str| {
-            OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
+            OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
         };
 
         let condition = if is_root {
@@ -135,7 +135,7 @@ impl<'tcx> OnUnimplementedDirective {
             {
                 if let Some(items) = item.meta_item_list() {
                     if let Ok(subcommand) =
-                        Self::parse(tcx, trait_def_id, &items, item.span(), false)
+                        Self::parse(tcx, item_def_id, &items, item.span(), false)
                     {
                         subcommands.push(subcommand);
                     } else {
@@ -178,19 +178,15 @@ impl<'tcx> OnUnimplementedDirective {
         }
     }
 
-    pub fn of_item(
-        tcx: TyCtxt<'tcx>,
-        trait_def_id: DefId,
-        impl_def_id: DefId,
-    ) -> Result<Option<Self>, ErrorGuaranteed> {
-        let attrs = tcx.get_attrs(impl_def_id);
+    pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
+        let attrs = tcx.get_attrs(item_def_id);
 
         let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else {
             return Ok(None);
         };
 
         let result = if let Some(items) = attr.meta_item_list() {
-            Self::parse(tcx, trait_def_id, &items, attr.span, true).map(Some)
+            Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
         } else if let Some(value) = attr.value_str() {
             Ok(Some(OnUnimplementedDirective {
                 condition: None,
@@ -198,7 +194,7 @@ impl<'tcx> OnUnimplementedDirective {
                 subcommands: vec![],
                 label: Some(OnUnimplementedFormatString::try_parse(
                     tcx,
-                    trait_def_id,
+                    item_def_id,
                     value,
                     attr.span,
                 )?),
@@ -209,7 +205,7 @@ impl<'tcx> OnUnimplementedDirective {
         } else {
             return Err(ErrorGuaranteed);
         };
-        debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result);
+        debug!("of_item({:?}) = {:?}", item_def_id, result);
         result
     }
 
@@ -280,23 +276,29 @@ impl<'tcx> OnUnimplementedDirective {
 impl<'tcx> OnUnimplementedFormatString {
     fn try_parse(
         tcx: TyCtxt<'tcx>,
-        trait_def_id: DefId,
+        item_def_id: DefId,
         from: Symbol,
         err_sp: Span,
     ) -> Result<Self, ErrorGuaranteed> {
         let result = OnUnimplementedFormatString(from);
-        result.verify(tcx, trait_def_id, err_sp)?;
+        result.verify(tcx, item_def_id, err_sp)?;
         Ok(result)
     }
 
     fn verify(
         &self,
         tcx: TyCtxt<'tcx>,
-        trait_def_id: DefId,
+        item_def_id: DefId,
         span: Span,
     ) -> Result<(), ErrorGuaranteed> {
-        let name = tcx.item_name(trait_def_id);
-        let generics = tcx.generics_of(trait_def_id);
+        let trait_def_id = if tcx.is_trait(item_def_id) {
+            item_def_id
+        } else {
+            tcx.trait_id_of_impl(item_def_id)
+                .expect("expected `on_unimplemented` to correspond to a trait")
+        };
+        let trait_name = tcx.item_name(trait_def_id);
+        let generics = tcx.generics_of(item_def_id);
         let s = self.0.as_str();
         let parser = Parser::new(s, None, None, false, ParseMode::Format);
         let mut result = Ok(());
@@ -307,7 +309,7 @@ impl<'tcx> OnUnimplementedFormatString {
                     // `{Self}` is allowed
                     Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (),
                     // `{ThisTraitsName}` is allowed
-                    Position::ArgumentNamed(s, _) if s == name => (),
+                    Position::ArgumentNamed(s, _) if s == trait_name => (),
                     // `{from_method}` is allowed
                     Position::ArgumentNamed(s, _) if s == sym::from_method => (),
                     // `{from_desugaring}` is allowed
@@ -329,9 +331,13 @@ impl<'tcx> OnUnimplementedFormatString {
                                     tcx.sess,
                                     span,
                                     E0230,
-                                    "there is no parameter `{}` on trait `{}`",
+                                    "there is no parameter `{}` on {}",
                                     s,
-                                    name
+                                    if trait_def_id == item_def_id {
+                                        format!("trait `{}`", trait_name)
+                                    } else {
+                                        "impl".to_string()
+                                    }
                                 )
                                 .emit();
                                 result = Err(ErrorGuaranteed);
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index c32c73c6384..ea48fab1ceb 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -295,6 +295,32 @@ where
     result
 }
 
+#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
+pub fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>(
+    selcx: &'a mut SelectionContext<'b, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    cause: ObligationCause<'tcx>,
+    depth: usize,
+    value: T,
+    obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> T
+where
+    T: TypeFoldable<'tcx>,
+{
+    debug!(obligations.len = obligations.len());
+    let mut normalizer = AssocTypeNormalizer::new_without_eager_inference_replacement(
+        selcx,
+        param_env,
+        cause,
+        depth,
+        obligations,
+    );
+    let result = ensure_sufficient_stack(|| normalizer.fold(value));
+    debug!(?result, obligations.len = normalizer.obligations.len());
+    debug!(?normalizer.obligations,);
+    result
+}
+
 pub(crate) fn needs_normalization<'tcx, T: TypeFoldable<'tcx>>(value: &T, reveal: Reveal) -> bool {
     match reveal {
         Reveal::UserFacing => value
@@ -314,6 +340,10 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> {
     obligations: &'a mut Vec<PredicateObligation<'tcx>>,
     depth: usize,
     universes: Vec<Option<ty::UniverseIndex>>,
+    /// If true, when a projection is unable to be completed, an inference
+    /// variable will be created and an obligation registered to project to that
+    /// inference variable. Also, constants will be eagerly evaluated.
+    eager_inference_replacement: bool,
 }
 
 impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
@@ -324,7 +354,33 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
         depth: usize,
         obligations: &'a mut Vec<PredicateObligation<'tcx>>,
     ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
-        AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }
+        AssocTypeNormalizer {
+            selcx,
+            param_env,
+            cause,
+            obligations,
+            depth,
+            universes: vec![],
+            eager_inference_replacement: true,
+        }
+    }
+
+    fn new_without_eager_inference_replacement(
+        selcx: &'a mut SelectionContext<'b, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        cause: ObligationCause<'tcx>,
+        depth: usize,
+        obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+    ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
+        AssocTypeNormalizer {
+            selcx,
+            param_env,
+            cause,
+            obligations,
+            depth,
+            universes: vec![],
+            eager_inference_replacement: false,
+        }
     }
 
     fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
@@ -428,14 +484,28 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                 // there won't be bound vars there.
 
                 let data = data.super_fold_with(self);
-                let normalized_ty = normalize_projection_type(
-                    self.selcx,
-                    self.param_env,
-                    data,
-                    self.cause.clone(),
-                    self.depth,
-                    &mut self.obligations,
-                );
+                let normalized_ty = if self.eager_inference_replacement {
+                    normalize_projection_type(
+                        self.selcx,
+                        self.param_env,
+                        data,
+                        self.cause.clone(),
+                        self.depth,
+                        &mut self.obligations,
+                    )
+                } else {
+                    opt_normalize_projection_type(
+                        self.selcx,
+                        self.param_env,
+                        data,
+                        self.cause.clone(),
+                        self.depth,
+                        &mut self.obligations,
+                    )
+                    .ok()
+                    .flatten()
+                    .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self)))
+                };
                 debug!(
                     ?self.depth,
                     ?ty,
@@ -501,7 +571,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
     }
 
     fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if self.selcx.tcx().lazy_normalization() {
+        if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement {
             constant
         } else {
             let constant = constant.super_fold_with(self);
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 435d709d37e..2df0d9f0f6f 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -112,7 +112,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         }
 
         ty::Adt(def, _) => {
-            if Some(def.did) == tcx.lang_items().manually_drop() {
+            if Some(def.did()) == tcx.lang_items().manually_drop() {
                 // `ManuallyDrop` never has a dtor.
                 true
             } else {
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 6a2bd9ce1ea..ed0ad5601aa 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -334,6 +334,21 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
         &mut self,
         constant: mir::ConstantKind<'tcx>,
     ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
-        constant.try_super_fold_with(self)
+        let constant_kind = match constant {
+            mir::ConstantKind::Ty(c) => {
+                let const_folded = c.try_fold_with(self)?;
+                match const_folded.val() {
+                    ty::ConstKind::Value(cv) => {
+                        // FIXME With Valtrees we need to convert `cv: ValTree`
+                        // to a `ConstValue` here.
+                        mir::ConstantKind::Val(cv, const_folded.ty())
+                    }
+                    _ => mir::ConstantKind::Ty(const_folded),
+                }
+            }
+            mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?,
+        };
+
+        Ok(constant_kind)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 2ed7a8f9cf9..67e3bf80486 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -12,7 +12,7 @@ use std::ops::ControlFlow;
 
 #[derive(Debug)]
 pub enum NonStructuralMatchTy<'tcx> {
-    Adt(&'tcx AdtDef),
+    Adt(AdtDef<'tcx>),
     Param,
     Dynamic,
     Foreign,
@@ -208,14 +208,14 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
             }
         };
 
-        if !self.seen.insert(adt_def.did) {
+        if !self.seen.insert(adt_def.did()) {
             debug!("Search already seen adt_def: {:?}", adt_def);
             return ControlFlow::CONTINUE;
         }
 
         if !self.type_marked_structural(ty) {
             debug!("Search found ty: {:?}", ty);
-            return ControlFlow::Break(NonStructuralMatchTy::Adt(&adt_def));
+            return ControlFlow::Break(NonStructuralMatchTy::Adt(adt_def));
         }
 
         // structural-match does not care about the
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 943f36efc15..b4ed5b95b10 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -540,7 +540,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
                 ty::Adt(def, substs) => {
                     // WfNominalType
-                    let obligations = self.nominal_obligations(def.did, substs);
+                    let obligations = self.nominal_obligations(def.did(), substs);
                     self.out.extend(obligations);
                 }
 
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 47b1ee04e77..9b85242e90a 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -166,13 +166,13 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
     ) -> Arc<chalk_solve::rust_ir::AdtDatum<RustInterner<'tcx>>> {
         let adt_def = adt_id.0;
 
-        let bound_vars = bound_vars_for_item(self.interner.tcx, adt_def.did);
+        let bound_vars = bound_vars_for_item(self.interner.tcx, adt_def.did());
         let binders = binders_for(self.interner, bound_vars);
 
-        let where_clauses = self.where_clauses_for(adt_def.did, bound_vars);
+        let where_clauses = self.where_clauses_for(adt_def.did(), bound_vars);
 
         let variants: Vec<_> = adt_def
-            .variants
+            .variants()
             .iter()
             .map(|variant| chalk_solve::rust_ir::AdtVariantDatum {
                 fields: variant
@@ -189,7 +189,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                 chalk_solve::rust_ir::AdtDatumBound { variants, where_clauses },
             ),
             flags: chalk_solve::rust_ir::AdtFlags {
-                upstream: !adt_def.did.is_local(),
+                upstream: !adt_def.did().is_local(),
                 fundamental: adt_def.is_fundamental(),
                 phantom_data: adt_def.is_phantom_data(),
             },
@@ -209,9 +209,9 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i)).intern(self.interner);
         let uint = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(i)).intern(self.interner);
         Arc::new(chalk_solve::rust_ir::AdtRepr {
-            c: adt_def.repr.c(),
-            packed: adt_def.repr.packed(),
-            int: adt_def.repr.int.map(|i| match i {
+            c: adt_def.repr().c(),
+            packed: adt_def.repr().packed(),
+            int: adt_def.repr().int.map(|i| match i {
                 attr::IntType::SignedInt(ty) => match ty {
                     ast::IntTy::Isize => int(chalk_ir::IntTy::Isize),
                     ast::IntTy::I8 => int(chalk_ir::IntTy::I8),
@@ -354,7 +354,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
             let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap();
             let self_ty = trait_ref.self_ty();
             let provides = match (self_ty.kind(), chalk_ty) {
-                (&ty::Adt(impl_adt_def, ..), Adt(id, ..)) => impl_adt_def.did == id.0.did,
+                (&ty::Adt(impl_adt_def, ..), Adt(id, ..)) => impl_adt_def.did() == id.0.did(),
                 (_, AssociatedType(_ty_id, ..)) => {
                     // FIXME(chalk): See https://github.com/rust-lang/rust/pull/77152#discussion_r494484774
                     false
@@ -671,7 +671,7 @@ impl<'tcx> chalk_ir::UnificationDatabase<RustInterner<'tcx>> for RustIrDatabase<
         &self,
         adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
     ) -> chalk_ir::Variances<RustInterner<'tcx>> {
-        let variances = self.interner.tcx.variances_of(adt_id.0.did);
+        let variances = self.interner.tcx.variances_of(adt_id.0.did());
         chalk_ir::Variances::from_iter(
             self.interner,
             variances.iter().map(|v| v.lower_into(self.interner)),
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 3658f8e5735..df5df176186 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -268,7 +268,7 @@ fn dtorck_constraint_for_ty<'tcx>(
 
         ty::Adt(def, substs) => {
             let DtorckConstraint { dtorck_types, outlives, overflows } =
-                tcx.at(span).adt_dtorck_constraint(def.did)?;
+                tcx.at(span).adt_dtorck_constraint(def.did())?;
             // FIXME: we can try to recursively `dtorck_constraint_on_ty`
             // there, but that needs some way to handle cycles.
             constraints.dtorck_types.extend(dtorck_types.iter().map(|t| t.subst(tcx, substs)));
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 322511be817..6195c712c58 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -16,7 +16,7 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>
     // parameter without a `Copy` bound, then we conservatively return that it
     // needs drop.
     let adt_has_dtor =
-        |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
+        |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant);
     let res =
         drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false).next().is_some();
 
@@ -78,7 +78,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
 
 impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
 where
-    F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult<I>,
+    F: Fn(ty::AdtDef<'tcx>, SubstsRef<'tcx>) -> NeedsDropResult<I>,
     I: Iterator<Item = Ty<'tcx>>,
 {
     type Item = NeedsDropResult<Ty<'tcx>>;
@@ -193,7 +193,7 @@ fn drop_tys_helper<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     param_env: rustc_middle::ty::ParamEnv<'tcx>,
-    adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
+    adt_has_dtor: impl Fn(ty::AdtDef<'tcx>) -> Option<DtorType>,
     only_significant: bool,
 ) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> {
     fn with_query_cache<'tcx>(
@@ -203,7 +203,7 @@ fn drop_tys_helper<'tcx>(
         iter.into_iter().try_fold(Vec::new(), |mut vec, subty| {
             match subty.kind() {
                 ty::Adt(adt_id, subst) => {
-                    for subty in tcx.adt_drop_tys(adt_id.did)? {
+                    for subty in tcx.adt_drop_tys(adt_id.did())? {
                         vec.push(subty.subst(tcx, subst));
                     }
                 }
@@ -213,7 +213,7 @@ fn drop_tys_helper<'tcx>(
         })
     }
 
-    let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
+    let adt_components = move |adt_def: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>| {
         if adt_def.is_manually_drop() {
             debug!("drop_tys_helper: `{:?}` is manually drop", adt_def);
             Ok(Vec::new())
@@ -260,9 +260,9 @@ fn drop_tys_helper<'tcx>(
 
 fn adt_consider_insignificant_dtor<'tcx>(
     tcx: TyCtxt<'tcx>,
-) -> impl Fn(&ty::AdtDef) -> Option<DtorType> + 'tcx {
-    move |adt_def: &ty::AdtDef| {
-        let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
+) -> impl Fn(ty::AdtDef<'tcx>) -> Option<DtorType> + 'tcx {
+    move |adt_def: ty::AdtDef<'tcx>| {
+        let is_marked_insig = tcx.has_attr(adt_def.did(), sym::rustc_insignificant_dtor);
         if is_marked_insig {
             // In some cases like `std::collections::HashMap` where the struct is a wrapper around
             // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies
@@ -281,11 +281,14 @@ fn adt_consider_insignificant_dtor<'tcx>(
     }
 }
 
-fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
+fn adt_drop_tys<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
     // This is for the "adt_drop_tys" query, that considers all `Drop` impls, therefore all dtors are
     // significant.
     let adt_has_dtor =
-        |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
+        |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant);
     // `tcx.type_of(def_id)` identical to `tcx.make_adt(def, identity_substs)`
     drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor, false)
         .collect::<Result<Vec<_>, _>>()
diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs
index 11a57688580..b8f3efe6462 100644
--- a/compiler/rustc_ty_utils/src/representability.rs
+++ b/compiler/rustc_ty_utils/src/representability.rs
@@ -33,7 +33,7 @@ pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> R
     // cleared when recursing to check A, but `shadow_seen` won't, so that we
     // can catch cases of mutual recursion where A also contains B).
     let mut seen: Vec<Ty<'_>> = Vec::new();
-    let mut shadow_seen: Vec<&'tcx ty::AdtDef> = Vec::new();
+    let mut shadow_seen: Vec<ty::AdtDef<'tcx>> = Vec::new();
     let mut representable_cache = FxHashMap::default();
     let mut force_result = false;
     let r = is_type_structurally_recursive(
@@ -63,7 +63,7 @@ fn are_inner_types_recursive<'tcx>(
     tcx: TyCtxt<'tcx>,
     sp: Span,
     seen: &mut Vec<Ty<'tcx>>,
-    shadow_seen: &mut Vec<&'tcx ty::AdtDef>,
+    shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
     ty: Ty<'tcx>,
     force_result: &mut bool,
@@ -150,7 +150,7 @@ fn are_inner_types_recursive<'tcx>(
                             .take(shadow_seen.len() - 1)
                             .any(|seen_def| seen_def == def)
                     {
-                        let adt_def_id = def.did;
+                        let adt_def_id = def.did();
                         let raw_adt_ty = tcx.type_of(adt_def_id);
                         debug!("are_inner_types_recursive: checking nested type: {:?}", raw_adt_ty);
 
@@ -236,7 +236,7 @@ fn are_inner_types_recursive<'tcx>(
     }
 }
 
-fn same_adt<'tcx>(ty: Ty<'tcx>, def: &'tcx ty::AdtDef) -> bool {
+fn same_adt<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
     match *ty.kind() {
         ty::Adt(ty_def, _) => ty_def == def,
         _ => false,
@@ -249,7 +249,7 @@ fn is_type_structurally_recursive<'tcx>(
     tcx: TyCtxt<'tcx>,
     sp: Span,
     seen: &mut Vec<Ty<'tcx>>,
-    shadow_seen: &mut Vec<&'tcx ty::AdtDef>,
+    shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
     ty: Ty<'tcx>,
     force_result: &mut bool,
@@ -281,7 +281,7 @@ fn is_type_structurally_recursive_inner<'tcx>(
     tcx: TyCtxt<'tcx>,
     sp: Span,
     seen: &mut Vec<Ty<'tcx>>,
-    shadow_seen: &mut Vec<&'tcx ty::AdtDef>,
+    shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
     ty: Ty<'tcx>,
     force_result: &mut bool,
@@ -332,7 +332,7 @@ fn is_type_structurally_recursive_inner<'tcx>(
             // For structs and enums, track all previously seen types by pushing them
             // onto the 'seen' stack.
             seen.push(ty);
-            shadow_seen.push(def);
+            shadow_seen.push(*def);
             let out = are_inner_types_recursive(
                 tcx,
                 sp,
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index e6ce3447548..44ef0a09a65 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -8,7 +8,7 @@ use rustc_trait_selection::traits;
 
 fn sized_constraint_for_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
-    adtdef: &ty::AdtDef,
+    adtdef: ty::AdtDef<'tcx>,
     ty: Ty<'tcx>,
 ) -> Vec<Ty<'tcx>> {
     use ty::TyKind::*;
@@ -56,7 +56,7 @@ fn sized_constraint_for_ty<'tcx>(
             })
             .without_const()
             .to_predicate(tcx);
-            let predicates = tcx.predicates_of(adtdef.did).predicates;
+            let predicates = tcx.predicates_of(adtdef.did()).predicates;
             if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] }
         }
 
@@ -99,7 +99,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain
     let def = tcx.adt_def(def_id);
 
     let result = tcx.mk_type_list(
-        def.variants
+        def.variants()
             .iter()
             .flat_map(|v| v.fields.last())
             .flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did))),
@@ -454,7 +454,7 @@ pub fn conservative_is_privately_uninhabited_raw<'tcx>(
             // (a) It has no variants (i.e. an empty `enum`);
             // (b) Each of its variants (a single one in the case of a `struct`) has at least
             //     one uninhabited field.
-            def.variants.iter().all(|var| {
+            def.variants().iter().all(|var| {
                 var.fields.iter().any(|field| {
                     let ty = tcx.type_of(field.did).subst(tcx, substs);
                     tcx.conservative_is_privately_uninhabited(param_env.and(ty))
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index d409cedddda..144953caa4c 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1788,9 +1788,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         if let ty::Adt(adt_def, _) = qself_ty.kind() {
             if adt_def.is_enum() {
                 let variant_def = adt_def
-                    .variants
+                    .variants()
                     .iter()
-                    .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did));
+                    .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
                 if let Some(variant_def) = variant_def {
                     if permit_variants {
                         tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
@@ -1845,7 +1845,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
                     if let Some(suggested_name) = find_best_match_for_name(
                         &adt_def
-                            .variants
+                            .variants()
                             .iter()
                             .map(|variant| variant.name)
                             .collect::<Vec<Symbol>>(),
@@ -1865,7 +1865,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         );
                     }
 
-                    if let Some(sp) = tcx.hir().span_if_local(adt_def.did) {
+                    if let Some(sp) = tcx.hir().span_if_local(adt_def.did()) {
                         let sp = tcx.sess.source_map().guess_head_span(sp);
                         err.span_label(sp, format!("variant `{}` not found here", assoc_ident));
                     }
@@ -2154,7 +2154,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap());
                 let (generics_def_id, index) = if let Some(adt_def) = adt_def {
                     debug_assert!(adt_def.is_enum());
-                    (adt_def.did, last)
+                    (adt_def.did(), last)
                 } else if last >= 1 && segments[last - 1].args.is_some() {
                     // Everything but the penultimate segment should have no
                     // parameters at all.
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 3d0f76f7a93..d3e9820834a 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -165,6 +165,12 @@ pub enum CastError {
     NonScalar,
     UnknownExprPtrKind,
     UnknownCastPtrKind,
+    /// Cast of int to (possibly) fat raw pointer.
+    ///
+    /// Argument is the specific name of the metadata in plain words, such as "a vtable"
+    /// or "a length". If this argument is None, then the metadata is unknown, for example,
+    /// when we're typechecking a type parameter with a ?Sized bound.
+    IntToFatCast(Option<&'static str>),
 }
 
 impl From<ErrorGuaranteed> for CastError {
@@ -522,6 +528,35 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 .diagnostic()
                 .emit();
             }
+            CastError::IntToFatCast(known_metadata) => {
+                let mut err = struct_span_err!(
+                    fcx.tcx.sess,
+                    self.cast_span,
+                    E0606,
+                    "cannot cast `{}` to a pointer that {} wide",
+                    fcx.ty_to_string(self.expr_ty),
+                    if known_metadata.is_some() { "is" } else { "may be" }
+                );
+
+                err.span_label(
+                    self.cast_span,
+                    format!(
+                        "creating a `{}` requires both an address and {}",
+                        self.cast_ty,
+                        known_metadata.unwrap_or("type-specific metadata"),
+                    ),
+                );
+
+                if fcx.tcx.sess.is_nightly_build() {
+                    err.span_label(
+                        self.expr.span,
+                        "consider casting this expression to `*const ()`, \
+                        then using `core::ptr::from_raw_parts`",
+                    );
+                }
+
+                err.emit();
+            }
             CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
                 let unknown_cast_to = match e {
                     CastError::UnknownCastPtrKind => true,
@@ -900,7 +935,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         match fcx.pointer_kind(m_cast.ty, self.span)? {
             None => Err(CastError::UnknownCastPtrKind),
             Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
-            _ => Err(CastError::IllegalCast),
+            Some(PointerKind::Vtable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
+            Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
+            Some(
+                PointerKind::OfProjection(_)
+                | PointerKind::OfOpaque(_, _)
+                | PointerKind::OfParam(_),
+            ) => Err(CastError::IntToFatCast(None)),
         }
     }
 
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 765b752691f..9016a8ffe9a 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -269,7 +269,7 @@ pub(super) fn check_fn<'a, 'tcx>(
                     let arg_is_panic_info = match *inputs[0].kind() {
                         ty::Ref(region, ty, mutbl) => match *ty.kind() {
                             ty::Adt(ref adt, _) => {
-                                adt.did == panic_info_did
+                                adt.did() == panic_info_did
                                     && mutbl == hir::Mutability::Not
                                     && !region.is_static()
                             }
@@ -310,7 +310,7 @@ pub(super) fn check_fn<'a, 'tcx>(
                 let span = hir.span(fn_id);
                 if inputs.len() == 1 {
                     let arg_is_alloc_layout = match inputs[0].kind() {
-                        ty::Adt(ref adt, _) => adt.did == alloc_layout_did,
+                        ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
                         _ => false,
                     };
 
@@ -345,7 +345,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
     def.destructor(tcx); // force the destructor to be evaluated
     check_representable(tcx, span, def_id);
 
-    if def.repr.simd() {
+    if def.repr().simd() {
         check_simd(tcx, span, def_id);
     }
 
@@ -742,12 +742,11 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
                     impl_trait_ref,
                     &impl_.items,
                 );
-                let trait_def_id = impl_trait_ref.def_id;
-                check_on_unimplemented(tcx, trait_def_id, it);
+                check_on_unimplemented(tcx, it);
             }
         }
         hir::ItemKind::Trait(_, _, _, _, ref items) => {
-            check_on_unimplemented(tcx, it.def_id.to_def_id(), it);
+            check_on_unimplemented(tcx, it);
 
             for item in items.iter() {
                 let item = tcx.hir().trait_item(item.id);
@@ -857,9 +856,9 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
     }
 }
 
-pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) {
+pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
     // an error would be reported if this fails.
-    let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item.def_id.to_def_id());
+    let _ = traits::OnUnimplementedDirective::of_item(tcx, item.def_id.to_def_id());
 }
 
 pub(super) fn check_specialization_validity<'tcx>(
@@ -1087,7 +1086,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
             }
 
             let len = if let ty::Array(_ty, c) = e.kind() {
-                c.try_eval_usize(tcx, tcx.param_env(def.did))
+                c.try_eval_usize(tcx, tcx.param_env(def.did()))
             } else {
                 Some(fields.len() as u64)
             };
@@ -1138,10 +1137,10 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
     }
 }
 
-pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) {
-    let repr = def.repr;
+pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
+    let repr = def.repr();
     if repr.packed() {
-        for attr in tcx.get_attrs(def.did).iter() {
+        for attr in tcx.get_attrs(def.did()).iter() {
             for r in attr::find_repr_attrs(&tcx.sess, attr) {
                 if let attr::ReprPacked(pack) = r
                     && let Some(repr_pack) = repr.pack
@@ -1166,7 +1165,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) {
             )
             .emit();
         } else {
-            if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) {
+            if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) {
                 let mut err = struct_span_err!(
                     tcx.sess,
                     sp,
@@ -1191,7 +1190,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) {
                             &if first {
                                 format!(
                                     "`{}` contains a field of type `{}`",
-                                    tcx.type_of(def.did),
+                                    tcx.type_of(def.did()),
                                     ident
                                 )
                             } else {
@@ -1215,16 +1214,16 @@ pub(super) fn check_packed_inner(
 ) -> Option<Vec<(DefId, Span)>> {
     if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() {
         if def.is_struct() || def.is_union() {
-            if def.repr.align.is_some() {
-                return Some(vec![(def.did, DUMMY_SP)]);
+            if def.repr().align.is_some() {
+                return Some(vec![(def.did(), DUMMY_SP)]);
             }
 
             stack.push(def_id);
             for field in &def.non_enum_variant().fields {
                 if let ty::Adt(def, _) = field.ty(tcx, substs).kind() {
-                    if !stack.contains(&def.did) {
-                        if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
-                            defs.push((def.did, field.ident(tcx).span));
+                    if !stack.contains(&def.did()) {
+                        if let Some(mut defs) = check_packed_inner(tcx, def.did(), stack) {
+                            defs.push((def.did(), field.ident(tcx).span));
                             return Some(defs);
                         }
                     }
@@ -1237,8 +1236,8 @@ pub(super) fn check_packed_inner(
     None
 }
 
-pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) {
-    if !adt.repr.transparent() {
+pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtDef<'tcx>) {
+    if !adt.repr().transparent() {
         return;
     }
     let sp = tcx.sess.source_map().guess_head_span(sp);
@@ -1253,9 +1252,9 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty
         .emit();
     }
 
-    if adt.variants.len() != 1 {
-        bad_variant_count(tcx, adt, sp, adt.did);
-        if adt.variants.is_empty() {
+    if adt.variants().len() != 1 {
+        bad_variant_count(tcx, adt, sp, adt.did());
+        if adt.variants().is_empty() {
             // Don't bother checking the fields. No variants (and thus no fields) exist.
             return;
         }
@@ -1318,7 +1317,7 @@ fn check_enum<'tcx>(
         }
     }
 
-    let repr_type_ty = def.repr.discr_type().to_ty(tcx);
+    let repr_type_ty = def.repr().discr_type().to_ty(tcx);
     if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
         if !tcx.features().repr128 {
             feature_err(
@@ -1337,7 +1336,7 @@ fn check_enum<'tcx>(
         }
     }
 
-    if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
+    if tcx.adt_def(def_id).repr().int.is_none() && tcx.features().arbitrary_enum_discriminant {
         let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
 
         let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
@@ -1356,7 +1355,7 @@ fn check_enum<'tcx>(
     for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) {
         // Check for duplicate discriminant values
         if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
-            let variant_did = def.variants[VariantIdx::new(i)].def_id;
+            let variant_did = def.variant(VariantIdx::new(i)).def_id;
             let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local());
             let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
             let i_span = match variant_i.disr_expr {
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index f01843ebaba..58e5c9315c3 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -299,15 +299,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 {
                     if e.hir_id == id {
                         if let Some(span) = expr.span.find_ancestor_inside(block_span) {
-                            let return_suggestions =
-                                if self.tcx.is_diagnostic_item(sym::Result, expected_adt.did) {
-                                    vec!["Ok(())".to_string()]
-                                } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did)
-                                {
-                                    vec!["None".to_string(), "Some(())".to_string()]
-                                } else {
-                                    return;
-                                };
+                            let return_suggestions = if self
+                                .tcx
+                                .is_diagnostic_item(sym::Result, expected_adt.did())
+                            {
+                                vec!["Ok(())".to_string()]
+                            } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
+                                vec!["None".to_string(), "Some(())".to_string()]
+                            } else {
+                                return;
+                            };
                             if let Some(indent) =
                                 self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
                             {
@@ -333,7 +334,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
 
             let compatible_variants: Vec<String> = expected_adt
-                .variants
+                .variants()
                 .iter()
                 .filter(|variant| variant.fields.len() == 1)
                 .filter_map(|variant| {
@@ -378,7 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     err.multipart_suggestions(
                         &format!(
                             "try wrapping the expression in a variant of `{}`",
-                            self.tcx.def_path_str(expected_adt.did)
+                            self.tcx.def_path_str(expected_adt.did())
                         ),
                         compatible_variants.into_iter().map(|variant| {
                             vec![
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index 26aade16fd4..1849ece9f76 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -40,13 +40,13 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
                 tcx,
                 drop_impl_did.expect_local(),
                 dtor_self_type,
-                adt_def.did,
+                adt_def.did(),
             )?;
 
             ensure_drop_predicates_are_implied_by_item_defn(
                 tcx,
                 dtor_predicates,
-                adt_def.did.expect_local(),
+                adt_def.did().expect_local(),
                 self_to_impl_substs,
             )
         }
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 8e245beaa3d..d944bb76241 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -43,7 +43,6 @@ use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
 use rustc_session::parse::feature_err;
-use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::Span;
@@ -1334,7 +1333,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Prohibit struct expressions when non-exhaustive flag is set.
         let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");
-        if !adt.did.is_local() && variant.is_field_list_non_exhaustive() {
+        if !adt.did().is_local() && variant.is_field_list_non_exhaustive() {
             self.tcx
                 .sess
                 .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() });
@@ -1864,7 +1863,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ty::Adt(base_def, substs) if !base_def.is_enum() => {
                     debug!("struct named {:?}", base_t);
                     let (ident, def_scope) =
-                        self.tcx.adjust_ident_and_get_scope(field, base_def.did, self.body_id);
+                        self.tcx.adjust_ident_and_get_scope(field, base_def.did(), self.body_id);
                     let fields = &base_def.non_enum_variant().fields;
                     if let Some(index) = fields
                         .iter()
@@ -1883,7 +1882,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
                             return field_ty;
                         }
-                        private_candidate = Some((adjustments, base_def.did, field_ty));
+                        private_candidate = Some((adjustments, base_def.did(), field_ty));
                     }
                 }
                 ty::Tuple(tys) => {
@@ -2010,8 +2009,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // We know by construction that `<expr>.await` is either on Rust 2015
             // or results in `ExprKind::Await`. Suggest switching the edition to 2018.
             err.note("to `.await` a `Future`, switch to Rust 2018 or later");
-            err.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
-            err.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+            err.help_use_latest_edition();
         }
 
         err.emit();
@@ -2105,9 +2103,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             if let ty::RawPtr(ty_and_mut) = expr_t.kind() {
                 if let ty::Adt(adt_def, _) = ty_and_mut.ty.kind() {
-                    if adt_def.variants.len() == 1
+                    if adt_def.variants().len() == 1
                         && adt_def
-                            .variants
+                            .variants()
                             .iter()
                             .next()
                             .unwrap()
@@ -2156,7 +2154,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn suggest_fields_on_recordish(
         &self,
         err: &mut Diagnostic,
-        def: &'tcx ty::AdtDef,
+        def: ty::AdtDef<'tcx>,
         field: Ident,
         access_span: Span,
     ) {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index b3213451d76..ed70b85e3f1 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1166,7 +1166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if let Some(self_ty) = self_ty =>
             {
                 let adt_def = self_ty.ty_adt_def().unwrap();
-                user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty });
+                user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty });
                 is_alias_variant_ctor = true;
             }
             Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index f165093c958..d336573c254 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -577,13 +577,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return None;
             }
             Res::Def(DefKind::Variant, _) => match ty.kind() {
-                ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)),
+                ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did(), substs)),
                 _ => bug!("unexpected type: {:?}", ty),
             },
             Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
             | Res::SelfTy { .. } => match ty.kind() {
                 ty::Adt(adt, substs) if !adt.is_enum() => {
-                    Some((adt.non_enum_variant(), adt.did, substs))
+                    Some((adt.non_enum_variant(), adt.did(), substs))
                 }
                 _ => None,
             },
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 523602d5b18..67d61668b6d 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -398,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let pin_box_found = self.tcx.mk_lang_item(box_found, LangItem::Pin).unwrap();
         let pin_found = self.tcx.mk_lang_item(found, LangItem::Pin).unwrap();
         match expected.kind() {
-            ty::Adt(def, _) if Some(def.did) == pin_did => {
+            ty::Adt(def, _) if Some(def.did()) == pin_did => {
                 if self.can_coerce(pin_box_found, expected) {
                     debug!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found, expected);
                     match found.kind() {
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 9684237be83..48d24170072 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -496,7 +496,7 @@ pub fn check_must_not_suspend_ty<'tcx>(
             let descr_pre = &format!("{}boxed ", data.descr_pre);
             check_must_not_suspend_ty(fcx, boxed_ty, hir_id, SuspendCheckData { descr_pre, ..data })
         }
-        ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did, hir_id, data),
+        ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did(), hir_id, data),
         // FIXME: support adding the attribute to TAITs
         ty::Opaque(def, _) => {
             let mut has_emitted = false;
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 7bb84581a82..1ca9c192096 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -589,9 +589,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if let ty::Adt(adt_def, _) = self_ty.kind() {
             if adt_def.is_enum() {
                 let variant_def = adt_def
-                    .variants
+                    .variants()
                     .iter()
-                    .find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did));
+                    .find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did()));
                 if let Some(variant_def) = variant_def {
                     // Braced variants generate unusable names in value namespace (reserved for
                     // possible future use), so variants resolved as associated items may refer to
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs
index bc2859719e8..dbc4adfb0a3 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs
@@ -297,7 +297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // for a "<" in `self_ty_name`.
             if !self_ty_name.contains('<') {
                 if let Adt(def, _) = self_ty.kind() {
-                    let generics = self.tcx.generics_of(def.did);
+                    let generics = self.tcx.generics_of(def.did());
                     if !generics.params.is_empty() {
                         let counts = generics.own_counts();
                         self_ty_name += &format!(
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 876c575781c..e79085fdad2 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -640,7 +640,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 self.assemble_inherent_impl_candidates_for_type(p.def_id());
             }
             ty::Adt(def, _) => {
-                self.assemble_inherent_impl_candidates_for_type(def.did);
+                self.assemble_inherent_impl_candidates_for_type(def.did());
             }
             ty::Foreign(did) => {
                 self.assemble_inherent_impl_candidates_for_type(did);
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 0ae2dfa180b..715671dd452 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -19,9 +19,10 @@ use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{source_map, FileName, MultiSpan, Span};
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
-    FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
+    FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
 };
 
 use std::cmp::Ordering;
@@ -397,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 let candidate_found = autoderef.any(|(ty, _)| {
                                     if let ty::Adt(adt_deref, _) = ty.kind() {
                                         self.tcx
-                                            .inherent_impls(adt_deref.did)
+                                            .inherent_impls(adt_deref.did())
                                             .iter()
                                             .filter_map(|def_id| {
                                                 self.associated_value(*def_id, item_name)
@@ -469,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 if let Some(def) = actual.ty_adt_def() {
-                    if let Some(full_sp) = tcx.hir().span_if_local(def.did) {
+                    if let Some(full_sp) = tcx.hir().span_if_local(def.did()) {
                         let def_sp = tcx.sess.source_map().guess_head_span(full_sp);
                         err.span_label(
                             def_sp,
@@ -483,150 +484,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
 
-                let mut label_span_not_found = || {
-                    if unsatisfied_predicates.is_empty() {
-                        err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
-                        let is_string_or_ref_str = match actual.kind() {
-                            ty::Ref(_, ty, _) => {
-                                ty.is_str()
-                                    || matches!(
-                                        ty.kind(),
-                                        ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did)
-                                    )
-                            }
-                            ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did),
-                            _ => false,
-                        };
-                        if is_string_or_ref_str && item_name.name == sym::iter {
-                            err.span_suggestion_verbose(
-                                item_name.span,
-                                "because of the in-memory representation of `&str`, to obtain \
-                                 an `Iterator` over each of its codepoint use method `chars`",
-                                String::from("chars"),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                        if let ty::Adt(adt, _) = rcvr_ty.kind() {
-                            let mut inherent_impls_candidate = self
-                                .tcx
-                                .inherent_impls(adt.did)
-                                .iter()
-                                .copied()
-                                .filter(|def_id| {
-                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
-                                        // Check for both mode is the same so we avoid suggesting
-                                        // incorrect associated item.
-                                        match (mode, assoc.fn_has_self_parameter, source) {
-                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
-                                                // We check that the suggest type is actually
-                                                // different from the received one
-                                                // So we avoid suggestion method with Box<Self>
-                                                // for instance
-                                                self.tcx.at(span).type_of(*def_id) != actual
-                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
-                                            }
-                                            (Mode::Path, false, _) => true,
-                                            _ => false,
-                                        }
-                                    } else {
-                                        false
-                                    }
-                                })
-                                .collect::<Vec<_>>();
-                            if !inherent_impls_candidate.is_empty() {
-                                inherent_impls_candidate.sort();
-                                inherent_impls_candidate.dedup();
-
-                                // number of type to shows at most.
-                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
-                                let type_candidates = inherent_impls_candidate
-                                    .iter()
-                                    .take(limit)
-                                    .map(|impl_item| {
-                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
-                                    })
-                                    .collect::<Vec<_>>()
-                                    .join("\n");
-                                let additional_types = if inherent_impls_candidate.len() > limit {
-                                    format!(
-                                        "\nand {} more types",
-                                        inherent_impls_candidate.len() - limit
-                                    )
-                                } else {
-                                    "".to_string()
-                                };
-                                err.note(&format!(
-                                    "the {item_kind} was found for\n{}{}",
-                                    type_candidates, additional_types
-                                ));
-                            }
-                        }
-                    } else {
-                        err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
-                    }
-                };
-
-                // If the method name is the name of a field with a function or closure type,
-                // give a helping note that it has to be called as `(x.f)(...)`.
-                if let SelfSource::MethodCall(expr) = source {
-                    let field_receiver =
-                        self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
-                            ty::Adt(def, substs) if !def.is_enum() => {
-                                let variant = &def.non_enum_variant();
-                                self.tcx.find_field_index(item_name, variant).map(|index| {
-                                    let field = &variant.fields[index];
-                                    let field_ty = field.ty(tcx, substs);
-                                    (field, field_ty)
-                                })
-                            }
-                            _ => None,
-                        });
-
-                    if let Some((field, field_ty)) = field_receiver {
-                        let scope = self.tcx.parent_module(self.body_id).to_def_id();
-                        let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
-
-                        if is_accessible {
-                            if self.is_fn_ty(field_ty, span) {
-                                let expr_span = expr.span.to(item_name.span);
-                                err.multipart_suggestion(
-                                    &format!(
-                                        "to call the function stored in `{}`, \
-                                         surround the field access with parentheses",
-                                        item_name,
-                                    ),
-                                    vec![
-                                        (expr_span.shrink_to_lo(), '('.to_string()),
-                                        (expr_span.shrink_to_hi(), ')'.to_string()),
-                                    ],
-                                    Applicability::MachineApplicable,
-                                );
-                            } else {
-                                let call_expr = self
-                                    .tcx
-                                    .hir()
-                                    .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-
-                                if let Some(span) = call_expr.span.trim_start(item_name.span) {
-                                    err.span_suggestion(
-                                        span,
-                                        "remove the arguments",
-                                        String::new(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                            }
-                        }
-
-                        let field_kind = if is_accessible { "field" } else { "private field" };
-                        err.span_label(item_name.span, format!("{}, not a method", field_kind));
-                    } else if lev_candidate.is_none() && static_sources.is_empty() {
-                        label_span_not_found();
-                    }
-                } else {
-                    label_span_not_found();
-                }
-
                 if self.is_fn_ty(rcvr_ty, span) {
                     fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
                         err.note(
@@ -645,12 +502,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
 
+                let mut custom_span_label = false;
+
                 if !static_sources.is_empty() {
                     err.note(
                         "found the following associated functions; to be used as methods, \
                          functions must have a `self` parameter",
                     );
                     err.span_label(span, "this is an associated function, not a method");
+                    custom_span_label = true;
                 }
                 if static_sources.len() == 1 {
                     let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
@@ -686,6 +546,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     report_candidates(span, &mut err, static_sources, sugg_span);
                 }
 
+                let mut bound_spans = vec![];
                 let mut restrict_type_params = false;
                 let mut unsatisfied_bounds = false;
                 if item_name.name == sym::count && self.is_slice_ty(actual, span) {
@@ -709,7 +570,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
                     };
                     let mut type_params = FxHashMap::default();
-                    let mut bound_spans = vec![];
+
+                    // Pick out the list of unimplemented traits on the receiver.
+                    // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
+                    let mut unimplemented_traits = FxHashMap::default();
+                    let mut unimplemented_traits_only = true;
+                    for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
+                        if let (ty::PredicateKind::Trait(p), Some(cause)) =
+                            (predicate.kind().skip_binder(), cause.as_ref())
+                        {
+                            if p.trait_ref.self_ty() != rcvr_ty {
+                                // This is necessary, not just to keep the errors clean, but also
+                                // because our derived obligations can wind up with a trait ref that
+                                // requires a different param_env to be correctly compared.
+                                continue;
+                            }
+                            unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
+                                predicate.kind().rebind(p.trait_ref),
+                                Obligation {
+                                    cause: cause.clone(),
+                                    param_env: self.param_env,
+                                    predicate: predicate.clone(),
+                                    recursion_depth: 0,
+                                },
+                            ));
+                        }
+                    }
+
+                    // Make sure that, if any traits other than the found ones were involved,
+                    // we don't don't report an unimplemented trait.
+                    // We don't want to say that `iter::Cloned` is not an interator, just
+                    // because of some non-Clone item being iterated over.
+                    for (predicate, _parent_pred, _cause) in &unsatisfied_predicates {
+                        match predicate.kind().skip_binder() {
+                            ty::PredicateKind::Trait(p)
+                                if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
+                            _ => {
+                                unimplemented_traits_only = false;
+                                break;
+                            }
+                        }
+                    }
 
                     let mut collect_type_param_suggestions =
                         |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
@@ -730,7 +631,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                                 .get(self.tcx.hir().local_def_id_to_hir_id(did)),
                                         )
                                     }
-                                    ty::Adt(def, _) => def.did.as_local().map(|def_id| {
+                                    ty::Adt(def, _) => def.did().as_local().map(|def_id| {
                                         self.tcx
                                             .hir()
                                             .get(self.tcx.hir().local_def_id_to_hir_id(def_id))
@@ -761,7 +662,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                         match &self_ty.kind() {
                             // Point at the type that couldn't satisfy the bound.
-                            ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)),
+                            ty::Adt(def, _) => bound_spans.push((def_span(def.did()), msg)),
                             // Point at the trait object that couldn't satisfy the bound.
                             ty::Dynamic(preds, _) => {
                                 for pred in preds.iter() {
@@ -945,11 +846,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
                     bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
                     bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
-                    bound_spans.sort();
-                    bound_spans.dedup();
-                    for (span, msg) in bound_spans.into_iter() {
-                        err.span_label(span, &msg);
-                    }
+
                     if !bound_list.is_empty() || !skip_list.is_empty() {
                         let bound_list = bound_list
                             .into_iter()
@@ -957,9 +854,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .collect::<Vec<_>>()
                             .join("\n");
                         let actual_prefix = actual.prefix_string(self.tcx);
-                        err.set_primary_message(&format!(
+                        info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
+                        let (primary_message, label) = if unimplemented_traits.len() == 1
+                            && unimplemented_traits_only
+                        {
+                            unimplemented_traits
+                                .into_iter()
+                                .next()
+                                .map(|(_, (trait_ref, obligation))| {
+                                    if trait_ref.self_ty().references_error()
+                                        || actual.references_error()
+                                    {
+                                        // Avoid crashing.
+                                        return (None, None);
+                                    }
+                                    let OnUnimplementedNote { message, label, .. } =
+                                        self.infcx.on_unimplemented_note(trait_ref, &obligation);
+                                    (message, label)
+                                })
+                                .unwrap_or((None, None))
+                        } else {
+                            (None, None)
+                        };
+                        let primary_message = primary_message.unwrap_or_else(|| format!(
                             "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
                         ));
+                        err.set_primary_message(&primary_message);
+                        if let Some(label) = label {
+                            custom_span_label = true;
+                            err.span_label(span, label);
+                        }
                         if !bound_list.is_empty() {
                             err.note(&format!(
                                 "the following trait bounds were not satisfied:\n{bound_list}"
@@ -971,6 +895,156 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
 
+                let mut label_span_not_found = || {
+                    if unsatisfied_predicates.is_empty() {
+                        err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+                        let is_string_or_ref_str = match actual.kind() {
+                            ty::Ref(_, ty, _) => {
+                                ty.is_str()
+                                    || matches!(
+                                        ty.kind(),
+                                        ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did())
+                                    )
+                            }
+                            ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did()),
+                            _ => false,
+                        };
+                        if is_string_or_ref_str && item_name.name == sym::iter {
+                            err.span_suggestion_verbose(
+                                item_name.span,
+                                "because of the in-memory representation of `&str`, to obtain \
+                                 an `Iterator` over each of its codepoint use method `chars`",
+                                String::from("chars"),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                        if let ty::Adt(adt, _) = rcvr_ty.kind() {
+                            let mut inherent_impls_candidate = self
+                                .tcx
+                                .inherent_impls(adt.did())
+                                .iter()
+                                .copied()
+                                .filter(|def_id| {
+                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
+                                        // Check for both mode is the same so we avoid suggesting
+                                        // incorrect associated item.
+                                        match (mode, assoc.fn_has_self_parameter, source) {
+                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+                                                // We check that the suggest type is actually
+                                                // different from the received one
+                                                // So we avoid suggestion method with Box<Self>
+                                                // for instance
+                                                self.tcx.at(span).type_of(*def_id) != actual
+                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+                                            }
+                                            (Mode::Path, false, _) => true,
+                                            _ => false,
+                                        }
+                                    } else {
+                                        false
+                                    }
+                                })
+                                .collect::<Vec<_>>();
+                            if !inherent_impls_candidate.is_empty() {
+                                inherent_impls_candidate.sort();
+                                inherent_impls_candidate.dedup();
+
+                                // number of type to shows at most.
+                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+                                let type_candidates = inherent_impls_candidate
+                                    .iter()
+                                    .take(limit)
+                                    .map(|impl_item| {
+                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+                                    })
+                                    .collect::<Vec<_>>()
+                                    .join("\n");
+                                let additional_types = if inherent_impls_candidate.len() > limit {
+                                    format!(
+                                        "\nand {} more types",
+                                        inherent_impls_candidate.len() - limit
+                                    )
+                                } else {
+                                    "".to_string()
+                                };
+                                err.note(&format!(
+                                    "the {item_kind} was found for\n{}{}",
+                                    type_candidates, additional_types
+                                ));
+                            }
+                        }
+                    } else {
+                        err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
+                    }
+                };
+
+                // If the method name is the name of a field with a function or closure type,
+                // give a helping note that it has to be called as `(x.f)(...)`.
+                if let SelfSource::MethodCall(expr) = source {
+                    let field_receiver =
+                        self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
+                            ty::Adt(def, substs) if !def.is_enum() => {
+                                let variant = &def.non_enum_variant();
+                                self.tcx.find_field_index(item_name, variant).map(|index| {
+                                    let field = &variant.fields[index];
+                                    let field_ty = field.ty(tcx, substs);
+                                    (field, field_ty)
+                                })
+                            }
+                            _ => None,
+                        });
+
+                    if let Some((field, field_ty)) = field_receiver {
+                        let scope = self.tcx.parent_module(self.body_id).to_def_id();
+                        let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
+
+                        if is_accessible {
+                            if self.is_fn_ty(field_ty, span) {
+                                let expr_span = expr.span.to(item_name.span);
+                                err.multipart_suggestion(
+                                    &format!(
+                                        "to call the function stored in `{}`, \
+                                         surround the field access with parentheses",
+                                        item_name,
+                                    ),
+                                    vec![
+                                        (expr_span.shrink_to_lo(), '('.to_string()),
+                                        (expr_span.shrink_to_hi(), ')'.to_string()),
+                                    ],
+                                    Applicability::MachineApplicable,
+                                );
+                            } else {
+                                let call_expr = self
+                                    .tcx
+                                    .hir()
+                                    .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+
+                                if let Some(span) = call_expr.span.trim_start(item_name.span) {
+                                    err.span_suggestion(
+                                        span,
+                                        "remove the arguments",
+                                        String::new(),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
+                            }
+                        }
+
+                        let field_kind = if is_accessible { "field" } else { "private field" };
+                        err.span_label(item_name.span, format!("{}, not a method", field_kind));
+                    } else if lev_candidate.is_none() && !custom_span_label {
+                        label_span_not_found();
+                    }
+                } else if !custom_span_label {
+                    label_span_not_found();
+                }
+
+                bound_spans.sort();
+                bound_spans.dedup();
+                for (span, msg) in bound_spans.into_iter() {
+                    err.span_label(span, &msg);
+                }
+
                 if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
                 } else {
                     self.suggest_traits_to_import(
@@ -990,7 +1064,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if unsatisfied_predicates.is_empty() && actual.is_enum() {
                     let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
                     if let Some(suggestion) = lev_distance::find_best_match_for_name(
-                        &adt_def.variants.iter().map(|s| s.name).collect::<Vec<_>>(),
+                        &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
                         item_name.name,
                         None,
                     ) {
@@ -1117,7 +1191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let all_local_types_needing_impls =
             errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() {
                 ty::PredicateKind::Trait(pred) => match pred.self_ty().kind() {
-                    ty::Adt(def, _) => def.did.is_local(),
+                    ty::Adt(def, _) => def.did().is_local(),
                     _ => false,
                 },
                 _ => false,
@@ -1133,7 +1207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let def_ids = preds
             .iter()
             .filter_map(|pred| match pred.self_ty().kind() {
-                ty::Adt(def, _) => Some(def.did),
+                ty::Adt(def, _) => Some(def.did()),
                 _ => None,
             })
             .collect::<FxHashSet<_>>();
@@ -1151,7 +1225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             match pred.self_ty().kind() {
                 ty::Adt(def, _) => {
                     spans.push_span_label(
-                        sm.guess_head_span(self.tcx.def_span(def.did)),
+                        sm.guess_head_span(self.tcx.def_span(def.did())),
                         format!("must implement `{}`", pred.trait_ref.print_only_trait_path()),
                     );
                 }
@@ -1199,7 +1273,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         for (pred, _, _) in unsatisfied_predicates {
             let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() else { continue };
             let adt = match trait_pred.self_ty().ty_adt_def() {
-                Some(adt) if adt.did.is_local() => adt,
+                Some(adt) if adt.did().is_local() => adt,
                 _ => continue,
             };
             if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) {
@@ -1217,7 +1291,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 };
                 if can_derive {
                     let self_name = trait_pred.self_ty().to_string();
-                    let self_span = self.tcx.def_span(adt.did);
+                    let self_span = self.tcx.def_span(adt.did());
                     if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() {
                         for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref())
                         {
@@ -1280,7 +1354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Print out the type for use in value namespace.
     fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
         match ty.kind() {
-            ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
+            ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did(), substs)),
             _ => self.ty_to_string(ty),
         }
     }
@@ -1874,7 +1948,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> bool {
         fn is_local(ty: Ty<'_>) -> bool {
             match ty.kind() {
-                ty::Adt(def, _) => def.did.is_local(),
+                ty::Adt(def, _) => def.did().is_local(),
                 ty::Foreign(did) => did.is_local(),
                 ty::Dynamic(tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()),
                 ty::Param(_) => true,
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 4c0eab51c35..31cc3fa2ac6 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -822,13 +822,13 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
 }
 
 /// Emit an error when encountering two or more variants in a transparent enum.
-fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) {
+fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
     let variant_spans: Vec<_> = adt
-        .variants
+        .variants()
         .iter()
         .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
         .collect();
-    let msg = format!("needs exactly one variant, but has {}", adt.variants.len(),);
+    let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
     let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg);
     err.span_label(sp, &msg);
     if let [start @ .., end] = &*variant_spans {
@@ -844,7 +844,7 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, d
 /// enum.
 fn bad_non_zero_sized_fields<'tcx>(
     tcx: TyCtxt<'tcx>,
-    adt: &'tcx ty::AdtDef,
+    adt: ty::AdtDef<'tcx>,
     field_count: usize,
     field_spans: impl Iterator<Item = Span>,
     sp: Span,
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index cd77e6d0384..af154e62a1e 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -576,7 +576,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let string_type = self.tcx.get_diagnostic_item(sym::String);
         let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() {
-            Some(ty_def) => Some(ty_def.did) == string_type,
+            Some(ty_def) => Some(ty_def.did()) == string_type,
             None => false,
         };
 
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 8a369797210..a264ee5d147 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -11,6 +11,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{HirId, Pat, PatKind};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable};
 use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_span::hygiene::DesugaringKind;
@@ -850,7 +851,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     _ => {
                         let (type_def_id, item_def_id) = match pat_ty.kind() {
                             Adt(def, _) => match res {
-                                Res::Def(DefKind::Const, def_id) => (Some(def.did), Some(def_id)),
+                                Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)),
                                 _ => (None, None),
                             },
                             _ => (None, None),
@@ -1286,7 +1287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // Require `..` if struct has non_exhaustive attribute.
-        let non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local();
+        let non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did().is_local();
         if non_exhaustive && !has_rest_pat {
             self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
         }
@@ -1308,6 +1309,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .copied()
                 .filter(|(field, _)| {
                     field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
+                        && !matches!(
+                            tcx.eval_stability(field.did, None, DUMMY_SP, None),
+                            EvalResult::Deny { .. }
+                        )
+                        // We only want to report the error if it is hidden and not local
+                        && !(tcx.is_doc_hidden(field.did) && !field.did.is_local())
                 })
                 .collect();
 
@@ -2042,8 +2049,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .find_map(|(ty, _)| {
                         match ty.kind() {
                             ty::Adt(adt_def, _)
-                                if self.tcx.is_diagnostic_item(sym::Option, adt_def.did)
-                                    || self.tcx.is_diagnostic_item(sym::Result, adt_def.did) =>
+                                if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
+                                    || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
                             {
                                 // Slicing won't work here, but `.as_deref()` might (issue #91328).
                                 err.span_suggestion(
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs
index 318979b4627..42eec177649 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_typeck/src/check/place_op.rs
@@ -1,6 +1,7 @@
 use crate::check::method::MethodCallee;
 use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
 use rustc_ast as ast;
+use rustc_data_structures::intern::Interned;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -125,7 +126,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ) = index_expr.kind
         {
             match adjusted_ty.kind() {
-                ty::Adt(ty::AdtDef { did, .. }, _)
+                ty::Adt(ty::AdtDef(Interned(ty::AdtDefData { did, .. }, _)), _)
                     if self.tcx.is_diagnostic_item(sym::Vec, *did) =>
                 {
                     return self.negative_index(adjusted_ty, index_expr.span, base_expr);
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 257846324b8..1a94b7261f7 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -458,10 +458,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// let s: String;  // hir_id_s
     /// let mut p: Point; // his_id_p
     /// let c = || {
-    ///        println!("{}", s);  // L1
+    ///        println!("{s}");  // L1
     ///        p.x += 10;  // L2
-    ///        println!("{}" , p.y) // L3
-    ///        println!("{}", p) // L4
+    ///        println!("{}" , p.y); // L3
+    ///        println!("{p}"); // L4
     ///        drop(s);   // L5
     /// };
     /// ```
@@ -785,7 +785,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // Add a label pointing to where a captured variable affected by drop order
                             // is dropped
                             if lint_note.reason.drop_order {
-                                let drop_location_span = drop_location_span(self.tcx, &closure_hir_id);
+                                let drop_location_span = drop_location_span(self.tcx, closure_hir_id);
 
                                 match &lint_note.captures_info {
                                     UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
@@ -1413,7 +1413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty::Adt(def, substs) => {
                 // Multi-varaint enums are captured in entirety,
                 // which would've been handled in the case of single empty slice in `captured_by_move_projs`.
-                assert_eq!(def.variants.len(), 1);
+                assert_eq!(def.variants().len(), 1);
 
                 // Only Field projections can be applied to a non-box Adt.
                 assert!(
@@ -1422,7 +1422,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ProjectionKind::Field(..)
                     ))
                 );
-                def.variants.get(VariantIdx::new(0)).unwrap().fields.iter().enumerate().any(
+                def.variants().get(VariantIdx::new(0)).unwrap().fields.iter().enumerate().any(
                     |(i, field)| {
                         let paths_using_field = captured_by_move_projs
                             .iter()
@@ -1649,7 +1649,7 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
         // Return true for fields of packed structs, unless those fields have alignment 1.
         match p.kind {
             ProjectionKind::Field(..) => match ty.kind() {
-                ty::Adt(def, _) if def.repr.packed() => {
+                ty::Adt(def, _) if def.repr().packed() => {
                     // We erase regions here because they cannot be hashed
                     match tcx.layout_of(param_env.and(tcx.erase_regions(p.ty))) {
                         Ok(layout) if layout.align.abi.bytes() == 1 => {
@@ -1697,8 +1697,8 @@ fn apply_capture_kind_on_capture_ty<'tcx>(
 }
 
 /// Returns the Span of where the value with the provided HirId would be dropped
-fn drop_location_span<'tcx>(tcx: TyCtxt<'tcx>, hir_id: &hir::HirId) -> Span {
-    let owner_id = tcx.hir().get_enclosing_scope(*hir_id).unwrap();
+fn drop_location_span<'tcx>(tcx: TyCtxt<'tcx>, hir_id: hir::HirId) -> Span {
+    let owner_id = tcx.hir().get_enclosing_scope(hir_id).unwrap();
 
     let owner_node = tcx.hir().get(owner_id);
     let owner_span = match owner_node {
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 8672bf65466..30603d6f487 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -995,7 +995,7 @@ fn check_type_defn<'tcx, F>(
 {
     for_item(tcx, item).with_fcx(|fcx| {
         let variants = lookup_fields(fcx);
-        let packed = tcx.adt_def(item.def_id).repr.packed();
+        let packed = tcx.adt_def(item.def_id).repr().packed();
 
         for variant in &variants {
             // For DST, or when drop needs to copy things around, all
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index ac1f2db848f..ef59df0dc88 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -154,8 +154,8 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
                 if def_a.is_struct() && def_b.is_struct() =>
             {
                 if def_a != def_b {
-                    let source_path = tcx.def_path_str(def_a.did);
-                    let target_path = tcx.def_path_str(def_b.did);
+                    let source_path = tcx.def_path_str(def_a.did());
+                    let target_path = tcx.def_path_str(def_b.did());
 
                     create_err(&format!(
                         "the trait `DispatchFromDyn` may only be implemented \
@@ -168,7 +168,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
                     return;
                 }
 
-                if def_a.repr.c() || def_a.repr.packed() {
+                if def_a.repr().c() || def_a.repr().packed() {
                     create_err(
                         "structs implementing `DispatchFromDyn` may not have \
                              `#[repr(packed)]` or `#[repr(C)]`",
@@ -353,8 +353,8 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                 if def_a.is_struct() && def_b.is_struct() =>
             {
                 if def_a != def_b {
-                    let source_path = tcx.def_path_str(def_a.did);
-                    let target_path = tcx.def_path_str(def_b.did);
+                    let source_path = tcx.def_path_str(def_a.did());
+                    let target_path = tcx.def_path_str(def_b.did());
                     struct_span_err!(
                         tcx.sess,
                         span,
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index 78e54997403..59c252dec05 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -48,7 +48,7 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
         let lang_items = self.tcx.lang_items();
         match *self_ty.kind() {
             ty::Adt(def, _) => {
-                self.check_def_id(item, def.did);
+                self.check_def_id(item, def.did());
             }
             ty::Foreign(did) => {
                 self.check_def_id(item, did);
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index 8ed47226d5f..a1bcd141e10 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -97,7 +97,7 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua
     if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
         let self_ty = trait_ref.self_ty();
         let opt_self_def_id = match *self_ty.kind() {
-            ty::Adt(self_def, _) => Some(self_def.did),
+            ty::Adt(self_def, _) => Some(self_def.did()),
             ty::Foreign(did) => Some(did),
             _ => None,
         };
@@ -181,7 +181,7 @@ fn emit_orphan_check_error<'tcx>(
                     // That way if we had `Vec<MyType>`, we will properly attribute the
                     // problem to `Vec<T>` and avoid confusing the user if they were to see
                     // `MyType` in the error.
-                    ty::Adt(def, _) => tcx.mk_adt(def, ty::List::empty()),
+                    ty::Adt(def, _) => tcx.mk_adt(*def, ty::List::empty()),
                     _ => ty,
                 };
                 let this = "this".to_string();
@@ -340,7 +340,7 @@ fn lint_auto_trait_impls(tcx: TyCtxt<'_>, trait_def_id: DefId, impls: &[LocalDef
         assert_eq!(trait_ref.substs.len(), 1);
         let self_ty = trait_ref.self_ty();
         let (self_type_did, substs) = match self_ty.kind() {
-            ty::Adt(def, substs) => (def.did, substs),
+            ty::Adt(def, substs) => (def.did(), substs),
             _ => {
                 // FIXME: should also lint for stuff like `&i32` but
                 // considering that auto traits are unstable, that
@@ -443,7 +443,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
                     // by only visiting each `DefId` once.
                     //
                     // This will be is incorrect in subtle cases, but I don't care :)
-                    if self.seen.insert(def.did) {
+                    if self.seen.insert(def.did()) {
                         for ty in def.all_fields().map(|field| field.ty(tcx, substs)) {
                             ty.visit_with(self)?;
                         }
@@ -457,7 +457,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
     }
 
     let self_ty_root = match self_ty.kind() {
-        ty::Adt(def, _) => tcx.mk_adt(def, InternalSubsts::identity_for_item(tcx, def.did)),
+        ty::Adt(def, _) => tcx.mk_adt(*def, InternalSubsts::identity_for_item(tcx, def.did())),
         _ => unimplemented!("unexpected self ty {:?}", self_ty),
     };
 
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 8229f4a80e1..cabdcdc214b 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -917,7 +917,7 @@ fn convert_variant_ctor(tcx: TyCtxt<'_>, ctor_id: hir::HirId) {
 
 fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::Variant<'_>]) {
     let def = tcx.adt_def(def_id);
-    let repr_type = def.repr.discr_type();
+    let repr_type = def.repr().discr_type();
     let initial = repr_type.initial_discriminant(tcx);
     let mut prev_discr = None::<Discr<'_>>;
 
@@ -1012,7 +1012,7 @@ fn convert_variant(
     )
 }
 
-fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef {
+fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
     use rustc_hir::*;
 
     let def_id = def_id.expect_local();
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 2867574e656..3247a292242 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -464,7 +464,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
 
                 Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx
                     .adt_def(tcx.hir().get_parent_item(hir_id))
-                    .repr
+                    .repr()
                     .discr_type()
                     .to_ty(tcx),
 
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 8c19bbd3214..be4958ea062 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -702,10 +702,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
     fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
         fn upvar_is_local_variable<'tcx>(
             upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
-            upvar_id: &hir::HirId,
+            upvar_id: hir::HirId,
             body_owner_is_closure: bool,
         ) -> bool {
-            upvars.map(|upvars| !upvars.contains_key(upvar_id)).unwrap_or(body_owner_is_closure)
+            upvars.map(|upvars| !upvars.contains_key(&upvar_id)).unwrap_or(body_owner_is_closure)
         }
 
         debug!("walk_captures({:?})", closure_expr);
@@ -727,7 +727,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                     PlaceBase::Upvar(upvar_id) => {
                         if upvar_is_local_variable(
                             upvars,
-                            &upvar_id.var_path.hir_id,
+                            upvar_id.var_path.hir_id,
                             body_owner_is_closure,
                         ) {
                             // The nested closure might be fake reading the current (enclosing) closure's local variables.
@@ -855,7 +855,7 @@ fn is_multivariant_adt(ty: Ty<'_>) -> bool {
             }
             AdtKind::Enum => def.is_variant_list_non_exhaustive(),
         };
-        def.variants.len() > 1 || (!def.did.is_local() && is_non_exhaustive)
+        def.variants().len() > 1 || (!def.did().is_local() && is_non_exhaustive)
     } else {
         false
     }
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index 876b1ae72ad..1464420090b 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -576,7 +576,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     ) -> McResult<usize> {
         let ty = self.typeck_results.node_type(pat_hir_id);
         match ty.kind() {
-            ty::Adt(adt_def, _) => Ok(adt_def.variants[variant_index].fields.len()),
+            ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()),
             _ => {
                 self.tcx()
                     .sess
diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
index 61ca09f6b98..00163c72974 100644
--- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
@@ -157,7 +157,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 // `['b => 'a, U => T]` and thus get the requirement that `T:
                 // 'a` holds for `Foo`.
                 debug!("Adt");
-                if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) {
+                if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) {
                     for (unsubstituted_predicate, &span) in unsubstituted_predicates {
                         // `unsubstituted_predicate` is `U: 'b` in the
                         // example above.  So apply the substitution to
@@ -178,7 +178,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 // let _: () = substs.region_at(0);
                 check_explicit_predicates(
                     tcx,
-                    def.did,
+                    def.did(),
                     substs,
                     required_predicates,
                     explicit_map,
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index 196e476b0e3..76755de4964 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -283,7 +283,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::Adt(def, substs) => {
-                self.add_constraints_from_substs(current, def.did, substs, variance);
+                self.add_constraints_from_substs(current, def.did(), substs, variance);
             }
 
             ty::Projection(ref data) => {
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index 9d4f9af91a5..bd7d721b5e1 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -397,7 +397,7 @@ pub mod __alloc_error_handler {
     // if there is no `#[alloc_error_handler]`
     #[rustc_std_internal_symbol]
     pub unsafe extern "C-unwind" fn __rdl_oom(size: usize, _align: usize) -> ! {
-        panic!("memory allocation of {} bytes failed", size)
+        panic!("memory allocation of {size} bytes failed")
     }
 
     // if there is an `#[alloc_error_handler]`
diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs
index 63234ee91f0..8b13e36c4b3 100644
--- a/library/alloc/src/borrow.rs
+++ b/library/alloc/src/borrow.rs
@@ -161,7 +161,7 @@ where
 /// let readonly = [1, 2];
 /// let borrowed = Items::new((&readonly[..]).into());
 /// match borrowed {
-///     Items { values: Cow::Borrowed(b) } => println!("borrowed {:?}", b),
+///     Items { values: Cow::Borrowed(b) } => println!("borrowed {b:?}"),
 ///     _ => panic!("expect borrowed value"),
 /// }
 ///
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 68bf59a01b3..7dce3db0a47 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -31,7 +31,7 @@
 //! }
 //!
 //! let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
-//! println!("{:?}", list);
+//! println!("{list:?}");
 //! ```
 //!
 //! This will print `Cons(1, Cons(2, Nil))`.
@@ -1170,8 +1170,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_box", issue = "92521")]
-unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box<T, A> {
+unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
     fn drop(&mut self) {
         // FIXME: Do nothing, drop is currently performed by compiler.
     }
@@ -1408,7 +1407,7 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
     /// let slice: &[u8] = &[104, 101, 108, 108, 111];
     /// let boxed_slice: Box<[u8]> = Box::from(slice);
     ///
-    /// println!("{:?}", boxed_slice);
+    /// println!("{boxed_slice:?}");
     /// ```
     fn from(slice: &[T]) -> Box<[T]> {
         let len = slice.len();
@@ -1450,7 +1449,7 @@ impl From<&str> for Box<str> {
     ///
     /// ```rust
     /// let boxed: Box<str> = Box::from("hello");
-    /// println!("{}", boxed);
+    /// println!("{boxed}");
     /// ```
     #[inline]
     fn from(s: &str) -> Box<str> {
@@ -1475,14 +1474,14 @@ impl From<Cow<'_, str>> for Box<str> {
     ///
     /// let unboxed = Cow::Borrowed("hello");
     /// let boxed: Box<str> = Box::from(unboxed);
-    /// println!("{}", boxed);
+    /// println!("{boxed}");
     /// ```
     ///
     /// ```rust
     /// # use std::borrow::Cow;
     /// let unboxed = Cow::Owned("hello".to_string());
     /// let boxed: Box<str> = Box::from(unboxed);
-    /// println!("{}", boxed);
+    /// println!("{boxed}");
     /// ```
     #[inline]
     fn from(cow: Cow<'_, str>) -> Box<str> {
@@ -1529,7 +1528,7 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
     ///
     /// ```rust
     /// let boxed: Box<[u8]> = Box::from([4, 2]);
-    /// println!("{:?}", boxed);
+    /// println!("{boxed:?}");
     /// ```
     fn from(array: [T; N]) -> Box<[T]> {
         box array
diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs
index e18cd8cd464..e6c3d38dab3 100644
--- a/library/alloc/src/collections/binary_heap.rs
+++ b/library/alloc/src/collections/binary_heap.rs
@@ -194,7 +194,7 @@ use super::SpecExtend;
 /// // We can iterate over the items in the heap, although they are returned in
 /// // a random order.
 /// for x in &heap {
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // If we instead pop these scores, they should come back in order.
@@ -779,7 +779,7 @@ impl<T: Ord> BinaryHeap<T> {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns
+    /// In other words, remove all elements `e` for which `f(&e)` returns
     /// `false`. The elements are visited in unsorted (and unspecified) order.
     ///
     /// # Examples
@@ -830,7 +830,7 @@ impl<T> BinaryHeap<T> {
     ///
     /// // Print 1, 2, 3, 4 in arbitrary order
     /// for x in heap.iter() {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1110,7 +1110,7 @@ impl<T> BinaryHeap<T> {
     ///
     /// // Will print in some order
     /// for x in vec {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     #[must_use = "`self` will be dropped if the result is not used"]
@@ -1179,7 +1179,7 @@ impl<T> BinaryHeap<T> {
     /// assert!(!heap.is_empty());
     ///
     /// for x in heap.drain() {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     ///
     /// assert!(heap.is_empty());
@@ -1624,7 +1624,7 @@ impl<T> IntoIterator for BinaryHeap<T> {
     /// // Print 1, 2, 3, 4 in arbitrary order
     /// for x in heap.into_iter() {
     ///     // x has type i32, not &i32
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     fn into_iter(self) -> IntoIter<T> {
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 7890c1040f0..d0ff3eb7475 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -104,8 +104,8 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
 /// let to_find = ["Up!", "Office Space"];
 /// for movie in &to_find {
 ///     match movie_reviews.get(movie) {
-///        Some(review) => println!("{}: {}", movie, review),
-///        None => println!("{} is unreviewed.", movie)
+///        Some(review) => println!("{movie}: {review}"),
+///        None => println!("{movie} is unreviewed.")
 ///     }
 /// }
 ///
@@ -114,7 +114,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
 ///
 /// // iterate over everything.
 /// for (movie, review) in &movie_reviews {
-///     println!("{}: \"{}\"", movie, review);
+///     println!("{movie}: \"{review}\"");
 /// }
 /// ```
 ///
@@ -963,7 +963,7 @@ impl<K, V> BTreeMap<K, V> {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+    /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
     /// The elements are visited in ascending key order.
     ///
     /// # Examples
@@ -1061,7 +1061,7 @@ impl<K, V> BTreeMap<K, V> {
     /// map.insert(5, "b");
     /// map.insert(8, "c");
     /// for (&key, &value) in map.range((Included(&4), Included(&8))) {
-    ///     println!("{}: {}", key, value);
+    ///     println!("{key}: {value}");
     /// }
     /// assert_eq!(Some((&5, &"b")), map.range(4..).next());
     /// ```
@@ -1104,7 +1104,7 @@ impl<K, V> BTreeMap<K, V> {
     ///     *balance += 100;
     /// }
     /// for (name, balance) in &map {
-    ///     println!("{} => {}", name, balance);
+    ///     println!("{name} => {balance}");
     /// }
     /// ```
     #[stable(feature = "btree_range", since = "1.17.0")]
@@ -2088,7 +2088,7 @@ impl<K, V> BTreeMap<K, V> {
     /// map.insert(1, "a");
     ///
     /// for (key, value) in map.iter() {
-    ///     println!("{}: {}", key, value);
+    ///     println!("{key}: {value}");
     /// }
     ///
     /// let (first_key, first_value) = map.iter().next().unwrap();
diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs
index 5cef007a46f..66608d09082 100644
--- a/library/alloc/src/collections/btree/map/entry.rs
+++ b/library/alloc/src/collections/btree/map/entry.rs
@@ -3,7 +3,7 @@ use core::marker::PhantomData;
 use core::mem;
 
 use super::super::borrow::DormantMutRef;
-use super::super::node::{marker, Handle, InsertResult::*, NodeRef};
+use super::super::node::{marker, Handle, NodeRef};
 use super::BTreeMap;
 
 use Entry::*;
@@ -313,13 +313,13 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(self, value: V) -> &'a mut V {
         let out_ptr = match self.handle.insert_recursing(self.key, value) {
-            (Fit(_), val_ptr) => {
+            (None, val_ptr) => {
                 // SAFETY: We have consumed self.handle and the handle returned.
                 let map = unsafe { self.dormant_map.awaken() };
                 map.length += 1;
                 val_ptr
             }
-            (Split(ins), val_ptr) => {
+            (Some(ins), val_ptr) => {
                 drop(ins.left);
                 // SAFETY: We have consumed self.handle and the reference returned.
                 let map = unsafe { self.dormant_map.awaken() };
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index 65468d5fe57..4d21df32417 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -1758,7 +1758,7 @@ fn test_ord_absence() {
     }
 
     fn map_debug<K: Debug>(mut map: BTreeMap<K, ()>) {
-        format!("{:?}", map);
+        format!("{map:?}");
         format!("{:?}", map.iter());
         format!("{:?}", map.iter_mut());
         format!("{:?}", map.keys());
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index dfce98f97bd..44f5bc850b8 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -861,11 +861,10 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
     /// this edge. This method splits the node if there isn't enough room.
     ///
     /// The returned pointer points to the inserted value.
-    fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) {
+    fn insert(mut self, key: K, val: V) -> (Option<SplitResult<'a, K, V, marker::Leaf>>, *mut V) {
         if self.node.len() < CAPACITY {
             let val_ptr = self.insert_fit(key, val);
-            let kv = unsafe { Handle::new_kv(self.node, self.idx) };
-            (InsertResult::Fit(kv), val_ptr)
+            (None, val_ptr)
         } else {
             let (middle_kv_idx, insertion) = splitpoint(self.idx);
             let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
@@ -879,7 +878,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
                 },
             };
             let val_ptr = insertion_edge.insert_fit(key, val);
-            (InsertResult::Split(result), val_ptr)
+            (Some(result), val_ptr)
         }
     }
 }
@@ -923,13 +922,12 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
         key: K,
         val: V,
         edge: Root<K, V>,
-    ) -> InsertResult<'a, K, V, marker::Internal> {
+    ) -> Option<SplitResult<'a, K, V, marker::Internal>> {
         assert!(edge.height == self.node.height - 1);
 
         if self.node.len() < CAPACITY {
             self.insert_fit(key, val, edge);
-            let kv = unsafe { Handle::new_kv(self.node, self.idx) };
-            InsertResult::Fit(kv)
+            None
         } else {
             let (middle_kv_idx, insertion) = splitpoint(self.idx);
             let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
@@ -943,7 +941,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
                 },
             };
             insertion_edge.insert_fit(key, val, edge);
-            InsertResult::Split(result)
+            Some(result)
         }
     }
 }
@@ -953,32 +951,26 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
     /// this edge. This method splits the node if there isn't enough room, and tries to
     /// insert the split off portion into the parent node recursively, until the root is reached.
     ///
-    /// If the returned result is a `Fit`, its handle's node can be this edge's node or an ancestor.
-    /// If the returned result is a `Split`, the `left` field will be the root node.
-    /// The returned pointer points to the inserted value.
+    /// If the returned result is some `SplitResult`, the `left` field will be the root node.
+    /// The returned pointer points to the inserted value, which in the case of `SplitResult`
+    /// is in the `left` or `right` tree.
     pub fn insert_recursing(
         self,
         key: K,
         value: V,
-    ) -> (InsertResult<'a, K, V, marker::LeafOrInternal>, *mut V) {
+    ) -> (Option<SplitResult<'a, K, V, marker::LeafOrInternal>>, *mut V) {
         let (mut split, val_ptr) = match self.insert(key, value) {
-            (InsertResult::Fit(handle), ptr) => {
-                return (InsertResult::Fit(handle.forget_node_type()), ptr);
-            }
-            (InsertResult::Split(split), val_ptr) => (split.forget_node_type(), val_ptr),
+            (None, val_ptr) => return (None, val_ptr),
+            (Some(split), val_ptr) => (split.forget_node_type(), val_ptr),
         };
 
         loop {
             split = match split.left.ascend() {
                 Ok(parent) => match parent.insert(split.kv.0, split.kv.1, split.right) {
-                    InsertResult::Fit(handle) => {
-                        return (InsertResult::Fit(handle.forget_node_type()), val_ptr);
-                    }
-                    InsertResult::Split(split) => split.forget_node_type(),
+                    None => return (None, val_ptr),
+                    Some(split) => split.forget_node_type(),
                 },
-                Err(root) => {
-                    return (InsertResult::Split(SplitResult { left: root, ..split }), val_ptr);
-                }
+                Err(root) => return (Some(SplitResult { left: root, ..split }), val_ptr),
             };
         }
     }
@@ -1529,14 +1521,6 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::K
     }
 }
 
-impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::KV> {
-    pub fn forget_node_type(
-        self,
-    ) -> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV> {
-        unsafe { Handle::new_kv(self.node.forget_type(), self.idx) }
-    }
-}
-
 impl<BorrowType, K, V, Type> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, Type> {
     /// Checks whether the underlying node is an `Internal` node or a `Leaf` node.
     pub fn force(
@@ -1621,7 +1605,7 @@ pub enum ForceResult<Leaf, Internal> {
 pub struct SplitResult<'a, K, V, NodeType> {
     // Altered node in existing tree with elements and edges that belong to the left of `kv`.
     pub left: NodeRef<marker::Mut<'a>, K, V, NodeType>,
-    // Some key and value split off, to be inserted elsewhere.
+    // Some key and value that existed before and were split off, to be inserted elsewhere.
     pub kv: (K, V),
     // Owned, unattached, new node with elements and edges that belong to the right of `kv`.
     pub right: NodeRef<marker::Owned, K, V, NodeType>,
@@ -1639,11 +1623,6 @@ impl<'a, K, V> SplitResult<'a, K, V, marker::Internal> {
     }
 }
 
-pub enum InsertResult<'a, K, V, NodeType> {
-    Fit(Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV>),
-    Split(SplitResult<'a, K, V, NodeType>),
-}
-
 pub mod marker {
     use core::marker::PhantomData;
 
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index bab6af82698..d6733425288 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -60,7 +60,7 @@ use super::Recover;
 ///
 /// // Iterate over everything.
 /// for book in &books {
-///     println!("{}", book);
+///     println!("{book}");
 /// }
 /// ```
 ///
@@ -284,7 +284,7 @@ impl<T> BTreeSet<T> {
     /// set.insert(5);
     /// set.insert(8);
     /// for &elem in set.range((Included(&4), Included(&8))) {
-    ///     println!("{}", elem);
+    ///     println!("{elem}");
     /// }
     /// assert_eq!(Some(&5), set.range(4..).next());
     /// ```
@@ -873,7 +873,7 @@ impl<T> BTreeSet<T> {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+    /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
     /// The elements are visited in ascending order.
     ///
     /// # Examples
diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs
index 7865d37ae51..032563e4f09 100644
--- a/library/alloc/src/collections/btree/set/tests.rs
+++ b/library/alloc/src/collections/btree/set/tests.rs
@@ -431,10 +431,10 @@ fn test_show() {
     set.insert(1);
     set.insert(2);
 
-    let set_str = format!("{:?}", set);
+    let set_str = format!("{set:?}");
 
     assert_eq!(set_str, "{1, 2}");
-    assert_eq!(format!("{:?}", empty), "{}");
+    assert_eq!(format!("{empty:?}"), "{}");
 }
 
 #[test]
@@ -649,7 +649,7 @@ fn test_ord_absence() {
     }
 
     fn set_debug<K: Debug>(set: BTreeSet<K>) {
-        format!("{:?}", set);
+        format!("{set:?}");
         format!("{:?}", set.iter());
         format!("{:?}", set.into_iter());
     }
diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs
index edadd666edc..e8290809276 100644
--- a/library/alloc/src/collections/vec_deque/iter.rs
+++ b/library/alloc/src/collections/vec_deque/iter.rs
@@ -1,5 +1,6 @@
 use core::fmt;
 use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
+use core::mem::MaybeUninit;
 use core::ops::Try;
 
 use super::{count, wrap_index, RingSlices};
@@ -12,7 +13,7 @@ use super::{count, wrap_index, RingSlices};
 /// [`iter`]: super::VecDeque::iter
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, T: 'a> {
-    pub(crate) ring: &'a [T],
+    pub(crate) ring: &'a [MaybeUninit<T>],
     pub(crate) tail: usize,
     pub(crate) head: usize,
 }
@@ -21,7 +22,15 @@ pub struct Iter<'a, T: 'a> {
 impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
-        f.debug_tuple("Iter").field(&front).field(&back).finish()
+        // Safety:
+        // - `self.head` and `self.tail` in a ring buffer are always valid indices.
+        // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized.
+        unsafe {
+            f.debug_tuple("Iter")
+                .field(&MaybeUninit::slice_assume_init_ref(front))
+                .field(&MaybeUninit::slice_assume_init_ref(back))
+                .finish()
+        }
     }
 }
 
@@ -44,7 +53,10 @@ impl<'a, T> Iterator for Iter<'a, T> {
         }
         let tail = self.tail;
         self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len());
-        unsafe { Some(self.ring.get_unchecked(tail)) }
+        // Safety:
+        // - `self.tail` in a ring buffer is always a valid index.
+        // - `self.head` and `self.tail` equality is checked above.
+        unsafe { Some(self.ring.get_unchecked(tail).assume_init_ref()) }
     }
 
     #[inline]
@@ -58,8 +70,13 @@ impl<'a, T> Iterator for Iter<'a, T> {
         F: FnMut(Acc, Self::Item) -> Acc,
     {
         let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
-        accum = front.iter().fold(accum, &mut f);
-        back.iter().fold(accum, &mut f)
+        // Safety:
+        // - `self.head` and `self.tail` in a ring buffer are always valid indices.
+        // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized.
+        unsafe {
+            accum = MaybeUninit::slice_assume_init_ref(front).iter().fold(accum, &mut f);
+            MaybeUninit::slice_assume_init_ref(back).iter().fold(accum, &mut f)
+        }
     }
 
     fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
@@ -70,17 +87,19 @@ impl<'a, T> Iterator for Iter<'a, T> {
     {
         let (mut iter, final_res);
         if self.tail <= self.head {
-            // single slice self.ring[self.tail..self.head]
-            iter = self.ring[self.tail..self.head].iter();
+            // Safety: single slice self.ring[self.tail..self.head] is initialized.
+            iter = unsafe { MaybeUninit::slice_assume_init_ref(&self.ring[self.tail..self.head]) }
+                .iter();
             final_res = iter.try_fold(init, &mut f);
         } else {
-            // two slices: self.ring[self.tail..], self.ring[..self.head]
+            // Safety: two slices: self.ring[self.tail..], self.ring[..self.head] both are initialized.
             let (front, back) = self.ring.split_at(self.tail);
-            let mut back_iter = back.iter();
+
+            let mut back_iter = unsafe { MaybeUninit::slice_assume_init_ref(back).iter() };
             let res = back_iter.try_fold(init, &mut f);
             let len = self.ring.len();
             self.tail = (self.ring.len() - back_iter.len()) & (len - 1);
-            iter = front[..self.head].iter();
+            iter = unsafe { MaybeUninit::slice_assume_init_ref(&front[..self.head]).iter() };
             final_res = iter.try_fold(res?, &mut f);
         }
         self.tail = self.head - iter.len();
@@ -109,7 +128,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
         // that is in bounds.
         unsafe {
             let idx = wrap_index(self.tail.wrapping_add(idx), self.ring.len());
-            self.ring.get_unchecked(idx)
+            self.ring.get_unchecked(idx).assume_init_ref()
         }
     }
 }
@@ -122,7 +141,10 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
             return None;
         }
         self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len());
-        unsafe { Some(self.ring.get_unchecked(self.head)) }
+        // Safety:
+        // - `self.head` in a ring buffer is always a valid index.
+        // - `self.head` and `self.tail` equality is checked above.
+        unsafe { Some(self.ring.get_unchecked(self.head).assume_init_ref()) }
     }
 
     fn rfold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
@@ -130,8 +152,13 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
         F: FnMut(Acc, Self::Item) -> Acc,
     {
         let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
-        accum = back.iter().rfold(accum, &mut f);
-        front.iter().rfold(accum, &mut f)
+        // Safety:
+        // - `self.head` and `self.tail` in a ring buffer are always valid indices.
+        // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized.
+        unsafe {
+            accum = MaybeUninit::slice_assume_init_ref(back).iter().rfold(accum, &mut f);
+            MaybeUninit::slice_assume_init_ref(front).iter().rfold(accum, &mut f)
+        }
     }
 
     fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
@@ -142,16 +169,20 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
     {
         let (mut iter, final_res);
         if self.tail <= self.head {
-            // single slice self.ring[self.tail..self.head]
-            iter = self.ring[self.tail..self.head].iter();
+            // Safety: single slice self.ring[self.tail..self.head] is initialized.
+            iter = unsafe {
+                MaybeUninit::slice_assume_init_ref(&self.ring[self.tail..self.head]).iter()
+            };
             final_res = iter.try_rfold(init, &mut f);
         } else {
-            // two slices: self.ring[self.tail..], self.ring[..self.head]
+            // Safety: two slices: self.ring[self.tail..], self.ring[..self.head] both are initialized.
             let (front, back) = self.ring.split_at(self.tail);
-            let mut front_iter = front[..self.head].iter();
+
+            let mut front_iter =
+                unsafe { MaybeUninit::slice_assume_init_ref(&front[..self.head]).iter() };
             let res = front_iter.try_rfold(init, &mut f);
             self.head = front_iter.len();
-            iter = back.iter();
+            iter = unsafe { MaybeUninit::slice_assume_init_ref(back).iter() };
             final_res = iter.try_rfold(res?, &mut f);
         }
         self.head = self.tail + iter.len();
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 7139a0fb94d..63280e56332 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -12,7 +12,7 @@ use core::fmt;
 use core::hash::{Hash, Hasher};
 use core::iter::{repeat_with, FromIterator};
 use core::marker::PhantomData;
-use core::mem::{self, ManuallyDrop};
+use core::mem::{self, ManuallyDrop, MaybeUninit};
 use core::ops::{Index, IndexMut, Range, RangeBounds};
 use core::ptr::{self, NonNull};
 use core::slice;
@@ -181,16 +181,28 @@ impl<T, A: Allocator> VecDeque<T, A> {
         }
     }
 
-    /// Turn ptr into a slice
+    /// Turn ptr into a slice, since the elements of the backing buffer may be uninitialized,
+    /// we will return a slice of [`MaybeUninit<T>`].
+    ///
+    /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and
+    /// incorrect usage of this method.
+    ///
+    /// [zeroed]: mem::MaybeUninit::zeroed
     #[inline]
-    unsafe fn buffer_as_slice(&self) -> &[T] {
-        unsafe { slice::from_raw_parts(self.ptr(), self.cap()) }
+    unsafe fn buffer_as_slice(&self) -> &[MaybeUninit<T>] {
+        unsafe { slice::from_raw_parts(self.ptr() as *mut MaybeUninit<T>, self.cap()) }
     }
 
-    /// Turn ptr into a mut slice
+    /// Turn ptr into a mut slice, since the elements of the backing buffer may be uninitialized,
+    /// we will return a slice of [`MaybeUninit<T>`].
+    ///
+    /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and
+    /// incorrect usage of this method.
+    ///
+    /// [zeroed]: mem::MaybeUninit::zeroed
     #[inline]
-    unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T] {
-        unsafe { slice::from_raw_parts_mut(self.ptr(), self.cap()) }
+    unsafe fn buffer_as_mut_slice(&mut self) -> &mut [MaybeUninit<T>] {
+        unsafe { slice::from_raw_parts_mut(self.ptr() as *mut MaybeUninit<T>, self.cap()) }
     }
 
     /// Moves an element out of the buffer
@@ -1055,9 +1067,13 @@ impl<T, A: Allocator> VecDeque<T, A> {
     #[inline]
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
     pub fn as_slices(&self) -> (&[T], &[T]) {
+        // Safety:
+        // - `self.head` and `self.tail` in a ring buffer are always valid indices.
+        // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized.
         unsafe {
             let buf = self.buffer_as_slice();
-            RingSlices::ring_slices(buf, self.head, self.tail)
+            let (front, back) = RingSlices::ring_slices(buf, self.head, self.tail);
+            (MaybeUninit::slice_assume_init_ref(front), MaybeUninit::slice_assume_init_ref(back))
         }
     }
 
@@ -1089,11 +1105,15 @@ impl<T, A: Allocator> VecDeque<T, A> {
     #[inline]
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
     pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
+        // Safety:
+        // - `self.head` and `self.tail` in a ring buffer are always valid indices.
+        // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized.
         unsafe {
             let head = self.head;
             let tail = self.tail;
             let buf = self.buffer_as_mut_slice();
-            RingSlices::ring_slices(buf, head, tail)
+            let (front, back) = RingSlices::ring_slices(buf, head, tail);
+            (MaybeUninit::slice_assume_init_mut(front), MaybeUninit::slice_assume_init_mut(back))
         }
     }
 
@@ -2119,7 +2139,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns false.
+    /// In other words, remove all elements `e` for which `f(&e)` returns false.
     /// This method operates in place, visiting each element exactly once in the
     /// original order, and preserves the order of the retained elements.
     ///
@@ -2158,7 +2178,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns false.
+    /// In other words, remove all elements `e` for which `f(&e)` returns false.
     /// This method operates in place, visiting each element exactly once in the
     /// original order, and preserves the order of the retained elements.
     ///
@@ -2327,7 +2347,14 @@ impl<T, A: Allocator> VecDeque<T, A> {
         if self.is_contiguous() {
             let tail = self.tail;
             let head = self.head;
-            return unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 };
+            // Safety:
+            // - `self.head` and `self.tail` in a ring buffer are always valid indices.
+            // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized.
+            return unsafe {
+                MaybeUninit::slice_assume_init_mut(
+                    RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0,
+                )
+            };
         }
 
         let buf = self.buf.ptr();
@@ -2413,7 +2440,14 @@ impl<T, A: Allocator> VecDeque<T, A> {
 
         let tail = self.tail;
         let head = self.head;
-        unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 }
+        // Safety:
+        // - `self.head` and `self.tail` in a ring buffer are always valid indices.
+        // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized.
+        unsafe {
+            MaybeUninit::slice_assume_init_mut(
+                RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0,
+            )
+        }
     }
 
     /// Rotates the double-ended queue `mid` places to the left.
diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index aeb7554f8e9..501a6353b2c 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -416,9 +416,9 @@
 //! fn main() {
 //!     let myvector = Vector2D { x: 3, y: 4 };
 //!
-//!     println!("{}", myvector);       // => "(3, 4)"
-//!     println!("{:?}", myvector);     // => "Vector2D {x: 3, y:4}"
-//!     println!("{:10.3b}", myvector); // => "     5.000"
+//!     println!("{myvector}");       // => "(3, 4)"
+//!     println!("{myvector:?}");     // => "Vector2D {x: 3, y:4}"
+//!     println!("{myvector:10.3b}"); // => "     5.000"
 //! }
 //! ```
 //!
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 82493f9c398..0a180b83355 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -140,7 +140,7 @@
 #![feature(box_syntax)]
 #![feature(cfg_sanitize)]
 #![feature(const_deref)]
-#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
 #![feature(const_mut_refs)]
 #![feature(const_ptr_write)]
 #![feature(const_precise_live_drops)]
diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs
index 843a9b07fa9..d7c28f80633 100644
--- a/library/alloc/src/rc/tests.rs
+++ b/library/alloc/src/rc/tests.rs
@@ -309,7 +309,7 @@ fn test_cowrc_clone_weak() {
 #[test]
 fn test_show() {
     let foo = Rc::new(75);
-    assert_eq!(format!("{:?}", foo), "75");
+    assert_eq!(format!("{foo:?}"), "75");
 }
 
 #[test]
@@ -324,7 +324,7 @@ fn test_maybe_thin_unsized() {
     use std::ffi::{CStr, CString};
 
     let x: Rc<CStr> = Rc::from(CString::new("swordfish").unwrap().into_boxed_c_str());
-    assert_eq!(format!("{:?}", x), "\"swordfish\"");
+    assert_eq!(format!("{x:?}"), "\"swordfish\"");
     let y: Weak<CStr> = Rc::downgrade(&x);
     drop(x);
 
@@ -451,7 +451,7 @@ fn test_from_box_trait_zero_sized() {
     let b: Box<dyn Debug> = box ();
     let r: Rc<dyn Debug> = Rc::from(b);
 
-    assert_eq!(format!("{:?}", r), "()");
+    assert_eq!(format!("{r:?}"), "()");
 }
 
 #[test]
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index f0397d08f95..f52871c73d9 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -48,7 +48,7 @@
 //! ```
 //! let numbers = &[0, 1, 2];
 //! for n in numbers {
-//!     println!("{} is a number!", n);
+//!     println!("{n} is a number!");
 //! }
 //! ```
 //!
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 716bb4983a6..71419c15196 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -2718,7 +2718,7 @@ impl From<String> for Vec<u8> {
     /// let v1 = Vec::from(s1);
     ///
     /// for b in v1 {
-    ///     println!("{}", b);
+    ///     println!("{b}");
     /// }
     /// ```
     fn from(string: String) -> Vec<u8> {
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 7e7670aad64..2140c3f168d 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -200,7 +200,7 @@ macro_rules! acquire {
 ///     let five = Arc::clone(&five);
 ///
 ///     thread::spawn(move || {
-///         println!("{:?}", five);
+///         println!("{five:?}");
 ///     });
 /// }
 /// ```
@@ -221,7 +221,7 @@ macro_rules! acquire {
 ///
 ///     thread::spawn(move || {
 ///         let v = val.fetch_add(1, Ordering::SeqCst);
-///         println!("{:?}", v);
+///         println!("{v:?}");
 ///     });
 /// }
 /// ```
diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs
index 4ccb32fbbf6..452a8877301 100644
--- a/library/alloc/src/sync/tests.rs
+++ b/library/alloc/src/sync/tests.rs
@@ -335,7 +335,7 @@ fn test_weak_count() {
 #[test]
 fn show_arc() {
     let a = Arc::new(5);
-    assert_eq!(format!("{:?}", a), "5");
+    assert_eq!(format!("{a:?}"), "5");
 }
 
 // Make sure deriving works with Arc<T>
@@ -347,7 +347,7 @@ struct Foo {
 #[test]
 fn test_unsized() {
     let x: Arc<[i32]> = Arc::new([1, 2, 3]);
-    assert_eq!(format!("{:?}", x), "[1, 2, 3]");
+    assert_eq!(format!("{x:?}"), "[1, 2, 3]");
     let y = Arc::downgrade(&x.clone());
     drop(x);
     assert!(y.upgrade().is_none());
@@ -359,7 +359,7 @@ fn test_maybe_thin_unsized() {
     use std::ffi::{CStr, CString};
 
     let x: Arc<CStr> = Arc::from(CString::new("swordfish").unwrap().into_boxed_c_str());
-    assert_eq!(format!("{:?}", x), "\"swordfish\"");
+    assert_eq!(format!("{x:?}"), "\"swordfish\"");
     let y: Weak<CStr> = Arc::downgrade(&x);
     drop(x);
 
@@ -509,7 +509,7 @@ fn test_from_box_trait_zero_sized() {
     let b: Box<dyn Debug> = box ();
     let r: Arc<dyn Debug> = Arc::from(b);
 
-    assert_eq!(format!("{:?}", r), "()");
+    assert_eq!(format!("{r:?}"), "()");
 }
 
 #[test]
diff --git a/library/alloc/src/tests.rs b/library/alloc/src/tests.rs
index b4741c35c58..299ed156a5d 100644
--- a/library/alloc/src/tests.rs
+++ b/library/alloc/src/tests.rs
@@ -47,8 +47,8 @@ fn any_move() {
 fn test_show() {
     let a = Box::new(8) as Box<dyn Any>;
     let b = Box::new(Test) as Box<dyn Any>;
-    let a_str = format!("{:?}", a);
-    let b_str = format!("{:?}", b);
+    let a_str = format!("{a:?}");
+    let b_str = format!("{b:?}");
     assert_eq!(a_str, "Any { .. }");
     assert_eq!(b_str, "Any { .. }");
 
@@ -56,9 +56,9 @@ fn test_show() {
     static TEST: Test = Test;
     let a = &EIGHT as &dyn Any;
     let b = &TEST as &dyn Any;
-    let s = format!("{:?}", a);
+    let s = format!("{a:?}");
     assert_eq!(s, "Any { .. }");
-    let s = format!("{:?}", b);
+    let s = format!("{b:?}");
     assert_eq!(s, "Any { .. }");
 }
 
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index c4c393f55ee..5131168db0c 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -169,7 +169,7 @@ mod spec_extend;
 /// vec.extend([1, 2, 3].iter().copied());
 ///
 /// for x in &vec {
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 /// assert_eq!(vec, [7, 1, 2, 3]);
 /// ```
@@ -211,7 +211,7 @@ mod spec_extend;
 ///
 /// while let Some(top) = stack.pop() {
 ///     // Prints 3, 2, 1
-///     println!("{}", top);
+///     println!("{top}");
 /// }
 /// ```
 ///
@@ -1297,7 +1297,7 @@ impl<T, A: Allocator> Vec<T, A> {
         #[cold]
         #[inline(never)]
         fn assert_failed(index: usize, len: usize) -> ! {
-            panic!("swap_remove index (is {}) should be < len (is {})", index, len);
+            panic!("swap_remove index (is {index}) should be < len (is {len})");
         }
 
         let len = self.len();
@@ -1338,7 +1338,7 @@ impl<T, A: Allocator> Vec<T, A> {
         #[cold]
         #[inline(never)]
         fn assert_failed(index: usize, len: usize) -> ! {
-            panic!("insertion index (is {}) should be <= len (is {})", index, len);
+            panic!("insertion index (is {index}) should be <= len (is {len})");
         }
 
         let len = self.len();
@@ -1397,7 +1397,7 @@ impl<T, A: Allocator> Vec<T, A> {
         #[inline(never)]
         #[track_caller]
         fn assert_failed(index: usize, len: usize) -> ! {
-            panic!("removal index (is {}) should be < len (is {})", index, len);
+            panic!("removal index (is {index}) should be < len (is {len})");
         }
 
         let len = self.len();
@@ -1424,7 +1424,7 @@ impl<T, A: Allocator> Vec<T, A> {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+    /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
     /// This method operates in place, visiting each element exactly once in the
     /// original order, and preserves the order of the retained elements.
     ///
@@ -1942,7 +1942,7 @@ impl<T, A: Allocator> Vec<T, A> {
         #[cold]
         #[inline(never)]
         fn assert_failed(at: usize, len: usize) -> ! {
-            panic!("`at` split index (is {}) should be <= len (is {})", at, len);
+            panic!("`at` split index (is {at}) should be <= len (is {len})");
         }
 
         if at > self.len() {
@@ -2568,7 +2568,7 @@ impl<T, A: Allocator> IntoIterator for Vec<T, A> {
     /// let v = vec!["a".to_string(), "b".to_string()];
     /// for s in v.into_iter() {
     ///     // s has type String, not &String
-    ///     println!("{}", s);
+    ///     println!("{s}");
     /// }
     /// ```
     #[inline]
diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs
index 0d7acfed8c6..9e5123be989 100644
--- a/library/alloc/tests/boxed.rs
+++ b/library/alloc/tests/boxed.rs
@@ -160,7 +160,7 @@ fn const_box() {
         *boxed = 42;
         assert!(*boxed == 42);
 
-        *boxed
+        *Box::leak(boxed)
     };
 
     assert!(VALUE == 42);
diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs
index 27ab6c07e43..1575a5999f9 100644
--- a/library/alloc/tests/fmt.rs
+++ b/library/alloc/tests/fmt.rs
@@ -84,8 +84,8 @@ fn test_format_macro_interface() {
     }
     t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
     t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
-    t!(format!("{:x}", A), "aloha");
-    t!(format!("{:X}", B), "adios");
+    t!(format!("{A:x}"), "aloha");
+    t!(format!("{B:X}"), "adios");
     t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
     t!(format!("{1} {0}", 0, 1), "1 0");
     t!(format!("{foo} {bar}", foo = 0, bar = 1), "0 1");
@@ -94,11 +94,11 @@ fn test_format_macro_interface() {
     t!(format!("{_foo}", _foo = 6usize), "6");
     t!(format!("{foo_bar}", foo_bar = 1), "1");
     t!(format!("{}", 5 + 5), "10");
-    t!(format!("{:#4}", C), "☃123");
-    t!(format!("{:b}", D), "aa☃bb");
+    t!(format!("{C:#4}"), "☃123");
+    t!(format!("{D:b}"), "aa☃bb");
 
     let a: &dyn fmt::Debug = &1;
-    t!(format!("{:?}", a), "1");
+    t!(format!("{a:?}"), "1");
 
     // Formatting strings and their arguments
     t!(format!("{}", "a"), "a");
@@ -206,7 +206,7 @@ fn test_format_macro_interface() {
     // Test that pointers don't get truncated.
     {
         let val = usize::MAX;
-        let exp = format!("{:#x}", val);
+        let exp = format!("{val:#x}");
         t!(format!("{:p}", val as *const isize), exp);
     }
 
@@ -216,14 +216,14 @@ fn test_format_macro_interface() {
 
     // make sure that format! doesn't move out of local variables
     let a = Box::new(3);
-    format!("{}", a);
-    format!("{}", a);
+    format!("{a}");
+    format!("{a}");
 
     // make sure that format! doesn't cause spurious unused-unsafe warnings when
     // it's inside of an outer unsafe block
     unsafe {
         let a: isize = ::std::mem::transmute(3_usize);
-        format!("{}", a);
+        format!("{a}");
     }
 
     // test that trailing commas are acceptable
@@ -315,9 +315,9 @@ fn test_once() {
 #[test]
 fn test_refcell() {
     let refcell = RefCell::new(5);
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
+    assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }");
     let borrow = refcell.borrow_mut();
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: <borrowed> }");
+    assert_eq!(format!("{refcell:?}"), "RefCell { value: <borrowed> }");
     drop(borrow);
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
+    assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }");
 }
diff --git a/library/alloc/tests/linked_list.rs b/library/alloc/tests/linked_list.rs
index 5f5bd9af2fe..66a9cca6644 100644
--- a/library/alloc/tests/linked_list.rs
+++ b/library/alloc/tests/linked_list.rs
@@ -302,10 +302,10 @@ fn test_ord_nan() {
 #[test]
 fn test_show() {
     let list: LinkedList<_> = (0..10).collect();
-    assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+    assert_eq!(format!("{list:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
 
     let list: LinkedList<_> = ["just", "one", "test", "more"].into_iter().collect();
-    assert_eq!(format!("{:?}", list), "[\"just\", \"one\", \"test\", \"more\"]");
+    assert_eq!(format!("{list:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
 }
 
 #[test]
diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs
index b93d7938bc9..b027a25a146 100644
--- a/library/alloc/tests/slice.rs
+++ b/library/alloc/tests/slice.rs
@@ -1045,10 +1045,10 @@ fn test_split_iterators_size_hint() {
             a(v.rsplit_mut(p), b, "rsplit_mut");
 
             for n in 0..=3 {
-                a(v.splitn(n, p), b, f!("splitn, n = {}", n));
-                a(v.splitn_mut(n, p), b, f!("splitn_mut, n = {}", n));
-                a(v.rsplitn(n, p), b, f!("rsplitn, n = {}", n));
-                a(v.rsplitn_mut(n, p), b, f!("rsplitn_mut, n = {}", n));
+                a(v.splitn(n, p), b, f!("splitn, n = {n}"));
+                a(v.splitn_mut(n, p), b, f!("splitn_mut, n = {n}"));
+                a(v.rsplitn(n, p), b, f!("rsplitn, n = {n}"));
+                a(v.rsplitn_mut(n, p), b, f!("rsplitn_mut, n = {n}"));
             }
         }
     }
@@ -1184,8 +1184,8 @@ fn test_show() {
     macro_rules! test_show_vec {
         ($x:expr, $x_str:expr) => {{
             let (x, x_str) = ($x, $x_str);
-            assert_eq!(format!("{:?}", x), x_str);
-            assert_eq!(format!("{:?}", x), x_str);
+            assert_eq!(format!("{x:?}"), x_str);
+            assert_eq!(format!("{x:?}"), x_str);
         }};
     }
     let empty = Vec::<i32>::new();
diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs
index 6b8be2506b6..f3ed611acda 100644
--- a/library/alloc/tests/str.rs
+++ b/library/alloc/tests/str.rs
@@ -1259,7 +1259,7 @@ fn test_chars_debug() {
     let s = "ศไทย中华Việt Nam";
     let c = s.chars();
     assert_eq!(
-        format!("{:?}", c),
+        format!("{c:?}"),
         r#"Chars(['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'])"#
     );
 }
@@ -1870,7 +1870,7 @@ mod pattern {
         }
 
         if let Some(err) = err {
-            panic!("Input skipped range at {}", err);
+            panic!("Input skipped range at {err}");
         }
 
         if first_index != haystack.len() {
@@ -2187,10 +2187,10 @@ fn utf8() {
     fn check_str_eq(a: String, b: String) {
         let mut i: isize = 0;
         for ab in a.bytes() {
-            println!("{}", i);
-            println!("{}", ab);
+            println!("{i}");
+            println!("{ab}");
             let bb: u8 = b.as_bytes()[i as usize];
-            println!("{}", bb);
+            println!("{bb}");
             assert_eq!(ab, bb);
             i += 1;
         }
diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs
index 893283e5a24..b6836fdc88e 100644
--- a/library/alloc/tests/string.rs
+++ b/library/alloc/tests/string.rs
@@ -470,7 +470,7 @@ fn test_simple_types() {
 #[test]
 fn test_vectors() {
     let x: Vec<i32> = vec![];
-    assert_eq!(format!("{:?}", x), "[]");
+    assert_eq!(format!("{x:?}"), "[]");
     assert_eq!(format!("{:?}", vec![1]), "[1]");
     assert_eq!(format!("{:?}", vec![1, 2, 3]), "[1, 2, 3]");
     assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == "[[], [1], [1, 1]]");
@@ -871,6 +871,6 @@ fn test_from_char() {
 fn test_str_concat() {
     let a: String = "hello".to_string();
     let b: String = "world".to_string();
-    let s: String = format!("{}{}", a, b);
+    let s: String = format!("{a}{b}");
     assert_eq!(s.as_bytes()[9], 'd' as u8);
 }
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 705914b4497..ca0fcc855c7 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -100,7 +100,7 @@ fn test_debug_fmt() {
     assert_eq!("[0, 1]", format!("{:?}", vec2));
 
     let slice: &[isize] = &[4, 5];
-    assert_eq!("[4, 5]", format!("{:?}", slice));
+    assert_eq!("[4, 5]", format!("{slice:?}"));
 }
 
 #[test]
@@ -918,7 +918,7 @@ fn test_into_iter_as_mut_slice() {
 fn test_into_iter_debug() {
     let vec = vec!['a', 'b', 'c'];
     let into_iter = vec.into_iter();
-    let debug = format!("{:?}", into_iter);
+    let debug = format!("{into_iter:?}");
     assert_eq!(debug, "IntoIter(['a', 'b', 'c'])");
 }
 
@@ -2336,7 +2336,7 @@ fn test_vec_dedup_panicking() {
     let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index);
 
     if !ok {
-        panic!("expected: {:?}\ngot: {:?}\n", expected, vec);
+        panic!("expected: {expected:?}\ngot: {vec:?}\n");
     }
 }
 
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index 18954f094c6..89cc7f905be 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -647,10 +647,10 @@ fn test_ord() {
 #[test]
 fn test_show() {
     let ringbuf: VecDeque<_> = (0..10).collect();
-    assert_eq!(format!("{:?}", ringbuf), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+    assert_eq!(format!("{ringbuf:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
 
     let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"].iter().cloned().collect();
-    assert_eq!(format!("{:?}", ringbuf), "[\"just\", \"one\", \"test\", \"more\"]");
+    assert_eq!(format!("{ringbuf:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
 }
 
 #[test]
diff --git a/library/core/benches/num/flt2dec/mod.rs b/library/core/benches/num/flt2dec/mod.rs
index a1ce33d0bb4..32fd5e626bc 100644
--- a/library/core/benches/num/flt2dec/mod.rs
+++ b/library/core/benches/num/flt2dec/mod.rs
@@ -12,7 +12,7 @@ use test::Bencher;
 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
     match decode(v).1 {
         FullDecoded::Finite(decoded) => decoded,
-        full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+        full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
     }
 }
 
diff --git a/library/core/benches/num/flt2dec/strategy/grisu.rs b/library/core/benches/num/flt2dec/strategy/grisu.rs
index 76425731e1d..8e47a046cde 100644
--- a/library/core/benches/num/flt2dec/strategy/grisu.rs
+++ b/library/core/benches/num/flt2dec/strategy/grisu.rs
@@ -6,7 +6,7 @@ use test::Bencher;
 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
     match decode(v).1 {
         FullDecoded::Finite(decoded) => decoded,
-        full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+        full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
     }
 }
 
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index 72528185707..3b15ab1e689 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -62,7 +62,7 @@
 //!             println!("String ({}): {}", as_string.len(), as_string);
 //!         }
 //!         None => {
-//!             println!("{:?}", value);
+//!             println!("{value:?}");
 //!         }
 //!     }
 //! }
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index ee79021ed53..20dfbc6347c 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -276,9 +276,10 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] {
 }
 
 #[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
-impl<T, I, const N: usize> Index<I> for [T; N]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I, const N: usize> const Index<I> for [T; N]
 where
-    [T]: Index<I>,
+    [T]: ~const Index<I>,
 {
     type Output = <[T] as Index<I>>::Output;
 
@@ -289,9 +290,10 @@ where
 }
 
 #[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
-impl<T, I, const N: usize> IndexMut<I> for [T; N]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I, const N: usize> const IndexMut<I> for [T; N]
 where
-    [T]: IndexMut<I>,
+    [T]: ~const IndexMut<I>,
 {
     #[inline]
     fn index_mut(&mut self, index: I) -> &mut Self::Output {
diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs
index 532208e41af..8a4cb78cc7f 100644
--- a/library/core/src/ascii.rs
+++ b/library/core/src/ascii.rs
@@ -98,22 +98,20 @@ pub fn escape_default(c: u8) -> EscapeDefault {
         b'\'' => ([b'\\', b'\'', 0, 0], 2),
         b'"' => ([b'\\', b'"', 0, 0], 2),
         b'\x20'..=b'\x7e' => ([c, 0, 0, 0], 1),
-        _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4),
+        _ => {
+            let hex_digits: &[u8; 16] = b"0123456789abcdef";
+            ([b'\\', b'x', hex_digits[(c >> 4) as usize], hex_digits[(c & 0xf) as usize]], 4)
+        }
     };
 
     return EscapeDefault { range: 0..len, data };
-
-    fn hexify(b: u8) -> u8 {
-        match b {
-            0..=9 => b'0' + b,
-            _ => b'a' + b - 10,
-        }
-    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Iterator for EscapeDefault {
     type Item = u8;
+
+    #[inline]
     fn next(&mut self) -> Option<u8> {
         self.range.next().map(|i| self.data[i as usize])
     }
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index aef7ad77568..9dbb5eecd46 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -85,7 +85,7 @@
 //!     // of scope then the subsequent borrow would cause a dynamic thread panic.
 //!     // This is the major hazard of using `RefCell`.
 //!     let total: i32 = shared_map.borrow().values().sum();
-//!     println!("{}", total);
+//!     println!("{total}");
 //! }
 //! ```
 //!
diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs
index 139841368d6..4ee0310b361 100644
--- a/library/core/src/char/convert.rs
+++ b/library/core/src/char/convert.rs
@@ -218,6 +218,8 @@ impl const From<u8> for char {
 }
 
 /// An error which can be returned when parsing a char.
+///
+/// This `struct` is created when using the [`char::from_str`] method.
 #[stable(feature = "char_from_str", since = "1.20.0")]
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ParseCharError {
@@ -300,7 +302,10 @@ impl TryFrom<u32> for char {
     }
 }
 
-/// The error type returned when a conversion from u32 to char fails.
+/// The error type returned when a conversion from [`prim@u32`] to [`prim@char`] fails.
+///
+/// This `struct` is created by the [`char::try_from<u32>`](char#impl-TryFrom<u32>) method.
+/// See its documentation for more.
 #[stable(feature = "try_from", since = "1.34.0")]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct CharTryFromError(());
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index c4c0a5a6c78..66de94d1b92 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -370,7 +370,7 @@ impl char {
     ///
     /// ```
     /// for c in '❤'.escape_unicode() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -448,7 +448,7 @@ impl char {
     ///
     /// ```
     /// for c in '\n'.escape_debug() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -504,7 +504,7 @@ impl char {
     ///
     /// ```
     /// for c in '"'.escape_default() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -949,7 +949,7 @@ impl char {
     ///
     /// ```
     /// for c in 'İ'.to_lowercase() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -1016,7 +1016,7 @@ impl char {
     ///
     /// ```
     /// for c in 'ß'.to_uppercase() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 6f9579043c3..1912694412b 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -127,7 +127,11 @@ pub trait Clone: Sized {
     /// allocations.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    fn clone_from(&mut self, source: &Self) {
+    #[default_method_body_is_const]
+    fn clone_from(&mut self, source: &Self)
+    where
+        Self: ~const Drop,
+    {
         *self = source.clone()
     }
 }
@@ -178,7 +182,8 @@ mod impls {
         ($($t:ty)*) => {
             $(
                 #[stable(feature = "rust1", since = "1.0.0")]
-                impl Clone for $t {
+                #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+                impl const Clone for $t {
                     #[inline]
                     fn clone(&self) -> Self {
                         *self
@@ -196,7 +201,8 @@ mod impls {
     }
 
     #[unstable(feature = "never_type", issue = "35121")]
-    impl Clone for ! {
+    #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+    impl const Clone for ! {
         #[inline]
         fn clone(&self) -> Self {
             *self
@@ -204,7 +210,8 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Clone for *const T {
+    #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+    impl<T: ?Sized> const Clone for *const T {
         #[inline]
         fn clone(&self) -> Self {
             *self
@@ -212,7 +219,8 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Clone for *mut T {
+    #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+    impl<T: ?Sized> const Clone for *mut T {
         #[inline]
         fn clone(&self) -> Self {
             *self
@@ -221,7 +229,8 @@ mod impls {
 
     /// Shared references can be cloned, but mutable references *cannot*!
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Clone for &T {
+    #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+    impl<T: ?Sized> const Clone for &T {
         #[inline]
         #[rustc_diagnostic_item = "noop_method_clone"]
         fn clone(&self) -> Self {
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 0ceedf93633..f5ea5f5ba50 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -300,7 +300,8 @@ pub trait Into<T>: Sized {
 /// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more
 /// details.
 ///
-/// **Note: This trait must not fail**. If the conversion can fail, use [`TryFrom`].
+/// **Note: This trait must not fail**. The `From` trait is intended for perfect conversions.
+/// If the conversion can fail or is not perfect, use [`TryFrom`].
 ///
 /// # Generic Implementations
 ///
@@ -690,7 +691,8 @@ impl AsMut<str> for str {
 pub enum Infallible {}
 
 #[stable(feature = "convert_infallible", since = "1.34.0")]
-impl Clone for Infallible {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl const Clone for Infallible {
     fn clone(&self) -> Infallible {
         match *self {}
     }
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 90c5719f486..84cf1753f86 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -64,7 +64,7 @@ pub mod rt {
 ///
 /// let pythagorean_triple = Triangle { a: 3.0, b: 4.0, c: 5.0 };
 ///
-/// assert_eq!(format!("{}", pythagorean_triple), "(3, 4, 5)");
+/// assert_eq!(format!("{pythagorean_triple}"), "(3, 4, 5)");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub type Result = result::Result<(), Error>;
@@ -174,7 +174,7 @@ pub trait Write {
     /// use std::fmt::{Error, Write};
     ///
     /// fn writer<W: Write>(f: &mut W, s: &str) -> Result<(), Error> {
-    ///     f.write_fmt(format_args!("{}", s))
+    ///     f.write_fmt(format_args!("{s}"))
     /// }
     ///
     /// let mut buf = String::new();
@@ -562,7 +562,7 @@ impl Display for Arguments<'_> {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {:?}", origin), "The origin is: Point { x: 0, y: 0 }");
+/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
 /// ```
 ///
 /// Manually implementing:
@@ -586,7 +586,7 @@ impl Display for Arguments<'_> {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {:?}", origin), "The origin is: Point { x: 0, y: 0 }");
+/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
 /// ```
 ///
 /// There are a number of helper methods on the [`Formatter`] struct to help you with manual
@@ -627,7 +627,7 @@ impl Display for Arguments<'_> {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {:#?}", origin),
+/// assert_eq!(format!("The origin is: {origin:#?}"),
 /// "The origin is: Point {
 ///     x: 0,
 ///     y: 0,
@@ -670,9 +670,9 @@ pub trait Debug {
     /// }
     ///
     /// let position = Position { longitude: 1.987, latitude: 2.983 };
-    /// assert_eq!(format!("{:?}", position), "(1.987, 2.983)");
+    /// assert_eq!(format!("{position:?}"), "(1.987, 2.983)");
     ///
-    /// assert_eq!(format!("{:#?}", position), "(
+    /// assert_eq!(format!("{position:#?}"), "(
     ///     1.987,
     ///     2.983,
     /// )");
@@ -724,7 +724,7 @@ pub use macros::Debug;
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {}", origin), "The origin is: (0, 0)");
+/// assert_eq!(format!("The origin is: {origin}"), "The origin is: (0, 0)");
 /// ```
 #[rustc_on_unimplemented(
     on(
@@ -786,8 +786,8 @@ pub trait Display {
 /// ```
 /// let x = 42; // 42 is '52' in octal
 ///
-/// assert_eq!(format!("{:o}", x), "52");
-/// assert_eq!(format!("{:#o}", x), "0o52");
+/// assert_eq!(format!("{x:o}"), "52");
+/// assert_eq!(format!("{x:#o}"), "0o52");
 ///
 /// assert_eq!(format!("{:o}", -16), "37777777760");
 /// ```
@@ -809,9 +809,9 @@ pub trait Display {
 ///
 /// let l = Length(9);
 ///
-/// assert_eq!(format!("l as octal is: {:o}", l), "l as octal is: 11");
+/// assert_eq!(format!("l as octal is: {l:o}"), "l as octal is: 11");
 ///
-/// assert_eq!(format!("l as octal is: {:#06o}", l), "l as octal is: 0o0011");
+/// assert_eq!(format!("l as octal is: {l:#06o}"), "l as octal is: 0o0011");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Octal {
@@ -840,8 +840,8 @@ pub trait Octal {
 /// ```
 /// let x = 42; // 42 is '101010' in binary
 ///
-/// assert_eq!(format!("{:b}", x), "101010");
-/// assert_eq!(format!("{:#b}", x), "0b101010");
+/// assert_eq!(format!("{x:b}"), "101010");
+/// assert_eq!(format!("{x:#b}"), "0b101010");
 ///
 /// assert_eq!(format!("{:b}", -16), "11111111111111111111111111110000");
 /// ```
@@ -863,10 +863,10 @@ pub trait Octal {
 ///
 /// let l = Length(107);
 ///
-/// assert_eq!(format!("l as binary is: {:b}", l), "l as binary is: 1101011");
+/// assert_eq!(format!("l as binary is: {l:b}"), "l as binary is: 1101011");
 ///
 /// assert_eq!(
-///     format!("l as binary is: {:#032b}", l),
+///     format!("l as binary is: {l:#032b}"),
 ///     "l as binary is: 0b000000000000000000000001101011"
 /// );
 /// ```
@@ -898,8 +898,8 @@ pub trait Binary {
 /// ```
 /// let x = 42; // 42 is '2a' in hex
 ///
-/// assert_eq!(format!("{:x}", x), "2a");
-/// assert_eq!(format!("{:#x}", x), "0x2a");
+/// assert_eq!(format!("{x:x}"), "2a");
+/// assert_eq!(format!("{x:#x}"), "0x2a");
 ///
 /// assert_eq!(format!("{:x}", -16), "fffffff0");
 /// ```
@@ -921,9 +921,9 @@ pub trait Binary {
 ///
 /// let l = Length(9);
 ///
-/// assert_eq!(format!("l as hex is: {:x}", l), "l as hex is: 9");
+/// assert_eq!(format!("l as hex is: {l:x}"), "l as hex is: 9");
 ///
-/// assert_eq!(format!("l as hex is: {:#010x}", l), "l as hex is: 0x00000009");
+/// assert_eq!(format!("l as hex is: {l:#010x}"), "l as hex is: 0x00000009");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait LowerHex {
@@ -953,8 +953,8 @@ pub trait LowerHex {
 /// ```
 /// let x = 42; // 42 is '2A' in hex
 ///
-/// assert_eq!(format!("{:X}", x), "2A");
-/// assert_eq!(format!("{:#X}", x), "0x2A");
+/// assert_eq!(format!("{x:X}"), "2A");
+/// assert_eq!(format!("{x:#X}"), "0x2A");
 ///
 /// assert_eq!(format!("{:X}", -16), "FFFFFFF0");
 /// ```
@@ -976,9 +976,9 @@ pub trait LowerHex {
 ///
 /// let l = Length(i32::MAX);
 ///
-/// assert_eq!(format!("l as hex is: {:X}", l), "l as hex is: 7FFFFFFF");
+/// assert_eq!(format!("l as hex is: {l:X}"), "l as hex is: 7FFFFFFF");
 ///
-/// assert_eq!(format!("l as hex is: {:#010X}", l), "l as hex is: 0x7FFFFFFF");
+/// assert_eq!(format!("l as hex is: {l:#010X}"), "l as hex is: 0x7FFFFFFF");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait UpperHex {
@@ -1003,7 +1003,7 @@ pub trait UpperHex {
 /// ```
 /// let x = &42;
 ///
-/// let address = format!("{:p}", x); // this produces something like '0x7f06092ac6d0'
+/// let address = format!("{x:p}"); // this produces something like '0x7f06092ac6d0'
 /// ```
 ///
 /// Implementing `Pointer` on a type:
@@ -1024,9 +1024,9 @@ pub trait UpperHex {
 ///
 /// let l = Length(42);
 ///
-/// println!("l is in memory here: {:p}", l);
+/// println!("l is in memory here: {l:p}");
 ///
-/// let l_ptr = format!("{:018p}", l);
+/// let l_ptr = format!("{l:018p}");
 /// assert_eq!(l_ptr.len(), 18);
 /// assert_eq!(&l_ptr[..2], "0x");
 /// ```
@@ -1054,7 +1054,7 @@ pub trait Pointer {
 /// ```
 /// let x = 42.0; // 42.0 is '4.2e1' in scientific notation
 ///
-/// assert_eq!(format!("{:e}", x), "4.2e1");
+/// assert_eq!(format!("{x:e}"), "4.2e1");
 /// ```
 ///
 /// Implementing `LowerExp` on a type:
@@ -1074,12 +1074,12 @@ pub trait Pointer {
 /// let l = Length(100);
 ///
 /// assert_eq!(
-///     format!("l in scientific notation is: {:e}", l),
+///     format!("l in scientific notation is: {l:e}"),
 ///     "l in scientific notation is: 1e2"
 /// );
 ///
 /// assert_eq!(
-///     format!("l in scientific notation is: {:05e}", l),
+///     format!("l in scientific notation is: {l:05e}"),
 ///     "l in scientific notation is: 001e2"
 /// );
 /// ```
@@ -1105,7 +1105,7 @@ pub trait LowerExp {
 /// ```
 /// let x = 42.0; // 42.0 is '4.2E1' in scientific notation
 ///
-/// assert_eq!(format!("{:E}", x), "4.2E1");
+/// assert_eq!(format!("{x:E}"), "4.2E1");
 /// ```
 ///
 /// Implementing `UpperExp` on a type:
@@ -1125,12 +1125,12 @@ pub trait LowerExp {
 /// let l = Length(100);
 ///
 /// assert_eq!(
-///     format!("l in scientific notation is: {:E}", l),
+///     format!("l in scientific notation is: {l:E}"),
 ///     "l in scientific notation is: 1E2"
 /// );
 ///
 /// assert_eq!(
-///     format!("l in scientific notation is: {:05E}", l),
+///     format!("l in scientific notation is: {l:05E}"),
 ///     "l in scientific notation is: 001E2"
 /// );
 /// ```
@@ -1429,8 +1429,8 @@ impl<'a> Formatter<'a> {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{:<4}", Foo), "Foo ");
-    /// assert_eq!(&format!("{:0>4}", Foo), "0Foo");
+    /// assert_eq!(&format!("{Foo:<4}"), "Foo ");
+    /// assert_eq!(&format!("{Foo:0>4}"), "0Foo");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn pad(&mut self, s: &str) -> Result {
@@ -1613,8 +1613,8 @@ impl<'a> Formatter<'a> {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{}", Foo), "Foo");
-    /// assert_eq!(&format!("{:0>8}", Foo), "Foo");
+    /// assert_eq!(&format!("{Foo}"), "Foo");
+    /// assert_eq!(&format!("{Foo:0>8}"), "Foo");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn write_str(&mut self, data: &str) -> Result {
@@ -1670,18 +1670,18 @@ impl<'a> Formatter<'a> {
     ///         let c = formatter.fill();
     ///         if let Some(width) = formatter.width() {
     ///             for _ in 0..width {
-    ///                 write!(formatter, "{}", c)?;
+    ///                 write!(formatter, "{c}")?;
     ///             }
     ///             Ok(())
     ///         } else {
-    ///             write!(formatter, "{}", c)
+    ///             write!(formatter, "{c}")
     ///         }
     ///     }
     /// }
     ///
     /// // We set alignment to the right with ">".
-    /// assert_eq!(&format!("{:G>3}", Foo), "GGG");
-    /// assert_eq!(&format!("{:t>6}", Foo), "tttttt");
+    /// assert_eq!(&format!("{Foo:G>3}"), "GGG");
+    /// assert_eq!(&format!("{Foo:t>6}"), "tttttt");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
@@ -1711,14 +1711,14 @@ impl<'a> Formatter<'a> {
     ///         } else {
     ///             "into the void"
     ///         };
-    ///         write!(formatter, "{}", s)
+    ///         write!(formatter, "{s}")
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{:<}", Foo), "left");
-    /// assert_eq!(&format!("{:>}", Foo), "right");
-    /// assert_eq!(&format!("{:^}", Foo), "center");
-    /// assert_eq!(&format!("{}", Foo), "into the void");
+    /// assert_eq!(&format!("{Foo:<}"), "left");
+    /// assert_eq!(&format!("{Foo:>}"), "right");
+    /// assert_eq!(&format!("{Foo:^}"), "center");
+    /// assert_eq!(&format!("{Foo}"), "into the void");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags_align", since = "1.28.0")]
diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs
index 0912f8675fa..8014dacdd98 100644
--- a/library/core/src/future/into_future.rs
+++ b/library/core/src/future/into_future.rs
@@ -9,20 +9,20 @@ pub trait IntoFuture {
 
     /// Which kind of future are we turning this into?
     #[unstable(feature = "into_future", issue = "67644")]
-    type Future: Future<Output = Self::Output>;
+    type IntoFuture: Future<Output = Self::Output>;
 
     /// Creates a future from a value.
     #[unstable(feature = "into_future", issue = "67644")]
     #[lang = "into_future"]
-    fn into_future(self) -> Self::Future;
+    fn into_future(self) -> Self::IntoFuture;
 }
 
 #[unstable(feature = "into_future", issue = "67644")]
 impl<F: Future> IntoFuture for F {
     type Output = F::Output;
-    type Future = F;
+    type IntoFuture = F;
 
-    fn into_future(self) -> Self::Future {
+    fn into_future(self) -> Self::IntoFuture {
         self
     }
 }
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 330c43d2948..58ea109c735 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -173,3 +173,126 @@ pub fn spin_loop() {
 pub const fn black_box<T>(dummy: T) -> T {
     crate::intrinsics::black_box(dummy)
 }
+
+/// An identity function that causes an `unused_must_use` warning to be
+/// triggered if the given value is not used (returned, stored in a variable,
+/// etc) by the caller.
+///
+/// This is primarily intended for use in macro-generated code, in which a
+/// [`#[must_use]` attribute][must_use] either on a type or a function would not
+/// be convenient.
+///
+/// [must_use]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
+///
+/// # Example
+///
+/// ```
+/// #![feature(hint_must_use)]
+///
+/// use core::fmt;
+///
+/// pub struct Error(/* ... */);
+///
+/// #[macro_export]
+/// macro_rules! make_error {
+///     ($($args:expr),*) => {
+///         core::hint::must_use({
+///             let error = $crate::make_error(core::format_args!($($args),*));
+///             error
+///         })
+///     };
+/// }
+///
+/// // Implementation detail of make_error! macro.
+/// #[doc(hidden)]
+/// pub fn make_error(args: fmt::Arguments<'_>) -> Error {
+///     Error(/* ... */)
+/// }
+///
+/// fn demo() -> Option<Error> {
+///     if true {
+///         // Oops, meant to write `return Some(make_error!("..."));`
+///         Some(make_error!("..."));
+///     }
+///     None
+/// }
+/// #
+/// # // Make rustdoc not wrap the whole snippet in fn main, so that $crate::make_error works
+/// # fn main() {}
+/// ```
+///
+/// In the above example, we'd like an `unused_must_use` lint to apply to the
+/// value created by `make_error!`. However, neither `#[must_use]` on a struct
+/// nor `#[must_use]` on a function is appropriate here, so the macro expands
+/// using `core::hint::must_use` instead.
+///
+/// - We wouldn't want `#[must_use]` on the `struct Error` because that would
+///   make the following unproblematic code trigger a warning:
+///
+///   ```
+///   # struct Error;
+///   #
+///   fn f(arg: &str) -> Result<(), Error>
+///   # { Ok(()) }
+///
+///   #[test]
+///   fn t() {
+///       // Assert that `f` returns error if passed an empty string.
+///       // A value of type `Error` is unused here but that's not a problem.
+///       f("").unwrap_err();
+///   }
+///   ```
+///
+/// - Using `#[must_use]` on `fn make_error` can't help because the return value
+///   *is* used, as the right-hand side of a `let` statement. The `let`
+///   statement looks useless but is in fact necessary for ensuring that
+///   temporaries within the `format_args` expansion are not kept alive past the
+///   creation of the `Error`, as keeping them alive past that point can cause
+///   autotrait issues in async code:
+///
+///   ```
+///   # #![feature(hint_must_use)]
+///   #
+///   # struct Error;
+///   #
+///   # macro_rules! make_error {
+///   #     ($($args:expr),*) => {
+///   #         core::hint::must_use({
+///   #             // If `let` isn't used, then `f()` produces a non-Send future.
+///   #             let error = make_error(core::format_args!($($args),*));
+///   #             error
+///   #         })
+///   #     };
+///   # }
+///   #
+///   # fn make_error(args: core::fmt::Arguments<'_>) -> Error {
+///   #     Error
+///   # }
+///   #
+///   async fn f() {
+///       // Using `let` inside the make_error expansion causes temporaries like
+///       // `unsync()` to drop at the semicolon of that `let` statement, which
+///       // is prior to the await point. They would otherwise stay around until
+///       // the semicolon on *this* statement, which is after the await point,
+///       // and the enclosing Future would not implement Send.
+///       log(make_error!("look: {:p}", unsync())).await;
+///   }
+///
+///   async fn log(error: Error) {/* ... */}
+///
+///   // Returns something without a Sync impl.
+///   fn unsync() -> *const () {
+///       0 as *const ()
+///   }
+///   #
+///   # fn test() {
+///   #     fn assert_send(_: impl Send) {}
+///   #     assert_send(f());
+///   # }
+///   ```
+#[unstable(feature = "hint_must_use", issue = "94745")]
+#[rustc_const_unstable(feature = "hint_must_use", issue = "94745")]
+#[must_use] // <-- :)
+pub const fn must_use<T>(value: T) -> T {
+    value
+}
diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs
index d2077a63e15..4b03449972c 100644
--- a/library/core/src/iter/adapters/map.rs
+++ b/library/core/src/iter/adapters/map.rs
@@ -34,7 +34,7 @@ use crate::ops::Try;
 ///
 /// for pair in ['a', 'b', 'c'].into_iter()
 ///                                .map(|letter| { c += 1; (letter, c) }) {
-///     println!("{:?}", pair);
+///     println!("{pair:?}");
 /// }
 /// ```
 ///
@@ -52,7 +52,7 @@ use crate::ops::Try;
 /// for pair in ['a', 'b', 'c'].into_iter()
 ///                                .map(|letter| { c += 1; (letter, c) })
 ///                                .rev() {
-///     println!("{:?}", pair);
+///     println!("{pair:?}");
 /// }
 /// ```
 #[must_use = "iterators are lazy and do nothing unless consumed"]
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index 65f56f64dbf..5a987733134 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -144,7 +144,7 @@
 //! let values = vec![1, 2, 3, 4, 5];
 //!
 //! for x in values {
-//!     println!("{}", x);
+//!     println!("{x}");
 //! }
 //! ```
 //!
@@ -164,7 +164,7 @@
 //! let values = vec![1, 2, 3, 4, 5];
 //!
 //! for x in values {
-//!     println!("{}", x);
+//!     println!("{x}");
 //! }
 //! ```
 //!
@@ -181,7 +181,7 @@
 //!                 None => break,
 //!             };
 //!             let x = next;
-//!             let () = { println!("{}", x); };
+//!             let () = { println!("{x}"); };
 //!         },
 //!     };
 //!     result
@@ -280,7 +280,7 @@
 //! ```
 //! # #![allow(unused_must_use)]
 //! let v = vec![1, 2, 3, 4, 5];
-//! v.iter().map(|x| println!("{}", x));
+//! v.iter().map(|x| println!("{x}"));
 //! ```
 //!
 //! This will not print any values, as we only created an iterator, rather than
@@ -297,10 +297,10 @@
 //! ```
 //! let v = vec![1, 2, 3, 4, 5];
 //!
-//! v.iter().for_each(|x| println!("{}", x));
+//! v.iter().for_each(|x| println!("{x}"));
 //! // or
 //! for x in &v {
-//!     println!("{}", x);
+//!     println!("{x}");
 //! }
 //! ```
 //!
@@ -329,7 +329,7 @@
 //! let five_numbers = numbers.take(5);
 //!
 //! for number in five_numbers {
-//!     println!("{}", number);
+//!     println!("{number}");
 //! }
 //! ```
 //!
@@ -345,7 +345,7 @@
 //! let ones = std::iter::repeat(1);
 //! let least = ones.min().unwrap(); // Oh no! An infinite loop!
 //! // `ones.min()` causes an infinite loop, so we won't reach this point!
-//! println!("The smallest number one is {}.", least);
+//! println!("The smallest number one is {least}.");
 //! ```
 //!
 //! [`take`]: Iterator::take
diff --git a/library/core/src/iter/sources/once.rs b/library/core/src/iter/sources/once.rs
index 27bc3dcfd79..6e9ed0d3c52 100644
--- a/library/core/src/iter/sources/once.rs
+++ b/library/core/src/iter/sources/once.rs
@@ -48,7 +48,7 @@ use crate::iter::{FusedIterator, TrustedLen};
 ///
 /// // this will give us all of the files in .foo as well as .foorc
 /// for f in files {
-///     println!("{:?}", f);
+///     println!("{f:?}");
 /// }
 /// ```
 #[stable(feature = "iter_once", since = "1.2.0")]
diff --git a/library/core/src/iter/sources/once_with.rs b/library/core/src/iter/sources/once_with.rs
index cf6a3c11524..d79f85c2559 100644
--- a/library/core/src/iter/sources/once_with.rs
+++ b/library/core/src/iter/sources/once_with.rs
@@ -52,7 +52,7 @@ use crate::iter::{FusedIterator, TrustedLen};
 ///
 /// // this will give us all of the files in .foo as well as .foorc
 /// for f in files {
-///     println!("{:?}", f);
+///     println!("{f:?}");
 /// }
 /// ```
 #[inline]
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 637d7bc4488..7b75ab96ee7 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -4,9 +4,11 @@
 /// created from an iterator. This is common for types which describe a
 /// collection of some kind.
 ///
-/// [`FromIterator::from_iter()`] is rarely called explicitly, and is instead
-/// used through [`Iterator::collect()`] method. See [`Iterator::collect()`]'s
-/// documentation for more examples.
+/// If you want to create a collection from the contents of an iterator, the
+/// [`Iterator::collect()`] method is preferred. However, when you need to
+/// specify the container type, [`FromIterator::from_iter()`] can be more
+/// readable than using a turbofish (e.g. `::<Vec<_>>()`). See the
+/// [`Iterator::collect()`] documentation for more examples of its use.
 ///
 /// See also: [`IntoIterator`].
 ///
@@ -32,6 +34,17 @@
 /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
 /// ```
 ///
+/// Using [`FromIterator::from_iter()`] as a more readable alternative to
+/// [`Iterator::collect()`]:
+///
+/// ```
+/// use std::collections::VecDeque;
+/// let first = (0..10).collect::<VecDeque<i32>>();
+/// let second = VecDeque::from_iter(0..10);
+///
+/// assert_eq!(first, second);
+/// ```
+///
 /// Implementing `FromIterator` for your type:
 ///
 /// ```
@@ -214,7 +227,7 @@ pub trait FromIterator<A>: Sized {
 /// {
 ///     collection
 ///         .into_iter()
-///         .map(|item| format!("{:?}", item))
+///         .map(|item| format!("{item:?}"))
 ///         .collect()
 /// }
 /// ```
@@ -332,7 +345,7 @@ impl<I: Iterator> IntoIterator for I {
 /// c.extend(vec![1, 2, 3]);
 ///
 /// // we've added these elements onto the end
-/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{:?}", c));
+/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{c:?}"));
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Extend<A> {
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index a6aed6d210b..bdf94c792c2 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -281,7 +281,7 @@ pub trait DoubleEndedIterator: Iterator {
     /// let zero = "0".to_string();
     ///
     /// let result = numbers.iter().rfold(zero, |acc, &x| {
-    ///     format!("({} + {})", x, acc)
+    ///     format!("({x} + {acc})")
     /// });
     ///
     /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index f5c0a3b5cd8..d980f593081 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -35,6 +35,11 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
               to have a bounded `RangeInclusive`: `0..=end`"
     ),
     on(
+        _Self = "[]",
+        label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
+    ),
+    on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
+    on(
         _Self = "&str",
         label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
     ),
@@ -704,13 +709,13 @@ pub trait Iterator {
     /// ```
     /// # #![allow(unused_must_use)]
     /// // don't do this:
-    /// (0..5).map(|x| println!("{}", x));
+    /// (0..5).map(|x| println!("{x}"));
     ///
     /// // it won't even execute, as it is lazy. Rust will warn you about this.
     ///
     /// // Instead, use for:
     /// for x in 0..5 {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     #[inline]
@@ -756,7 +761,7 @@ pub trait Iterator {
     /// (0..5).flat_map(|x| x * 100 .. x * 110)
     ///       .enumerate()
     ///       .filter(|&(i, x)| (i + x) % 3 == 0)
-    ///       .for_each(|(i, x)| println!("{}:{}", i, x));
+    ///       .for_each(|(i, x)| println!("{i}:{x}"));
     /// ```
     #[inline]
     #[stable(feature = "iterator_for_each", since = "1.21.0")]
@@ -1570,17 +1575,17 @@ pub trait Iterator {
     ///     .filter(|x| x % 2 == 0)
     ///     .fold(0, |sum, i| sum + i);
     ///
-    /// println!("{}", sum);
+    /// println!("{sum}");
     ///
     /// // let's add some inspect() calls to investigate what's happening
     /// let sum = a.iter()
     ///     .cloned()
-    ///     .inspect(|x| println!("about to filter: {}", x))
+    ///     .inspect(|x| println!("about to filter: {x}"))
     ///     .filter(|x| x % 2 == 0)
-    ///     .inspect(|x| println!("made it through filter: {}", x))
+    ///     .inspect(|x| println!("made it through filter: {x}"))
     ///     .fold(0, |sum, i| sum + i);
     ///
-    /// println!("{}", sum);
+    /// println!("{sum}");
     /// ```
     ///
     /// This will print:
@@ -1606,13 +1611,13 @@ pub trait Iterator {
     ///     .map(|line| line.parse::<i32>())
     ///     .inspect(|num| {
     ///         if let Err(ref e) = *num {
-    ///             println!("Parsing error: {}", e);
+    ///             println!("Parsing error: {e}");
     ///         }
     ///     })
     ///     .filter_map(Result::ok)
     ///     .sum();
     ///
-    /// println!("Sum: {}", sum);
+    /// println!("Sum: {sum}");
     /// ```
     ///
     /// This will print:
@@ -1859,6 +1864,77 @@ pub trait Iterator {
         try_process(self, |i| i.collect())
     }
 
+    /// Collects all the items from an iterator into a collection.
+    ///
+    /// This method consumes the iterator and adds all its items to the
+    /// passed collection. The collection is then returned, so the call chain
+    /// can be continued.
+    ///
+    /// This is useful when you already have a collection and wants to add
+    /// the iterator items to it.
+    ///
+    /// This method is a convenience method to call [Extend::extend](trait.Extend.html),
+    /// but instead of being called on a collection, it's called on an iterator.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_collect_into)]
+    ///
+    /// let a = [1, 2, 3];
+    /// let mut vec: Vec::<i32> = vec![0, 1];
+    ///
+    /// a.iter().map(|&x| x * 2).collect_into(&mut vec);
+    /// a.iter().map(|&x| x * 10).collect_into(&mut vec);
+    ///
+    /// assert_eq!(vec![0, 1, 2, 4, 6, 10, 20, 30], vec);
+    /// ```
+    ///
+    /// `Vec` can have a manual set capacity to avoid reallocating it:
+    ///
+    /// ```
+    /// #![feature(iter_collect_into)]
+    ///
+    /// let a = [1, 2, 3];
+    /// let mut vec: Vec::<i32> = Vec::with_capacity(6);
+    ///
+    /// a.iter().map(|&x| x * 2).collect_into(&mut vec);
+    /// a.iter().map(|&x| x * 10).collect_into(&mut vec);
+    ///
+    /// assert_eq!(6, vec.capacity());
+    /// println!("{:?}", vec);
+    /// ```
+    ///
+    /// The returned mutable reference can be used to continue the call chain:
+    ///
+    /// ```
+    /// #![feature(iter_collect_into)]
+    ///
+    /// let a = [1, 2, 3];
+    /// let mut vec: Vec::<i32> = Vec::with_capacity(6);
+    ///
+    /// let count = a.iter().collect_into(&mut vec).iter().count();
+    ///
+    /// assert_eq!(count, vec.len());
+    /// println!("Vec len is {}", count);
+    ///
+    /// let count = a.iter().collect_into(&mut vec).iter().count();
+    ///
+    /// assert_eq!(count, vec.len());
+    /// println!("Vec len now is {}", count);
+    /// ```
+    #[inline]
+    #[unstable(feature = "iter_collect_into", reason = "new API", issue = "94780")]
+    fn collect_into<E: Extend<Self::Item>>(self, collection: &mut E) -> &mut E
+    where
+        Self: Sized,
+    {
+        collection.extend(self);
+        collection
+    }
+
     /// Consumes an iterator, creating two collections from it.
     ///
     /// The predicate passed to `partition()` can return `true`, or `false`.
@@ -2129,7 +2205,7 @@ pub trait Iterator {
     ///
     /// let data = ["no_tea.txt", "stale_bread.json", "torrential_rain.png"];
     ///
-    /// let res = data.iter().try_for_each(|x| writeln!(stdout(), "{}", x));
+    /// let res = data.iter().try_for_each(|x| writeln!(stdout(), "{x}"));
     /// assert!(res.is_ok());
     ///
     /// let mut it = data.iter().cloned();
@@ -2243,7 +2319,7 @@ pub trait Iterator {
     /// let zero = "0".to_string();
     ///
     /// let result = numbers.iter().fold(zero, |acc, &x| {
-    ///     format!("({} + {})", acc, x)
+    ///     format!("({acc} + {x})")
     /// });
     ///
     /// assert_eq!(result, "(((((0 + 1) + 2) + 3) + 4) + 5)");
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 45fbcf44b35..1ab7481b7ba 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -104,6 +104,7 @@
 #![feature(const_caller_location)]
 #![feature(const_cell_into_inner)]
 #![feature(const_char_convert)]
+#![feature(const_clone)]
 #![feature(const_discriminant)]
 #![feature(const_eval_select)]
 #![feature(const_float_bits_conv)]
@@ -148,6 +149,8 @@
 #![feature(variant_count)]
 #![feature(const_array_from_ref)]
 #![feature(const_slice_from_ref)]
+#![feature(const_slice_index)]
+#![feature(const_is_char_boundary)]
 //
 // Language features:
 #![feature(abi_unadjusted)]
@@ -158,14 +161,15 @@
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_has_atomic_equal_alignment)]
 #![feature(const_fn_floating_point_arithmetic)]
-#![feature(const_fn_fn_ptr_basics)]
-#![feature(const_fn_trait_bound)]
-#![feature(const_impl_trait)]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
+#![cfg_attr(bootstrap, feature(const_impl_trait))]
 #![feature(const_mut_refs)]
 #![feature(const_precise_live_drops)]
 #![feature(const_refs_to_cell)]
 #![feature(decl_macro)]
 #![feature(derive_default_enum)]
+#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))]
 #![feature(doc_cfg)]
 #![feature(doc_notable_trait)]
 #![feature(rustdoc_internals)]
@@ -408,12 +412,10 @@ pub mod arch {
 #[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
 #[allow(rustdoc::bare_urls)]
 #[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(all(miri, doctest)))] // Skip SIMD doctests in Miri
 mod core_simd;
 
 #[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
 #[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(all(miri, doctest)))] // Skip SIMD doctests in Miri
 pub mod simd {
     #[unstable(feature = "portable_simd", issue = "86656")]
     pub use crate::core_simd::simd::*;
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 65a2c3ff6ed..ba7ae55ec6f 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -895,7 +895,7 @@ pub(crate) mod builtin {
     ///
     /// ```
     /// let path: &'static str = env!("PATH");
-    /// println!("the $PATH variable at the time of compiling was: {}", path);
+    /// println!("the $PATH variable at the time of compiling was: {path}");
     /// ```
     ///
     /// You can customize the error message by passing a string as the second
@@ -935,7 +935,7 @@ pub(crate) mod builtin {
     ///
     /// ```
     /// let key: Option<&'static str> = option_env!("SECRET_KEY");
-    /// println!("the secret key might be: {:?}", key);
+    /// println!("the secret key might be: {key:?}");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
@@ -1046,7 +1046,7 @@ pub(crate) mod builtin {
     ///
     /// ```
     /// let current_line = line!();
-    /// println!("defined on line: {}", current_line);
+    /// println!("defined on line: {current_line}");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
@@ -1074,7 +1074,7 @@ pub(crate) mod builtin {
     ///
     /// ```
     /// let current_col = column!();
-    /// println!("defined on column: {}", current_col);
+    /// println!("defined on column: {current_col}");
     /// ```
     ///
     /// `column!` counts Unicode code points, not bytes or graphemes. As a result, the first two
@@ -1112,7 +1112,7 @@ pub(crate) mod builtin {
     ///
     /// ```
     /// let this_file = file!();
-    /// println!("defined in file: {}", this_file);
+    /// println!("defined in file: {this_file}");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
@@ -1176,7 +1176,7 @@ pub(crate) mod builtin {
     /// fn main() {
     ///     let my_str = include_str!("spanish.in");
     ///     assert_eq!(my_str, "adiós\n");
-    ///     print!("{}", my_str);
+    ///     print!("{my_str}");
     /// }
     /// ```
     ///
@@ -1325,7 +1325,7 @@ pub(crate) mod builtin {
     /// fn main() {
     ///     let my_string = include!("monkeys.in");
     ///     assert_eq!("🙈🙊🙉🙈🙊🙉", my_string);
-    ///     println!("{}", my_string);
+    ///     println!("{my_string}");
     /// }
     /// ```
     ///
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 71eea43aa54..82bac2640b4 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -219,7 +219,7 @@ pub trait StructuralEq {
 ///
 /// // `x` has moved into `y`, and so cannot be used
 ///
-/// // println!("{:?}", x); // error: use of moved value
+/// // println!("{x:?}"); // error: use of moved value
 /// ```
 ///
 /// However, if a type implements `Copy`, it instead has 'copy semantics':
@@ -236,7 +236,7 @@ pub trait StructuralEq {
 ///
 /// // `y` is a copy of `x`
 ///
-/// println!("{:?}", x); // A-OK!
+/// println!("{x:?}"); // A-OK!
 /// ```
 ///
 /// It's important to note that in these two examples, the only difference is whether you
diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs
index 2b280773e4c..541adb69b8e 100644
--- a/library/core/src/num/dec2flt/mod.rs
+++ b/library/core/src/num/dec2flt/mod.rs
@@ -112,21 +112,24 @@ macro_rules! from_str_float_impl {
             /// * '2.5E-10'
             /// * '5.'
             /// * '.5', or, equivalently, '0.5'
-            /// * 'inf', '-inf', 'NaN'
+            /// * 'inf', '-inf', '+infinity', 'NaN'
+            ///
+            /// Note that alphabetical characters are not case-sensitive.
             ///
             /// Leading and trailing whitespace represent an error.
             ///
             /// # Grammar
             ///
-            /// All strings that adhere to the following [EBNF] grammar
-            /// will result in an [`Ok`] being returned:
+            /// All strings that adhere to the following [EBNF] grammar when
+            /// lowercased will result in an [`Ok`] being returned:
             ///
             /// ```txt
-            /// Float  ::= Sign? ( 'inf' | 'NaN' | Number )
+            /// Float  ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
             /// Number ::= ( Digit+ |
+            ///              '.' Digit* |
             ///              Digit+ '.' Digit* |
             ///              Digit* '.' Digit+ ) Exp?
-            /// Exp    ::= [eE] Sign? Digit+
+            /// Exp    ::= 'e' Sign? Digit+
             /// Sign   ::= [+-]
             /// Digit  ::= [0-9]
             /// ```
@@ -163,7 +166,7 @@ from_str_float_impl!(f64);
 /// use std::str::FromStr;
 ///
 /// if let Err(e) = f64::from_str("a.12") {
-///     println!("Failed conversion to f64: {}", e);
+///     println!("Failed conversion to f64: {e}");
 /// }
 /// ```
 #[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index 8a9ecbe98df..1a223016dae 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -61,7 +61,7 @@ impl const From<!> for TryFromIntError {
 ///
 /// ```
 /// if let Err(e) = i32::from_str_radix("a12", 10) {
-///     println!("Failed conversion to i32: {}", e);
+///     println!("Failed conversion to i32: {e}");
 /// }
 /// ```
 #[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 199af081560..3665573ab0f 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2166,7 +2166,8 @@ macro_rules! int_impl {
 
             let r = try_opt!(self.checked_rem(rhs));
             let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
-                try_opt!(r.checked_add(rhs))
+                // r + rhs cannot overflow because they have opposite signs
+                r + rhs
             } else {
                 r
             };
@@ -2174,7 +2175,8 @@ macro_rules! int_impl {
             if m == 0 {
                 Some(self)
             } else {
-                self.checked_add(try_opt!(rhs.checked_sub(m)))
+                // rhs - m cannot overflow because m has the same sign as rhs
+                self.checked_add(rhs - m)
             }
         }
 
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 72105888f94..07fd317e074 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -809,7 +809,7 @@ impl u8 {
         ascii::escape_default(self)
     }
 
-    pub(crate) fn is_utf8_char_boundary(self) -> bool {
+    pub(crate) const fn is_utf8_char_boundary(self) -> bool {
         // This is bit magic equivalent to: b < 128 || b >= 192
         (self as i8) >= -0x40
     }
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 1ebd1c58f2b..5bdd78aa2de 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -989,3 +989,104 @@ macro_rules! nonzero_unsigned_is_power_of_two {
 }
 
 nonzero_unsigned_is_power_of_two! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize }
+
+macro_rules! nonzero_min_max_unsigned {
+    ( $( $Ty: ident($Int: ident); )+ ) => {
+        $(
+            impl $Ty {
+                /// The smallest value that can be represented by this non-zero
+                /// integer type, 1.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_min_max)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), 1", stringify!($Int), ");")]
+                /// ```
+                #[unstable(feature = "nonzero_min_max", issue = "89065")]
+                pub const MIN: Self = Self::new(1).unwrap();
+
+                /// The largest value that can be represented by this non-zero
+                /// integer type,
+                #[doc = concat!("equal to [`", stringify!($Int), "::MAX`].")]
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_min_max)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")]
+                /// ```
+                #[unstable(feature = "nonzero_min_max", issue = "89065")]
+                pub const MAX: Self = Self::new(<$Int>::MAX).unwrap();
+            }
+        )+
+    }
+}
+
+macro_rules! nonzero_min_max_signed {
+    ( $( $Ty: ident($Int: ident); )+ ) => {
+        $(
+            impl $Ty {
+                /// The smallest value that can be represented by this non-zero
+                /// integer type,
+                #[doc = concat!("equal to [`", stringify!($Int), "::MIN`].")]
+                ///
+                /// Note: While most integer types are defined for every whole
+                /// number between `MIN` and `MAX`, signed non-zero integers are
+                /// a special case. They have a "gap" at 0.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_min_max)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), ", stringify!($Int), "::MIN);")]
+                /// ```
+                #[unstable(feature = "nonzero_min_max", issue = "89065")]
+                pub const MIN: Self = Self::new(<$Int>::MIN).unwrap();
+
+                /// The largest value that can be represented by this non-zero
+                /// integer type,
+                #[doc = concat!("equal to [`", stringify!($Int), "::MAX`].")]
+                ///
+                /// Note: While most integer types are defined for every whole
+                /// number between `MIN` and `MAX`, signed non-zero integers are
+                /// a special case. They have a "gap" at 0.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_min_max)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")]
+                /// ```
+                #[unstable(feature = "nonzero_min_max", issue = "89065")]
+                pub const MAX: Self = Self::new(<$Int>::MAX).unwrap();
+            }
+        )+
+    }
+}
+
+nonzero_min_max_unsigned! {
+    NonZeroU8(u8);
+    NonZeroU16(u16);
+    NonZeroU32(u32);
+    NonZeroU64(u64);
+    NonZeroU128(u128);
+    NonZeroUsize(usize);
+}
+
+nonzero_min_max_signed! {
+    NonZeroI8(i8);
+    NonZeroI16(i16);
+    NonZeroI32(i32);
+    NonZeroI64(i64);
+    NonZeroI128(i128);
+    NonZeroIsize(isize);
+}
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index feec448ebbd..baa23e08fe7 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -2119,7 +2119,8 @@ macro_rules! uint_impl {
         pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
             match try_opt!(self.checked_rem(rhs)) {
                 0 => Some(self),
-                r => self.checked_add(try_opt!(rhs.checked_sub(r)))
+                // rhs - r cannot overflow because r is smaller than rhs
+                r => self.checked_add(rhs - r)
             }
         }
 
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs
index 964378cc9c3..e2e569cb7ea 100644
--- a/library/core/src/ops/index.rs
+++ b/library/core/src/ops/index.rs
@@ -106,7 +106,7 @@ pub trait Index<Idx: ?Sized> {
 ///     type Output = Weight;
 ///
 ///     fn index(&self, index: Side) -> &Self::Output {
-///         println!("Accessing {:?}-side of balance immutably", index);
+///         println!("Accessing {index:?}-side of balance immutably");
 ///         match index {
 ///             Side::Left => &self.left,
 ///             Side::Right => &self.right,
@@ -116,7 +116,7 @@ pub trait Index<Idx: ?Sized> {
 ///
 /// impl IndexMut<Side> for Balance {
 ///     fn index_mut(&mut self, index: Side) -> &mut Self::Output {
-///         println!("Accessing {:?}-side of balance mutably", index);
+///         println!("Accessing {index:?}-side of balance mutably");
 ///         match index {
 ///             Side::Left => &mut self.left,
 ///             Side::Right => &mut self.right,
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index 11367220678..a3b14847342 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -446,7 +446,7 @@ impl RangeInclusive<usize> {
     /// Converts to an exclusive `Range` for `SliceIndex` implementations.
     /// The caller is responsible for dealing with `end == usize::MAX`.
     #[inline]
-    pub(crate) fn into_slice_range(self) -> Range<usize> {
+    pub(crate) const fn into_slice_range(self) -> Range<usize> {
         // If we're not exhausted, we want to simply slice `start..end + 1`.
         // If we are exhausted, then slicing with `end + 1..end + 1` gives us an
         // empty range that is still subject to bounds-checks for that endpoint.
@@ -653,7 +653,7 @@ impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
 /// map.insert(8, "c");
 ///
 /// for (key, value) in map.range((Excluded(3), Included(8))) {
-///     println!("{}: {}", key, value);
+///     println!("{key}: {value}");
 /// }
 ///
 /// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next());
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 508837f63c3..de1628f83ad 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -34,7 +34,7 @@
 //! // Pattern match to retrieve the value
 //! match result {
 //!     // The division was valid
-//!     Some(x) => println!("Result: {}", x),
+//!     Some(x) => println!("Result: {x}"),
 //!     // The division was invalid
 //!     None    => println!("Cannot divide by 0"),
 //! }
@@ -66,7 +66,7 @@
 //!
 //! fn check_optional(optional: Option<Box<i32>>) {
 //!     match optional {
-//!         Some(p) => println!("has value {}", p),
+//!         Some(p) => println!("has value {p}"),
 //!         None => println!("has no value"),
 //!     }
 //! }
@@ -493,7 +493,7 @@
 //! }
 //!
 //! match name_of_biggest_animal {
-//!     Some(name) => println!("the biggest animal is {}", name),
+//!     Some(name) => println!("the biggest animal is {name}"),
 //!     None => println!("there are no animals :("),
 //! }
 //! ```
@@ -551,7 +551,7 @@ impl<T> Option<T> {
         matches!(*self, Some(_))
     }
 
-    /// Returns `true` if the option is a [`Some`] wrapping a value matching the predicate.
+    /// Returns `true` if the option is a [`Some`] and the value inside of it matches a predicate.
     ///
     /// # Examples
     ///
@@ -559,18 +559,18 @@ impl<T> Option<T> {
     /// #![feature(is_some_with)]
     ///
     /// let x: Option<u32> = Some(2);
-    /// assert_eq!(x.is_some_with(|&x| x > 1), true);
+    /// assert_eq!(x.is_some_and(|&x| x > 1), true);
     ///
     /// let x: Option<u32> = Some(0);
-    /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+    /// assert_eq!(x.is_some_and(|&x| x > 1), false);
     ///
     /// let x: Option<u32> = None;
-    /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+    /// assert_eq!(x.is_some_and(|&x| x > 1), false);
     /// ```
     #[must_use]
     #[inline]
     #[unstable(feature = "is_some_with", issue = "93050")]
-    pub fn is_some_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+    pub fn is_some_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
         matches!(self, Some(x) if f(x))
     }
 
@@ -615,7 +615,7 @@ impl<T> Option<T> {
     /// // First, cast `Option<String>` to `Option<&String>` with `as_ref`,
     /// // then consume *that* with `map`, leaving `text` on the stack.
     /// let text_length: Option<usize> = text.as_ref().map(|s| s.len());
-    /// println!("still can print text: {:?}", text);
+    /// println!("still can print text: {text:?}");
     /// ```
     #[inline]
     #[rustc_const_stable(feature = "const_option", since = "1.48.0")]
@@ -918,10 +918,10 @@ impl<T> Option<T> {
     /// let v = vec![1, 2, 3, 4, 5];
     ///
     /// // prints "got: 4"
-    /// let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {}", x));
+    /// let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {x}"));
     ///
     /// // prints nothing
-    /// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {}", x));
+    /// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {x}"));
     /// ```
     #[inline]
     #[unstable(feature = "result_option_inspect", issue = "91345")]
@@ -1857,7 +1857,11 @@ const fn expect_failed(msg: &str) -> ! {
 /////////////////////////////////////////////////////////////////////////////
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone> Clone for Option<T> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T> const Clone for Option<T>
+where
+    T: ~const Clone + ~const Drop,
+{
     #[inline]
     fn clone(&self) -> Self {
         match self {
@@ -1972,7 +1976,7 @@ impl<'a, T> const From<&'a Option<T>> for Option<&'a T> {
     /// let s: Option<String> = Some(String::from("Hello, Rustaceans!"));
     /// let o: Option<usize> = Option::from(&s).map(|ss: &String| ss.len());
     ///
-    /// println!("Can still print s: {:?}", s);
+    /// println!("Can still print s: {s:?}");
     ///
     /// assert_eq!(o, Some(18));
     /// ```
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index be8598fae09..1923155ebc1 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -16,7 +16,7 @@ use crate::panic::Location;
 ///
 /// panic::set_hook(Box::new(|panic_info| {
 ///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
-///         println!("panic occurred: {:?}", s);
+///         println!("panic occurred: {s:?}");
 ///     } else {
 ///         println!("panic occurred");
 ///     }
@@ -75,7 +75,7 @@ impl<'a> PanicInfo<'a> {
     ///
     /// panic::set_hook(Box::new(|panic_info| {
     ///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
-    ///         println!("panic occurred: {:?}", s);
+    ///         println!("panic occurred: {s:?}");
     ///     } else {
     ///         println!("panic occurred");
     ///     }
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 89cebaa653f..a908b1f3ba4 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -39,7 +39,7 @@ use crate::panic::{Location, PanicInfo};
 #[rustc_const_unstable(feature = "core_panic", issue = "none")]
 #[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
 pub const fn panic(expr: &'static str) -> ! {
-    // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
+    // Use Arguments::new_v1 instead of format_args!("{expr}") to potentially
     // reduce size overhead. The format_args! macro uses str's Display trait to
     // write expr, which calls Formatter::pad, which must accommodate string
     // truncation and padding (even though none is used here). Using
@@ -81,7 +81,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
         super::intrinsics::abort()
     }
 
-    panic!("index out of bounds: the len is {} but the index is {}", len, index)
+    panic!("index out of bounds: the len is {len} but the index is {index}")
 }
 
 // This function is called directly by the codegen backend, and must not have
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index ebb1d8971b9..225a679efd2 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -607,7 +607,7 @@ mod prim_pointer {}
 ///
 /// // This loop prints: 0 1 2
 /// for x in array {
-///     print!("{} ", x);
+///     print!("{x} ");
 /// }
 /// ```
 ///
@@ -646,19 +646,19 @@ mod prim_pointer {}
 /// // This creates a slice iterator, producing references to each value.
 /// for item in array.into_iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // The `array_into_iter` lint suggests this change for future compatibility:
 /// for item in array.iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
 /// for item in IntoIterator::into_iter(array).enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
@@ -673,13 +673,13 @@ mod prim_pointer {}
 /// // This iterates by reference:
 /// for item in array.iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in array.into_iter().enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
@@ -702,26 +702,26 @@ mod prim_pointer {}
 /// // This iterates by reference:
 /// for item in array.iter() {
 ///     let x: &i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in IntoIterator::into_iter(array) {
 ///     let x: i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in array {
 ///     let x: i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // IntoIter can also start a chain.
 /// // This iterates by value:
 /// for item in IntoIterator::into_iter(array).enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 485a5965f4c..75322066983 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -153,7 +153,7 @@ impl<T: ?Sized> *const T {
     ///
     /// unsafe {
     ///     if let Some(val_back) = ptr.as_ref() {
-    ///         println!("We got back the value: {}!", val_back);
+    ///         println!("We got back the value: {val_back}!");
     ///     }
     /// }
     /// ```
@@ -169,7 +169,7 @@ impl<T: ?Sized> *const T {
     ///
     /// unsafe {
     ///     let val_back = &*ptr;
-    ///     println!("We got back the value: {}!", val_back);
+    ///     println!("We got back the value: {val_back}!");
     /// }
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
@@ -1032,10 +1032,11 @@ impl<T> *const [T] {
     /// }
     /// ```
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
+    pub const unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
     where
-        I: SliceIndex<[T]>,
+        I: ~const SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
         unsafe { index.get_unchecked(self) }
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 1412e836ebf..861412703d3 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -160,7 +160,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// unsafe {
     ///     if let Some(val_back) = ptr.as_ref() {
-    ///         println!("We got back the value: {}!", val_back);
+    ///         println!("We got back the value: {val_back}!");
     ///     }
     /// }
     /// ```
@@ -176,7 +176,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// unsafe {
     ///     let val_back = &*ptr;
-    ///     println!("We got back the value: {}!", val_back);
+    ///     println!("We got back the value: {val_back}!");
     /// }
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
@@ -409,7 +409,7 @@ impl<T: ?Sized> *mut T {
     /// let first_value = unsafe { ptr.as_mut().unwrap() };
     /// *first_value = 4;
     /// # assert_eq!(s, [4, 2, 3]);
-    /// println!("{:?}", s); // It'll print: "[4, 2, 3]".
+    /// println!("{s:?}"); // It'll print: "[4, 2, 3]".
     /// ```
     ///
     /// # Null-unchecked version
@@ -424,7 +424,7 @@ impl<T: ?Sized> *mut T {
     /// let first_value = unsafe { &mut *ptr };
     /// *first_value = 4;
     /// # assert_eq!(s, [4, 2, 3]);
-    /// println!("{:?}", s); // It'll print: "[4, 2, 3]".
+    /// println!("{s:?}"); // It'll print: "[4, 2, 3]".
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
@@ -1302,10 +1302,11 @@ impl<T> *mut [T] {
     /// }
     /// ```
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline(always)]
-    pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
+    pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
     where
-        I: SliceIndex<[T]>,
+        I: ~const SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
         unsafe { index.get_unchecked_mut(self) }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 0aa8e9960a8..a698aec51ca 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -314,7 +314,7 @@ impl<T: ?Sized> NonNull<T> {
     /// let ptr = NonNull::new(&mut x as *mut _).expect("ptr is null!");
     ///
     /// let ref_x = unsafe { ptr.as_ref() };
-    /// println!("{}", ref_x);
+    /// println!("{ref_x}");
     /// ```
     ///
     /// [the module documentation]: crate::ptr#safety
@@ -630,10 +630,11 @@ impl<T> NonNull<[T]> {
     /// }
     /// ```
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
+    pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
     where
-        I: SliceIndex<[T]>,
+        I: ~const SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
         // As a consequence, the resulting pointer cannot be null.
@@ -642,7 +643,8 @@ impl<T> NonNull<[T]> {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> Clone for NonNull<T> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T: ?Sized> const Clone for NonNull<T> {
     #[inline]
     fn clone(&self) -> Self {
         *self
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index 661d111c99d..cff68f64f78 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -146,7 +146,8 @@ impl<T: ?Sized> Unique<T> {
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> Clone for Unique<T> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T: ?Sized> const Clone for Unique<T> {
     #[inline]
     fn clone(&self) -> Self {
         *self
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 801e3a0b3a4..9a243cbc3a2 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -35,8 +35,8 @@
 //!
 //! let version = parse_version(&[1, 2, 3, 4]);
 //! match version {
-//!     Ok(v) => println!("working with version: {:?}", v),
-//!     Err(e) => println!("error parsing header: {:?}", e),
+//!     Ok(v) => println!("working with version: {v:?}"),
+//!     Err(e) => println!("error parsing header: {e:?}"),
 //! }
 //! ```
 //!
@@ -447,9 +447,9 @@
 //!    .collect();
 //! assert_eq!(errs.len(), 3);
 //! assert_eq!(nums, [17, 99]);
-//! println!("results {:?}", results);
-//! println!("errs {:?}", errs);
-//! println!("nums {:?}", nums);
+//! println!("results {results:?}");
+//! println!("errs {errs:?}");
+//! println!("nums {nums:?}");
 //! ```
 //!
 //! ## Collecting into `Result`
@@ -542,7 +542,7 @@ impl<T, E> Result<T, E> {
         matches!(*self, Ok(_))
     }
 
-    /// Returns `true` if the result is [`Ok`] wrapping a value matching the predicate.
+    /// Returns `true` if the result is [`Ok`] and the value inside of it matches a predicate.
     ///
     /// # Examples
     ///
@@ -550,18 +550,18 @@ impl<T, E> Result<T, E> {
     /// #![feature(is_some_with)]
     ///
     /// let x: Result<u32, &str> = Ok(2);
-    /// assert_eq!(x.is_ok_with(|&x| x > 1), true);
+    /// assert_eq!(x.is_ok_and(|&x| x > 1), true);
     ///
     /// let x: Result<u32, &str> = Ok(0);
-    /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+    /// assert_eq!(x.is_ok_and(|&x| x > 1), false);
     ///
     /// let x: Result<u32, &str> = Err("hey");
-    /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+    /// assert_eq!(x.is_ok_and(|&x| x > 1), false);
     /// ```
     #[must_use]
     #[inline]
     #[unstable(feature = "is_some_with", issue = "93050")]
-    pub fn is_ok_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+    pub fn is_ok_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
         matches!(self, Ok(x) if f(x))
     }
 
@@ -586,7 +586,7 @@ impl<T, E> Result<T, E> {
         !self.is_ok()
     }
 
-    /// Returns `true` if the result is [`Err`] wrapping a value matching the predicate.
+    /// Returns `true` if the result is [`Err`] and the value inside of it matches a predicate.
     ///
     /// # Examples
     ///
@@ -595,18 +595,18 @@ impl<T, E> Result<T, E> {
     /// use std::io::{Error, ErrorKind};
     ///
     /// let x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, "!"));
-    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), true);
+    /// assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), true);
     ///
     /// let x: Result<u32, Error> = Err(Error::new(ErrorKind::PermissionDenied, "!"));
-    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+    /// assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);
     ///
     /// let x: Result<u32, Error> = Ok(123);
-    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+    /// assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);
     /// ```
     #[must_use]
     #[inline]
     #[unstable(feature = "is_some_with", issue = "93050")]
-    pub fn is_err_with(&self, f: impl FnOnce(&E) -> bool) -> bool {
+    pub fn is_err_and(&self, f: impl FnOnce(&E) -> bool) -> bool {
         matches!(self, Err(x) if f(x))
     }
 
@@ -632,10 +632,16 @@ impl<T, E> Result<T, E> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn ok(self) -> Option<T> {
+    #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
+    pub const fn ok(self) -> Option<T>
+    where
+        E: ~const Drop,
+    {
         match self {
             Ok(x) => Some(x),
-            Err(_) => None,
+            // FIXME: ~const Drop doesn't quite work right yet
+            #[allow(unused_variables)]
+            Err(x) => None,
         }
     }
 
@@ -657,9 +663,15 @@ impl<T, E> Result<T, E> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn err(self) -> Option<E> {
+    #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
+    pub const fn err(self) -> Option<E>
+    where
+        T: ~const Drop,
+    {
         match self {
-            Ok(_) => None,
+            // FIXME: ~const Drop doesn't quite work right yet
+            #[allow(unused_variables)]
+            Ok(x) => None,
             Err(x) => Some(x),
         }
     }
@@ -744,7 +756,7 @@ impl<T, E> Result<T, E> {
     ///
     /// for num in line.lines() {
     ///     match num.parse::<i32>().map(|i| i * 2) {
-    ///         Ok(n) => println!("{}", n),
+    ///         Ok(n) => println!("{n}"),
     ///         Err(..) => {}
     ///     }
     /// }
@@ -826,7 +838,7 @@ impl<T, E> Result<T, E> {
     /// Basic usage:
     ///
     /// ```
-    /// fn stringify(x: u32) -> String { format!("error code: {}", x) }
+    /// fn stringify(x: u32) -> String { format!("error code: {x}") }
     ///
     /// let x: Result<u32, u32> = Ok(2);
     /// assert_eq!(x.map_err(stringify), Ok(2));
@@ -852,7 +864,7 @@ impl<T, E> Result<T, E> {
     ///
     /// let x: u8 = "4"
     ///     .parse::<u8>()
-    ///     .inspect(|x| println!("original: {}", x))
+    ///     .inspect(|x| println!("original: {x}"))
     ///     .map(|x| x.pow(3))
     ///     .expect("failed to parse number");
     /// ```
@@ -877,7 +889,7 @@ impl<T, E> Result<T, E> {
     ///
     /// fn read() -> io::Result<String> {
     ///     fs::read_to_string("address.txt")
-    ///         .inspect_err(|e| eprintln!("failed to read file: {}", e))
+    ///         .inspect_err(|e| eprintln!("failed to read file: {e}"))
     /// }
     /// ```
     #[inline]
@@ -1186,7 +1198,7 @@ impl<T, E> Result<T, E> {
     /// }
     ///
     /// let s: String = only_good_news().into_ok();
-    /// println!("{}", s);
+    /// println!("{s}");
     /// ```
     #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
     #[inline]
@@ -1223,7 +1235,7 @@ impl<T, E> Result<T, E> {
     /// }
     ///
     /// let error: String = only_bad_news().into_err();
-    /// println!("{}", error);
+    /// println!("{error}");
     /// ```
     #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
     #[inline]
@@ -1266,10 +1278,18 @@ impl<T, E> Result<T, E> {
     /// assert_eq!(x.and(y), Ok("different result type"));
     /// ```
     #[inline]
+    #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
+    pub const fn and<U>(self, res: Result<U, E>) -> Result<U, E>
+    where
+        T: ~const Drop,
+        U: ~const Drop,
+        E: ~const Drop,
+    {
         match self {
-            Ok(_) => res,
+            // FIXME: ~const Drop doesn't quite work right yet
+            #[allow(unused_variables)]
+            Ok(x) => res,
             Err(e) => Err(e),
         }
     }
@@ -1343,11 +1363,19 @@ impl<T, E> Result<T, E> {
     /// assert_eq!(x.or(y), Ok(2));
     /// ```
     #[inline]
+    #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
+    pub const fn or<F>(self, res: Result<T, F>) -> Result<T, F>
+    where
+        T: ~const Drop,
+        E: ~const Drop,
+        F: ~const Drop,
+    {
         match self {
             Ok(v) => Ok(v),
-            Err(_) => res,
+            // FIXME: ~const Drop doesn't quite work right yet
+            #[allow(unused_variables)]
+            Err(e) => res,
         }
     }
 
@@ -1399,11 +1427,18 @@ impl<T, E> Result<T, E> {
     /// assert_eq!(x.unwrap_or(default), default);
     /// ```
     #[inline]
+    #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or(self, default: T) -> T {
+    pub const fn unwrap_or(self, default: T) -> T
+    where
+        T: ~const Drop,
+        E: ~const Drop,
+    {
         match self {
             Ok(t) => t,
-            Err(_) => default,
+            // FIXME: ~const Drop doesn't quite work right yet
+            #[allow(unused_variables)]
+            Err(e) => default,
         }
     }
 
@@ -1746,7 +1781,7 @@ impl<T> Result<T, T> {
 #[cold]
 #[track_caller]
 fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
-    panic!("{}: {:?}", msg, error)
+    panic!("{msg}: {error:?}")
 }
 
 // This is a separate function to avoid constructing a `dyn Debug`
@@ -1766,7 +1801,12 @@ fn unwrap_failed<T>(_msg: &str, _error: &T) -> ! {
 /////////////////////////////////////////////////////////////////////////////
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone, E: Clone> Clone for Result<T, E> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T, E> const Clone for Result<T, E>
+where
+    T: ~const Clone + ~const Drop,
+    E: ~const Clone + ~const Drop,
+{
     #[inline]
     fn clone(&self) -> Self {
         match self {
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 0298bba8d32..3353c239866 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -1,12 +1,14 @@
 //! Indexing implementations for `[T]`.
 
+use crate::intrinsics::const_eval_select;
 use crate::ops;
 use crate::ptr;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::Index<I> for [T]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I> const ops::Index<I> for [T]
 where
-    I: SliceIndex<[T]>,
+    I: ~const SliceIndex<[T]>,
 {
     type Output = I::Output;
 
@@ -17,9 +19,10 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::IndexMut<I> for [T]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I> const ops::IndexMut<I> for [T]
 where
-    I: SliceIndex<[T]>,
+    I: ~const SliceIndex<[T]>,
 {
     #[inline]
     fn index_mut(&mut self, index: I) -> &mut I::Output {
@@ -31,31 +34,72 @@ where
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
-    panic!("range start index {} out of range for slice of length {}", index, len);
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
+    // SAFETY: we are just panicking here
+    unsafe {
+        const_eval_select(
+            (index, len),
+            slice_start_index_len_fail_ct,
+            slice_start_index_len_fail_rt,
+        )
+    }
+}
+
+// FIXME const-hack
+fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! {
+    panic!("range start index {index} out of range for slice of length {len}");
+}
+
+const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
+    panic!("slice start index is out of range for slice");
 }
 
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
-    panic!("range end index {} out of range for slice of length {}", index, len);
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
+    // SAFETY: we are just panicking here
+    unsafe {
+        const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt)
+    }
+}
+
+// FIXME const-hack
+fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! {
+    panic!("range end index {index} out of range for slice of length {len}");
+}
+
+const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
+    panic!("slice end index is out of range for slice");
 }
 
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-fn slice_index_order_fail(index: usize, end: usize) -> ! {
-    panic!("slice index starts at {} but ends at {}", index, end);
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+const fn slice_index_order_fail(index: usize, end: usize) -> ! {
+    // SAFETY: we are just panicking here
+    unsafe { const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) }
+}
+
+// FIXME const-hack
+fn slice_index_order_fail_rt(index: usize, end: usize) -> ! {
+    panic!("slice index starts at {index} but ends at {end}");
+}
+
+const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! {
+    panic!("slice index start is larger than end");
 }
 
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-fn slice_start_index_overflow_fail() -> ! {
+const fn slice_start_index_overflow_fail() -> ! {
     panic!("attempted to index slice from after maximum usize");
 }
 
@@ -63,7 +107,7 @@ fn slice_start_index_overflow_fail() -> ! {
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-fn slice_end_index_overflow_fail() -> ! {
+const fn slice_end_index_overflow_fail() -> ! {
     panic!("attempted to index slice up to maximum usize");
 }
 
@@ -153,7 +197,8 @@ pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for usize {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for usize {
     type Output = T;
 
     #[inline]
@@ -197,7 +242,8 @@ unsafe impl<T> SliceIndex<[T]> for usize {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
     type Output = [T];
 
     #[inline]
@@ -261,7 +307,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeTo<usize> {
     type Output = [T];
 
     #[inline]
@@ -298,7 +345,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
     type Output = [T];
 
     #[inline]
@@ -343,7 +391,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull {
     type Output = [T];
 
     #[inline]
@@ -378,7 +427,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
 }
 
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
     type Output = [T];
 
     #[inline]
@@ -421,7 +471,8 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
 }
 
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> {
     type Output = [T];
 
     #[inline]
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index d260cc69469..82bd7dbcf6c 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -55,7 +55,7 @@ fn size_from_ptr<T>(_: *const T) -> usize {
 ///
 /// // Then, we iterate over it:
 /// for element in slice.iter() {
-///     println!("{}", element);
+///     println!("{element}");
 /// }
 /// ```
 ///
@@ -176,7 +176,7 @@ impl<T> AsRef<[T]> for Iter<'_, T> {
 /// }
 ///
 /// // We now have "[2, 3, 4]":
-/// println!("{:?}", slice);
+/// println!("{slice:?}");
 /// ```
 ///
 /// [`iter_mut`]: slice::iter_mut
@@ -266,7 +266,7 @@ impl<'a, T> IterMut<'a, T> {
     ///     *iter.next().unwrap() += 1;
     /// }
     /// // Now slice is "[2, 2, 3]":
-    /// println!("{:?}", slice);
+    /// println!("{slice:?}");
     /// ```
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "iter_to_slice", since = "1.4.0")]
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 9467c7f54ba..c0eb000e877 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -16,7 +16,6 @@ use crate::option::Option::{None, Some};
 use crate::ptr;
 use crate::result::Result;
 use crate::result::Result::{Err, Ok};
-#[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
 use crate::simd::{self, Simd};
 use crate::slice;
 
@@ -324,10 +323,11 @@ impl<T> [T] {
     /// assert_eq!(None, v.get(0..4));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub fn get<I>(&self, index: I) -> Option<&I::Output>
+    pub const fn get<I>(&self, index: I) -> Option<&I::Output>
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         index.get(self)
     }
@@ -348,10 +348,11 @@ impl<T> [T] {
     /// assert_eq!(x, &[0, 42, 2]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
+    pub const fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         index.get_mut(self)
     }
@@ -379,10 +380,11 @@ impl<T> [T] {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
+    pub const unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
         // the slice is dereferenceable because `self` is a safe reference.
@@ -415,10 +417,11 @@ impl<T> [T] {
     /// assert_eq!(x, &[1, 13, 4]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
+    pub const unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
         // the slice is dereferenceable because `self` is a safe reference.
@@ -2008,7 +2011,7 @@ impl<T> [T] {
     /// let v = [10, 40, 30, 20, 60, 50];
     ///
     /// for group in v.splitn(2, |num| *num % 3 == 0) {
-    ///     println!("{:?}", group);
+    ///     println!("{group:?}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -2063,7 +2066,7 @@ impl<T> [T] {
     /// let v = [10, 40, 30, 20, 60, 50];
     ///
     /// for group in v.rsplitn(2, |num| *num % 3 == 0) {
-    ///     println!("{:?}", group);
+    ///     println!("{group:?}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -3533,14 +3536,13 @@ impl<T> [T] {
     ///         suffix.iter().copied().sum(),
     ///     ]);
     ///     let sums = middle.iter().copied().fold(sums, f32x4::add);
-    ///     sums.horizontal_sum()
+    ///     sums.reduce_sum()
     /// }
     ///
     /// let numbers: Vec<f32> = (1..101).map(|x| x as _).collect();
     /// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
     /// ```
     #[unstable(feature = "portable_simd", issue = "86656")]
-    #[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
     pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
     where
         Simd<T, LANES>: AsRef<[T; LANES]>,
@@ -3584,7 +3586,6 @@ impl<T> [T] {
     /// be lifted in a way that would make it possible to see panics from this
     /// method for something like `LANES == 3`.
     #[unstable(feature = "portable_simd", issue = "86656")]
-    #[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
     pub fn as_simd_mut<const LANES: usize>(&mut self) -> (&mut [T], &mut [Simd<T, LANES>], &mut [T])
     where
         Simd<T, LANES>: AsMut<[T; LANES]>,
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 09709dc3cf6..b1d36f27107 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -79,7 +79,23 @@ use iter::{MatchesInternal, SplitNInternal};
 #[inline(never)]
 #[cold]
 #[track_caller]
-fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
+#[rustc_allow_const_fn_unstable(const_eval_select)]
+const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
+    // SAFETY: panics for both branches
+    unsafe {
+        crate::intrinsics::const_eval_select(
+            (s, begin, end),
+            slice_error_fail_ct,
+            slice_error_fail_rt,
+        )
+    }
+}
+
+const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! {
+    panic!("failed to slice string");
+}
+
+fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! {
     const MAX_DISPLAY_LENGTH: usize = 256;
     let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH);
     let s_trunc = &s[..trunc_len];
@@ -88,7 +104,7 @@ fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
     // 1. out of bounds
     if begin > s.len() || end > s.len() {
         let oob_index = if begin > s.len() { begin } else { end };
-        panic!("byte index {} is out of bounds of `{}`{}", oob_index, s_trunc, ellipsis);
+        panic!("byte index {oob_index} is out of bounds of `{s_trunc}`{ellipsis}");
     }
 
     // 2. begin <= end
@@ -189,8 +205,9 @@ impl str {
     /// ```
     #[must_use]
     #[stable(feature = "is_char_boundary", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_is_char_boundary", issue = "none")]
     #[inline]
-    pub fn is_char_boundary(&self, index: usize) -> bool {
+    pub const fn is_char_boundary(&self, index: usize) -> bool {
         // 0 is always ok.
         // Test for 0 explicitly so that it can optimize out the check
         // easily and skip reading string data for that case.
@@ -418,8 +435,9 @@ impl str {
     /// assert!(v.get(..42).is_none());
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
+    pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
         i.get(self)
     }
 
@@ -450,8 +468,9 @@ impl str {
     /// assert_eq!("HEllo", v);
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
+    pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
         i.get_mut(self)
     }
 
@@ -482,8 +501,9 @@ impl str {
     /// }
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
+    pub const unsafe fn get_unchecked<I: ~const SliceIndex<str>>(&self, i: I) -> &I::Output {
         // SAFETY: the caller must uphold the safety contract for `get_unchecked`;
         // the slice is dereferenceable because `self` is a safe reference.
         // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
@@ -517,8 +537,12 @@ impl str {
     /// }
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
+    pub const unsafe fn get_unchecked_mut<I: ~const SliceIndex<str>>(
+        &mut self,
+        i: I,
+    ) -> &mut I::Output {
         // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
         // the slice is dereferenceable because `self` is a safe reference.
         // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
@@ -2422,7 +2446,7 @@ impl str {
     ///
     /// ```
     /// for c in "❤\n!".escape_debug() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -2468,7 +2492,7 @@ impl str {
     ///
     /// ```
     /// for c in "❤\n!".escape_default() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -2506,7 +2530,7 @@ impl str {
     ///
     /// ```
     /// for c in "❤\n!".escape_unicode() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index 95267624748..8b6b4fa02f8 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -53,9 +53,10 @@ impl PartialOrd for str {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ops::Index<I> for str
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<I> const ops::Index<I> for str
 where
-    I: SliceIndex<str>,
+    I: ~const SliceIndex<str>,
 {
     type Output = I::Output;
 
@@ -66,9 +67,10 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ops::IndexMut<I> for str
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<I> const ops::IndexMut<I> for str
 where
-    I: SliceIndex<str>,
+    I: ~const SliceIndex<str>,
 {
     #[inline]
     fn index_mut(&mut self, index: I) -> &mut I::Output {
@@ -79,7 +81,7 @@ where
 #[inline(never)]
 #[cold]
 #[track_caller]
-fn str_index_overflow_fail() -> ! {
+const fn str_index_overflow_fail() -> ! {
     panic!("attempted to index str up to maximum usize");
 }
 
@@ -96,7 +98,8 @@ fn str_index_overflow_fail() -> ! {
 ///
 /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeFull {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeFull {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -160,7 +163,8 @@ unsafe impl SliceIndex<str> for ops::RangeFull {
 /// // &s[3 .. 100];
 /// ```
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::Range<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::Range<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -247,7 +251,8 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
 /// Panics if `end` does not point to the starting byte offset of a
 /// character (as defined by `is_char_boundary`), or if `end > len`.
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeTo<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -317,7 +322,8 @@ unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
 /// Panics if `begin` does not point to the starting byte offset of
 /// a character (as defined by `is_char_boundary`), or if `begin > len`.
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeFrom<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -393,7 +399,8 @@ unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
 /// to the ending byte offset of a character (`end + 1` is either a starting
 /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeInclusive<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -444,7 +451,8 @@ unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
 /// (`end + 1` is either a starting byte offset as defined by
 /// `is_char_boundary`, or equal to `len`), or if `end >= len`.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 2b8bbe19244..62103f5b075 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -94,7 +94,7 @@
 //!     }
 //!
 //!     if let Err(panic) = thread.join() {
-//!         println!("Thread had an error: {:?}", panic);
+//!         println!("Thread had an error: {panic:?}");
 //!     }
 //! }
 //! ```
@@ -352,7 +352,7 @@ impl AtomicBool {
     /// let a = &*AtomicBool::from_mut_slice(&mut some_bools);
     /// std::thread::scope(|s| {
     ///     for i in 0..a.len() {
-    ///         s.spawn(move |_| a[i].store(true, Ordering::Relaxed));
+    ///         s.spawn(move || a[i].store(true, Ordering::Relaxed));
     ///     }
     /// });
     /// assert_eq!(some_bools, [true; 10]);
@@ -984,7 +984,7 @@ impl<T> AtomicPtr<T> {
     /// let a = &*AtomicPtr::from_mut_slice(&mut some_ptrs);
     /// std::thread::scope(|s| {
     ///     for i in 0..a.len() {
-    ///         s.spawn(move |_| {
+    ///         s.spawn(move || {
     ///             let name = Box::new(format!("thread{i}"));
     ///             a[i].store(Box::into_raw(name), Ordering::Relaxed);
     ///         });
@@ -1345,7 +1345,7 @@ impl const From<bool> for AtomicBool {
     /// ```
     /// use std::sync::atomic::AtomicBool;
     /// let atomic_bool = AtomicBool::from(true);
-    /// assert_eq!(format!("{:?}", atomic_bool), "true")
+    /// assert_eq!(format!("{atomic_bool:?}"), "true")
     /// ```
     #[inline]
     fn from(b: bool) -> Self {
@@ -1533,7 +1533,7 @@ macro_rules! atomic_int {
             #[doc = concat!("let a = &*", stringify!($atomic_type), "::from_mut_slice(&mut some_ints);")]
             /// std::thread::scope(|s| {
             ///     for i in 0..a.len() {
-            ///         s.spawn(move |_| a[i].store(i as _, Ordering::Relaxed));
+            ///         s.spawn(move || a[i].store(i as _, Ordering::Relaxed));
             ///     }
             /// });
             /// for (i, n) in some_ints.into_iter().enumerate() {
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 243c044b5d9..bd72d82b71c 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -1214,7 +1214,7 @@ impl fmt::Debug for Duration {
 /// use std::time::Duration;
 ///
 /// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
-///     println!("Failed conversion to Duration: {}", e);
+///     println!("Failed conversion to Duration: {e}");
 /// }
 /// ```
 #[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/library/core/src/unit.rs b/library/core/src/unit.rs
index f41f4a5e94a..6656dd5c40b 100644
--- a/library/core/src/unit.rs
+++ b/library/core/src/unit.rs
@@ -9,7 +9,7 @@ use crate::iter::FromIterator;
 /// use std::io::*;
 /// let data = vec![1, 2, 3, 4, 5];
 /// let res: Result<()> = data.iter()
-///     .map(|x| writeln!(stdout(), "{}", x))
+///     .map(|x| writeln!(stdout(), "{x}"))
 ///     .collect();
 /// assert!(res.is_ok());
 /// ```
diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs
index b36d6f0d404..eccddcbbf59 100644
--- a/library/core/tests/any.rs
+++ b/library/core/tests/any.rs
@@ -46,12 +46,12 @@ fn any_downcast_ref() {
 
     match a.downcast_ref::<usize>() {
         Some(&5) => {}
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match a.downcast_ref::<Test>() {
         None => {}
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 }
 
@@ -69,7 +69,7 @@ fn any_downcast_mut() {
             assert_eq!(*x, 5);
             *x = 612;
         }
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match b_r.downcast_mut::<usize>() {
@@ -77,27 +77,27 @@ fn any_downcast_mut() {
             assert_eq!(*x, 7);
             *x = 413;
         }
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match a_r.downcast_mut::<Test>() {
         None => (),
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match b_r.downcast_mut::<Test>() {
         None => (),
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match a_r.downcast_mut::<usize>() {
         Some(&mut 612) => {}
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match b_r.downcast_mut::<usize>() {
         Some(&mut 413) => {}
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 }
 
diff --git a/library/core/tests/cell.rs b/library/core/tests/cell.rs
index 4707cc7076e..f15e03076ca 100644
--- a/library/core/tests/cell.rs
+++ b/library/core/tests/cell.rs
@@ -62,10 +62,10 @@ fn cell_update() {
 #[test]
 fn cell_has_sensible_show() {
     let x = Cell::new("foo bar");
-    assert!(format!("{:?}", x).contains(x.get()));
+    assert!(format!("{x:?}").contains(x.get()));
 
     x.set("baz qux");
-    assert!(format!("{:?}", x).contains(x.get()));
+    assert!(format!("{x:?}").contains(x.get()));
 }
 
 #[test]
@@ -73,11 +73,11 @@ fn ref_and_refmut_have_sensible_show() {
     let refcell = RefCell::new("foo");
 
     let refcell_refmut = refcell.borrow_mut();
-    assert!(format!("{:?}", refcell_refmut).contains("foo"));
+    assert!(format!("{refcell_refmut:?}").contains("foo"));
     drop(refcell_refmut);
 
     let refcell_ref = refcell.borrow();
-    assert!(format!("{:?}", refcell_ref).contains("foo"));
+    assert!(format!("{refcell_ref:?}").contains("foo"));
     drop(refcell_ref);
 }
 
diff --git a/library/core/tests/fmt/builders.rs b/library/core/tests/fmt/builders.rs
index 9567479c813..487ce46be28 100644
--- a/library/core/tests/fmt/builders.rs
+++ b/library/core/tests/fmt/builders.rs
@@ -11,8 +11,8 @@ mod debug_struct {
             }
         }
 
-        assert_eq!("Foo", format!("{:?}", Foo));
-        assert_eq!("Foo", format!("{:#?}", Foo));
+        assert_eq!("Foo", format!("{Foo:?}"));
+        assert_eq!("Foo", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -25,12 +25,12 @@ mod debug_struct {
             }
         }
 
-        assert_eq!("Foo { bar: true }", format!("{:?}", Foo));
+        assert_eq!("Foo { bar: true }", format!("{Foo:?}"));
         assert_eq!(
             "Foo {
     bar: true,
 }",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -47,13 +47,13 @@ mod debug_struct {
             }
         }
 
-        assert_eq!("Foo { bar: true, baz: 10/20 }", format!("{:?}", Foo));
+        assert_eq!("Foo { bar: true, baz: 10/20 }", format!("{Foo:?}"));
         assert_eq!(
             "Foo {
     bar: true,
     baz: 10/20,
 }",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -80,7 +80,7 @@ mod debug_struct {
 
         assert_eq!(
             "Bar { foo: Foo { bar: true, baz: 10/20 }, hello: \"world\" }",
-            format!("{:?}", Bar)
+            format!("{Bar:?}")
         );
         assert_eq!(
             "Bar {
@@ -90,7 +90,7 @@ mod debug_struct {
     },
     hello: \"world\",
 }",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 
@@ -104,8 +104,8 @@ mod debug_struct {
             }
         }
 
-        assert_eq!("Foo { .. }", format!("{:?}", Foo));
-        assert_eq!("Foo { .. }", format!("{:#?}", Foo));
+        assert_eq!("Foo { .. }", format!("{Foo:?}"));
+        assert_eq!("Foo { .. }", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -121,14 +121,14 @@ mod debug_struct {
             }
         }
 
-        assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{:?}", Foo));
+        assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{Foo:?}"));
         assert_eq!(
             "Foo {
     bar: true,
     baz: 10/20,
     ..
 }",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -158,7 +158,7 @@ mod debug_struct {
 
         assert_eq!(
             "Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: \"world\", .. }",
-            format!("{:?}", Bar)
+            format!("{Bar:?}")
         );
         assert_eq!(
             "Bar {
@@ -170,7 +170,7 @@ mod debug_struct {
     hello: \"world\",
     ..
 }",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 }
@@ -188,8 +188,8 @@ mod debug_tuple {
             }
         }
 
-        assert_eq!("Foo", format!("{:?}", Foo));
-        assert_eq!("Foo", format!("{:#?}", Foo));
+        assert_eq!("Foo", format!("{Foo:?}"));
+        assert_eq!("Foo", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -202,12 +202,12 @@ mod debug_tuple {
             }
         }
 
-        assert_eq!("Foo(true)", format!("{:?}", Foo));
+        assert_eq!("Foo(true)", format!("{Foo:?}"));
         assert_eq!(
             "Foo(
     true,
 )",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -221,13 +221,13 @@ mod debug_tuple {
             }
         }
 
-        assert_eq!("Foo(true, 10/20)", format!("{:?}", Foo));
+        assert_eq!("Foo(true, 10/20)", format!("{Foo:?}"));
         assert_eq!(
             "Foo(
     true,
     10/20,
 )",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -249,7 +249,7 @@ mod debug_tuple {
             }
         }
 
-        assert_eq!("Bar(Foo(true, 10/20), \"world\")", format!("{:?}", Bar));
+        assert_eq!("Bar(Foo(true, 10/20), \"world\")", format!("{Bar:?}"));
         assert_eq!(
             "Bar(
     Foo(
@@ -258,7 +258,7 @@ mod debug_tuple {
     ),
     \"world\",
 )",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 }
@@ -276,8 +276,8 @@ mod debug_map {
             }
         }
 
-        assert_eq!("{}", format!("{:?}", Foo));
-        assert_eq!("{}", format!("{:#?}", Foo));
+        assert_eq!("{}", format!("{Foo:?}"));
+        assert_eq!("{}", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -298,15 +298,15 @@ mod debug_map {
             }
         }
 
-        assert_eq!(format!("{:?}", Entry), format!("{:?}", KeyValue));
-        assert_eq!(format!("{:#?}", Entry), format!("{:#?}", KeyValue));
+        assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
+        assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
 
-        assert_eq!("{\"bar\": true}", format!("{:?}", Entry));
+        assert_eq!("{\"bar\": true}", format!("{Entry:?}"));
         assert_eq!(
             "{
     \"bar\": true,
 }",
-            format!("{:#?}", Entry)
+            format!("{Entry:#?}")
         );
     }
 
@@ -336,16 +336,16 @@ mod debug_map {
             }
         }
 
-        assert_eq!(format!("{:?}", Entry), format!("{:?}", KeyValue));
-        assert_eq!(format!("{:#?}", Entry), format!("{:#?}", KeyValue));
+        assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
+        assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
 
-        assert_eq!("{\"bar\": true, 10: 10/20}", format!("{:?}", Entry));
+        assert_eq!("{\"bar\": true, 10: 10/20}", format!("{Entry:?}"));
         assert_eq!(
             "{
     \"bar\": true,
     10: 10/20,
 }",
-            format!("{:#?}", Entry)
+            format!("{Entry:#?}")
         );
     }
 
@@ -373,7 +373,7 @@ mod debug_map {
         assert_eq!(
             "{\"foo\": {\"bar\": true, 10: 10/20}, \
                     {\"bar\": true, 10: 10/20}: \"world\"}",
-            format!("{:?}", Bar)
+            format!("{Bar:?}")
         );
         assert_eq!(
             "{
@@ -386,7 +386,7 @@ mod debug_map {
         10: 10/20,
     }: \"world\",
 }",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 
@@ -441,7 +441,7 @@ mod debug_map {
             }
         }
 
-        format!("{:?}", Foo);
+        format!("{Foo:?}");
     }
 
     #[test]
@@ -455,7 +455,7 @@ mod debug_map {
             }
         }
 
-        format!("{:?}", Foo);
+        format!("{Foo:?}");
     }
 
     #[test]
@@ -469,7 +469,7 @@ mod debug_map {
             }
         }
 
-        format!("{:?}", Foo);
+        format!("{Foo:?}");
     }
 }
 
@@ -486,8 +486,8 @@ mod debug_set {
             }
         }
 
-        assert_eq!("{}", format!("{:?}", Foo));
-        assert_eq!("{}", format!("{:#?}", Foo));
+        assert_eq!("{}", format!("{Foo:?}"));
+        assert_eq!("{}", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -500,12 +500,12 @@ mod debug_set {
             }
         }
 
-        assert_eq!("{true}", format!("{:?}", Foo));
+        assert_eq!("{true}", format!("{Foo:?}"));
         assert_eq!(
             "{
     true,
 }",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -519,13 +519,13 @@ mod debug_set {
             }
         }
 
-        assert_eq!("{true, 10/20}", format!("{:?}", Foo));
+        assert_eq!("{true, 10/20}", format!("{Foo:?}"));
         assert_eq!(
             "{
     true,
     10/20,
 }",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -547,7 +547,7 @@ mod debug_set {
             }
         }
 
-        assert_eq!("{{true, 10/20}, \"world\"}", format!("{:?}", Bar));
+        assert_eq!("{{true, 10/20}, \"world\"}", format!("{Bar:?}"));
         assert_eq!(
             "{
     {
@@ -556,7 +556,7 @@ mod debug_set {
     },
     \"world\",
 }",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 }
@@ -574,8 +574,8 @@ mod debug_list {
             }
         }
 
-        assert_eq!("[]", format!("{:?}", Foo));
-        assert_eq!("[]", format!("{:#?}", Foo));
+        assert_eq!("[]", format!("{Foo:?}"));
+        assert_eq!("[]", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -588,12 +588,12 @@ mod debug_list {
             }
         }
 
-        assert_eq!("[true]", format!("{:?}", Foo));
+        assert_eq!("[true]", format!("{Foo:?}"));
         assert_eq!(
             "[
     true,
 ]",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -607,13 +607,13 @@ mod debug_list {
             }
         }
 
-        assert_eq!("[true, 10/20]", format!("{:?}", Foo));
+        assert_eq!("[true, 10/20]", format!("{Foo:?}"));
         assert_eq!(
             "[
     true,
     10/20,
 ]",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -635,7 +635,7 @@ mod debug_list {
             }
         }
 
-        assert_eq!("[[true, 10/20], \"world\"]", format!("{:?}", Bar));
+        assert_eq!("[[true, 10/20], \"world\"]", format!("{Bar:?}"));
         assert_eq!(
             "[
     [
@@ -644,7 +644,7 @@ mod debug_list {
     ],
     \"world\",
 ]",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 }
@@ -668,13 +668,13 @@ fn test_formatting_parameters_are_forwarded() {
     set.insert(1024);
     set.insert(7);
 
-    assert_eq!(format!("{:03?}", struct_), "Foo { bar: 1024, baz: 007 }");
-    assert_eq!(format!("{:03?}", tuple), "(1024, 007)");
-    assert_eq!(format!("{:03?}", list), "[1024, 007]");
-    assert_eq!(format!("{:03?}", map), r#"{"bar": 1024, "baz": 007}"#);
-    assert_eq!(format!("{:03?}", set), "{007, 1024}");
+    assert_eq!(format!("{struct_:03?}"), "Foo { bar: 1024, baz: 007 }");
+    assert_eq!(format!("{tuple:03?}"), "(1024, 007)");
+    assert_eq!(format!("{list:03?}"), "[1024, 007]");
+    assert_eq!(format!("{map:03?}"), r#"{"bar": 1024, "baz": 007}"#);
+    assert_eq!(format!("{set:03?}"), "{007, 1024}");
     assert_eq!(
-        format!("{:#03?}", struct_),
+        format!("{struct_:#03?}"),
         "
 Foo {
     bar: 1024,
@@ -684,7 +684,7 @@ Foo {
         .trim()
     );
     assert_eq!(
-        format!("{:#03?}", tuple),
+        format!("{tuple:#03?}"),
         "
 (
     1024,
@@ -694,7 +694,7 @@ Foo {
         .trim()
     );
     assert_eq!(
-        format!("{:#03?}", list),
+        format!("{list:#03?}"),
         "
 [
     1024,
@@ -704,7 +704,7 @@ Foo {
         .trim()
     );
     assert_eq!(
-        format!("{:#03?}", map),
+        format!("{map:#03?}"),
         r#"
 {
     "bar": 1024,
@@ -714,7 +714,7 @@ Foo {
         .trim()
     );
     assert_eq!(
-        format!("{:#03?}", set),
+        format!("{set:#03?}"),
         "
 {
     007,
diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs
index 7b281ce48e6..61807635813 100644
--- a/library/core/tests/fmt/mod.rs
+++ b/library/core/tests/fmt/mod.rs
@@ -6,7 +6,7 @@ mod num;
 fn test_format_flags() {
     // No residual flags left by pointer formatting
     let p = "".as_ptr();
-    assert_eq!(format!("{:p} {:x}", p, 16), format!("{:p} 10", p));
+    assert_eq!(format!("{:p} {:x}", p, 16), format!("{p:p} 10"));
 
     assert_eq!(format!("{: >3}", 'a'), "  a");
 }
@@ -15,8 +15,8 @@ fn test_format_flags() {
 fn test_pointer_formats_data_pointer() {
     let b: &[u8] = b"";
     let s: &str = "";
-    assert_eq!(format!("{:p}", s), format!("{:p}", s.as_ptr()));
-    assert_eq!(format!("{:p}", b), format!("{:p}", b.as_ptr()));
+    assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr()));
+    assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr()));
 }
 
 #[test]
@@ -41,5 +41,5 @@ fn pad_integral_resets() {
         }
     }
 
-    assert_eq!(format!("{:<03}", Bar), "1  0051  ");
+    assert_eq!(format!("{Bar:<03}"), "1  0051  ");
 }
diff --git a/library/core/tests/fmt/num.rs b/library/core/tests/fmt/num.rs
index b958422d14f..b9ede65c9ff 100644
--- a/library/core/tests/fmt/num.rs
+++ b/library/core/tests/fmt/num.rs
@@ -126,7 +126,7 @@ fn test_format_int_exp_limits() {
 fn test_format_int_exp_precision() {
     //test that float and integer match
     let big_int: u32 = 314_159_265;
-    assert_eq!(format!("{:.1e}", big_int), format!("{:.1e}", f64::from(big_int)));
+    assert_eq!(format!("{big_int:.1e}"), format!("{:.1e}", f64::from(big_int)));
 
     //test adding precision
     assert_eq!(format!("{:.10e}", i8::MIN), "-1.2800000000e2");
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index cf69f0a7a4d..32bd68e3d25 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -543,6 +543,14 @@ fn test_try_collect() {
     assert_eq!(v, Continue(vec![4, 5]));
 }
 
+#[test]
+fn test_collect_into() {
+    let a = vec![1, 2, 3, 4, 5];
+    let mut b = Vec::new();
+    a.iter().cloned().collect_into(&mut b);
+    assert!(a == b);
+}
+
 // just tests by whether or not this compiles
 fn _empty_impl_all_auto_traits<T>() {
     use std::panic::{RefUnwindSafe, UnwindSafe};
diff --git a/library/core/tests/lazy.rs b/library/core/tests/lazy.rs
index 064024ab87b..416d2b2dae4 100644
--- a/library/core/tests/lazy.rs
+++ b/library/core/tests/lazy.rs
@@ -113,7 +113,7 @@ fn aliasing_in_get() {
     x.set(42).unwrap();
     let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option<T>` --+
     let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>`   |
-    println!("{}", at_x); // <------- up until here ---------------------------+
+    println!("{at_x}"); // <------- up until here ---------------------------+
 }
 
 #[test]
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 2437f4afdeb..dc374022827 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -62,6 +62,7 @@
 #![feature(slice_partition_dedup)]
 #![feature(int_log)]
 #![feature(iter_advance_by)]
+#![feature(iter_collect_into)]
 #![feature(iter_partition_in_place)]
 #![feature(iter_intersperse)]
 #![feature(iter_is_partitioned)]
diff --git a/library/core/tests/num/dec2flt/mod.rs b/library/core/tests/num/dec2flt/mod.rs
index 4990d4a083d..c4e105cba60 100644
--- a/library/core/tests/num/dec2flt/mod.rs
+++ b/library/core/tests/num/dec2flt/mod.rs
@@ -15,7 +15,7 @@ macro_rules! test_literal {
         for input in inputs {
             assert_eq!(input.parse(), Ok(x64));
             assert_eq!(input.parse(), Ok(x32));
-            let neg_input = &format!("-{}", input);
+            let neg_input = &format!("-{input}");
             assert_eq!(neg_input.parse(), Ok(-x64));
             assert_eq!(neg_input.parse(), Ok(-x32));
         }
@@ -123,9 +123,9 @@ fn inf() {
 #[test]
 fn massive_exponent() {
     let max = i64::MAX;
-    assert_eq!(format!("1e{}000", max).parse(), Ok(f64::INFINITY));
-    assert_eq!(format!("1e-{}000", max).parse(), Ok(0.0));
-    assert_eq!(format!("1e{}000", max).parse(), Ok(f64::INFINITY));
+    assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY));
+    assert_eq!(format!("1e-{max}000").parse(), Ok(0.0));
+    assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY));
 }
 
 #[test]
diff --git a/library/core/tests/num/dec2flt/parse.rs b/library/core/tests/num/dec2flt/parse.rs
index 473feacc91f..edc77377d58 100644
--- a/library/core/tests/num/dec2flt/parse.rs
+++ b/library/core/tests/num/dec2flt/parse.rs
@@ -46,7 +46,7 @@ fn valid() {
     assert_eq!(parse_positive(b".1e300"), Some(new_number(299, 1)));
     assert_eq!(parse_positive(b"101e-33"), Some(new_number(-33, 101)));
     let zeros = "0".repeat(25);
-    let s = format!("1.5e{}", zeros);
+    let s = format!("1.5e{zeros}");
     assert_eq!(parse_positive(s.as_bytes()), Some(new_number(-1, 15)));
 }
 
diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs
index 4874e8ec09f..798473bbde3 100644
--- a/library/core/tests/num/flt2dec/mod.rs
+++ b/library/core/tests/num/flt2dec/mod.rs
@@ -20,7 +20,7 @@ mod random;
 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
     match decode(v).1 {
         FullDecoded::Finite(decoded) => decoded,
-        full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+        full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
     }
 }
 
diff --git a/library/core/tests/num/flt2dec/random.rs b/library/core/tests/num/flt2dec/random.rs
index 57b3dcf8e1e..d0950039314 100644
--- a/library/core/tests/num/flt2dec/random.rs
+++ b/library/core/tests/num/flt2dec/random.rs
@@ -15,7 +15,7 @@ use rand::SeedableRng;
 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
     match decode(v).1 {
         FullDecoded::Finite(decoded) => decoded,
-        full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+        full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
     }
 }
 
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 9c65871ac4b..af8e78f1f4e 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -550,7 +550,7 @@ fn dyn_metadata() {
     assert_eq!(meta.align_of(), std::mem::align_of::<Something>());
     assert_eq!(meta.layout(), std::alloc::Layout::new::<Something>());
 
-    assert!(format!("{:?}", meta).starts_with("DynMetadata(0x"));
+    assert!(format!("{meta:?}").starts_with("DynMetadata(0x"));
 }
 
 #[test]
diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs
index 1652c1b83de..98b870512b0 100644
--- a/library/core/tests/result.rs
+++ b/library/core/tests/result.rs
@@ -80,9 +80,9 @@ fn test_fmt_default() {
     let ok: Result<isize, &'static str> = Ok(100);
     let err: Result<isize, &'static str> = Err("Err");
 
-    let s = format!("{:?}", ok);
+    let s = format!("{ok:?}");
     assert_eq!(s, "Ok(100)");
-    let s = format!("{:?}", err);
+    let s = format!("{err:?}");
     assert_eq!(s, "Err(\"Err\")");
 }
 
diff --git a/library/portable-simd/beginners-guide.md b/library/portable-simd/beginners-guide.md
index dfd357c4592..75158e5aa85 100644
--- a/library/portable-simd/beginners-guide.md
+++ b/library/portable-simd/beginners-guide.md
@@ -33,7 +33,7 @@ SIMD has a few special vocabulary terms you should know:
 
 * **Vertical:** When an operation is "vertical", each lane processes individually without regard to the other lanes in the same vector. For example, a "vertical add" between two vectors would add lane 0 in `a` with lane 0 in `b`, with the total in lane 0 of `out`, and then the same thing for lanes 1, 2, etc. Most SIMD operations are vertical operations, so if your problem is a vertical problem then you can probably solve it with SIMD.
 
-* **Horizontal:** When an operation is "horizontal", the lanes within a single vector interact in some way. A "horizontal add" might add up lane 0 of `a` with lane 1 of `a`, with the total in lane 0 of `out`.
+* **Reducing/Reduce:** When an operation is "reducing" (functions named `reduce_*`), the lanes within a single vector are merged using some operation such as addition, returning the merged value as a scalar. For instance, a reducing add would return the sum of all the lanes' values.
 
 * **Target Feature:** Rust calls a CPU architecture extension a `target_feature`. Proper SIMD requires various CPU extensions to be enabled (details below). Don't confuse this with `feature`, which is a Cargo crate concept.
 
@@ -83,4 +83,4 @@ Fortunately, most SIMD types have a fairly predictable size. `i32x4` is bit-equi
 However, this is not the same as alignment. Computer architectures generally prefer aligned accesses, especially when moving data between memory and vector registers, and while some support specialized operations that can bend the rules to help with this, unaligned access is still typically slow, or even undefined behavior. In addition, different architectures can require different alignments when interacting with their native SIMD types. For this reason, any `#[repr(simd)]` type has a non-portable alignment. If it is necessary to directly interact with the alignment of these types, it should be via [`mem::align_of`].
 
 [`mem::transmute`]: https://doc.rust-lang.org/core/mem/fn.transmute.html
-[`mem::align_of`]: https://doc.rust-lang.org/core/mem/fn.align_of.html
\ No newline at end of file
+[`mem::align_of`]: https://doc.rust-lang.org/core/mem/fn.align_of.html
diff --git a/library/portable-simd/crates/core_simd/Cargo.toml b/library/portable-simd/crates/core_simd/Cargo.toml
index d2ff5f3b1b1..8877c6df66e 100644
--- a/library/portable-simd/crates/core_simd/Cargo.toml
+++ b/library/portable-simd/crates/core_simd/Cargo.toml
@@ -9,7 +9,7 @@ categories = ["hardware-support", "no-std"]
 license = "MIT OR Apache-2.0"
 
 [features]
-default = ["std", "generic_const_exprs"]
+default = []
 std = []
 generic_const_exprs = []
 
diff --git a/library/portable-simd/crates/core_simd/examples/matrix_inversion.rs b/library/portable-simd/crates/core_simd/examples/matrix_inversion.rs
index c51a566deb5..39f530f68f5 100644
--- a/library/portable-simd/crates/core_simd/examples/matrix_inversion.rs
+++ b/library/portable-simd/crates/core_simd/examples/matrix_inversion.rs
@@ -233,7 +233,7 @@ pub fn simd_inv4x4(m: Matrix4x4) -> Option<Matrix4x4> {
     let det = det.rotate_lanes_right::<2>() + det;
     let det = det.reverse().rotate_lanes_right::<2>() + det;
 
-    if det.horizontal_sum() == 0. {
+    if det.reduce_sum() == 0. {
         return None;
     }
     // calculate the reciprocal
diff --git a/library/portable-simd/crates/core_simd/examples/nbody.rs b/library/portable-simd/crates/core_simd/examples/nbody.rs
index 7b1e6840f64..df38a00967f 100644
--- a/library/portable-simd/crates/core_simd/examples/nbody.rs
+++ b/library/portable-simd/crates/core_simd/examples/nbody.rs
@@ -107,10 +107,10 @@ mod nbody {
         let mut e = 0.;
         for i in 0..N_BODIES {
             let bi = &bodies[i];
-            e += bi.mass * (bi.v * bi.v).horizontal_sum() * 0.5;
+            e += bi.mass * (bi.v * bi.v).reduce_sum() * 0.5;
             for bj in bodies.iter().take(N_BODIES).skip(i + 1) {
                 let dx = bi.x - bj.x;
-                e -= bi.mass * bj.mass / (dx * dx).horizontal_sum().sqrt()
+                e -= bi.mass * bj.mass / (dx * dx).reduce_sum().sqrt()
             }
         }
         e
@@ -134,8 +134,8 @@ mod nbody {
         let mut mag = [0.0; N];
         for i in (0..N).step_by(2) {
             let d2s = f64x2::from_array([
-                (r[i] * r[i]).horizontal_sum(),
-                (r[i + 1] * r[i + 1]).horizontal_sum(),
+                (r[i] * r[i]).reduce_sum(),
+                (r[i + 1] * r[i + 1]).reduce_sum(),
             ]);
             let dmags = f64x2::splat(dt) / (d2s * d2s.sqrt());
             mag[i] = dmags[0];
@@ -187,7 +187,7 @@ mod tests {
 fn main() {
     {
         let (energy_before, energy_after) = nbody::run(1000);
-        println!("Energy before: {}", energy_before);
-        println!("Energy after:  {}", energy_after);
+        println!("Energy before: {energy_before}");
+        println!("Energy after:  {energy_after}");
     }
 }
diff --git a/library/portable-simd/crates/core_simd/examples/spectral_norm.rs b/library/portable-simd/crates/core_simd/examples/spectral_norm.rs
index c515dad4dea..012182e090b 100644
--- a/library/portable-simd/crates/core_simd/examples/spectral_norm.rs
+++ b/library/portable-simd/crates/core_simd/examples/spectral_norm.rs
@@ -20,7 +20,7 @@ fn mult_av(v: &[f64], out: &mut [f64]) {
             sum += b / a;
             j += 2
         }
-        *out = sum.horizontal_sum();
+        *out = sum.reduce_sum();
     }
 }
 
@@ -38,7 +38,7 @@ fn mult_atv(v: &[f64], out: &mut [f64]) {
             sum += b / a;
             j += 2
         }
-        *out = sum.horizontal_sum();
+        *out = sum.reduce_sum();
     }
 }
 
diff --git a/library/portable-simd/crates/core_simd/src/comparisons.rs b/library/portable-simd/crates/core_simd/src/comparisons.rs
index d024cf4ddbe..7b0d0a6864b 100644
--- a/library/portable-simd/crates/core_simd/src/comparisons.rs
+++ b/library/portable-simd/crates/core_simd/src/comparisons.rs
@@ -66,3 +66,55 @@ where
         unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
     }
 }
+
+macro_rules! impl_ord_methods_vector {
+    { $type:ty } => {
+        impl<const LANES: usize> Simd<$type, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            /// Returns the lane-wise minimum with `other`.
+            #[must_use = "method returns a new vector and does not mutate the original value"]
+            #[inline]
+            pub fn min(self, other: Self) -> Self {
+                self.lanes_gt(other).select(other, self)
+            }
+
+            /// Returns the lane-wise maximum with `other`.
+            #[must_use = "method returns a new vector and does not mutate the original value"]
+            #[inline]
+            pub fn max(self, other: Self) -> Self {
+                self.lanes_lt(other).select(other, self)
+            }
+
+            /// Restrict each lane to a certain interval.
+            ///
+            /// For each lane, returns `max` if `self` is greater than `max`, and `min` if `self` is
+            /// less than `min`. Otherwise returns `self`.
+            ///
+            /// # Panics
+            ///
+            /// Panics if `min > max` on any lane.
+            #[must_use = "method returns a new vector and does not mutate the original value"]
+            #[inline]
+            pub fn clamp(self, min: Self, max: Self) -> Self {
+                assert!(
+                    min.lanes_le(max).all(),
+                    "each lane in `min` must be less than or equal to the corresponding lane in `max`",
+                );
+                self.max(min).min(max)
+            }
+        }
+    }
+}
+
+impl_ord_methods_vector!(i8);
+impl_ord_methods_vector!(i16);
+impl_ord_methods_vector!(i32);
+impl_ord_methods_vector!(i64);
+impl_ord_methods_vector!(isize);
+impl_ord_methods_vector!(u8);
+impl_ord_methods_vector!(u16);
+impl_ord_methods_vector!(u32);
+impl_ord_methods_vector!(u64);
+impl_ord_methods_vector!(usize);
diff --git a/library/portable-simd/crates/core_simd/src/intrinsics.rs b/library/portable-simd/crates/core_simd/src/intrinsics.rs
index cf2c0a02351..426c4de6ab1 100644
--- a/library/portable-simd/crates/core_simd/src/intrinsics.rs
+++ b/library/portable-simd/crates/core_simd/src/intrinsics.rs
@@ -18,7 +18,6 @@
 //!
 //! Unless stated otherwise, all intrinsics for binary operations require SIMD vectors of equal types and lengths.
 
-
 // These intrinsics aren't linked directly from LLVM and are mostly undocumented, however they are
 // mostly lowered to the matching LLVM instructions by the compiler in a fairly straightforward manner.
 // The associated LLVM instruction or intrinsic is documented alongside each Rust intrinsic function.
@@ -130,6 +129,14 @@ extern "platform-intrinsic" {
     pub(crate) fn simd_reduce_xor<T, U>(x: T) -> U;
 
     // truncate integer vector to bitmask
+    // `fn simd_bitmask(vector) -> unsigned integer` takes a vector of integers and
+    // returns either an unsigned integer or array of `u8`.
+    // Every element in the vector becomes a single bit in the returned bitmask.
+    // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
+    // The bit order of the result depends on the byte endianness. LSB-first for little
+    // endian and MSB-first for big endian.
+    //
+    // UB if called on a vector with values other than 0 and -1.
     #[allow(unused)]
     pub(crate) fn simd_bitmask<T, U>(x: T) -> U;
 
diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs
index 91ae34c05e0..2632073622e 100644
--- a/library/portable-simd/crates/core_simd/src/lib.rs
+++ b/library/portable-simd/crates/core_simd/src/lib.rs
@@ -1,6 +1,5 @@
-#![cfg_attr(not(feature = "std"), no_std)]
+#![no_std]
 #![feature(
-    const_fn_trait_bound,
     convert_float_to_int,
     decl_macro,
     intra_doc_pointers,
diff --git a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs
index 1c2037764c1..c263f6a4eec 100644
--- a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs
+++ b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs
@@ -50,6 +50,9 @@ macro_rules! impl_integer_intrinsic {
 }
 
 impl_integer_intrinsic! {
+    unsafe impl ToBitMask<BitMask=u8> for Mask<_, 1>
+    unsafe impl ToBitMask<BitMask=u8> for Mask<_, 2>
+    unsafe impl ToBitMask<BitMask=u8> for Mask<_, 4>
     unsafe impl ToBitMask<BitMask=u8> for Mask<_, 8>
     unsafe impl ToBitMask<BitMask=u16> for Mask<_, 16>
     unsafe impl ToBitMask<BitMask=u32> for Mask<_, 32>
diff --git a/library/portable-simd/crates/core_simd/src/math.rs b/library/portable-simd/crates/core_simd/src/math.rs
index 0b4e40983af..606021e983e 100644
--- a/library/portable-simd/crates/core_simd/src/math.rs
+++ b/library/portable-simd/crates/core_simd/src/math.rs
@@ -10,8 +10,7 @@ macro_rules! impl_uint_arith {
             /// # Examples
             /// ```
             /// # #![feature(portable_simd)]
-            /// # #[cfg(feature = "std")] use core_simd::Simd;
-            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            /// # use core::simd::Simd;
             #[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
             /// let x = Simd::from_array([2, 1, 0, MAX]);
             /// let max = Simd::splat(MAX);
@@ -31,8 +30,7 @@ macro_rules! impl_uint_arith {
             /// # Examples
             /// ```
             /// # #![feature(portable_simd)]
-            /// # #[cfg(feature = "std")] use core_simd::Simd;
-            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            /// # use core::simd::Simd;
             #[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
             /// let x = Simd::from_array([2, 1, 0, MAX]);
             /// let max = Simd::splat(MAX);
@@ -58,8 +56,7 @@ macro_rules! impl_int_arith {
             /// # Examples
             /// ```
             /// # #![feature(portable_simd)]
-            /// # #[cfg(feature = "std")] use core_simd::Simd;
-            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            /// # use core::simd::Simd;
             #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
             /// let x = Simd::from_array([MIN, 0, 1, MAX]);
             /// let max = Simd::splat(MAX);
@@ -79,8 +76,7 @@ macro_rules! impl_int_arith {
             /// # Examples
             /// ```
             /// # #![feature(portable_simd)]
-            /// # #[cfg(feature = "std")] use core_simd::Simd;
-            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            /// # use core::simd::Simd;
             #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
             /// let x = Simd::from_array([MIN, -2, -1, MAX]);
             /// let max = Simd::splat(MAX);
@@ -100,8 +96,7 @@ macro_rules! impl_int_arith {
             /// # Examples
             /// ```
             /// # #![feature(portable_simd)]
-            /// # #[cfg(feature = "std")] use core_simd::Simd;
-            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            /// # use core::simd::Simd;
             #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
             /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
             /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
@@ -119,8 +114,7 @@ macro_rules! impl_int_arith {
             /// # Examples
             /// ```
             /// # #![feature(portable_simd)]
-            /// # #[cfg(feature = "std")] use core_simd::Simd;
-            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            /// # use core::simd::Simd;
             #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
             /// let xs = Simd::from_array([MIN, -2, 0, 3]);
             /// let unsat = xs.abs();
@@ -142,8 +136,7 @@ macro_rules! impl_int_arith {
             /// # Examples
             /// ```
             /// # #![feature(portable_simd)]
-            /// # #[cfg(feature = "std")] use core_simd::Simd;
-            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            /// # use core::simd::Simd;
             #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
             /// let x = Simd::from_array([MIN, -2, 3, MAX]);
             /// let unsat = -x;
diff --git a/library/portable-simd/crates/core_simd/src/reduction.rs b/library/portable-simd/crates/core_simd/src/reduction.rs
index e1cd743e442..3177fd167fc 100644
--- a/library/portable-simd/crates/core_simd/src/reduction.rs
+++ b/library/portable-simd/crates/core_simd/src/reduction.rs
@@ -11,30 +11,30 @@ macro_rules! impl_integer_reductions {
         where
             LaneCount<LANES>: SupportedLaneCount,
         {
-            /// Horizontal wrapping add.  Returns the sum of the lanes of the vector, with wrapping addition.
+            /// Reducing wrapping add.  Returns the sum of the lanes of the vector, with wrapping addition.
             #[inline]
-            pub fn horizontal_sum(self) -> $scalar {
+            pub fn reduce_sum(self) -> $scalar {
                 // Safety: `self` is an integer vector
                 unsafe { simd_reduce_add_ordered(self, 0) }
             }
 
-            /// Horizontal wrapping multiply.  Returns the product of the lanes of the vector, with wrapping multiplication.
+            /// Reducing wrapping multiply.  Returns the product of the lanes of the vector, with wrapping multiplication.
             #[inline]
-            pub fn horizontal_product(self) -> $scalar {
+            pub fn reduce_product(self) -> $scalar {
                 // Safety: `self` is an integer vector
                 unsafe { simd_reduce_mul_ordered(self, 1) }
             }
 
-            /// Horizontal maximum.  Returns the maximum lane in the vector.
+            /// Reducing maximum.  Returns the maximum lane in the vector.
             #[inline]
-            pub fn horizontal_max(self) -> $scalar {
+            pub fn reduce_max(self) -> $scalar {
                 // Safety: `self` is an integer vector
                 unsafe { simd_reduce_max(self) }
             }
 
-            /// Horizontal minimum.  Returns the minimum lane in the vector.
+            /// Reducing minimum.  Returns the minimum lane in the vector.
             #[inline]
-            pub fn horizontal_min(self) -> $scalar {
+            pub fn reduce_min(self) -> $scalar {
                 // Safety: `self` is an integer vector
                 unsafe { simd_reduce_min(self) }
             }
@@ -60,9 +60,9 @@ macro_rules! impl_float_reductions {
             LaneCount<LANES>: SupportedLaneCount,
         {
 
-            /// Horizontal add.  Returns the sum of the lanes of the vector.
+            /// Reducing add.  Returns the sum of the lanes of the vector.
             #[inline]
-            pub fn horizontal_sum(self) -> $scalar {
+            pub fn reduce_sum(self) -> $scalar {
                 // LLVM sum is inaccurate on i586
                 if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
                     self.as_array().iter().sum()
@@ -72,9 +72,9 @@ macro_rules! impl_float_reductions {
                 }
             }
 
-            /// Horizontal multiply.  Returns the product of the lanes of the vector.
+            /// Reducing multiply.  Returns the product of the lanes of the vector.
             #[inline]
-            pub fn horizontal_product(self) -> $scalar {
+            pub fn reduce_product(self) -> $scalar {
                 // LLVM product is inaccurate on i586
                 if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
                     self.as_array().iter().product()
@@ -84,22 +84,22 @@ macro_rules! impl_float_reductions {
                 }
             }
 
-            /// Horizontal maximum.  Returns the maximum lane in the vector.
+            /// Reducing maximum.  Returns the maximum lane in the vector.
             ///
             /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
             /// return either.  This function will not return `NaN` unless all lanes are `NaN`.
             #[inline]
-            pub fn horizontal_max(self) -> $scalar {
+            pub fn reduce_max(self) -> $scalar {
                 // Safety: `self` is a float vector
                 unsafe { simd_reduce_max(self) }
             }
 
-            /// Horizontal minimum.  Returns the minimum lane in the vector.
+            /// Reducing minimum.  Returns the minimum lane in the vector.
             ///
             /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
             /// return either.  This function will not return `NaN` unless all lanes are `NaN`.
             #[inline]
-            pub fn horizontal_min(self) -> $scalar {
+            pub fn reduce_min(self) -> $scalar {
                 // Safety: `self` is a float vector
                 unsafe { simd_reduce_min(self) }
             }
@@ -116,10 +116,10 @@ where
     T: SimdElement + BitAnd<T, Output = T>,
     LaneCount<LANES>: SupportedLaneCount,
 {
-    /// Horizontal bitwise "and".  Returns the cumulative bitwise "and" across the lanes of
+    /// Reducing bitwise "and".  Returns the cumulative bitwise "and" across the lanes of
     /// the vector.
     #[inline]
-    pub fn horizontal_and(self) -> T {
+    pub fn reduce_and(self) -> T {
         unsafe { simd_reduce_and(self) }
     }
 }
@@ -130,10 +130,10 @@ where
     T: SimdElement + BitOr<T, Output = T>,
     LaneCount<LANES>: SupportedLaneCount,
 {
-    /// Horizontal bitwise "or".  Returns the cumulative bitwise "or" across the lanes of
+    /// Reducing bitwise "or".  Returns the cumulative bitwise "or" across the lanes of
     /// the vector.
     #[inline]
-    pub fn horizontal_or(self) -> T {
+    pub fn reduce_or(self) -> T {
         unsafe { simd_reduce_or(self) }
     }
 }
@@ -144,10 +144,10 @@ where
     T: SimdElement + BitXor<T, Output = T>,
     LaneCount<LANES>: SupportedLaneCount,
 {
-    /// Horizontal bitwise "xor".  Returns the cumulative bitwise "xor" across the lanes of
+    /// Reducing bitwise "xor".  Returns the cumulative bitwise "xor" across the lanes of
     /// the vector.
     #[inline]
-    pub fn horizontal_xor(self) -> T {
+    pub fn reduce_xor(self) -> T {
         unsafe { simd_reduce_xor(self) }
     }
 }
diff --git a/library/portable-simd/crates/core_simd/src/select.rs b/library/portable-simd/crates/core_simd/src/select.rs
index 3acf07260e1..065c5987d3f 100644
--- a/library/portable-simd/crates/core_simd/src/select.rs
+++ b/library/portable-simd/crates/core_simd/src/select.rs
@@ -14,8 +14,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
-    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+    /// # use core::simd::{Simd, Mask};
     /// let a = Simd::from_array([0, 1, 2, 3]);
     /// let b = Simd::from_array([4, 5, 6, 7]);
     /// let mask = Mask::from_array([true, false, false, true]);
@@ -45,8 +44,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::Mask;
-    /// # #[cfg(not(feature = "std"))] use core::simd::Mask;
+    /// # use core::simd::Mask;
     /// let a = Mask::<i32, 4>::from_array([true, true, false, false]);
     /// let b = Mask::<i32, 4>::from_array([false, false, true, true]);
     /// let mask = Mask::<i32, 4>::from_array([true, false, false, true]);
diff --git a/library/portable-simd/crates/core_simd/src/swizzle.rs b/library/portable-simd/crates/core_simd/src/swizzle.rs
index 08b2add1166..ef47c4f3a4c 100644
--- a/library/portable-simd/crates/core_simd/src/swizzle.rs
+++ b/library/portable-simd/crates/core_simd/src/swizzle.rs
@@ -12,8 +12,7 @@ use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
 /// ## One source vector
 /// ```
 /// # #![feature(portable_simd)]
-/// # #[cfg(feature = "std")] use core_simd::{Simd, simd_swizzle};
-/// # #[cfg(not(feature = "std"))] use core::simd::{Simd, simd_swizzle};
+/// # use core::simd::{Simd, simd_swizzle};
 /// let v = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
 ///
 /// // Keeping the same size
@@ -28,8 +27,7 @@ use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
 /// ## Two source vectors
 /// ```
 /// # #![feature(portable_simd)]
-/// # #[cfg(feature = "std")] use core_simd::{Simd, simd_swizzle, Which};
-/// # #[cfg(not(feature = "std"))] use core::simd::{Simd, simd_swizzle, Which};
+/// # use core::simd::{Simd, simd_swizzle, Which};
 /// use Which::*;
 /// let a = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
 /// let b = Simd::<f32, 4>::from_array([4., 5., 6., 7.]);
@@ -273,8 +271,7 @@ where
     ///
     /// ```
     /// #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::Simd;
-    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// # use core::simd::Simd;
     /// let a = Simd::from_array([0, 1, 2, 3]);
     /// let b = Simd::from_array([4, 5, 6, 7]);
     /// let (x, y) = a.interleave(b);
@@ -337,8 +334,7 @@ where
     ///
     /// ```
     /// #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::Simd;
-    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// # use core::simd::Simd;
     /// let a = Simd::from_array([0, 4, 1, 5]);
     /// let b = Simd::from_array([2, 6, 3, 7]);
     /// let (x, y) = a.deinterleave(b);
diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs
index 3ccaf54b2a3..b9cd2e2021e 100644
--- a/library/portable-simd/crates/core_simd/src/vector.rs
+++ b/library/portable-simd/crates/core_simd/src/vector.rs
@@ -153,8 +153,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::Simd;
-    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// # use core::simd::Simd;
     /// let floats: Simd<f32, 4> = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]);
     /// let ints = floats.cast::<i32>();
     /// assert_eq!(ints, Simd::from_array([1, -4, i32::MAX, 0]));
@@ -180,8 +179,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::Simd;
-    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// # use core::simd::Simd;
     /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 5]);
     /// let alt = Simd::from_array([-5, -4, -3, -2]);
@@ -201,8 +199,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::Simd;
-    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// # use core::simd::Simd;
     /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 5]);
     ///
@@ -225,8 +222,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
-    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+    /// # use core::simd::{Simd, Mask};
     /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 5]);
     /// let alt = Simd::from_array([-5, -4, -3, -2]);
@@ -260,8 +256,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
-    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+    /// # use core::simd::{Simd, Mask};
     /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 5]);
     /// let alt = Simd::from_array([-5, -4, -3, -2]);
@@ -296,8 +291,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::Simd;
-    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// # use core::simd::Simd;
     /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 0]);
     /// let vals = Simd::from_array([-27, 82, -41, 124]);
@@ -319,8 +313,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
-    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+    /// # use core::simd::{Simd, Mask};
     /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 0]);
     /// let vals = Simd::from_array([-27, 82, -41, 124]);
@@ -354,8 +347,7 @@ where
     /// # Examples
     /// ```
     /// # #![feature(portable_simd)]
-    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
-    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+    /// # use core::simd::{Simd, Mask};
     /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
     /// let idxs = Simd::from_array([9, 3, 0, 0]);
     /// let vals = Simd::from_array([-27, 82, -41, 124]);
diff --git a/library/portable-simd/crates/core_simd/tests/i16_ops.rs b/library/portable-simd/crates/core_simd/tests/i16_ops.rs
index f6c5d74fbbc..171e5b472fa 100644
--- a/library/portable-simd/crates/core_simd/tests/i16_ops.rs
+++ b/library/portable-simd/crates/core_simd/tests/i16_ops.rs
@@ -1,5 +1,32 @@
 #![feature(portable_simd)]
+use core_simd::i16x2;
 
 #[macro_use]
 mod ops_macros;
 impl_signed_tests! { i16 }
+
+#[test]
+fn max_is_not_lexicographic() {
+    let a = i16x2::splat(10);
+    let b = i16x2::from_array([-4, 12]);
+    assert_eq!(a.max(b), i16x2::from_array([10, 12]));
+}
+
+#[test]
+fn min_is_not_lexicographic() {
+    let a = i16x2::splat(10);
+    let b = i16x2::from_array([12, -4]);
+    assert_eq!(a.min(b), i16x2::from_array([10, -4]));
+}
+
+#[test]
+fn clamp_is_not_lexicographic() {
+    let a = i16x2::splat(10);
+    let lo = i16x2::from_array([-12, -4]);
+    let up = i16x2::from_array([-4, 12]);
+    assert_eq!(a.clamp(lo, up), i16x2::from_array([-4, 10]));
+
+    let x = i16x2::from_array([1, 10]);
+    let y = x.clamp(i16x2::splat(0), i16x2::splat(9));
+    assert_eq!(y, i16x2::from_array([1, 9]));
+}
diff --git a/library/portable-simd/crates/core_simd/tests/ops_macros.rs b/library/portable-simd/crates/core_simd/tests/ops_macros.rs
index 50f7a4ca170..7c9b17673ef 100644
--- a/library/portable-simd/crates/core_simd/tests/ops_macros.rs
+++ b/library/portable-simd/crates/core_simd/tests/ops_macros.rs
@@ -94,70 +94,70 @@ macro_rules! impl_binary_checked_op_test {
 macro_rules! impl_common_integer_tests {
     { $vector:ident, $scalar:ident } => {
         test_helpers::test_lanes! {
-            fn horizontal_sum<const LANES: usize>() {
+            fn reduce_sum<const LANES: usize>() {
                 test_helpers::test_1(&|x| {
                     test_helpers::prop_assert_biteq! (
-                        $vector::<LANES>::from_array(x).horizontal_sum(),
+                        $vector::<LANES>::from_array(x).reduce_sum(),
                         x.iter().copied().fold(0 as $scalar, $scalar::wrapping_add),
                     );
                     Ok(())
                 });
             }
 
-            fn horizontal_product<const LANES: usize>() {
+            fn reduce_product<const LANES: usize>() {
                 test_helpers::test_1(&|x| {
                     test_helpers::prop_assert_biteq! (
-                        $vector::<LANES>::from_array(x).horizontal_product(),
+                        $vector::<LANES>::from_array(x).reduce_product(),
                         x.iter().copied().fold(1 as $scalar, $scalar::wrapping_mul),
                     );
                     Ok(())
                 });
             }
 
-            fn horizontal_and<const LANES: usize>() {
+            fn reduce_and<const LANES: usize>() {
                 test_helpers::test_1(&|x| {
                     test_helpers::prop_assert_biteq! (
-                        $vector::<LANES>::from_array(x).horizontal_and(),
+                        $vector::<LANES>::from_array(x).reduce_and(),
                         x.iter().copied().fold(-1i8 as $scalar, <$scalar as core::ops::BitAnd>::bitand),
                     );
                     Ok(())
                 });
             }
 
-            fn horizontal_or<const LANES: usize>() {
+            fn reduce_or<const LANES: usize>() {
                 test_helpers::test_1(&|x| {
                     test_helpers::prop_assert_biteq! (
-                        $vector::<LANES>::from_array(x).horizontal_or(),
+                        $vector::<LANES>::from_array(x).reduce_or(),
                         x.iter().copied().fold(0 as $scalar, <$scalar as core::ops::BitOr>::bitor),
                     );
                     Ok(())
                 });
             }
 
-            fn horizontal_xor<const LANES: usize>() {
+            fn reduce_xor<const LANES: usize>() {
                 test_helpers::test_1(&|x| {
                     test_helpers::prop_assert_biteq! (
-                        $vector::<LANES>::from_array(x).horizontal_xor(),
+                        $vector::<LANES>::from_array(x).reduce_xor(),
                         x.iter().copied().fold(0 as $scalar, <$scalar as core::ops::BitXor>::bitxor),
                     );
                     Ok(())
                 });
             }
 
-            fn horizontal_max<const LANES: usize>() {
+            fn reduce_max<const LANES: usize>() {
                 test_helpers::test_1(&|x| {
                     test_helpers::prop_assert_biteq! (
-                        $vector::<LANES>::from_array(x).horizontal_max(),
+                        $vector::<LANES>::from_array(x).reduce_max(),
                         x.iter().copied().max().unwrap(),
                     );
                     Ok(())
                 });
             }
 
-            fn horizontal_min<const LANES: usize>() {
+            fn reduce_min<const LANES: usize>() {
                 test_helpers::test_1(&|x| {
                     test_helpers::prop_assert_biteq! (
-                        $vector::<LANES>::from_array(x).horizontal_min(),
+                        $vector::<LANES>::from_array(x).reduce_min(),
                         x.iter().copied().min().unwrap(),
                     );
                     Ok(())
@@ -222,6 +222,35 @@ macro_rules! impl_signed_tests {
                     assert_eq!(a % b, Vector::<LANES>::splat(0));
                 }
 
+                fn min<const LANES: usize>() {
+                    let a = Vector::<LANES>::splat(Scalar::MIN);
+                    let b = Vector::<LANES>::splat(0);
+                    assert_eq!(a.min(b), a);
+                    let a = Vector::<LANES>::splat(Scalar::MAX);
+                    let b = Vector::<LANES>::splat(0);
+                    assert_eq!(a.min(b), b);
+                }
+
+                fn max<const LANES: usize>() {
+                    let a = Vector::<LANES>::splat(Scalar::MIN);
+                    let b = Vector::<LANES>::splat(0);
+                    assert_eq!(a.max(b), b);
+                    let a = Vector::<LANES>::splat(Scalar::MAX);
+                    let b = Vector::<LANES>::splat(0);
+                    assert_eq!(a.max(b), a);
+                }
+
+                fn clamp<const LANES: usize>() {
+                    let min = Vector::<LANES>::splat(Scalar::MIN);
+                    let max = Vector::<LANES>::splat(Scalar::MAX);
+                    let zero = Vector::<LANES>::splat(0);
+                    let one = Vector::<LANES>::splat(1);
+                    let negone = Vector::<LANES>::splat(-1);
+                    assert_eq!(zero.clamp(min, max), zero);
+                    assert_eq!(zero.clamp(min, one), zero);
+                    assert_eq!(zero.clamp(one, max), one);
+                    assert_eq!(zero.clamp(min, negone), negone);
+                }
             }
 
             test_helpers::test_lanes_panic! {
@@ -499,29 +528,29 @@ macro_rules! impl_float_tests {
                     })
                 }
 
-                fn horizontal_sum<const LANES: usize>() {
+                fn reduce_sum<const LANES: usize>() {
                     test_helpers::test_1(&|x| {
                         test_helpers::prop_assert_biteq! (
-                            Vector::<LANES>::from_array(x).horizontal_sum(),
+                            Vector::<LANES>::from_array(x).reduce_sum(),
                             x.iter().sum(),
                         );
                         Ok(())
                     });
                 }
 
-                fn horizontal_product<const LANES: usize>() {
+                fn reduce_product<const LANES: usize>() {
                     test_helpers::test_1(&|x| {
                         test_helpers::prop_assert_biteq! (
-                            Vector::<LANES>::from_array(x).horizontal_product(),
+                            Vector::<LANES>::from_array(x).reduce_product(),
                             x.iter().product(),
                         );
                         Ok(())
                     });
                 }
 
-                fn horizontal_max<const LANES: usize>() {
+                fn reduce_max<const LANES: usize>() {
                     test_helpers::test_1(&|x| {
-                        let vmax = Vector::<LANES>::from_array(x).horizontal_max();
+                        let vmax = Vector::<LANES>::from_array(x).reduce_max();
                         let smax = x.iter().copied().fold(Scalar::NAN, Scalar::max);
                         // 0 and -0 are treated the same
                         if !(x.contains(&0.) && x.contains(&-0.) && vmax.abs() == 0. && smax.abs() == 0.) {
@@ -531,9 +560,9 @@ macro_rules! impl_float_tests {
                     });
                 }
 
-                fn horizontal_min<const LANES: usize>() {
+                fn reduce_min<const LANES: usize>() {
                     test_helpers::test_1(&|x| {
-                        let vmax = Vector::<LANES>::from_array(x).horizontal_min();
+                        let vmax = Vector::<LANES>::from_array(x).reduce_min();
                         let smax = x.iter().copied().fold(Scalar::NAN, Scalar::min);
                         // 0 and -0 are treated the same
                         if !(x.contains(&0.) && x.contains(&-0.) && vmax.abs() == 0. && smax.abs() == 0.) {
diff --git a/library/portable-simd/crates/core_simd/tests/round.rs b/library/portable-simd/crates/core_simd/tests/round.rs
index 53732329237..7feb0320a16 100644
--- a/library/portable-simd/crates/core_simd/tests/round.rs
+++ b/library/portable-simd/crates/core_simd/tests/round.rs
@@ -9,7 +9,6 @@ macro_rules! float_rounding_test {
             type Scalar = $scalar;
             type IntScalar = $int_scalar;
 
-            #[cfg(feature = "std")]
             test_helpers::test_lanes! {
                 fn ceil<const LANES: usize>() {
                     test_helpers::test_unary_elementwise(
diff --git a/library/portable-simd/crates/std_float/Cargo.toml b/library/portable-simd/crates/std_float/Cargo.toml
index 82f66b8dcb7..84c69774cbd 100644
--- a/library/portable-simd/crates/std_float/Cargo.toml
+++ b/library/portable-simd/crates/std_float/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-core_simd = { path = "../core_simd" }
+core_simd = { path = "../core_simd", default-features = false }
 
 [features]
 default = ["as_crate"]
diff --git a/library/portable-simd/crates/test_helpers/src/lib.rs b/library/portable-simd/crates/test_helpers/src/lib.rs
index 7edd6096381..8bf7f5ed3d2 100644
--- a/library/portable-simd/crates/test_helpers/src/lib.rs
+++ b/library/portable-simd/crates/test_helpers/src/lib.rs
@@ -77,11 +77,21 @@ impl<T: core::fmt::Debug + DefaultStrategy, const LANES: usize> DefaultStrategy
     }
 }
 
+#[cfg(not(miri))]
+fn make_runner() -> proptest::test_runner::TestRunner {
+    Default::default()
+}
+#[cfg(miri)]
+fn make_runner() -> proptest::test_runner::TestRunner {
+    // Only run a few tests on Miri
+    proptest::test_runner::TestRunner::new(proptest::test_runner::Config::with_cases(4))
+}
+
 /// Test a function that takes a single value.
 pub fn test_1<A: core::fmt::Debug + DefaultStrategy>(
     f: &dyn Fn(A) -> proptest::test_runner::TestCaseResult,
 ) {
-    let mut runner = proptest::test_runner::TestRunner::default();
+    let mut runner = make_runner();
     runner.run(&A::default_strategy(), f).unwrap();
 }
 
@@ -89,7 +99,7 @@ pub fn test_1<A: core::fmt::Debug + DefaultStrategy>(
 pub fn test_2<A: core::fmt::Debug + DefaultStrategy, B: core::fmt::Debug + DefaultStrategy>(
     f: &dyn Fn(A, B) -> proptest::test_runner::TestCaseResult,
 ) {
-    let mut runner = proptest::test_runner::TestRunner::default();
+    let mut runner = make_runner();
     runner
         .run(&(A::default_strategy(), B::default_strategy()), |(a, b)| {
             f(a, b)
@@ -105,7 +115,7 @@ pub fn test_3<
 >(
     f: &dyn Fn(A, B, C) -> proptest::test_runner::TestCaseResult,
 ) {
-    let mut runner = proptest::test_runner::TestRunner::default();
+    let mut runner = make_runner();
     runner
         .run(
             &(
@@ -361,24 +371,28 @@ macro_rules! test_lanes {
 
                 #[test]
                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+                #[cfg(not(miri))] // Miri intrinsic implementations are uniform and larger tests are sloooow
                 fn lanes_8() {
                     implementation::<8>();
                 }
 
                 #[test]
                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+                #[cfg(not(miri))] // Miri intrinsic implementations are uniform and larger tests are sloooow
                 fn lanes_16() {
                     implementation::<16>();
                 }
 
                 #[test]
                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+                #[cfg(not(miri))] // Miri intrinsic implementations are uniform and larger tests are sloooow
                 fn lanes_32() {
                     implementation::<32>();
                 }
 
                 #[test]
                 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+                #[cfg(not(miri))] // Miri intrinsic implementations are uniform and larger tests are sloooow
                 fn lanes_64() {
                     implementation::<64>();
                 }
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index c5afca6d56a..5338cd07757 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -20,8 +20,8 @@
 #![feature(rustc_allow_const_fn_unstable)]
 #![feature(nll)]
 #![feature(staged_api)]
-#![feature(const_fn_trait_bound)]
-#![feature(const_fn_fn_ptr_basics)]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
 #![feature(allow_internal_unstable)]
 #![feature(decl_macro)]
 #![feature(extern_types)]
@@ -1106,7 +1106,7 @@ impl Literal {
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn f32_unsuffixed(n: f32) -> Literal {
         if !n.is_finite() {
-            panic!("Invalid float literal {}", n);
+            panic!("Invalid float literal {n}");
         }
         let mut repr = n.to_string();
         if !repr.contains('.') {
@@ -1131,7 +1131,7 @@ impl Literal {
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn f32_suffixed(n: f32) -> Literal {
         if !n.is_finite() {
-            panic!("Invalid float literal {}", n);
+            panic!("Invalid float literal {n}");
         }
         Literal(bridge::client::Literal::f32(&n.to_string()))
     }
@@ -1151,7 +1151,7 @@ impl Literal {
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn f64_unsuffixed(n: f64) -> Literal {
         if !n.is_finite() {
-            panic!("Invalid float literal {}", n);
+            panic!("Invalid float literal {n}");
         }
         let mut repr = n.to_string();
         if !repr.contains('.') {
@@ -1176,7 +1176,7 @@ impl Literal {
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn f64_suffixed(n: f64) -> Literal {
         if !n.is_finite() {
-            panic!("Invalid float literal {}", n);
+            panic!("Invalid float literal {n}");
         }
         Literal(bridge::client::Literal::f64(&n.to_string()))
     }
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index 8ee55234cea..a8804396246 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -83,7 +83,7 @@ pub use alloc_crate::alloc::*;
 ///
 /// fn main() {
 ///     let a = Box::new(4); // Allocates from the system allocator.
-///     println!("{}", a);
+///     println!("{a}");
 /// }
 /// ```
 ///
diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs
index f5da93f93fd..4dfbf88e83e 100644
--- a/library/std/src/backtrace/tests.rs
+++ b/library/std/src/backtrace/tests.rs
@@ -57,10 +57,10 @@ fn test_debug() {
     \n    { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\
     \n]";
 
-    assert_eq!(format!("{:#?}", backtrace), expected);
+    assert_eq!(format!("{backtrace:#?}"), expected);
 
     // Format the backtrace a second time, just to make sure lazily resolved state is stable
-    assert_eq!(format!("{:#?}", backtrace), expected);
+    assert_eq!(format!("{backtrace:#?}"), expected);
 }
 
 #[test]
@@ -91,5 +91,5 @@ fn test_frames() {
 
     let mut iter = frames.iter().zip(expected.iter());
 
-    assert!(iter.all(|(f, e)| format!("{:#?}", f) == *e));
+    assert!(iter.all(|(f, e)| format!("{f:#?}") == *e));
 }
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index c0524352193..6b63191eb58 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -109,8 +109,8 @@ use crate::sys;
 /// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"];
 /// for &book in &to_find {
 ///     match book_reviews.get(book) {
-///         Some(review) => println!("{}: {}", book, review),
-///         None => println!("{} is unreviewed.", book)
+///         Some(review) => println!("{book}: {review}"),
+///         None => println!("{book} is unreviewed.")
 ///     }
 /// }
 ///
@@ -119,7 +119,7 @@ use crate::sys;
 ///
 /// // Iterate over everything.
 /// for (book, review) in &book_reviews {
-///     println!("{}: \"{}\"", book, review);
+///     println!("{book}: \"{review}\"");
 /// }
 /// ```
 ///
@@ -199,7 +199,7 @@ use crate::sys;
 ///
 /// // Use derived implementation to print the status of the vikings.
 /// for (viking, health) in &vikings {
-///     println!("{:?} has {} hp", viking, health);
+///     println!("{viking:?} has {health} hp");
 /// }
 /// ```
 
@@ -341,7 +341,7 @@ impl<K, V, S> HashMap<K, V, S> {
     /// ]);
     ///
     /// for key in map.keys() {
-    ///     println!("{}", key);
+    ///     println!("{key}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -392,7 +392,7 @@ impl<K, V, S> HashMap<K, V, S> {
     /// ]);
     ///
     /// for val in map.values() {
-    ///     println!("{}", val);
+    ///     println!("{val}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -419,7 +419,7 @@ impl<K, V, S> HashMap<K, V, S> {
     /// }
     ///
     /// for val in map.values() {
-    ///     println!("{}", val);
+    ///     println!("{val}");
     /// }
     /// ```
     #[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -470,7 +470,7 @@ impl<K, V, S> HashMap<K, V, S> {
     /// ]);
     ///
     /// for (key, val) in map.iter() {
-    ///     println!("key: {} val: {}", key, val);
+    ///     println!("key: {key} val: {val}");
     /// }
     /// ```
     #[rustc_lint_query_instability]
@@ -500,7 +500,7 @@ impl<K, V, S> HashMap<K, V, S> {
     /// }
     ///
     /// for (key, val) in &map {
-    ///     println!("key: {} val: {}", key, val);
+    ///     println!("key: {key} val: {val}");
     /// }
     /// ```
     #[rustc_lint_query_instability]
@@ -621,7 +621,7 @@ impl<K, V, S> HashMap<K, V, S> {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+    /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
     /// The elements are visited in unsorted (and unspecified) order.
     ///
     /// # Examples
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index 30da22b8084..7ebc41588b3 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -515,10 +515,10 @@ fn test_show() {
     map.insert(1, 2);
     map.insert(3, 4);
 
-    let map_str = format!("{:?}", map);
+    let map_str = format!("{map:?}");
 
     assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
-    assert_eq!(format!("{:?}", empty), "{}");
+    assert_eq!(format!("{empty:?}"), "{}");
 }
 
 #[test]
@@ -702,7 +702,7 @@ fn test_entry_take_doesnt_corrupt() {
     // Test for #19292
     fn check(m: &HashMap<i32, ()>) {
         for k in m.keys() {
-            assert!(m.contains_key(k), "{} is in keys() but not in the map?", k);
+            assert!(m.contains_key(k), "{k} is in keys() but not in the map?");
         }
     }
 
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index 2eb4cacabb8..fa471a3c3f3 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -66,7 +66,7 @@ use super::map::{map_try_reserve_error, RandomState};
 ///
 /// // Iterate over everything.
 /// for book in &books {
-///     println!("{}", book);
+///     println!("{book}");
 /// }
 /// ```
 ///
@@ -91,7 +91,7 @@ use super::map::{map_try_reserve_error, RandomState};
 ///
 /// // Use derived implementation to print the vikings.
 /// for x in &vikings {
-///     println!("{:?}", x);
+///     println!("{x:?}");
 /// }
 /// ```
 ///
@@ -181,7 +181,7 @@ impl<T, S> HashSet<T, S> {
     ///
     /// // Will print in an arbitrary order.
     /// for x in set.iter() {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     #[inline]
@@ -244,7 +244,7 @@ impl<T, S> HashSet<T, S> {
     ///
     /// // print 1, 2, 3 in an arbitrary order
     /// for i in set.drain() {
-    ///     println!("{}", i);
+    ///     println!("{i}");
     /// }
     ///
     /// assert!(set.is_empty());
@@ -300,7 +300,7 @@ impl<T, S> HashSet<T, S> {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+    /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
     /// The elements are visited in unsorted (and unspecified) order.
     ///
     /// # Examples
@@ -525,7 +525,7 @@ where
     ///
     /// // Can be seen as `a - b`.
     /// for x in a.difference(&b) {
-    ///     println!("{}", x); // Print 1
+    ///     println!("{x}"); // Print 1
     /// }
     ///
     /// let diff: HashSet<_> = a.difference(&b).collect();
@@ -555,7 +555,7 @@ where
     ///
     /// // Print 1, 4 in arbitrary order.
     /// for x in a.symmetric_difference(&b) {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     ///
     /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect();
@@ -586,7 +586,7 @@ where
     ///
     /// // Print 2, 3 in arbitrary order.
     /// for x in a.intersection(&b) {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     ///
     /// let intersection: HashSet<_> = a.intersection(&b).collect();
@@ -615,7 +615,7 @@ where
     ///
     /// // Print 1, 2, 3, 4 in arbitrary order.
     /// for x in a.union(&b) {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     ///
     /// let union: HashSet<_> = a.union(&b).collect();
@@ -1451,7 +1451,7 @@ impl<T, S> IntoIterator for HashSet<T, S> {
     ///
     /// // Will print in an arbitrary order.
     /// for x in &v {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     #[inline]
diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs
index 6a625e6243c..233db276b9e 100644
--- a/library/std/src/collections/hash/set/tests.rs
+++ b/library/std/src/collections/hash/set/tests.rs
@@ -301,10 +301,10 @@ fn test_show() {
     set.insert(1);
     set.insert(2);
 
-    let set_str = format!("{:?}", set);
+    let set_str = format!("{set:?}");
 
     assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
-    assert_eq!(format!("{:?}", empty), "{}");
+    assert_eq!(format!("{empty:?}"), "{}");
 }
 
 #[test]
diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs
index b5e81deb480..0caec8fe05a 100644
--- a/library/std/src/collections/mod.rs
+++ b/library/std/src/collections/mod.rs
@@ -199,7 +199,7 @@
 //! ```
 //! let vec = vec![1, 2, 3, 4];
 //! for x in vec.iter() {
-//!    println!("vec contained {}", x);
+//!    println!("vec contained {x:?}");
 //! }
 //! ```
 //!
@@ -246,7 +246,7 @@
 //! ```
 //! let vec = vec![1, 2, 3, 4];
 //! for x in vec.iter().rev() {
-//!    println!("vec contained {}", x);
+//!    println!("vec contained {x:?}");
 //! }
 //! ```
 //!
@@ -306,7 +306,7 @@
 //!
 //! println!("Number of occurrences of each character");
 //! for (char, count) in &count {
-//!     println!("{}: {}", char, count);
+//!     println!("{char}: {count}");
 //! }
 //! ```
 //!
@@ -339,7 +339,7 @@
 //!     // Check if they're sober enough to have another beer.
 //!     if person.blood_alcohol > 0.3 {
 //!         // Too drunk... for now.
-//!         println!("Sorry {}, I have to cut you off", id);
+//!         println!("Sorry {id}, I have to cut you off");
 //!     } else {
 //!         // Have another!
 //!         person.blood_alcohol += 0.1;
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 5ed9fa9d6f0..05f08c498e6 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -118,7 +118,7 @@ pub struct VarsOs {
 /// // We will iterate through the references to the element returned by
 /// // env::vars();
 /// for (key, value) in env::vars() {
-///     println!("{}: {}", key, value);
+///     println!("{key}: {value}");
 /// }
 /// ```
 ///
@@ -148,7 +148,7 @@ pub fn vars() -> Vars {
 /// // We will iterate through the references to the element returned by
 /// // env::vars_os();
 /// for (key, value) in env::vars_os() {
-///     println!("{:?}: {:?}", key, value);
+///     println!("{key:?}: {value:?}");
 /// }
 /// ```
 #[must_use]
@@ -212,8 +212,8 @@ impl fmt::Debug for VarsOs {
 ///
 /// let key = "HOME";
 /// match env::var(key) {
-///     Ok(val) => println!("{}: {:?}", key, val),
-///     Err(e) => println!("couldn't interpret {}: {}", key, e),
+///     Ok(val) => println!("{key}: {val:?}"),
+///     Err(e) => println!("couldn't interpret {key}: {e}"),
 /// }
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
@@ -252,8 +252,8 @@ fn _var(key: &OsStr) -> Result<String, VarError> {
 ///
 /// let key = "HOME";
 /// match env::var_os(key) {
-///     Some(val) => println!("{}: {:?}", key, val),
-///     None => println!("{} is not defined in the environment.", key)
+///     Some(val) => println!("{key}: {val:?}"),
+///     None => println!("{key} is not defined in the environment.")
 /// }
 /// ```
 #[must_use]
@@ -343,7 +343,7 @@ pub fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
 
 fn _set_var(key: &OsStr, value: &OsStr) {
     os_imp::setenv(key, value).unwrap_or_else(|e| {
-        panic!("failed to set environment variable `{:?}` to `{:?}`: {}", key, value, e)
+        panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}")
     })
 }
 
@@ -385,7 +385,7 @@ pub fn remove_var<K: AsRef<OsStr>>(key: K) {
 
 fn _remove_var(key: &OsStr) {
     os_imp::unsetenv(key)
-        .unwrap_or_else(|e| panic!("failed to remove environment variable `{:?}`: {}", key, e))
+        .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}"))
 }
 
 /// An iterator that splits an environment variable into paths according to
@@ -421,7 +421,7 @@ pub struct SplitPaths<'a> {
 ///             println!("'{}'", path.display());
 ///         }
 ///     }
-///     None => println!("{} is not defined in the environment.", key)
+///     None => println!("{key} is not defined in the environment.")
 /// }
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
@@ -684,7 +684,7 @@ pub fn temp_dir() -> PathBuf {
 /// match env::current_exe() {
 ///     Ok(exe_path) => println!("Path of this executable is: {}",
 ///                              exe_path.display()),
-///     Err(e) => println!("failed to get current exe path: {}", e),
+///     Err(e) => println!("failed to get current exe path: {e}"),
 /// };
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
@@ -755,7 +755,7 @@ pub struct ArgsOs {
 ///
 /// // Prints each argument on a separate line
 /// for argument in env::args() {
-///     println!("{}", argument);
+///     println!("{argument}");
 /// }
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
@@ -790,7 +790,7 @@ pub fn args() -> Args {
 ///
 /// // Prints each argument on a separate line
 /// for argument in env::args_os() {
-///     println!("{:?}", argument);
+///     println!("{argument:?}");
 /// }
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 1a96b9c9282..c3cb71a5dee 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -96,7 +96,7 @@ pub trait Error: Debug + Display {
     /// fn main() {
     ///     match get_super_error() {
     ///         Err(e) => {
-    ///             println!("Error: {}", e);
+    ///             println!("Error: {e}");
     ///             println!("Caused by: {}", e.source().unwrap());
     ///         }
     ///         _ => println!("No error"),
@@ -139,7 +139,7 @@ pub trait Error: Debug + Display {
     /// ```
     /// if let Err(e) = "xc".parse::<u32>() {
     ///     // Print `e` itself, no need for description().
-    ///     eprintln!("Error: {}", e);
+    ///     eprintln!("Error: {e}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1074,7 +1074,7 @@ impl<E> Report<E> {
     ///
     /// let error = SuperError { source: SuperErrorSideKick };
     /// let report = Report::new(error).pretty(true);
-    /// eprintln!("Error: {:?}", report);
+    /// eprintln!("Error: {report:?}");
     /// ```
     ///
     /// This example produces the following output:
@@ -1135,7 +1135,7 @@ impl<E> Report<E> {
     /// let source = SuperErrorSideKick { source };
     /// let error = SuperError { source };
     /// let report = Report::new(error).pretty(true);
-    /// eprintln!("Error: {:?}", report);
+    /// eprintln!("Error: {report:?}");
     /// ```
     ///
     /// This example produces the following output:
@@ -1210,7 +1210,7 @@ impl<E> Report<E> {
     /// let source = SuperErrorSideKick::new();
     /// let error = SuperError { source };
     /// let report = Report::new(error).pretty(true).show_backtrace(true);
-    /// eprintln!("Error: {:?}", report);
+    /// eprintln!("Error: {report:?}");
     /// ```
     ///
     /// This example produces something similar to the following output:
@@ -1267,7 +1267,7 @@ where
         let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
 
         for cause in sources {
-            write!(f, ": {}", cause)?;
+            write!(f, ": {cause}")?;
         }
 
         Ok(())
@@ -1278,7 +1278,7 @@ where
     fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let error = &self.error;
 
-        write!(f, "{}", error)?;
+        write!(f, "{error}")?;
 
         if let Some(cause) = error.source() {
             write!(f, "\n\nCaused by:")?;
@@ -1289,9 +1289,9 @@ where
                 writeln!(f)?;
                 let mut indented = Indented { inner: f };
                 if multiple {
-                    write!(indented, "{: >4}: {}", ind, error)?;
+                    write!(indented, "{ind: >4}: {error}")?;
                 } else {
-                    write!(indented, "      {}", error)?;
+                    write!(indented, "      {error}")?;
                 }
             }
         }
@@ -1333,7 +1333,7 @@ impl Report<Box<dyn Error>> {
         let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
 
         for cause in sources {
-            write!(f, ": {}", cause)?;
+            write!(f, ": {cause}")?;
         }
 
         Ok(())
@@ -1344,7 +1344,7 @@ impl Report<Box<dyn Error>> {
     fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let error = &self.error;
 
-        write!(f, "{}", error)?;
+        write!(f, "{error}")?;
 
         if let Some(cause) = error.source() {
             write!(f, "\n\nCaused by:")?;
@@ -1355,9 +1355,9 @@ impl Report<Box<dyn Error>> {
                 writeln!(f)?;
                 let mut indented = Indented { inner: f };
                 if multiple {
-                    write!(indented, "{: >4}: {}", ind, error)?;
+                    write!(indented, "{ind: >4}: {error}")?;
                 } else {
-                    write!(indented, "      {}", error)?;
+                    write!(indented, "      {error}")?;
                 }
             }
         }
diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs
index eae5f43ff3c..a2a35d96ec9 100644
--- a/library/std/src/error/tests.rs
+++ b/library/std/src/error/tests.rs
@@ -130,7 +130,7 @@ Stack backtrace:
     error.backtrace = Some(trace);
     let report = Report::new(error).pretty(true).show_backtrace(true);
 
-    println!("Error: {}", report);
+    println!("Error: {report}");
     assert_eq!(expected.trim_end(), report.to_string());
 }
 
@@ -155,7 +155,7 @@ Stack backtrace:
     let error = GenericError::new_with_source("Error with two sources", error);
     let report = Report::new(error).pretty(true).show_backtrace(true);
 
-    println!("Error: {}", report);
+    println!("Error: {report}");
     assert_eq!(expected.trim_end(), report.to_string());
 }
 
@@ -355,7 +355,7 @@ Caused by:
    1: The message goes on and on.";
 
     let actual = report.to_string();
-    println!("{}", actual);
+    println!("{actual}");
     assert_eq!(expected, actual);
 }
 
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 1678367290e..b833d0e2ca5 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -1120,7 +1120,7 @@ impl fmt::Display for FromBytesWithNulError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str(self.description())?;
         if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
-            write!(f, " at byte pos {}", pos)?;
+            write!(f, " at byte pos {pos}")?;
         }
         Ok(())
     }
@@ -1134,7 +1134,7 @@ impl fmt::Display for FromVecWithNulError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.error_kind {
             FromBytesWithNulErrorKind::InteriorNul(pos) => {
-                write!(f, "data provided contains an interior nul byte at pos {}", pos)
+                write!(f, "data provided contains an interior nul byte at pos {pos}")
             }
             FromBytesWithNulErrorKind::NotNulTerminated => {
                 write!(f, "data provided is not nul terminated")
diff --git a/library/std/src/ffi/c_str/tests.rs b/library/std/src/ffi/c_str/tests.rs
index 00ba5460821..8d603229315 100644
--- a/library/std/src/ffi/c_str/tests.rs
+++ b/library/std/src/ffi/c_str/tests.rs
@@ -35,7 +35,7 @@ fn build_with_zero2() {
 #[test]
 fn formatted() {
     let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
-    assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
+    assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
 }
 
 #[test]
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 0b65336a5a7..c99d9b279a9 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1123,7 +1123,7 @@ impl Metadata {
     ///     let metadata = fs::metadata("foo.txt")?;
     ///
     ///     if let Ok(time) = metadata.modified() {
-    ///         println!("{:?}", time);
+    ///         println!("{time:?}");
     ///     } else {
     ///         println!("Not supported on this platform");
     ///     }
@@ -1158,7 +1158,7 @@ impl Metadata {
     ///     let metadata = fs::metadata("foo.txt")?;
     ///
     ///     if let Ok(time) = metadata.accessed() {
-    ///         println!("{:?}", time);
+    ///         println!("{time:?}");
     ///     } else {
     ///         println!("Not supported on this platform");
     ///     }
@@ -1190,7 +1190,7 @@ impl Metadata {
     ///     let metadata = fs::metadata("foo.txt")?;
     ///
     ///     if let Ok(time) = metadata.created() {
-    ///         println!("{:?}", time);
+    ///         println!("{time:?}");
     ///     } else {
     ///         println!("Not supported on this platform or filesystem");
     ///     }
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 16b8bf68242..6d67c396c62 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1,5 +1,6 @@
 use crate::io::prelude::*;
 
+use crate::env;
 use crate::fs::{self, File, OpenOptions};
 use crate::io::{ErrorKind, SeekFrom};
 use crate::path::Path;
@@ -30,7 +31,7 @@ macro_rules! check {
     ($e:expr) => {
         match $e {
             Ok(t) => t,
-            Err(e) => panic!("{} failed with: {}", stringify!($e), e),
+            Err(e) => panic!("{} failed with: {e}", stringify!($e)),
         }
     };
 }
@@ -470,7 +471,7 @@ fn file_test_directoryinfo_readdir() {
     check!(fs::create_dir(dir));
     let prefix = "foo";
     for n in 0..3 {
-        let f = dir.join(&format!("{}.txt", n));
+        let f = dir.join(&format!("{n}.txt"));
         let mut w = check!(File::create(&f));
         let msg_str = format!("{}{}", prefix, n.to_string());
         let msg = msg_str.as_bytes();
@@ -906,7 +907,14 @@ fn read_link() {
         // junction
         assert_eq!(check!(fs::read_link(r"C:\Users\Default User")), Path::new(r"C:\Users\Default"));
         // junction with special permissions
-        assert_eq!(check!(fs::read_link(r"C:\Documents and Settings\")), Path::new(r"C:\Users"));
+        // Since not all localized windows versions contain the folder "Documents and Settings" in english,
+        // we will briefly check, if it exists and otherwise skip the test. Except during CI we will always execute the test.
+        if Path::new(r"C:\Documents and Settings\").exists() || env::var_os("CI").is_some() {
+            assert_eq!(
+                check!(fs::read_link(r"C:\Documents and Settings\")),
+                Path::new(r"C:\Users")
+            );
+        }
     }
     let tmpdir = tmpdir();
     let link = tmpdir.join("link");
@@ -1329,7 +1337,7 @@ fn dir_entry_methods() {
                 assert!(file.file_type().unwrap().is_file());
                 assert!(file.metadata().unwrap().is_file());
             }
-            f => panic!("unknown file name: {:?}", f),
+            f => panic!("unknown file name: {f:?}"),
         }
     }
 }
@@ -1340,7 +1348,7 @@ fn dir_entry_debug() {
     File::create(&tmpdir.join("b")).unwrap();
     let mut read_dir = tmpdir.path().read_dir().unwrap();
     let dir_entry = read_dir.next().unwrap().unwrap();
-    let actual = format!("{:?}", dir_entry);
+    let actual = format!("{dir_entry:?}");
     let expected = format!("DirEntry({:?})", dir_entry.0.path());
     assert_eq!(actual, expected);
 }
@@ -1409,7 +1417,7 @@ fn metadata_access_times() {
                     || e1.kind() == ErrorKind::Unsupported
                         && e2.kind() == ErrorKind::Unsupported => {}
             (a, b) => {
-                panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,)
+                panic!("creation time must be always supported or not supported: {a:?} {b:?}")
             }
         }
     }
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index e7eee443624..989cec976b7 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -41,7 +41,7 @@ use crate::mem::MaybeUninit;
 ///
 ///     let mut line = String::new();
 ///     let len = reader.read_line(&mut line)?;
-///     println!("First line is {} bytes long", len);
+///     println!("First line is {len} bytes long");
 ///     Ok(())
 /// }
 /// ```
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 17e2b97545a..4a50e647c64 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -457,7 +457,7 @@ impl From<ErrorKind> for Error {
     ///
     /// let not_found = ErrorKind::NotFound;
     /// let error = Error::from(not_found);
-    /// assert_eq!("entity not found", format!("{}", error));
+    /// assert_eq!("entity not found", format!("{error}"));
     /// ```
     #[inline]
     fn from(kind: ErrorKind) -> Error {
@@ -561,7 +561,7 @@ impl Error {
     /// use std::io::Error;
     ///
     /// let os_error = Error::last_os_error();
-    /// println!("last OS error: {:?}", os_error);
+    /// println!("last OS error: {os_error:?}");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
@@ -618,7 +618,7 @@ impl Error {
     ///
     /// fn print_os_error(err: &Error) {
     ///     if let Some(raw_os_err) = err.raw_os_error() {
-    ///         println!("raw OS error: {:?}", raw_os_err);
+    ///         println!("raw OS error: {raw_os_err:?}");
     ///     } else {
     ///         println!("Not an OS error");
     ///     }
@@ -657,7 +657,7 @@ impl Error {
     ///
     /// fn print_error(err: &Error) {
     ///     if let Some(inner_err) = err.get_ref() {
-    ///         println!("Inner error: {:?}", inner_err);
+    ///         println!("Inner error: {inner_err:?}");
     ///     } else {
     ///         println!("No inner error");
     ///     }
@@ -731,7 +731,7 @@ impl Error {
     ///
     /// fn print_error(err: &Error) {
     ///     if let Some(inner_err) = err.get_ref() {
-    ///         println!("Inner error: {}", inner_err);
+    ///         println!("Inner error: {inner_err}");
     ///     } else {
     ///         println!("No inner error");
     ///     }
@@ -770,7 +770,7 @@ impl Error {
     ///
     /// fn print_error(err: Error) {
     ///     if let Some(inner_err) = err.into_inner() {
-    ///         println!("Inner error: {}", inner_err);
+    ///         println!("Inner error: {inner_err}");
     ///     } else {
     ///         println!("No inner error");
     ///     }
@@ -852,7 +852,7 @@ impl fmt::Display for Error {
         match self.repr.data() {
             ErrorData::Os(code) => {
                 let detail = sys::os::error_string(code);
-                write!(fmt, "{} (os error {})", detail, code)
+                write!(fmt, "{detail} (os error {code})")
             }
             ErrorData::Custom(ref c) => c.error.fmt(fmt),
             ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()),
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 4301e941b3d..1a0538f861a 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -161,8 +161,7 @@ impl Repr {
         // only run in libstd's tests, unless the user uses -Zbuild-std)
         debug_assert!(
             matches!(res.data(), ErrorData::Os(c) if c == code),
-            "repr(os) encoding failed for {}",
-            code,
+            "repr(os) encoding failed for {code}"
         );
         res
     }
diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs
index c2c51553b20..6fd15fa8048 100644
--- a/library/std/src/io/error/tests.rs
+++ b/library/std/src/io/error/tests.rs
@@ -33,7 +33,7 @@ fn test_debug_error() {
          }}",
         code, kind, msg
     );
-    assert_eq!(format!("{:?}", err), expected);
+    assert_eq!(format!("{err:?}"), expected);
 }
 
 #[test]
@@ -65,8 +65,8 @@ fn test_const() {
 
     assert_eq!(E.kind(), ErrorKind::NotFound);
     assert_eq!(E.to_string(), "hello");
-    assert!(format!("{:?}", E).contains("\"hello\""));
-    assert!(format!("{:?}", E).contains("NotFound"));
+    assert!(format!("{E:?}").contains("\"hello\""));
+    assert!(format!("{E:?}").contains("NotFound"));
 }
 
 #[test]
@@ -101,7 +101,7 @@ fn test_simple_message_packing() {
             let e = &$err;
             // Check that the public api is right.
             assert_eq!(e.kind(), $kind);
-            assert!(format!("{:?}", e).contains($msg));
+            assert!(format!("{e:?}").contains($msg));
             // and we got what we expected
             assert_matches!(
                 e.repr.data(),
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 3fa965d08e6..6005270a75f 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -91,7 +91,7 @@
 //!     // read a line into buffer
 //!     reader.read_line(&mut buffer)?;
 //!
-//!     println!("{}", buffer);
+//!     println!("{buffer}");
 //!     Ok(())
 //! }
 //! ```
@@ -1035,7 +1035,7 @@ pub trait Read {
 /// fn main() -> io::Result<()> {
 ///     let stdin = io::read_to_string(io::stdin())?;
 ///     println!("Stdin was:");
-///     println!("{}", stdin);
+///     println!("{stdin}");
 ///     Ok(())
 /// }
 /// ```
@@ -1761,7 +1761,7 @@ pub trait Seek {
     ///     .open("foo.txt").unwrap();
     ///
     /// let hello = "Hello!\n";
-    /// write!(f, "{}", hello).unwrap();
+    /// write!(f, "{hello}").unwrap();
     /// f.rewind().unwrap();
     ///
     /// let mut buf = String::new();
@@ -1804,7 +1804,7 @@ pub trait Seek {
     ///     let mut f = File::open("foo.txt")?;
     ///
     ///     let len = f.stream_len()?;
-    ///     println!("The file is currently {} bytes long", len);
+    ///     println!("The file is currently {len} bytes long");
     ///     Ok(())
     /// }
     /// ```
@@ -1988,7 +1988,7 @@ pub trait BufRead: Read {
     /// let buffer = stdin.fill_buf().unwrap();
     ///
     /// // work with buffer
-    /// println!("{:?}", buffer);
+    /// println!("{buffer:?}");
     ///
     /// // ensure the bytes we worked with aren't returned again later
     /// let length = buffer.len();
@@ -2042,7 +2042,7 @@ pub trait BufRead: Read {
     ///     let mut line = String::new();
     ///     stdin.read_line(&mut line).unwrap();
     ///     // work with line
-    ///     println!("{:?}", line);
+    ///     println!("{line:?}");
     /// }
     /// ```
     #[unstable(feature = "buf_read_has_data_left", reason = "recently added", issue = "86423")]
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 5414ff648d4..50344e602a9 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -349,10 +349,10 @@ impl Stdin {
     /// let mut input = String::new();
     /// match io::stdin().read_line(&mut input) {
     ///     Ok(n) => {
-    ///         println!("{} bytes read", n);
-    ///         println!("{}", input);
+    ///         println!("{n} bytes read");
+    ///         println!("{input}");
     ///     }
-    ///     Err(error) => println!("error: {}", error),
+    ///     Err(error) => println!("error: {error}"),
     /// }
     /// ```
     ///
@@ -953,7 +953,7 @@ where
     }
 
     if let Err(e) = global_s().write_fmt(args) {
-        panic!("failed printing to {}: {}", label, e);
+        panic!("failed printing to {label}: {e}");
     }
 }
 
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 5b76259afc1..542b793f6da 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -64,7 +64,7 @@ mod as_keyword {}
 /// }
 ///
 /// assert_eq!(last, 12);
-/// println!("{}", last);
+/// println!("{last}");
 /// ```
 ///
 /// A break expression is normally associated with the innermost loop enclosing the
@@ -72,10 +72,10 @@ mod as_keyword {}
 ///
 ///```rust
 /// 'outer: for i in 1..=5 {
-///     println!("outer iteration (i): {}", i);
+///     println!("outer iteration (i): {i}");
 ///
 ///     '_inner: for j in 1..=200 {
-///         println!("    inner iteration (j): {}", j);
+///         println!("    inner iteration (j): {j}");
 ///         if j >= 3 {
 ///             // breaks from inner loop, lets outer loop continue.
 ///             break;
@@ -106,7 +106,7 @@ mod as_keyword {}
 /// };
 /// // first number in Fibonacci sequence over 10:
 /// assert_eq!(result, 13);
-/// println!("{}", result);
+/// println!("{result}");
 /// ```
 ///
 /// For more details consult the [Reference on "break expression"] and the [Reference on "break and
@@ -200,7 +200,7 @@ mod const_keyword {}
 ///     if number % 2 == 0 {
 ///         continue;
 ///     }
-///     println!("{}", number);
+///     println!("{number}");
 /// }
 ///```
 ///
@@ -515,7 +515,7 @@ mod fn_keyword {}
 /// }
 ///
 /// for i in std::iter::repeat(5) {
-///     println!("turns out {} never stops being 5", i);
+///     println!("turns out {i} never stops being 5");
 ///     break; // would loop forever otherwise
 /// }
 ///
@@ -776,7 +776,7 @@ mod in_keyword {}
 /// let shadowing_example = true;
 /// let shadowing_example = 123.4;
 /// let shadowing_example = shadowing_example as u32;
-/// let mut shadowing_example = format!("cool! {}", shadowing_example);
+/// let mut shadowing_example = format!("cool! {shadowing_example}");
 /// shadowing_example += " something else!"; // not shadowing
 /// ```
 ///
@@ -805,7 +805,7 @@ mod let_keyword {}
 /// let mut counter = 0;
 ///
 /// while counter < 10 {
-///     println!("{}", counter);
+///     println!("{counter}");
 ///     counter += 1;
 /// }
 /// ```
@@ -836,7 +836,7 @@ mod let_keyword {}
 ///     if i == 10 {
 ///         counter = None;
 ///     } else {
-///         println!("{}", i);
+///         println!("{i}");
 ///         counter = Some (i + 1);
 ///     }
 /// }
@@ -866,7 +866,7 @@ mod while_keyword {}
 ///
 /// let mut i = 1;
 /// loop {
-///     println!("i is {}", i);
+///     println!("i is {i}");
 ///     if i > 100 {
 ///         break;
 ///     }
@@ -920,8 +920,8 @@ mod loop_keyword {}
 ///
 /// let a_number = Option::Some(10);
 /// match a_number {
-///     Some(x) if x <= 5 => println!("0 to 5 num = {}", x),
-///     Some(x @ 6..=10) => println!("6 to 10 num = {}", x),
+///     Some(x) if x <= 5 => println!("0 to 5 num = {x}"),
+///     Some(x @ 6..=10) => println!("6 to 10 num = {x}"),
 ///     None => panic!(),
 ///     // all other numbers
 ///     _ => panic!(),
@@ -940,8 +940,8 @@ mod loop_keyword {}
 ///
 /// let get_inner = Outer::Double(None, Some(String::new()));
 /// match get_inner {
-///     Outer::Double(None, Some(st)) => println!("{}", st),
-///     Outer::Single(opt) => println!("{:?}", opt),
+///     Outer::Double(None, Some(st)) => println!("{st}"),
+///     Outer::Single(opt) => println!("{opt:?}"),
 ///     _ => panic!(),
 /// }
 /// ```
@@ -988,7 +988,7 @@ mod mod_keyword {}
 ///
 /// ```rust
 /// let data = vec![1, 2, 3];
-/// let closure = move || println!("captured {:?} by value", data);
+/// let closure = move || println!("captured {data:?} by value");
 ///
 /// // data is no longer available, it is owned by the closure
 /// ```
@@ -1001,7 +1001,7 @@ mod mod_keyword {}
 /// ```rust
 /// fn create_fn() -> impl Fn() {
 ///     let text = "Fn".to_owned();
-///     move || println!("This is a: {}", text)
+///     move || println!("This is a: {text}")
 /// }
 ///
 /// let fn_plain = create_fn();
@@ -1014,7 +1014,7 @@ mod mod_keyword {}
 /// let data = vec![1, 2, 3];
 ///
 /// std::thread::spawn(move || {
-///     println!("captured {:?} by value", data)
+///     println!("captured {data:?} by value")
 /// }).join().unwrap();
 ///
 /// // data was moved to the spawned thread, so we cannot use it here
@@ -1025,7 +1025,7 @@ mod mod_keyword {}
 /// ```rust
 /// let capture = "hello".to_owned();
 /// let block = async move {
-///     println!("rust says {} from async block", capture);
+///     println!("rust says {capture} from async block");
 /// };
 /// ```
 ///
@@ -1124,7 +1124,7 @@ mod pub_keyword {}
 /// let maybe_name = Some(String::from("Alice"));
 /// // The variable 'maybe_name' is consumed here ...
 /// match maybe_name {
-///     Some(n) => println!("Hello, {}", n),
+///     Some(n) => println!("Hello, {n}"),
 ///     _ => println!("Hello, world"),
 /// }
 /// // ... and is now unavailable.
@@ -1138,7 +1138,7 @@ mod pub_keyword {}
 /// let maybe_name = Some(String::from("Alice"));
 /// // Using `ref`, the value is borrowed, not moved ...
 /// match maybe_name {
-///     Some(ref n) => println!("Hello, {}", n),
+///     Some(ref n) => println!("Hello, {n}"),
 ///     _ => println!("Hello, world"),
 /// }
 /// // ... so it's available here!
@@ -1423,7 +1423,7 @@ mod self_upper_keyword {}
 /// // With a strictly read-only static, references will have the same address
 /// assert_eq!(r1, r2);
 /// // A static item can be used just like a variable in many cases
-/// println!("{:?}", FOO);
+/// println!("{FOO:?}");
 /// ```
 ///
 /// # Mutable `static`s
@@ -1675,7 +1675,7 @@ mod super_keyword {}
 /// # #![allow(dead_code)]
 /// fn debug_iter<I: Iterator>(it: I) where I::Item: std::fmt::Debug {
 ///     for elem in it {
-///         println!("{:#?}", elem);
+///         println!("{elem:#?}");
 ///     }
 /// }
 ///
@@ -2313,7 +2313,7 @@ mod dyn_keyword {}
 ///     match u {
 ///         IntOrFloat { i: 10 } => println!("Found exactly ten!"),
 ///         // Matching the field `f` provides an `f32`.
-///         IntOrFloat { f } => println!("Found f = {} !", f),
+///         IntOrFloat { f } => println!("Found f = {f} !"),
 ///     }
 /// }
 /// ```
@@ -2337,7 +2337,7 @@ mod dyn_keyword {}
 /// let i = unsafe { &mut u.i };
 ///
 /// *i = 10;
-/// println!("f = {} and i = {}", f, i);
+/// println!("f = {f} and i = {i}");
 /// ```
 ///
 /// See the [Reference][union] for more informations on `union`s.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 36e6032b5e4..a464f2d4c74 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -231,6 +231,7 @@
 #![feature(assert_matches)]
 #![feature(associated_type_bounds)]
 #![feature(async_iterator)]
+#![feature(atomic_mut_ptr)]
 #![feature(bench_black_box)]
 #![feature(box_syntax)]
 #![feature(c_unwind)]
@@ -242,8 +243,8 @@
 #![feature(char_internals)]
 #![feature(concat_bytes)]
 #![feature(concat_idents)]
-#![feature(const_fn_fn_ptr_basics)]
-#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
 #![feature(const_format_args)]
 #![feature(const_io_structs)]
 #![feature(const_ip)]
@@ -262,6 +263,7 @@
 #![feature(doc_cfg)]
 #![feature(doc_cfg_hide)]
 #![feature(rustdoc_internals)]
+#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))]
 #![feature(doc_masked)]
 #![feature(doc_notable_trait)]
 #![feature(dropck_eyepatch)]
@@ -362,6 +364,11 @@ extern crate std as realstd;
 #[macro_use]
 mod macros;
 
+// The runtime entry point and a few unstable public functions used by the
+// compiler
+#[macro_use]
+pub mod rt;
+
 // The Rust prelude
 pub mod prelude;
 
@@ -494,10 +501,8 @@ pub mod lazy;
 #[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
 #[allow(rustdoc::bare_urls)]
 #[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
 mod std_float;
 
-#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
 #[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
 #[unstable(feature = "portable_simd", issue = "86656")]
 pub mod simd {
@@ -546,11 +551,6 @@ pub mod arch {
 #[stable(feature = "simd_x86", since = "1.27.0")]
 pub use std_detect::is_x86_feature_detected;
 
-// The runtime entry point and a few unstable public functions used by the
-// compiler
-#[macro_use]
-pub mod rt;
-
 // Platform-abstraction modules
 mod sys;
 mod sys_common;
diff --git a/library/std/src/net/addr/tests.rs b/library/std/src/net/addr/tests.rs
index 40f5a84bcd5..585a17451a0 100644
--- a/library/std/src/net/addr/tests.rs
+++ b/library/std/src/net/addr/tests.rs
@@ -169,30 +169,30 @@ fn is_v6() {
 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!("{:<20}", socket), "192.168.0.1:8080    ");
-    assert_eq!(format!("{:>20}", socket), "    192.168.0.1:8080");
-    assert_eq!(format!("{:^20}", socket), "  192.168.0.1:8080  ");
-    assert_eq!(format!("{:.10}", socket), "192.168.0.");
+    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!("{:<24}", socket), "[2a02:6b8:0:1::1]:53    ");
-    assert_eq!(format!("{:>24}", socket), "    [2a02:6b8:0:1::1]:53");
-    assert_eq!(format!("{:^24}", socket), "  [2a02:6b8:0:1::1]:53  ");
-    assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::");
+    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!("{:<24}", socket), "[2a02:6b8:0:1::1%5]:53  ");
-    assert_eq!(format!("{:>24}", socket), "  [2a02:6b8:0:1::1%5]:53");
-    assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1%5]:53 ");
-    assert_eq!(format!("{:.18}", socket), "[2a02:6b8:0:1::1%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]
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index cc4e4fd4fdc..f5d3c4905e0 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -595,10 +595,10 @@ impl TcpStream {
     ///             // via platform-specific APIs such as epoll or IOCP
     ///             wait_for_fd();
     ///         }
-    ///         Err(e) => panic!("encountered IO error: {}", e),
+    ///         Err(e) => panic!("encountered IO error: {e}"),
     ///     };
     /// };
-    /// println!("bytes: {:?}", buf);
+    /// println!("bytes: {buf:?}");
     /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
@@ -799,8 +799,8 @@ impl TcpListener {
     ///
     /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
     /// match listener.accept() {
-    ///     Ok((_socket, addr)) => println!("new client: {:?}", addr),
-    ///     Err(e) => println!("couldn't get client: {:?}", e),
+    ///     Ok((_socket, addr)) => println!("new client: {addr:?}"),
+    ///     Err(e) => println!("couldn't get client: {e:?}"),
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -991,7 +991,7 @@ impl TcpListener {
     ///             wait_for_fd();
     ///             continue;
     ///         }
-    ///         Err(e) => panic!("encountered IO error: {}", e),
+    ///         Err(e) => panic!("encountered IO error: {e}"),
     ///     }
     /// }
     /// ```
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
index c2061c13512..8c0adcfb0eb 100644
--- a/library/std/src/net/tcp/tests.rs
+++ b/library/std/src/net/tcp/tests.rs
@@ -142,8 +142,7 @@ fn write_close() {
                     e.kind() == ErrorKind::ConnectionReset
                         || e.kind() == ErrorKind::BrokenPipe
                         || e.kind() == ErrorKind::ConnectionAborted,
-                    "unknown error: {}",
-                    e
+                    "unknown error: {e}"
                 );
             }
         }
@@ -508,7 +507,7 @@ fn close_readwrite_smoke() {
 }
 
 #[test]
-#[cfg(unix)] // test doesn't work on Windows, see #31657
+#[cfg_attr(target_env = "sgx", ignore)]
 fn close_read_wakes_up() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -655,7 +654,7 @@ fn debug() {
         inner_name,
         render_inner(&listener)
     );
-    assert_eq!(format!("{:?}", listener), compare);
+    assert_eq!(format!("{listener:?}"), compare);
 
     let stream = t!(TcpStream::connect(&("localhost", socket_addr.port())));
     let compare = format!(
@@ -665,7 +664,7 @@ fn debug() {
         inner_name,
         render_inner(&stream)
     );
-    assert_eq!(format!("{:?}", stream), compare);
+    assert_eq!(format!("{stream:?}"), compare);
 }
 
 // FIXME: re-enabled openbsd tests once their socket timeout code
@@ -832,7 +831,7 @@ fn set_nonblocking() {
     match stream.read(&mut buf) {
         Ok(_) => panic!("expected error"),
         Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
-        Err(e) => panic!("unexpected error {}", e),
+        Err(e) => panic!("unexpected error {e}"),
     }
 }
 
@@ -862,7 +861,7 @@ fn peek() {
         match c.peek(&mut b) {
             Ok(_) => panic!("expected error"),
             Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
-            Err(e) => panic!("unexpected error {}", e),
+            Err(e) => panic!("unexpected error {e}"),
         }
         t!(txdone.send(()));
     })
diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs
index 11a696e92c8..864e1b0f345 100644
--- a/library/std/src/net/udp.rs
+++ b/library/std/src/net/udp.rs
@@ -605,9 +605,9 @@ impl UdpSocket {
     ///
     /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
     /// match socket.take_error() {
-    ///     Ok(Some(error)) => println!("UdpSocket error: {:?}", error),
+    ///     Ok(Some(error)) => println!("UdpSocket error: {error:?}"),
     ///     Ok(None) => println!("No error"),
-    ///     Err(error) => println!("UdpSocket.take_error failed: {:?}", error),
+    ///     Err(error) => println!("UdpSocket.take_error failed: {error:?}"),
     /// }
     /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
@@ -686,8 +686,8 @@ impl UdpSocket {
     /// socket.connect("127.0.0.1:8080").expect("connect function failed");
     /// let mut buf = [0; 10];
     /// match socket.recv(&mut buf) {
-    ///     Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]),
-    ///     Err(e) => println!("recv function failed: {:?}", e),
+    ///     Ok(received) => println!("received {received} bytes {:?}", &buf[..received]),
+    ///     Err(e) => println!("recv function failed: {e:?}"),
     /// }
     /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
@@ -726,8 +726,8 @@ impl UdpSocket {
     /// socket.connect("127.0.0.1:8080").expect("connect function failed");
     /// let mut buf = [0; 10];
     /// match socket.peek(&mut buf) {
-    ///     Ok(received) => println!("received {} bytes", received),
-    ///     Err(e) => println!("peek function failed: {:?}", e),
+    ///     Ok(received) => println!("received {received} bytes"),
+    ///     Err(e) => println!("peek function failed: {e:?}"),
     /// }
     /// ```
     #[stable(feature = "peek", since = "1.18.0")]
@@ -770,7 +770,7 @@ impl UdpSocket {
     ///             // via platform-specific APIs such as epoll or IOCP
     ///             wait_for_fd();
     ///         }
-    ///         Err(e) => panic!("encountered IO error: {}", e),
+    ///         Err(e) => panic!("encountered IO error: {e}"),
     ///     }
     /// };
     /// println!("bytes: {:?}", &buf[..num_bytes_read]);
diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs
index a51113dd9e7..f82904ffbbf 100644
--- a/library/std/src/net/udp/tests.rs
+++ b/library/std/src/net/udp/tests.rs
@@ -173,8 +173,8 @@ fn debug() {
 
     let udpsock = t!(UdpSocket::bind(&socket_addr));
     let udpsock_inner = udpsock.0.socket().as_raw();
-    let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner);
-    assert_eq!(format!("{:?}", udpsock), compare);
+    let compare = format!("UdpSocket {{ addr: {socket_addr:?}, {name}: {udpsock_inner:?} }}");
+    assert_eq!(format!("{udpsock:?}"), compare);
 }
 
 // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code
@@ -359,7 +359,7 @@ fn set_nonblocking() {
         match socket.recv(&mut buf) {
             Ok(_) => panic!("expected error"),
             Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
-            Err(e) => panic!("unexpected error {}", e),
+            Err(e) => panic!("unexpected error {e}"),
         }
     })
 }
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 75d65e6d5fc..3fc6cc44ce4 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -47,7 +47,7 @@ pub trait FileExt {
     ///
     ///     // We now read 8 bytes from the offset 10.
     ///     let num_bytes_read = file.read_at(&mut buf, 10)?;
-    ///     println!("read {} bytes: {:?}", num_bytes_read, buf);
+    ///     println!("read {num_bytes_read} bytes: {buf:?}");
     ///     Ok(())
     /// }
     /// ```
@@ -861,7 +861,7 @@ pub trait DirEntryExt2: Sealed {
     ///     entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
     ///
     ///     for p in entries {
-    ///         println!("{:?}", p);
+    ///         println!("{p:?}");
     ///     }
     ///
     ///     Ok(())
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index 034fa301ba1..a3ef4b2d92c 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -86,7 +86,7 @@ impl<'a> fmt::Display for AsciiEscaped<'a> {
 /// let socket = match UnixListener::bind("/tmp/sock") {
 ///     Ok(sock) => sock,
 ///     Err(e) => {
-///         println!("Couldn't bind: {:?}", e);
+///         println!("Couldn't bind: {e:?}");
 ///         return
 ///     }
 /// };
@@ -140,12 +140,11 @@ impl SocketAddr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(unix_socket_creation)]
     /// use std::os::unix::net::SocketAddr;
     /// use std::path::Path;
     ///
     /// # fn main() -> std::io::Result<()> {
-    /// let address = SocketAddr::from_path("/path/to/socket")?;
+    /// let address = SocketAddr::from_pathname("/path/to/socket")?;
     /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
     /// # Ok(())
     /// # }
@@ -154,13 +153,12 @@ impl SocketAddr {
     /// Creating a `SocketAddr` with a NULL byte results in an error.
     ///
     /// ```
-    /// #![feature(unix_socket_creation)]
     /// use std::os::unix::net::SocketAddr;
     ///
-    /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err());
+    /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err());
     /// ```
-    #[unstable(feature = "unix_socket_creation", issue = "93423")]
-    pub fn from_path<P>(path: P) -> io::Result<SocketAddr>
+    #[stable(feature = "unix_socket_creation", since = "1.61.0")]
+    pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
     where
         P: AsRef<Path>,
     {
@@ -307,7 +305,7 @@ impl SocketAddr {
     ///     let listener = match UnixListener::bind_addr(&addr) {
     ///         Ok(sock) => sock,
     ///         Err(err) => {
-    ///             println!("Couldn't bind: {:?}", err);
+    ///             println!("Couldn't bind: {err:?}");
     ///             return Err(err);
     ///         }
     ///     };
@@ -346,7 +344,7 @@ impl fmt::Debug for SocketAddr {
         match self.address() {
             AddressKind::Unnamed => write!(fmt, "(unnamed)"),
             AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
-            AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
+            AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
         }
     }
 }
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
index 6e6f5212b46..fb1ff4b725c 100644
--- a/library/std/src/os/unix/net/ancillary.rs
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -396,7 +396,7 @@ impl<'a> Iterator for Messages<'a> {
 ///     for ancillary_result in ancillary.messages() {
 ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
 ///             for fd in scm_rights {
-///                 println!("receive file descriptor: {}", fd);
+///                 println!("receive file descriptor: {fd}");
 ///             }
 ///         }
 ///     }
@@ -568,7 +568,7 @@ impl<'a> SocketAncillary<'a> {
     ///     for ancillary_result in ancillary.messages() {
     ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
     ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
+    ///                 println!("receive file descriptor: {fd}");
     ///             }
     ///         }
     ///     }
@@ -579,7 +579,7 @@ impl<'a> SocketAncillary<'a> {
     ///     for ancillary_result in ancillary.messages() {
     ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
     ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
+    ///                 println!("receive file descriptor: {fd}");
     ///             }
     ///         }
     ///     }
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index a2caccc7849..59c91e9a82e 100644
--- a/library/std/src/os/unix/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -95,7 +95,7 @@ impl UnixDatagram {
     /// let sock = match UnixDatagram::bind("/path/to/the/socket") {
     ///     Ok(sock) => sock,
     ///     Err(e) => {
-    ///         println!("Couldn't bind: {:?}", e);
+    ///         println!("Couldn't bind: {e:?}");
     ///         return
     ///     }
     /// };
@@ -127,7 +127,7 @@ impl UnixDatagram {
     ///     let sock2 = match UnixDatagram::bind_addr(&addr) {
     ///         Ok(sock) => sock,
     ///         Err(err) => {
-    ///             println!("Couldn't bind: {:?}", err);
+    ///             println!("Couldn't bind: {err:?}");
     ///             return Err(err);
     ///         }
     ///     };
@@ -157,7 +157,7 @@ impl UnixDatagram {
     /// let sock = match UnixDatagram::unbound() {
     ///     Ok(sock) => sock,
     ///     Err(e) => {
-    ///         println!("Couldn't unbound: {:?}", e);
+    ///         println!("Couldn't unbound: {e:?}");
     ///         return
     ///     }
     /// };
@@ -180,7 +180,7 @@ impl UnixDatagram {
     /// let (sock1, sock2) = match UnixDatagram::pair() {
     ///     Ok((sock1, sock2)) => (sock1, sock2),
     ///     Err(e) => {
-    ///         println!("Couldn't unbound: {:?}", e);
+    ///         println!("Couldn't unbound: {e:?}");
     ///         return
     ///     }
     /// };
@@ -210,7 +210,7 @@ impl UnixDatagram {
     ///     match sock.connect("/path/to/the/socket") {
     ///         Ok(sock) => sock,
     ///         Err(e) => {
-    ///             println!("Couldn't connect: {:?}", e);
+    ///             println!("Couldn't connect: {e:?}");
     ///             return Err(e)
     ///         }
     ///     };
@@ -243,7 +243,7 @@ impl UnixDatagram {
     ///     match sock.connect_addr(&addr) {
     ///         Ok(sock) => sock,
     ///         Err(e) => {
-    ///             println!("Couldn't connect: {:?}", e);
+    ///             println!("Couldn't connect: {e:?}");
     ///             return Err(e)
     ///         }
     ///     };
@@ -367,7 +367,7 @@ impl UnixDatagram {
     ///     let sock = UnixDatagram::unbound()?;
     ///     let mut buf = vec![0; 10];
     ///     let (size, sender) = sock.recv_from(buf.as_mut_slice())?;
-    ///     println!("received {} bytes from {:?}", size, sender);
+    ///     println!("received {size} bytes from {sender:?}");
     ///     Ok(())
     /// }
     /// ```
@@ -422,11 +422,11 @@ impl UnixDatagram {
     ///     let mut ancillary_buffer = [0; 128];
     ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
     ///     let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?;
-    ///     println!("received {}", size);
+    ///     println!("received {size}");
     ///     for ancillary_result in ancillary.messages() {
     ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
     ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
+    ///                 println!("receive file descriptor: {fd}");
     ///             }
     ///         }
     ///     }
@@ -479,11 +479,11 @@ impl UnixDatagram {
     ///     let mut ancillary_buffer = [0; 128];
     ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
     ///     let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
-    ///     println!("received {}", size);
+    ///     println!("received {size}");
     ///     for ancillary_result in ancillary.messages() {
     ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
     ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
+    ///                 println!("receive file descriptor: {fd}");
     ///             }
     ///         }
     ///     }
@@ -893,7 +893,7 @@ impl UnixDatagram {
     /// fn main() -> std::io::Result<()> {
     ///     let sock = UnixDatagram::unbound()?;
     ///     if let Ok(Some(err)) = sock.take_error() {
-    ///         println!("Got error: {:?}", err);
+    ///         println!("Got error: {err:?}");
     ///     }
     ///     Ok(())
     /// }
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index b23dd6062f6..8e11d32f130 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -63,7 +63,7 @@ impl UnixListener {
     /// let listener = match UnixListener::bind("/path/to/the/socket") {
     ///     Ok(sock) => sock,
     ///     Err(e) => {
-    ///         println!("Couldn't connect: {:?}", e);
+    ///         println!("Couldn't connect: {e:?}");
     ///         return
     ///     }
     /// };
@@ -98,7 +98,7 @@ impl UnixListener {
     ///     let listener2 = match UnixListener::bind_addr(&addr) {
     ///         Ok(sock) => sock,
     ///         Err(err) => {
-    ///             println!("Couldn't bind: {:?}", err);
+    ///             println!("Couldn't bind: {err:?}");
     ///             return Err(err);
     ///         }
     ///     };
@@ -136,8 +136,8 @@ impl UnixListener {
     ///     let listener = UnixListener::bind("/path/to/the/socket")?;
     ///
     ///     match listener.accept() {
-    ///         Ok((socket, addr)) => println!("Got a client: {:?}", addr),
-    ///         Err(e) => println!("accept function failed: {:?}", e),
+    ///         Ok((socket, addr)) => println!("Got a client: {addr:?}"),
+    ///         Err(e) => println!("accept function failed: {e:?}"),
     ///     }
     ///     Ok(())
     /// }
@@ -226,7 +226,7 @@ impl UnixListener {
     ///     let listener = UnixListener::bind("/tmp/sock")?;
     ///
     ///     if let Ok(Some(err)) = listener.take_error() {
-    ///         println!("Got error: {:?}", err);
+    ///         println!("Got error: {err:?}");
     ///     }
     ///     Ok(())
     /// }
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 583f861a925..3943b4fed09 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -57,7 +57,7 @@ pub use ucred::UCred;
 ///     stream.write_all(b"hello world")?;
 ///     let mut response = String::new();
 ///     stream.read_to_string(&mut response)?;
-///     println!("{}", response);
+///     println!("{response}");
 ///     Ok(())
 /// }
 /// ```
@@ -90,7 +90,7 @@ impl UnixStream {
     /// let socket = match UnixStream::connect("/tmp/sock") {
     ///     Ok(sock) => sock,
     ///     Err(e) => {
-    ///         println!("Couldn't connect: {:?}", e);
+    ///         println!("Couldn't connect: {e:?}");
     ///         return
     ///     }
     /// };
@@ -123,7 +123,7 @@ impl UnixStream {
     ///     let sock = match UnixStream::connect_addr(&addr) {
     ///         Ok(sock) => sock,
     ///         Err(e) => {
-    ///             println!("Couldn't connect: {:?}", e);
+    ///             println!("Couldn't connect: {e:?}");
     ///             return Err(e)
     ///         }
     ///     };
@@ -155,7 +155,7 @@ impl UnixStream {
     /// let (sock1, sock2) = match UnixStream::pair() {
     ///     Ok((sock1, sock2)) => (sock1, sock2),
     ///     Err(e) => {
-    ///         println!("Couldn't create a pair of sockets: {:?}", e);
+    ///         println!("Couldn't create a pair of sockets: {e:?}");
     ///         return
     ///     }
     /// };
@@ -443,7 +443,7 @@ impl UnixStream {
     /// fn main() -> std::io::Result<()> {
     ///     let socket = UnixStream::connect("/tmp/sock")?;
     ///     if let Ok(Some(err)) = socket.take_error() {
-    ///         println!("Got error: {:?}", err);
+    ///         println!("Got error: {err:?}");
     ///     }
     ///     Ok(())
     /// }
@@ -530,11 +530,11 @@ impl UnixStream {
     ///     let mut ancillary_buffer = [0; 128];
     ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
     ///     let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
-    ///     println!("received {}", size);
+    ///     println!("received {size}");
     ///     for ancillary_result in ancillary.messages() {
     ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
     ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
+    ///                 println!("receive file descriptor: {fd}");
     ///             }
     ///         }
     ///     }
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs
index 7ad4a02611e..aa0df61c192 100644
--- a/library/std/src/os/unix/net/tests.rs
+++ b/library/std/src/os/unix/net/tests.rs
@@ -29,7 +29,7 @@ macro_rules! or_panic {
     ($e:expr) => {
         match $e {
             Ok(e) => e,
-            Err(e) => panic!("{}", e),
+            Err(e) => panic!("{e}"),
         }
     };
 }
@@ -161,19 +161,19 @@ fn long_path() {
     );
     match UnixStream::connect(&socket_path) {
         Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
+        Err(e) => panic!("unexpected error {e}"),
         Ok(_) => panic!("unexpected success"),
     }
 
     match UnixListener::bind(&socket_path) {
         Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
+        Err(e) => panic!("unexpected error {e}"),
         Ok(_) => panic!("unexpected success"),
     }
 
     match UnixDatagram::bind(&socket_path) {
         Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
+        Err(e) => panic!("unexpected error {e}"),
         Ok(_) => panic!("unexpected success"),
     }
 }
@@ -524,7 +524,7 @@ fn test_abstract_namespace_too_long() {
         jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
     ) {
         Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
+        Err(e) => panic!("unexpected error {e}"),
         Ok(_) => panic!("unexpected success"),
     }
 }
@@ -564,7 +564,7 @@ fn test_unix_stream_peek() {
     match stream.peek(&mut buf) {
         Ok(_) => panic!("expected error"),
         Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
-        Err(e) => panic!("unexpected error: {}", e),
+        Err(e) => panic!("unexpected error: {e}"),
     }
 
     or_panic!(txdone.send(()));
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 2b9ae3210de..03de7eed6d4 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -283,7 +283,7 @@ fn default_hook(info: &PanicInfo<'_>) {
     let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
 
     let write = |err: &mut dyn crate::io::Write| {
-        let _ = writeln!(err, "thread '{}' panicked at '{}', {}", name, msg, location);
+        let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
 
         static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
 
@@ -677,7 +677,7 @@ fn rust_panic_with_hook(
             // Unfortunately, this does not print a backtrace, because creating
             // a `Backtrace` will allocate, which we must to avoid here.
             let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
-            rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
+            rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n");
         }
         crate::sys::abort_internal();
     }
@@ -745,5 +745,5 @@ fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
         let obj = &mut msg as *mut &mut dyn BoxMeUp;
         __rust_start_panic(obj)
     };
-    rtabort!("failed to initiate panic, error {}", code)
+    rtabort!("failed to initiate panic, error {code}")
 }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index e544608f83c..bcf5c9328b7 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -592,7 +592,7 @@ impl AsRef<Path> for Component<'_> {
 /// let path = Path::new("/tmp/foo/bar.txt");
 ///
 /// for component in path.components() {
-///     println!("{:?}", component);
+///     println!("{component:?}");
 /// }
 /// ```
 ///
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index 6e863787b7f..c8dc768d3fc 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -1586,17 +1586,17 @@ fn test_components_debug() {
     let mut components = path.components();
 
     let expected = "Components([RootDir, Normal(\"tmp\")])";
-    let actual = format!("{:?}", components);
+    let actual = format!("{components:?}");
     assert_eq!(expected, actual);
 
     let _ = components.next().unwrap();
     let expected = "Components([Normal(\"tmp\")])";
-    let actual = format!("{:?}", components);
+    let actual = format!("{components:?}");
     assert_eq!(expected, actual);
 
     let _ = components.next().unwrap();
     let expected = "Components([])";
-    let actual = format!("{:?}", components);
+    let actual = format!("{components:?}");
     assert_eq!(expected, actual);
 }
 
@@ -1608,17 +1608,17 @@ fn test_iter_debug() {
     let mut iter = path.iter();
 
     let expected = "Iter([\"/\", \"tmp\"])";
-    let actual = format!("{:?}", iter);
+    let actual = format!("{iter:?}");
     assert_eq!(expected, actual);
 
     let _ = iter.next().unwrap();
     let expected = "Iter([\"tmp\"])";
-    let actual = format!("{:?}", iter);
+    let actual = format!("{iter:?}");
     assert_eq!(expected, actual);
 
     let _ = iter.next().unwrap();
     let expected = "Iter([])";
-    let actual = format!("{:?}", iter);
+    let actual = format!("{iter:?}");
     assert_eq!(expected, actual);
 }
 
@@ -1770,7 +1770,7 @@ fn test_windows_absolute() {
 fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
     let prefix = "my/home";
     let mut paths: Vec<_> =
-        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
 
     paths.sort();
 
@@ -1783,7 +1783,7 @@ fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
 fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
     let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
     let paths: Vec<_> =
-        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
 
     let mut set = BTreeSet::new();
 
@@ -1801,7 +1801,7 @@ fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
 fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
     let prefix = "my/home";
     let paths: Vec<_> =
-        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
 
     let mut set = BTreeSet::new();
 
@@ -1819,7 +1819,7 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
 fn bench_path_hashset(b: &mut test::Bencher) {
     let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
     let paths: Vec<_> =
-        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
 
     let mut set = HashSet::new();
 
@@ -1837,7 +1837,7 @@ fn bench_path_hashset(b: &mut test::Bencher) {
 fn bench_path_hashset_miss(b: &mut test::Bencher) {
     let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
     let paths: Vec<_> =
-        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
 
     let mut set = HashSet::new();
 
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index ebb1d8971b9..225a679efd2 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -607,7 +607,7 @@ mod prim_pointer {}
 ///
 /// // This loop prints: 0 1 2
 /// for x in array {
-///     print!("{} ", x);
+///     print!("{x} ");
 /// }
 /// ```
 ///
@@ -646,19 +646,19 @@ mod prim_pointer {}
 /// // This creates a slice iterator, producing references to each value.
 /// for item in array.into_iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // The `array_into_iter` lint suggests this change for future compatibility:
 /// for item in array.iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
 /// for item in IntoIterator::into_iter(array).enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
@@ -673,13 +673,13 @@ mod prim_pointer {}
 /// // This iterates by reference:
 /// for item in array.iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in array.into_iter().enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
@@ -702,26 +702,26 @@ mod prim_pointer {}
 /// // This iterates by reference:
 /// for item in array.iter() {
 ///     let x: &i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in IntoIterator::into_iter(array) {
 ///     let x: i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in array {
 ///     let x: i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // IntoIter can also start a chain.
 /// // This iterates by value:
 /// for item in IntoIterator::into_iter(array).enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index e3fff155e47..d88ab625371 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -915,7 +915,7 @@ impl Command {
     ///                      .status()
     ///                      .expect("failed to execute process");
     ///
-    /// println!("process finished with: {}", status);
+    /// println!("process finished with: {status}");
     ///
     /// assert!(status.success());
     /// ```
@@ -1434,7 +1434,7 @@ impl ExitStatus {
     ///                      .status()
     ///                      .expect("ls could not be executed");
     ///
-    /// println!("ls: {}", status);
+    /// println!("ls: {status}");
     /// status.exit_ok().expect_err("/dev/nonexistent could be listed!");
     /// # } // cfg!(unix)
     /// ```
@@ -1459,7 +1459,7 @@ impl ExitStatus {
     /// if status.success() {
     ///     println!("'projects/' directory created");
     /// } else {
-    ///     println!("failed to create 'projects/' directory: {}", status);
+    ///     println!("failed to create 'projects/' directory: {status}");
     /// }
     /// ```
     #[must_use]
@@ -1490,7 +1490,7 @@ impl ExitStatus {
     ///                      .expect("failed to execute mkdir");
     ///
     /// match status.code() {
-    ///     Some(code) => println!("Exited with status code: {}", code),
+    ///     Some(code) => println!("Exited with status code: {code}"),
     ///     None       => println!("Process terminated by signal")
     /// }
     /// ```
@@ -1806,13 +1806,13 @@ impl Child {
     /// let mut child = Command::new("ls").spawn().unwrap();
     ///
     /// match child.try_wait() {
-    ///     Ok(Some(status)) => println!("exited with: {}", status),
+    ///     Ok(Some(status)) => println!("exited with: {status}"),
     ///     Ok(None) => {
     ///         println!("status not ready yet, let's really wait");
     ///         let res = child.wait();
-    ///         println!("result: {:?}", res);
+    ///         println!("result: {res:?}");
     ///     }
-    ///     Err(e) => println!("error attempting to wait: {}", e),
+    ///     Err(e) => println!("error attempting to wait: {e}"),
     /// }
     /// ```
     #[stable(feature = "process_try_wait", since = "1.18.0")]
@@ -1912,7 +1912,7 @@ impl Child {
 ///     std::process::exit(match run_app() {
 ///         Ok(_) => 0,
 ///         Err(err) => {
-///             eprintln!("error: {:?}", err);
+///             eprintln!("error: {err:?}");
 ///             1
 ///         }
 ///     });
@@ -2071,7 +2071,7 @@ impl Termination for ! {
 impl<E: fmt::Debug> Termination for Result<!, E> {
     fn report(self) -> ExitCode {
         let Err(err) = self;
-        eprintln!("Error: {:?}", err);
+        eprintln!("Error: {err:?}");
         ExitCode::FAILURE.report()
     }
 }
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index e5cdc473706..4f779ab4e78 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -64,7 +64,7 @@ fn signal_reported_right() {
     p.kill().unwrap();
     match p.wait().unwrap().signal() {
         Some(9) => {}
-        result => panic!("not terminated by signal 9 (instead, {:?})", result),
+        result => panic!("not terminated by signal 9 (instead, {result:?})"),
     }
 }
 
@@ -252,8 +252,7 @@ fn test_override_env() {
 
     assert!(
         output.contains("RUN_TEST_NEW_ENV=123"),
-        "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
-        output
+        "didn't find RUN_TEST_NEW_ENV inside of:\n\n{output}",
     );
 }
 
@@ -265,8 +264,7 @@ fn test_add_to_env() {
 
     assert!(
         output.contains("RUN_TEST_NEW_ENV=123"),
-        "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
-        output
+        "didn't find RUN_TEST_NEW_ENV inside of:\n\n{output}"
     );
 }
 
@@ -288,13 +286,11 @@ fn test_capture_env_at_spawn() {
 
     assert!(
         output.contains("RUN_TEST_NEW_ENV1=123"),
-        "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}",
-        output
+        "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{output}"
     );
     assert!(
         output.contains("RUN_TEST_NEW_ENV2=456"),
-        "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}",
-        output
+        "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{output}"
     );
 }
 
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index ee35598bab5..87d01daeafc 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -19,7 +19,7 @@
 //!         B = 4;
 //!         A = A + B;
 //!         C = B;
-//!         println!("{} {} {}", A, B, C);
+//!         println!("{A} {B} {C}");
 //!         C = A;
 //!     }
 //! }
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index 2e54321e127..e85a8723965 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -129,7 +129,7 @@
 //!
 //! // Unbounded receiver waiting for all senders to complete.
 //! while let Ok(msg) = rx.recv() {
-//!     println!("{}", msg);
+//!     println!("{msg}");
 //! }
 //!
 //! println!("completed");
@@ -376,7 +376,7 @@ impl<T> !Sync for Receiver<T> {}
 /// });
 ///
 /// for x in recv.iter() {
-///     println!("Got: {}", x);
+///     println!("Got: {x}");
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -419,7 +419,7 @@ pub struct Iter<'a, T: 'a> {
 /// thread::sleep(Duration::from_secs(2)); // block for two seconds
 ///
 /// for x in receiver.try_iter() {
-///     println!("Got: {}", x);
+///     println!("Got: {x}");
 /// }
 /// ```
 #[stable(feature = "receiver_try_iter", since = "1.15.0")]
@@ -453,7 +453,7 @@ pub struct TryIter<'a, T: 'a> {
 /// });
 ///
 /// for x in recv.into_iter() {
-///     println!("Got: {}", x);
+///     println!("Got: {x}");
 /// }
 /// ```
 #[stable(feature = "receiver_into_iter", since = "1.1.0")]
@@ -544,16 +544,16 @@ impl<T> !Sync for Sender<T> {}
 /// let mut msg;
 ///
 /// msg = receiver.recv().unwrap();
-/// println!("message {} received", msg);
+/// println!("message {msg} received");
 ///
 /// // "Thread unblocked!" will be printed now
 ///
 /// msg = receiver.recv().unwrap();
-/// println!("message {} received", msg);
+/// println!("message {msg} received");
 ///
 /// msg = receiver.recv().unwrap();
 ///
-/// println!("message {} received", msg);
+/// println!("message {msg} received");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SyncSender<T> {
@@ -996,14 +996,14 @@ impl<T> SyncSender<T> {
     ///
     /// let mut msg;
     /// msg = receiver.recv().unwrap();
-    /// println!("message {} received", msg);
+    /// println!("message {msg} received");
     ///
     /// msg = receiver.recv().unwrap();
-    /// println!("message {} received", msg);
+    /// println!("message {msg} received");
     ///
     /// // Third message may have never been sent
     /// match receiver.try_recv() {
-    ///     Ok(msg) => println!("message {} received", msg),
+    ///     Ok(msg) => println!("message {msg} received"),
     ///     Err(_) => println!("the third message was never sent"),
     /// }
     /// ```
diff --git a/library/std/src/sync/mpsc/shared.rs b/library/std/src/sync/mpsc/shared.rs
index 8487a5f8b50..56162655544 100644
--- a/library/std/src/sync/mpsc/shared.rs
+++ b/library/std/src/sync/mpsc/shared.rs
@@ -369,7 +369,7 @@ impl<T> Packet<T> {
         match self.channels.fetch_sub(1, Ordering::SeqCst) {
             1 => {}
             n if n > 1 => return,
-            n => panic!("bad number of channels left {}", n),
+            n => panic!("bad number of channels left {n}"),
         }
 
         match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) {
diff --git a/library/std/src/sync/mutex/tests.rs b/library/std/src/sync/mutex/tests.rs
index a1b5aeddcb6..93900566f11 100644
--- a/library/std/src/sync/mutex/tests.rs
+++ b/library/std/src/sync/mutex/tests.rs
@@ -94,7 +94,7 @@ fn test_into_inner_poison() {
     assert!(m.is_poisoned());
     match Arc::try_unwrap(m).unwrap().into_inner() {
         Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
-        Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
+        Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {x:?}"),
     }
 }
 
@@ -118,7 +118,7 @@ fn test_get_mut_poison() {
     assert!(m.is_poisoned());
     match Arc::try_unwrap(m).unwrap().get_mut() {
         Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
-        Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
+        Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {x:?}"),
     }
 }
 
diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs
index fa950331e64..07a90da449c 100644
--- a/library/std/src/sync/poison.rs
+++ b/library/std/src/sync/poison.rs
@@ -73,7 +73,7 @@ pub struct Guard {
 ///     Ok(_) => unreachable!(),
 ///     Err(p_err) => {
 ///         let data = p_err.get_ref();
-///         println!("recovered: {}", data);
+///         println!("recovered: {data}");
 ///     }
 /// };
 /// ```
diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs
index e9b74fb3ecc..53aa2b1e38a 100644
--- a/library/std/src/sync/rwlock/tests.rs
+++ b/library/std/src/sync/rwlock/tests.rs
@@ -218,7 +218,7 @@ fn test_into_inner_poison() {
     assert!(m.is_poisoned());
     match Arc::try_unwrap(m).unwrap().into_inner() {
         Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
-        Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
+        Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {x:?}"),
     }
 }
 
@@ -242,6 +242,6 @@ fn test_get_mut_poison() {
     assert!(m.is_poisoned());
     match Arc::try_unwrap(m).unwrap().get_mut() {
         Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
-        Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
+        Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"),
     }
 }
diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs
index 5df08a4ff59..9508c387415 100644
--- a/library/std/src/sys/sgx/abi/mod.rs
+++ b/library/std/src/sys/sgx/abi/mod.rs
@@ -95,7 +95,7 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
 pub(super) fn exit_with_code(code: isize) -> ! {
     if code != 0 {
         if let Some(mut out) = panic::SgxPanicOutput::new() {
-            let _ = write!(out, "Exited with status code {}", code);
+            let _ = write!(out, "Exited with status code {code}");
         }
     }
     usercalls::exit(code != 0);
diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs
index a6a659df291..4030355f135 100644
--- a/library/std/src/sys/sgx/abi/usercalls/mod.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs
@@ -83,7 +83,7 @@ pub fn close(fd: Fd) {
 
 fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
     String::from_utf8(buf.copy_user_buffer())
-        .unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
+        .unwrap_or_else(|_| rtabort!("Usercall {usercall}: expected {arg} to be valid UTF-8"))
 }
 
 /// Usercall `bind_stream`. See the ABI documentation for more information.
@@ -287,7 +287,7 @@ fn check_os_error(err: Result) -> i32 {
     {
         err
     } else {
-        rtabort!("Usercall: returned invalid error value {}", err)
+        rtabort!("Usercall: returned invalid error value {err}")
     }
 }
 
diff --git a/library/std/src/sys/sgx/abi/usercalls/raw.rs b/library/std/src/sys/sgx/abi/usercalls/raw.rs
index b0e6a6aaed7..4267b96ccd5 100644
--- a/library/std/src/sys/sgx/abi/usercalls/raw.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/raw.rs
@@ -132,7 +132,7 @@ impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> {
 
 impl ReturnValue for ! {
     fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
-        rtabort!("Usercall {}: did not expect to be re-entered", call);
+        rtabort!("Usercall {call}: did not expect to be re-entered");
     }
 }
 
diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs
index d14990c6877..feb0b62dcd1 100644
--- a/library/std/src/sys/sgx/net.rs
+++ b/library/std/src/sys/sgx/net.rs
@@ -501,7 +501,7 @@ impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
     type Error = io::Error;
 
     fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
-        LookupHost::new(format!("{}:{}", host, port))
+        LookupHost::new(format!("{host}:{port}"))
     }
 }
 
diff --git a/library/std/src/sys/sgx/os.rs b/library/std/src/sys/sgx/os.rs
index 5f8b8def7c6..5da0257f35d 100644
--- a/library/std/src/sys/sgx/os.rs
+++ b/library/std/src/sys/sgx/os.rs
@@ -22,7 +22,7 @@ pub fn error_string(errno: i32) -> String {
     if errno == RESULT_SUCCESS {
         "operation successful".into()
     } else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) {
-        format!("user-specified error {:08x}", errno)
+        format!("user-specified error {errno:08x}")
     } else {
         decode_error_kind(errno).as_str().into()
     }
diff --git a/library/std/src/sys/sgx/stdio.rs b/library/std/src/sys/sgx/stdio.rs
index 8ccf043b5b5..2e680e740fd 100644
--- a/library/std/src/sys/sgx/stdio.rs
+++ b/library/std/src/sys/sgx/stdio.rs
@@ -83,6 +83,6 @@ pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
     }
     let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) };
     if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
-        eprint!("{}", s);
+        eprint!("{s}");
     }
 }
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
index 2082c940153..049460755d6 100644
--- a/library/std/src/sys/solid/mod.rs
+++ b/library/std/src/sys/solid/mod.rs
@@ -87,7 +87,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
     unsafe {
         let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit();
         let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16);
-        assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {}", result);
+        assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {result}");
         let [x1, x2] = out.assume_init();
         (x1, x2)
     }
diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs
index a43407bd0f8..faeda5a854d 100644
--- a/library/std/src/sys/solid/net.rs
+++ b/library/std/src/sys/solid/net.rs
@@ -157,7 +157,7 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
         };
         Err(io::Error::new(
             io::ErrorKind::Uncategorized,
-            &format!("failed to lookup address information: {}", msg)[..],
+            &format!("failed to lookup address information: {msg}")[..],
         ))
     }
 }
diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs
index 22239e1fa8e..127cca3acca 100644
--- a/library/std/src/sys/solid/os.rs
+++ b/library/std/src/sys/solid/os.rs
@@ -26,7 +26,7 @@ pub fn errno() -> i32 {
 }
 
 pub fn error_string(errno: i32) -> String {
-    if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{}", errno) }
+    if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{errno}") }
 }
 
 pub fn getcwd() -> io::Result<PathBuf> {
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 03684608f75..a3e6b081936 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -228,23 +228,54 @@ struct Dir(*mut libc::DIR);
 unsafe impl Send for Dir {}
 unsafe impl Sync for Dir {}
 
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "fuchsia",
+    target_os = "redox"
+))]
 pub struct DirEntry {
-    entry: dirent64,
     dir: Arc<InnerReadDir>,
+    entry: dirent64_min,
     // We need to store an owned copy of the entry name on platforms that use
     // readdir() (not readdir_r()), because a) struct dirent may use a flexible
     // array to store the name, b) it lives only until the next readdir() call.
-    #[cfg(any(
-        target_os = "android",
-        target_os = "linux",
-        target_os = "solaris",
-        target_os = "illumos",
-        target_os = "fuchsia",
-        target_os = "redox"
-    ))]
     name: CString,
 }
 
+// Define a minimal subset of fields we need from `dirent64`, especially since
+// we're not using the immediate `d_name` on these targets. Keeping this as an
+// `entry` field in `DirEntry` helps reduce the `cfg` boilerplate elsewhere.
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "fuchsia",
+    target_os = "redox"
+))]
+struct dirent64_min {
+    d_ino: u64,
+    #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+    d_type: u8,
+}
+
+#[cfg(not(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "fuchsia",
+    target_os = "redox"
+)))]
+pub struct DirEntry {
+    dir: Arc<InnerReadDir>,
+    // The full entry includes a fixed-length `d_name`.
+    entry: dirent64,
+}
+
 #[derive(Clone, Debug)]
 pub struct OpenOptions {
     // generic
@@ -501,8 +532,14 @@ impl Iterator for ReadDir {
                 let entry_name = entry_bytes.add(name_offset);
                 ptr::copy_nonoverlapping(entry_bytes, copy_bytes, name_offset);
 
+                let entry = dirent64_min {
+                    d_ino: copy.d_ino as u64,
+                    #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+                    d_type: copy.d_type as u8,
+                };
+
                 let ret = DirEntry {
-                    entry: copy,
+                    entry,
                     // d_name is guaranteed to be null-terminated.
                     name: CStr::from_ptr(entry_name as *const _).to_owned(),
                     dir: Arc::clone(&self.inner),
@@ -1604,17 +1641,15 @@ mod remove_dir_impl {
         }
     }
 
-    fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> {
-        let pcstr = cstr(p)?;
-
+    fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> {
         // try opening as directory
-        let fd = match openat_nofollow_dironly(parent_fd, &pcstr) {
+        let fd = match openat_nofollow_dironly(parent_fd, &path) {
             Err(err) if err.raw_os_error() == Some(libc::ENOTDIR) => {
                 // not a directory - don't traverse further
                 return match parent_fd {
                     // unlink...
                     Some(parent_fd) => {
-                        cvt(unsafe { unlinkat(parent_fd, pcstr.as_ptr(), 0) }).map(drop)
+                        cvt(unsafe { unlinkat(parent_fd, path.as_ptr(), 0) }).map(drop)
                     }
                     // ...unless this was supposed to be the deletion root directory
                     None => Err(err),
@@ -1627,26 +1662,27 @@ mod remove_dir_impl {
         let (dir, fd) = fdreaddir(fd)?;
         for child in dir {
             let child = child?;
+            let child_name = child.name_cstr();
             match is_dir(&child) {
                 Some(true) => {
-                    remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+                    remove_dir_all_recursive(Some(fd), child_name)?;
                 }
                 Some(false) => {
-                    cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) })?;
+                    cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?;
                 }
                 None => {
                     // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
                     // if the process has the appropriate privileges. This however can causing orphaned
                     // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
                     // into it first instead of trying to unlink() it.
-                    remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+                    remove_dir_all_recursive(Some(fd), child_name)?;
                 }
             }
         }
 
         // unlink the directory after removing its contents
         cvt(unsafe {
-            unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), pcstr.as_ptr(), libc::AT_REMOVEDIR)
+            unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), path.as_ptr(), libc::AT_REMOVEDIR)
         })?;
         Ok(())
     }
@@ -1659,7 +1695,7 @@ mod remove_dir_impl {
         if attr.file_type().is_symlink() {
             crate::fs::remove_file(p)
         } else {
-            remove_dir_all_recursive(None, p)
+            remove_dir_all_recursive(None, &cstr(p)?)
         }
     }
 
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 61c15ecd85d..e6fd9a0c827 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -54,7 +54,7 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
 
     Err(io::Error::new(
         io::ErrorKind::Uncategorized,
-        &format!("failed to lookup address information: {}", detail)[..],
+        &format!("failed to lookup address information: {detail}")[..],
     ))
 }
 
diff --git a/library/std/src/sys/unix/os_str/tests.rs b/library/std/src/sys/unix/os_str/tests.rs
index 37967378155..213277f01f2 100644
--- a/library/std/src/sys/unix/os_str/tests.rs
+++ b/library/std/src/sys/unix/os_str/tests.rs
@@ -4,7 +4,7 @@ use super::*;
 fn slice_debug_output() {
     let input = Slice::from_u8_slice(b"\xF0hello,\tworld");
     let expected = r#""\xF0hello,\tworld""#;
-    let output = format!("{:?}", input);
+    let output = format!("{input:?}");
 
     assert_eq!(output, expected);
 }
diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs
index 09bfd9680f5..e3347ab12a7 100644
--- a/library/std/src/sys/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/unix/process/process_fuchsia.rs
@@ -211,7 +211,7 @@ impl Process {
                     return Ok(None);
                 }
                 _ => {
-                    panic!("Failed to wait on process handle: {}", status);
+                    panic!("Failed to wait on process handle: {status}");
                 }
             }
             zx_cvt(zx_object_get_info(
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 07a0339c066..9c477e5addc 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -120,7 +120,7 @@ impl Command {
                 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                 Err(e) => {
                     assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
-                    panic!("the CLOEXEC pipe failed: {:?}", e)
+                    panic!("the CLOEXEC pipe failed: {e:?}")
                 }
                 Ok(..) => {
                     // pipe I/O up to PIPE_BUF bytes should be atomic
@@ -682,15 +682,15 @@ impl From<c_int> for ExitStatus {
 impl fmt::Display for ExitStatus {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if let Some(code) = self.code() {
-            write!(f, "exit status: {}", code)
+            write!(f, "exit status: {code}")
         } else if let Some(signal) = self.signal() {
             if self.core_dumped() {
-                write!(f, "signal: {} (core dumped)", signal)
+                write!(f, "signal: {signal} (core dumped)")
             } else {
-                write!(f, "signal: {}", signal)
+                write!(f, "signal: {signal}")
             }
         } else if let Some(signal) = self.stopped_signal() {
-            write!(f, "stopped (not terminated) by signal: {}", signal)
+            write!(f, "stopped (not terminated) by signal: {signal}")
         } else if self.continued() {
             write!(f, "continued (WIFCONTINUED)")
         } else {
diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs
index 56ed6cfeb6a..016bc20ec0a 100644
--- a/library/std/src/sys/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/unix/process/process_vxworks.rs
@@ -239,10 +239,10 @@ impl From<c_int> for ExitStatus {
 impl fmt::Display for ExitStatus {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if let Some(code) = self.code() {
-            write!(f, "exit code: {}", code)
+            write!(f, "exit code: {code}")
         } else {
             let signal = self.signal().unwrap();
-            write!(f, "signal: {}", signal)
+            write!(f, "signal: {signal}")
         }
     }
 }
diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs
index 7a3f6b0d95a..17e8efbe097 100644
--- a/library/std/src/sys/unix/rand.rs
+++ b/library/std/src/sys/unix/rand.rs
@@ -82,7 +82,7 @@ mod imp {
                 } else if err == libc::EAGAIN {
                     return false;
                 } else {
-                    panic!("unexpected getrandom error: {}", err);
+                    panic!("unexpected getrandom error: {err}");
                 }
             } else {
                 read += result as usize;
diff --git a/library/std/src/sys/unix/rwlock.rs b/library/std/src/sys/unix/rwlock.rs
index b1faf12c226..1318c5b8e3a 100644
--- a/library/std/src/sys/unix/rwlock.rs
+++ b/library/std/src/sys/unix/rwlock.rs
@@ -48,9 +48,9 @@ impl RWLock {
             }
             panic!("rwlock read lock would result in deadlock");
         } else {
-            // According to POSIX, for a properly initialized rwlock this can only
-            // return EAGAIN or EDEADLK or 0. We rely on that.
-            debug_assert_eq!(r, 0);
+            // POSIX does not make guarantees about all the errors that may be returned.
+            // See issue #94705 for more details.
+            assert_eq!(r, 0, "unexpected error during rwlock read lock: {:?}", r);
             self.num_readers.fetch_add(1, Ordering::Relaxed);
         }
     }
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index dc288176346..6097e628768 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -224,8 +224,14 @@ where
             } as usize;
             if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
                 n *= 2;
-            } else if k >= n {
+            } else if k > n {
                 n = k;
+            } else if k == n {
+                // It is impossible to reach this point.
+                // On success, k is the returned string length excluding the null.
+                // On failure, k is the required buffer length including the null.
+                // Therefore k never equals n.
+                unreachable!();
             } else {
                 return Ok(f2(&buf[..k]));
             }
diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs
index 5f8556c3bc3..450bceae000 100644
--- a/library/std/src/sys/windows/os.rs
+++ b/library/std/src/sys/windows/os.rs
@@ -64,7 +64,7 @@ pub fn error_string(mut errnum: i32) -> String {
         if res == 0 {
             // Sometimes FormatMessageW can fail e.g., system doesn't like langId,
             let fm_err = errno();
-            return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
+            return format!("OS Error {errnum} (FormatMessageW() returned error {fm_err})");
         }
 
         match String::from_utf16(&buf[..res]) {
diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs
index d18c3d855bc..d8c9beb0c19 100644
--- a/library/std/src/sys/windows/process/tests.rs
+++ b/library/std/src/sys/windows/process/tests.rs
@@ -121,9 +121,7 @@ fn windows_env_unicode_case() {
             assert_eq!(
                 env::var(key).ok(),
                 value.map(|s| s.to_string_lossy().into_owned()),
-                "command environment mismatch: {} {}",
-                a,
-                b
+                "command environment mismatch: {a} {b}",
             );
         }
     }
diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs
index 5a8011a9588..5888ee8e34b 100644
--- a/library/std/src/sys/windows/thread_parker.rs
+++ b/library/std/src/sys/windows/thread_parker.rs
@@ -230,7 +230,7 @@ fn keyed_event_handle() -> c::HANDLE {
                     0,
                 ) {
                     c::STATUS_SUCCESS => {}
-                    r => panic!("Unable to create keyed event handle: error {}", r),
+                    r => panic!("Unable to create keyed event handle: error {r}"),
                 }
             }
             match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) {
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index b0b55592f6f..31164afdc7b 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -174,7 +174,7 @@ pub fn output_filename(
         if let Some(cwd) = cwd {
             if let Ok(stripped) = file.strip_prefix(&cwd) {
                 if let Some(s) = stripped.to_str() {
-                    return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
+                    return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR);
                 }
             }
         }
diff --git a/library/std/src/sys_common/net/tests.rs b/library/std/src/sys_common/net/tests.rs
index 7d45621e09a..ac75d9ebfc8 100644
--- a/library/std/src/sys_common/net/tests.rs
+++ b/library/std/src/sys_common/net/tests.rs
@@ -6,7 +6,7 @@ fn no_lookup_host_duplicates() {
     let mut addrs = HashMap::new();
     let lh = match LookupHost::try_from(("localhost", 0)) {
         Ok(lh) => lh,
-        Err(e) => panic!("couldn't resolve `localhost': {}", e),
+        Err(e) => panic!("couldn't resolve `localhost': {e}"),
     };
     for sa in lh {
         *addrs.entry(sa).or_insert(0) += 1;
diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parker/generic.rs
index d99e901bb5f..ffb61200e15 100644
--- a/library/std/src/sys_common/thread_parker/generic.rs
+++ b/library/std/src/sys_common/thread_parker/generic.rs
@@ -84,7 +84,7 @@ impl Parker {
         match self.state.swap(EMPTY, SeqCst) {
             NOTIFIED => {} // got a notification, hurray!
             PARKED => {}   // no notification, alas
-            n => panic!("inconsistent park_timeout state: {}", n),
+            n => panic!("inconsistent park_timeout state: {n}"),
         }
     }
 
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 7a6e6246357..10ef6662115 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -830,7 +830,7 @@ pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 {
 #[inline(never)]
 pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! {
     assert!(begin <= end);
-    panic!("index {} and/or {} in `{:?}` do not lie on character boundary", begin, end, s);
+    panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary");
 }
 
 /// Iterator for the code points of a WTF-8 string.
diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs
index 1bafbaa6939..931996791fb 100644
--- a/library/std/src/sys_common/wtf8/tests.rs
+++ b/library/std/src/sys_common/wtf8/tests.rs
@@ -266,7 +266,7 @@ fn wtf8buf_extend() {
 fn wtf8buf_show() {
     let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r");
     string.push(CodePoint::from_u32(0xD800).unwrap());
-    assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
+    assert_eq!(format!("{string:?}"), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
 }
 
 #[test]
@@ -278,7 +278,7 @@ fn wtf8buf_as_slice() {
 fn wtf8buf_show_str() {
     let text = "a\té 💩\r";
     let string = Wtf8Buf::from_str(text);
-    assert_eq!(format!("{:?}", text), format!("{:?}", string));
+    assert_eq!(format!("{text:?}"), format!("{string:?}"));
 }
 
 #[test]
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 5ffc86b4560..ae292caaed9 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -613,7 +613,7 @@ impl Builder {
 ///
 /// let receiver = thread::spawn(move || {
 ///     let value = rx.recv().expect("Unable to receive from channel");
-///     println!("{}", value);
+///     println!("{value}");
 /// });
 ///
 /// sender.join().expect("The sender thread has panicked");
@@ -633,7 +633,7 @@ impl Builder {
 /// });
 ///
 /// let result = computation.join().unwrap();
-/// println!("{}", result);
+/// println!("{result}");
 /// ```
 ///
 /// [`channels`]: crate::sync::mpsc
@@ -979,7 +979,7 @@ pub fn park_timeout_ms(ms: u32) {
 ///     if elapsed >= timeout {
 ///         break;
 ///     }
-///     println!("restarting park_timeout after {:?}", elapsed);
+///     println!("restarting park_timeout after {elapsed:?}");
 ///     timeout_remaining = timeout - elapsed;
 /// }
 /// ```
@@ -1287,12 +1287,31 @@ unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {}
 
 impl<'scope, T> Drop for Packet<'scope, T> {
     fn drop(&mut self) {
+        // If this packet was for a thread that ran in a scope, the thread
+        // panicked, and nobody consumed the panic payload, we make sure
+        // the scope function will panic.
+        let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
+        // Drop the result without causing unwinding.
+        // This is only relevant for threads that aren't join()ed, as
+        // join() will take the `result` and set it to None, such that
+        // there is nothing left to drop here.
+        // If this panics, we should handle that, because we're outside the
+        // outermost `catch_unwind` of our thread.
+        // We just abort in that case, since there's nothing else we can do.
+        // (And even if we tried to handle it somehow, we'd also need to handle
+        // the case where the panic payload we get out of it also panics on
+        // drop, and so on. See issue #86027.)
+        if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+            *self.result.get_mut() = None;
+        })) {
+            rtabort!("thread result panicked on drop");
+        }
         // Book-keeping so the scope knows when it's done.
         if let Some(scope) = self.scope {
-            // If this packet was for a thread that ran in a scope, the thread
-            // panicked, and nobody consumed the panic payload, we make sure
-            // the scope function will panic.
-            let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
+            // Now that there will be no more user code running on this thread
+            // that can use 'scope, mark the thread as 'finished'.
+            // It's important we only do this after the `result` has been dropped,
+            // since dropping it might still use things it borrowed from 'scope.
             scope.decrement_num_running_threads(unhandled_panic);
         }
     }
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index ea9623be63b..07e113f3b62 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -9,23 +9,24 @@ use crate::sync::Arc;
 /// A scope to spawn scoped threads in.
 ///
 /// See [`scope`] for details.
-pub struct Scope<'env> {
+pub struct Scope<'scope, 'env: 'scope> {
     data: ScopeData,
-    /// Invariance over 'env, to make sure 'env cannot shrink,
+    /// Invariance over 'scope, to make sure 'scope cannot shrink,
     /// which is necessary for soundness.
     ///
     /// Without invariance, this would compile fine but be unsound:
     ///
-    /// ```compile_fail
+    /// ```compile_fail,E0373
     /// #![feature(scoped_threads)]
     ///
     /// std::thread::scope(|s| {
-    ///     s.spawn(|s| {
+    ///     s.spawn(|| {
     ///         let a = String::from("abcd");
-    ///         s.spawn(|_| println!("{:?}", a)); // might run after `a` is dropped
+    ///         s.spawn(|| println!("{a:?}")); // might run after `a` is dropped
     ///     });
     /// });
     /// ```
+    scope: PhantomData<&'scope mut &'scope ()>,
     env: PhantomData<&'env mut &'env ()>,
 }
 
@@ -88,12 +89,12 @@ impl ScopeData {
 /// let mut x = 0;
 ///
 /// thread::scope(|s| {
-///     s.spawn(|_| {
+///     s.spawn(|| {
 ///         println!("hello from the first scoped thread");
 ///         // We can borrow `a` here.
 ///         dbg!(&a);
 ///     });
-///     s.spawn(|_| {
+///     s.spawn(|| {
 ///         println!("hello from the second scoped thread");
 ///         // We can even mutably borrow `x` here,
 ///         // because no other threads are using it.
@@ -106,10 +107,28 @@ impl ScopeData {
 /// a.push(4);
 /// assert_eq!(x, a.len());
 /// ```
+///
+/// # Lifetimes
+///
+/// Scoped threads involve two lifetimes: `'scope` and `'env`.
+///
+/// The `'scope` lifetime represents the lifetime of the scope itself.
+/// That is: the time during which new scoped threads may be spawned,
+/// and also the time during which they might still be running.
+/// Once this lifetime ends, all scoped threads are joined.
+/// This lifetime starts within the `scope` function, before `f` (the argument to `scope`) starts.
+/// It ends after `f` returns and all scoped threads have been joined, but before `scope` returns.
+///
+/// The `'env` lifetime represents the lifetime of whatever is borrowed by the scoped threads.
+/// This lifetime must outlast the call to `scope`, and thus cannot be smaller than `'scope`.
+/// It can be as small as the call to `scope`, meaning that anything that outlives this call,
+/// such as local variables defined right before the scope, can be borrowed by the scoped threads.
+///
+/// The `'env: 'scope` bound is part of the definition of the `Scope` type.
 #[track_caller]
 pub fn scope<'env, F, T>(f: F) -> T
 where
-    F: FnOnce(&Scope<'env>) -> T,
+    F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
 {
     let scope = Scope {
         data: ScopeData {
@@ -118,6 +137,7 @@ where
             a_thread_panicked: AtomicBool::new(false),
         },
         env: PhantomData,
+        scope: PhantomData,
     };
 
     // Run `f`, but catch panics so we can make sure to wait for all the threads to join.
@@ -138,7 +158,7 @@ where
     }
 }
 
-impl<'env> Scope<'env> {
+impl<'scope, 'env> Scope<'scope, 'env> {
     /// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it.
     ///
     /// Unlike non-scoped threads, threads spawned with this function may
@@ -163,10 +183,10 @@ impl<'env> Scope<'env> {
     /// to recover from such errors.
     ///
     /// [`join`]: ScopedJoinHandle::join
-    pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
+    pub fn spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
     where
-        F: FnOnce(&Scope<'env>) -> T + Send + 'env,
-        T: Send + 'env,
+        F: FnOnce() -> T + Send + 'scope,
+        T: Send + 'scope,
     {
         Builder::new().spawn_scoped(self, f).expect("failed to spawn thread")
     }
@@ -196,7 +216,7 @@ impl Builder {
     /// thread::scope(|s| {
     ///     thread::Builder::new()
     ///         .name("first".to_string())
-    ///         .spawn_scoped(s, |_|
+    ///         .spawn_scoped(s, ||
     ///     {
     ///         println!("hello from the {:?} scoped thread", thread::current().name());
     ///         // We can borrow `a` here.
@@ -205,7 +225,7 @@ impl Builder {
     ///     .unwrap();
     ///     thread::Builder::new()
     ///         .name("second".to_string())
-    ///         .spawn_scoped(s, |_|
+    ///         .spawn_scoped(s, ||
     ///     {
     ///         println!("hello from the {:?} scoped thread", thread::current().name());
     ///         // We can even mutably borrow `x` here,
@@ -222,14 +242,14 @@ impl Builder {
     /// ```
     pub fn spawn_scoped<'scope, 'env, F, T>(
         self,
-        scope: &'scope Scope<'env>,
+        scope: &'scope Scope<'scope, 'env>,
         f: F,
     ) -> io::Result<ScopedJoinHandle<'scope, T>>
     where
-        F: FnOnce(&Scope<'env>) -> T + Send + 'env,
-        T: Send + 'env,
+        F: FnOnce() -> T + Send + 'scope,
+        T: Send + 'scope,
     {
-        Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(|| f(scope), Some(&scope.data)) }?))
+        Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(&scope.data)) }?))
     }
 }
 
@@ -244,7 +264,7 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
     /// use std::thread;
     ///
     /// thread::scope(|s| {
-    ///     let t = s.spawn(|_| {
+    ///     let t = s.spawn(|| {
     ///         println!("hello");
     ///     });
     ///     println!("thread id: {:?}", t.thread().id());
@@ -277,7 +297,7 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
     /// use std::thread;
     ///
     /// thread::scope(|s| {
-    ///     let t = s.spawn(|_| {
+    ///     let t = s.spawn(|| {
     ///         panic!("oh no");
     ///     });
     ///     assert!(t.join().is_err());
@@ -302,7 +322,7 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
     }
 }
 
-impl<'env> fmt::Debug for Scope<'env> {
+impl fmt::Debug for Scope<'_, '_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Scope")
             .field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed))
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index 3323ba36bf3..7386fe1c442 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -4,10 +4,11 @@ use crate::mem;
 use crate::panic::panic_any;
 use crate::result;
 use crate::sync::{
+    atomic::{AtomicBool, Ordering},
     mpsc::{channel, Sender},
     Arc, Barrier,
 };
-use crate::thread::{self, ThreadId};
+use crate::thread::{self, Scope, ThreadId};
 use crate::time::Duration;
 use crate::time::Instant;
 
@@ -293,5 +294,25 @@ fn test_thread_id_not_equal() {
     assert!(thread::current().id() != spawned_id);
 }
 
-// NOTE: the corresponding test for stderr is in ui/thread-stderr, due
-// to the test harness apparently interfering with stderr configuration.
+#[test]
+fn test_scoped_threads_drop_result_before_join() {
+    let actually_finished = &AtomicBool::new(false);
+    struct X<'scope, 'env>(&'scope Scope<'scope, 'env>, &'env AtomicBool);
+    impl Drop for X<'_, '_> {
+        fn drop(&mut self) {
+            thread::sleep(Duration::from_millis(20));
+            let actually_finished = self.1;
+            self.0.spawn(move || {
+                thread::sleep(Duration::from_millis(20));
+                actually_finished.store(true, Ordering::Relaxed);
+            });
+        }
+    }
+    thread::scope(|s| {
+        s.spawn(move || {
+            thread::sleep(Duration::from_millis(20));
+            X(s, actually_finished)
+        });
+    });
+    assert!(actually_finished.load(Ordering::Relaxed));
+}
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index df8a726e64e..2f8eb557b4f 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -191,7 +191,7 @@ pub struct Instant(time::Instant);
 ///        }
 ///        Err(e) => {
 ///            // an error occurred!
-///            println!("Error: {:?}", e);
+///            println!("Error: {e:?}");
 ///        }
 ///    }
 /// }
@@ -513,7 +513,7 @@ impl SystemTime {
     /// let new_sys_time = SystemTime::now();
     /// let difference = new_sys_time.duration_since(sys_time)
     ///     .expect("Clock may have gone backwards");
-    /// println!("{:?}", difference);
+    /// println!("{difference:?}");
     /// ```
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> {
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
index d1a69ff8697..d710a574465 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/src/time/tests.rs
@@ -55,10 +55,10 @@ fn instant_elapsed() {
 fn instant_math() {
     let a = Instant::now();
     let b = Instant::now();
-    println!("a: {:?}", a);
-    println!("b: {:?}", b);
+    println!("a: {a:?}");
+    println!("b: {b:?}");
     let dur = b.duration_since(a);
-    println!("dur: {:?}", dur);
+    println!("dur: {dur:?}");
     assert_almost_eq!(b - dur, a);
     assert_almost_eq!(a + dur, b);
 
diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs
index b39701a3d42..000f5fa3f58 100644
--- a/library/test/src/cli.rs
+++ b/library/test/src/cli.rs
@@ -149,7 +149,7 @@ fn optgroups() -> getopts::Options {
 }
 
 fn usage(binary: &str, options: &getopts::Options) {
-    let message = format!("Usage: {} [OPTIONS] [FILTERS...]", binary);
+    let message = format!("Usage: {binary} [OPTIONS] [FILTERS...]");
     println!(
         r#"{usage}
 
@@ -360,7 +360,7 @@ fn get_shuffle_seed(matches: &getopts::Matches, allow_unstable: bool) -> OptPart
         shuffle_seed = match env::var("RUST_TEST_SHUFFLE_SEED") {
             Ok(val) => match val.parse::<u64>() {
                 Ok(n) => Some(n),
-                Err(_) => panic!("RUST_TEST_SHUFFLE_SEED is `{}`, should be a number.", val),
+                Err(_) => panic!("RUST_TEST_SHUFFLE_SEED is `{val}`, should be a number."),
             },
             Err(_) => None,
         };
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index 22fcd77dccc..c7e8507113e 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -114,11 +114,11 @@ impl ConsoleTestState {
                 match *result {
                     TestResult::TrOk => "ok".to_owned(),
                     TestResult::TrFailed => "failed".to_owned(),
-                    TestResult::TrFailedMsg(ref msg) => format!("failed: {}", msg),
+                    TestResult::TrFailedMsg(ref msg) => format!("failed: {msg}"),
                     TestResult::TrIgnored => {
                         #[cfg(not(bootstrap))]
                         if let Some(msg) = ignore_message {
-                            format!("ignored, {}", msg)
+                            format!("ignored, {msg}")
                         } else {
                             "ignored".to_owned()
                         }
@@ -132,7 +132,7 @@ impl ConsoleTestState {
             )
         })?;
         if let Some(exec_time) = exec_time {
-            self.write_log(|| format!(" <{}>", exec_time))?;
+            self.write_log(|| format!(" <{exec_time}>"))?;
         }
         self.write_log(|| "\n")
     }
@@ -171,14 +171,14 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Res
             }
         };
 
-        writeln!(output, "{}: {}", name, fntype)?;
-        st.write_log(|| format!("{} {}\n", fntype, name))?;
+        writeln!(output, "{name}: {fntype}")?;
+        st.write_log(|| format!("{fntype} {name}\n"))?;
     }
 
     fn plural(count: u32, s: &str) -> String {
         match count {
-            1 => format!("{} {}", 1, s),
-            n => format!("{} {}s", n, s),
+            1 => format!("1 {s}"),
+            n => format!("{n} {s}s"),
         }
     }
 
@@ -218,7 +218,7 @@ fn handle_test_result(st: &mut ConsoleTestState, completed_test: CompletedTest)
         TestResult::TrFailedMsg(msg) => {
             st.failed += 1;
             let mut stdout = stdout;
-            stdout.extend_from_slice(format!("note: {}", msg).as_bytes());
+            stdout.extend_from_slice(format!("note: {msg}").as_bytes());
             st.failures.push((test, stdout));
         }
         TestResult::TrTimedFail => {
diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs
index 54e9860ab54..e6fb4f5707b 100644
--- a/library/test/src/formatters/junit.rs
+++ b/library/test/src/formatters/junit.rs
@@ -97,7 +97,7 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
                         test_name,
                         duration.as_secs_f64()
                     ))?;
-                    self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?;
+                    self.write_message(&*format!("<failure message=\"{m}\" type=\"assert\"/>"))?;
                     self.write_message("</testcase>")?;
                 }
 
diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs
index 041df5216d7..f55d390aa56 100644
--- a/library/test/src/formatters/pretty.rs
+++ b/library/test/src/formatters/pretty.rs
@@ -96,7 +96,7 @@ impl<T: Write> PrettyFormatter<T> {
         exec_time: Option<&time::TestExecTime>,
     ) -> io::Result<()> {
         if let (Some(opts), Some(time)) = (self.time_options, exec_time) {
-            let time_str = format!(" <{}>", time);
+            let time_str = format!(" <{time}>");
 
             let color = if self.use_color {
                 if opts.is_critical(desc, time) {
@@ -124,7 +124,7 @@ impl<T: Write> PrettyFormatter<T> {
         inputs: &Vec<(TestDesc, Vec<u8>)>,
         results_type: &str,
     ) -> io::Result<()> {
-        let results_out_str = format!("\n{}:\n", results_type);
+        let results_out_str = format!("\n{results_type}:\n");
 
         self.write_plain(&results_out_str)?;
 
@@ -147,7 +147,7 @@ impl<T: Write> PrettyFormatter<T> {
         self.write_plain(&results_out_str)?;
         results.sort();
         for name in &results {
-            self.write_plain(&format!("    {}\n", name))?;
+            self.write_plain(&format!("    {name}\n"))?;
         }
         Ok(())
     }
@@ -167,9 +167,9 @@ impl<T: Write> PrettyFormatter<T> {
     fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
         let name = desc.padded_name(self.max_name_len, desc.name.padding());
         if let Some(test_mode) = desc.test_mode() {
-            self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+            self.write_plain(&format!("test {name} - {test_mode} ... "))?;
         } else {
-            self.write_plain(&format!("test {} ... ", name))?;
+            self.write_plain(&format!("test {name} ... "))?;
         }
 
         Ok(())
@@ -180,11 +180,11 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
     fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> {
         let noun = if test_count != 1 { "tests" } else { "test" };
         let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed {
-            format!(" (shuffle seed: {})", shuffle_seed)
+            format!(" (shuffle seed: {shuffle_seed})")
         } else {
             String::new()
         };
-        self.write_plain(&format!("\nrunning {} {}{}\n", test_count, noun, shuffle_seed_msg))
+        self.write_plain(&format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
     }
 
     fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
@@ -266,7 +266,7 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
         self.write_plain(&s)?;
 
         if let Some(ref exec_time) = state.exec_time {
-            let time_str = format!("; finished in {}", exec_time);
+            let time_str = format!("; finished in {exec_time}");
             self.write_plain(&time_str)?;
         }
 
diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs
index 12aca7cd9a4..fb40f86b42e 100644
--- a/library/test/src/formatters/terse.rs
+++ b/library/test/src/formatters/terse.rs
@@ -122,7 +122,7 @@ impl<T: Write> TerseFormatter<T> {
         self.write_plain("\nsuccesses:\n")?;
         successes.sort();
         for name in &successes {
-            self.write_plain(&format!("    {}\n", name))?;
+            self.write_plain(&format!("    {name}\n"))?;
         }
         Ok(())
     }
@@ -148,7 +148,7 @@ impl<T: Write> TerseFormatter<T> {
         self.write_plain("\nfailures:\n")?;
         failures.sort();
         for name in &failures {
-            self.write_plain(&format!("    {}\n", name))?;
+            self.write_plain(&format!("    {name}\n"))?;
         }
         Ok(())
     }
@@ -156,9 +156,9 @@ impl<T: Write> TerseFormatter<T> {
     fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
         let name = desc.padded_name(self.max_name_len, desc.name.padding());
         if let Some(test_mode) = desc.test_mode() {
-            self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+            self.write_plain(&format!("test {name} - {test_mode} ... "))?;
         } else {
-            self.write_plain(&format!("test {} ... ", name))?;
+            self.write_plain(&format!("test {name} ... "))?;
         }
 
         Ok(())
@@ -170,11 +170,11 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> {
         self.total_test_count = test_count;
         let noun = if test_count != 1 { "tests" } else { "test" };
         let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed {
-            format!(" (shuffle seed: {})", shuffle_seed)
+            format!(" (shuffle seed: {shuffle_seed})")
         } else {
             String::new()
         };
-        self.write_plain(&format!("\nrunning {} {}{}\n", test_count, noun, shuffle_seed_msg))
+        self.write_plain(&format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
     }
 
     fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
@@ -247,7 +247,7 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> {
         self.write_plain(&s)?;
 
         if let Some(ref exec_time) = state.exec_time {
-            let time_str = format!("; finished in {}", exec_time);
+            let time_str = format!("; finished in {exec_time}");
             self.write_plain(&time_str)?;
         }
 
diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs
index e25f524ec05..eb211157371 100644
--- a/library/test/src/helpers/concurrency.rs
+++ b/library/test/src/helpers/concurrency.rs
@@ -6,7 +6,7 @@ pub fn get_concurrency() -> usize {
     if let Ok(value) = env::var("RUST_TEST_THREADS") {
         match value.parse::<NonZeroUsize>().ok() {
             Some(n) => n.get(),
-            _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", value),
+            _ => panic!("RUST_TEST_THREADS is `{value}`, should be a positive integer."),
         }
     } else {
         thread::available_parallelism().map(|n| n.get()).unwrap_or(1)
diff --git a/library/test/src/helpers/exit_code.rs b/library/test/src/helpers/exit_code.rs
index 50bb260762a..f762f88819d 100644
--- a/library/test/src/helpers/exit_code.rs
+++ b/library/test/src/helpers/exit_code.rs
@@ -13,7 +13,7 @@ pub fn get_exit_code(status: ExitStatus) -> Result<i32, String> {
     match status.code() {
         Some(code) => Ok(code),
         None => match status.signal() {
-            Some(signal) => Err(format!("child process exited with signal {}", signal)),
+            Some(signal) => Err(format!("child process exited with signal {signal}")),
             None => Err("child process exited with unknown signal".into()),
         },
     }
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 8fc2b4ed748..088e3a23ea4 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -99,7 +99,7 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
     let mut opts = match cli::parse_opts(args) {
         Some(Ok(o)) => o,
         Some(Err(msg)) => {
-            eprintln!("error: {}", msg);
+            eprintln!("error: {msg}");
             process::exit(ERROR_EXIT_CODE);
         }
         None => return,
@@ -109,7 +109,7 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
     }
     if opts.list {
         if let Err(e) = console::list_tests_console(&opts, tests) {
-            eprintln!("error: io error when listing tests: {:?}", e);
+            eprintln!("error: io error when listing tests: {e:?}");
             process::exit(ERROR_EXIT_CODE);
         }
     } else {
@@ -117,7 +117,7 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
             Ok(true) => {}
             Ok(false) => process::exit(ERROR_EXIT_CODE),
             Err(e) => {
-                eprintln!("error: io error when listing tests: {:?}", e);
+                eprintln!("error: io error when listing tests: {e:?}");
                 process::exit(ERROR_EXIT_CODE);
             }
         }
@@ -153,7 +153,7 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) {
             .filter(|test| test.desc.name.as_slice() == name)
             .map(make_owned_test)
             .next()
-            .unwrap_or_else(|| panic!("couldn't find a test with the provided name '{}'", name));
+            .unwrap_or_else(|| panic!("couldn't find a test with the provided name '{name}'"));
         let TestDescAndFn { desc, testfn } = test;
         let testfn = match testfn {
             StaticTestFn(f) => f,
@@ -524,7 +524,7 @@ pub fn run_test(
                     Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()();
                     None
                 }
-                Err(e) => panic!("failed to spawn thread to run test: {}", e),
+                Err(e) => panic!("failed to spawn thread to run test: {e}"),
             }
         } else {
             runtest();
@@ -678,7 +678,7 @@ fn run_test_in_spawned_subprocess(desc: TestDesc, testfn: Box<dyn FnOnce() + Sen
         // We don't support serializing TrFailedMsg, so just
         // print the message out to stderr.
         if let TrFailedMsg(msg) = &test_result {
-            eprintln!("{}", msg);
+            eprintln!("{msg}");
         }
 
         if let Some(info) = panic_info {
diff --git a/library/test/src/term/terminfo/parm.rs b/library/test/src/term/terminfo/parm.rs
index 0d37eb7359d..0756c8374aa 100644
--- a/library/test/src/term/terminfo/parm.rs
+++ b/library/test/src/term/terminfo/parm.rs
@@ -268,7 +268,7 @@ pub(crate) fn expand(
                     },
                     'e' => state = SeekIfEnd(0),
                     ';' => (),
-                    _ => return Err(format!("unrecognized format option {}", cur)),
+                    _ => return Err(format!("unrecognized format option {cur}")),
                 }
             }
             PushParam => {
diff --git a/library/test/src/term/terminfo/parm/tests.rs b/library/test/src/term/terminfo/parm/tests.rs
index 256d1aaf446..c738f3ba04f 100644
--- a/library/test/src/term/terminfo/parm/tests.rs
+++ b/library/test/src/term/terminfo/parm/tests.rs
@@ -78,15 +78,15 @@ fn test_push_bad_param() {
 fn test_comparison_ops() {
     let v = [('<', [1u8, 0u8, 0u8]), ('=', [0u8, 1u8, 0u8]), ('>', [0u8, 0u8, 1u8])];
     for &(op, bs) in v.iter() {
-        let s = format!("%{{1}}%{{2}}%{}%d", op);
+        let s = format!("%{{1}}%{{2}}%{op}%d");
         let res = expand(s.as_bytes(), &[], &mut Variables::new());
         assert!(res.is_ok(), "{}", res.unwrap_err());
         assert_eq!(res.unwrap(), vec![b'0' + bs[0]]);
-        let s = format!("%{{1}}%{{1}}%{}%d", op);
+        let s = format!("%{{1}}%{{1}}%{op}%d");
         let res = expand(s.as_bytes(), &[], &mut Variables::new());
         assert!(res.is_ok(), "{}", res.unwrap_err());
         assert_eq!(res.unwrap(), vec![b'0' + bs[1]]);
-        let s = format!("%{{2}}%{{1}}%{}%d", op);
+        let s = format!("%{{2}}%{{1}}%{op}%d");
         let res = expand(s.as_bytes(), &[], &mut Variables::new());
         assert!(res.is_ok(), "{}", res.unwrap_err());
         assert_eq!(res.unwrap(), vec![b'0' + bs[2]]);
diff --git a/library/test/src/term/terminfo/parser/compiled.rs b/library/test/src/term/terminfo/parser/compiled.rs
index b24f3f8b05e..5d40b7988b5 100644
--- a/library/test/src/term/terminfo/parser/compiled.rs
+++ b/library/test/src/term/terminfo/parser/compiled.rs
@@ -198,7 +198,7 @@ pub(crate) fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo
     let extended = match magic {
         0o0432 => false,
         0o01036 => true,
-        _ => return Err(format!("invalid magic number, found {:o}", magic)),
+        _ => return Err(format!("invalid magic number, found {magic:o}")),
     };
 
     // According to the spec, these fields must be >= -1 where -1 means that the feature is not
diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs
index 8c216a1e0e7..7f44d6e3d0f 100644
--- a/library/test/src/test_result.rs
+++ b/library/test/src/test_result.rs
@@ -89,7 +89,7 @@ pub fn get_result_from_exit_code(
     let result = match code {
         TR_OK => TestResult::TrOk,
         TR_FAILED => TestResult::TrFailed,
-        _ => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)),
+        _ => TestResult::TrFailedMsg(format!("got unexpected return code {code}")),
     };
 
     // If test is already failed (or allowed to fail), do not change the result.
diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs
index c8c5528b104..432628613f5 100644
--- a/library/unwind/src/libunwind.rs
+++ b/library/unwind/src/libunwind.rs
@@ -249,6 +249,10 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
     extern "C-unwind" {
         pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
     }
+    #[cfg_attr(
+        all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
+        link(name = "unwind", kind = "static", modifiers = "-bundle")
+    )]
     extern "C" {
         pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
                                  trace_argument: *mut c_void)
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index fe9d6a727ed..4c32547f059 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -3,6 +3,7 @@ name = "bootstrap"
 version = "0.0.0"
 edition = "2021"
 build = "build.rs"
+default-run = "bootstrap"
 
 [lib]
 path = "lib.rs"
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 6c1128b393f..71b8f3c4553 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1233,16 +1233,18 @@ def bootstrap(help_triggered):
     build.verbose = args.verbose
     build.clean = args.clean
 
-    # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then fallback to `config.toml` (if it
-    # exists).
+    # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`,
+    # then `config.toml` in the root directory.
     toml_path = args.config or os.getenv('RUST_BOOTSTRAP_CONFIG')
-    if not toml_path and os.path.exists('config.toml'):
+    using_default_path = toml_path is None
+    if using_default_path:
         toml_path = 'config.toml'
-
-    if toml_path:
         if not os.path.exists(toml_path):
             toml_path = os.path.join(build.rust_root, toml_path)
 
+    # Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
+    # but not if `config.toml` hasn't been created.
+    if not using_default_path or os.path.exists(toml_path):
         with open(toml_path) as config:
             build.config_toml = config.read()
 
@@ -1267,7 +1269,7 @@ def bootstrap(help_triggered):
     build.check_vendored_status()
 
     build_dir = build.get_toml('build-dir', 'build') or 'build'
-    build.build_dir = os.path.abspath(build_dir.replace("$ROOT", build.rust_root))
+    build.build_dir = os.path.abspath(build_dir)
 
     with open(os.path.join(build.rust_root, "src", "stage0.json")) as f:
         data = json.load(f)
@@ -1302,10 +1304,7 @@ def bootstrap(help_triggered):
     env = os.environ.copy()
     env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
     env["BOOTSTRAP_PYTHON"] = sys.executable
-    env["BUILD_DIR"] = build.build_dir
     env["RUSTC_BOOTSTRAP"] = '1'
-    if toml_path:
-        env["BOOTSTRAP_CONFIG"] = toml_path
     if build.rustc_commit is not None:
         env["BOOTSTRAP_DOWNLOAD_RUSTC"] = '1'
     run(args, env=env, verbose=build.verbose, is_bootstrap=True)
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index fc55c8626d9..68ae7f2be96 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -169,7 +169,7 @@ impl PathSet {
 
     fn one<P: Into<PathBuf>>(path: P, kind: Kind) -> PathSet {
         let mut set = BTreeSet::new();
-        set.insert(TaskPath { path: path.into(), kind: Some(kind.into()) });
+        set.insert(TaskPath { path: path.into(), kind: Some(kind) });
         PathSet::Set(set)
     }
 
@@ -372,10 +372,7 @@ impl<'a> ShouldRun<'a> {
     // multiple aliases for the same job
     pub fn paths(mut self, paths: &[&str]) -> Self {
         self.paths.insert(PathSet::Set(
-            paths
-                .iter()
-                .map(|p| TaskPath { path: p.into(), kind: Some(self.kind.into()) })
-                .collect(),
+            paths.iter().map(|p| TaskPath { path: p.into(), kind: Some(self.kind) }).collect(),
         ));
         self
     }
@@ -388,8 +385,7 @@ impl<'a> ShouldRun<'a> {
     }
 
     pub fn suite_path(mut self, suite: &str) -> Self {
-        self.paths
-            .insert(PathSet::Suite(TaskPath { path: suite.into(), kind: Some(self.kind.into()) }));
+        self.paths.insert(PathSet::Suite(TaskPath { path: suite.into(), kind: Some(self.kind) }));
         self
     }
 
@@ -883,7 +879,7 @@ impl<'a> Builder<'a> {
     }
 
     pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
-        let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
+        let mut cmd = Command::new(&self.bootstrap_out.join("rustdoc"));
         cmd.env("RUSTC_STAGE", compiler.stage.to_string())
             .env("RUSTC_SYSROOT", self.sysroot(compiler))
             // Note that this is *not* the sysroot_libdir because rustdoc must be linked
@@ -1249,7 +1245,7 @@ impl<'a> Builder<'a> {
             .env("RUSTC_STAGE", stage.to_string())
             .env("RUSTC_SYSROOT", &sysroot)
             .env("RUSTC_LIBDIR", &libdir)
-            .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
+            .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
             .env(
                 "RUSTDOC_REAL",
                 if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) {
@@ -1263,7 +1259,7 @@ impl<'a> Builder<'a> {
         // Clippy support is a hack and uses the default `cargo-clippy` in path.
         // Don't override RUSTC so that the `cargo-clippy` in path will be run.
         if cmd != "clippy" {
-            cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc"));
+            cargo.env("RUSTC", self.bootstrap_out.join("rustc"));
         }
 
         // Dealing with rpath here is a little special, so let's go into some
@@ -1769,7 +1765,7 @@ impl<'a> Builder<'a> {
             if should_run.paths.iter().any(|s| s.has(path, Some(desc.kind)))
                 && !desc.is_excluded(
                     self,
-                    &PathSet::Suite(TaskPath { path: path.clone(), kind: Some(desc.kind.into()) }),
+                    &PathSet::Suite(TaskPath { path: path.clone(), kind: Some(desc.kind) }),
                 )
             {
                 return true;
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index bc710344969..b76bb569852 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -8,10 +8,10 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
     config.save_toolstates = None;
     config.dry_run = true;
     config.ninja_in_file = false;
-    // try to avoid spurious failures in dist where we create/delete each others file
     config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap());
     config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap());
     config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap());
+    // try to avoid spurious failures in dist where we create/delete each others file
     let dir = config
         .out
         .join("tmp-rustbuild-tests")
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index b17b94f2893..0c0a4733231 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -6,7 +6,6 @@
 use std::cmp;
 use std::collections::{HashMap, HashSet};
 use std::env;
-use std::ffi::OsString;
 use std::fmt;
 use std::fs;
 use std::path::{Path, PathBuf};
@@ -392,7 +391,6 @@ derive_merge! {
         build: Option<String>,
         host: Option<Vec<String>>,
         target: Option<Vec<String>>,
-        // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable
         build_dir: Option<String>,
         cargo: Option<String>,
         rustc: Option<String>,
@@ -588,18 +586,6 @@ derive_merge! {
 }
 
 impl Config {
-    fn path_from_python(var_key: &str) -> PathBuf {
-        match env::var_os(var_key) {
-            Some(var_val) => Self::normalize_python_path(var_val),
-            _ => panic!("expected '{}' to be set", var_key),
-        }
-    }
-
-    /// Normalizes paths from Python slightly. We don't trust paths from Python (#49785).
-    fn normalize_python_path(path: OsString) -> PathBuf {
-        Path::new(&path).components().collect()
-    }
-
     pub fn default_opts() -> Config {
         let mut config = Config::default();
         config.llvm_optimize = true;
@@ -625,7 +611,7 @@ impl Config {
         let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
         // Undo `src/bootstrap`
         config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned();
-        config.out = Config::path_from_python("BUILD_DIR");
+        config.out = PathBuf::from("build");
 
         config.initial_cargo = PathBuf::from(env!("CARGO"));
         config.initial_rustc = PathBuf::from(env!("RUSTC"));
@@ -655,19 +641,14 @@ impl Config {
         config.llvm_profile_use = flags.llvm_profile_use;
         config.llvm_profile_generate = flags.llvm_profile_generate;
 
-        if config.dry_run {
-            let dir = config.out.join("tmp-dry-run");
-            t!(fs::create_dir_all(&dir));
-            config.out = dir;
-        }
-
         #[cfg(test)]
         let get_toml = |_| TomlConfig::default();
         #[cfg(not(test))]
         let get_toml = |file: &Path| {
             use std::process;
 
-            let contents = t!(fs::read_to_string(file), "`include` config not found");
+            let contents =
+                t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
             match toml::from_str(&contents) {
                 Ok(table) => table,
                 Err(err) => {
@@ -677,7 +658,25 @@ impl Config {
             }
         };
 
-        let mut toml = flags.config.as_deref().map(get_toml).unwrap_or_else(TomlConfig::default);
+        // Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory.
+        let toml_path = flags
+            .config
+            .clone()
+            .or_else(|| env::var_os("RUST_BOOTSTRAP_CONFIG").map(PathBuf::from));
+        let using_default_path = toml_path.is_none();
+        let mut toml_path = toml_path.unwrap_or_else(|| PathBuf::from("config.toml"));
+        if using_default_path && !toml_path.exists() {
+            toml_path = config.src.join(toml_path);
+        }
+
+        // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
+        // but not if `config.toml` hasn't been created.
+        let mut toml = if !using_default_path || toml_path.exists() {
+            get_toml(&toml_path)
+        } else {
+            TomlConfig::default()
+        };
+
         if let Some(include) = &toml.profile {
             let mut include_path = config.src.clone();
             include_path.push("src");
@@ -689,12 +688,25 @@ impl Config {
         }
 
         config.changelog_seen = toml.changelog_seen;
-        if let Some(cfg) = flags.config {
-            config.config = cfg;
-        }
+        config.config = toml_path;
 
         let build = toml.build.unwrap_or_default();
 
+        set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
+        set(&mut config.out, build.build_dir.map(PathBuf::from));
+        // NOTE: Bootstrap spawns various commands with different working directories.
+        // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
+        if !config.out.is_absolute() {
+            // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead.
+            config.out = crate::util::absolute(&config.out);
+        }
+
+        if config.dry_run {
+            let dir = config.out.join("tmp-dry-run");
+            t!(fs::create_dir_all(&dir));
+            config.out = dir;
+        }
+
         config.hosts = if let Some(arg_host) = flags.host {
             arg_host
         } else if let Some(file_host) = build.host {
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 94424cb4548..87a130a0982 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -279,6 +279,10 @@ def build():
 
 
 def set(key, value):
+    if isinstance(value, list):
+        # Remove empty values, which value.split(',') tends to generate.
+        value = [v for v in value if v]
+
     s = "{:20} := {}".format(key, value)
     if len(s) < 70:
         p(s)
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index e34b40a93ff..1a4e6a96888 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -3,7 +3,6 @@
 //! This module implements the command-line parsing of the build system which
 //! has various flags to configure how it's run.
 
-use std::env;
 use std::path::PathBuf;
 use std::process;
 
@@ -541,7 +540,6 @@ Arguments:
         // Get any optional paths which occur after the subcommand
         let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
 
-        let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
         let verbose = matches.opt_present("verbose");
 
         // User passed in -h/--help?
@@ -671,7 +669,7 @@ Arguments:
             } else {
                 None
             },
-            config: cfg_file,
+            config: matches.opt_str("config").map(PathBuf::from),
             jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")),
             cmd,
             incremental: matches.opt_present("incremental"),
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index ccc8516a89a..2ee67d623ee 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -193,7 +193,6 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
     (None, "bootstrap", None),
     (Some(Mode::Rustc), "parallel_compiler", None),
     (Some(Mode::ToolRustc), "parallel_compiler", None),
-    (Some(Mode::Std), "miri", None),
     (Some(Mode::Std), "stdarch_intel_sde", None),
     (Some(Mode::Std), "no_fp_fmt_parse", None),
     (Some(Mode::Std), "no_global_oom_handling", None),
@@ -261,6 +260,7 @@ pub struct Build {
     // Properties derived from the above configuration
     src: PathBuf,
     out: PathBuf,
+    bootstrap_out: PathBuf,
     rust_info: channel::GitInfo,
     cargo_info: channel::GitInfo,
     rls_info: channel::GitInfo,
@@ -435,6 +435,20 @@ impl Build {
             .expect("failed to read src/version");
         let version = version.trim();
 
+        let bootstrap_out = if std::env::var("BOOTSTRAP_PYTHON").is_ok() {
+            out.join("bootstrap").join("debug")
+        } else {
+            let workspace_target_dir = std::env::var("CARGO_TARGET_DIR")
+                .map(PathBuf::from)
+                .unwrap_or_else(|_| src.join("target"));
+            let bootstrap_out = workspace_target_dir.join("debug");
+            if !bootstrap_out.join("rustc").exists() {
+                // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
+                panic!("run `cargo build --bins` before `cargo run`")
+            }
+            bootstrap_out
+        };
+
         let mut build = Build {
             initial_rustc: config.initial_rustc.clone(),
             initial_cargo: config.initial_cargo.clone(),
@@ -453,6 +467,7 @@ impl Build {
             version: version.to_string(),
             src,
             out,
+            bootstrap_out,
 
             rust_info,
             cargo_info,
@@ -629,7 +644,7 @@ impl Build {
         }
 
         if let Subcommand::Setup { profile } = &self.config.cmd {
-            return setup::setup(&self.config.src, *profile);
+            return setup::setup(&self.config, *profile);
         }
 
         {
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index f00c5ce5aa6..0fe39defae8 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -259,18 +259,6 @@ impl Step for Llvm {
             cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
         }
 
-        // For distribution we want the LLVM tools to be *statically* linked to libstdc++.
-        // We also do this if the user explicitly requested static libstdc++.
-        if builder.config.llvm_tools_enabled || builder.config.llvm_static_stdcpp {
-            if !target.contains("msvc") && !target.contains("netbsd") {
-                if target.contains("apple") {
-                    ldflags.push_all("-static-libstdc++");
-                } else {
-                    ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++");
-                }
-            }
-        }
-
         if target.starts_with("riscv") && !target.contains("freebsd") {
             // RISC-V GCC erroneously requires linking against
             // `libatomic` when using 1-byte and 2-byte C++
@@ -576,6 +564,18 @@ fn configure_cmake(
         ldflags.push_all(&flags);
     }
 
+    // For distribution we want the LLVM tools to be *statically* linked to libstdc++.
+    // We also do this if the user explicitly requested static libstdc++.
+    if builder.config.llvm_tools_enabled || builder.config.llvm_static_stdcpp {
+        if !target.contains("msvc") && !target.contains("netbsd") {
+            if target.contains("apple") {
+                ldflags.push_all("-static-libstdc++");
+            } else {
+                ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++");
+            }
+        }
+    }
+
     cfg.define("CMAKE_SHARED_LINKER_FLAGS", &ldflags.shared);
     cfg.define("CMAKE_MODULE_LINKER_FLAGS", &ldflags.module);
     cfg.define("CMAKE_EXE_LINKER_FLAGS", &ldflags.exe);
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 9a9ef0b7695..aff2b6c3cbf 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -1,5 +1,5 @@
-use crate::TargetSelection;
 use crate::{t, VERSION};
+use crate::{Config, TargetSelection};
 use std::env::consts::EXE_SUFFIX;
 use std::fmt::Write as _;
 use std::fs::File;
@@ -81,24 +81,22 @@ impl fmt::Display for Profile {
     }
 }
 
-pub fn setup(src_path: &Path, profile: Profile) {
-    let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
+pub fn setup(config: &Config, profile: Profile) {
+    let path = &config.config;
 
-    if cfg_file.as_ref().map_or(false, |f| f.exists()) {
-        let file = cfg_file.unwrap();
+    if path.exists() {
         println!(
             "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
-            file.display()
+            path.display()
         );
-        println!("help: try adding `profile = \"{}\"` at the top of {}", profile, file.display());
+        println!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display());
         println!(
             "note: this will use the configuration in {}",
-            profile.include_path(src_path).display()
+            profile.include_path(&config.src).display()
         );
         std::process::exit(1);
     }
 
-    let path = cfg_file.unwrap_or_else(|| "config.toml".into());
     let settings = format!(
         "# Includes one of the default files in src/bootstrap/defaults\n\
     profile = \"{}\"\n\
@@ -107,7 +105,7 @@ pub fn setup(src_path: &Path, profile: Profile) {
     );
     t!(fs::write(path, settings));
 
-    let include_path = profile.include_path(src_path);
+    let include_path = profile.include_path(&config.src);
     println!("`x.py` will now use the configuration at {}", include_path.display());
 
     let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
@@ -138,7 +136,7 @@ pub fn setup(src_path: &Path, profile: Profile) {
 
     println!();
 
-    t!(install_git_hook_maybe(src_path));
+    t!(install_git_hook_maybe(&config.src));
 
     println!();
 
@@ -163,9 +161,9 @@ fn rustup_installed() -> bool {
 }
 
 fn stage_dir_exists(stage_path: &str) -> bool {
-    match fs::create_dir(&stage_path[..]) {
+    match fs::create_dir(&stage_path) {
         Ok(_) => true,
-        Err(_) => Path::new(&stage_path[..]).exists(),
+        Err(_) => Path::new(&stage_path).exists(),
     }
 }
 
@@ -181,7 +179,7 @@ fn attempt_toolchain_link(stage_path: &str) {
         return;
     }
 
-    if try_link_toolchain(&stage_path[..]) {
+    if try_link_toolchain(&stage_path) {
         println!(
             "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
         );
@@ -190,7 +188,7 @@ fn attempt_toolchain_link(stage_path: &str) {
         println!(
             "To manually link stage 1 build to `stage1` toolchain, run:\n
             `rustup toolchain link stage1 {}`",
-            &stage_path[..]
+            &stage_path
         );
     }
 }
@@ -224,7 +222,7 @@ fn toolchain_is_linked() -> bool {
 fn try_link_toolchain(stage_path: &str) -> bool {
     Command::new("rustup")
         .stdout(std::process::Stdio::null())
-        .args(&["toolchain", "link", "stage1", &stage_path[..]])
+        .args(&["toolchain", "link", "stage1", &stage_path])
         .output()
         .map_or(false, |output| output.status.success())
 }
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index e4fcb287f12..58b73ebed50 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -730,7 +730,7 @@ impl Step for RustdocTheme {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
+        let rustdoc = builder.bootstrap_out.join("rustdoc");
         let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
         cmd.arg(rustdoc.to_str().unwrap())
             .arg(builder.src.join("src/librustdoc/html/static/css/themes").to_str().unwrap())
@@ -2346,6 +2346,8 @@ impl Step for Bootstrap {
             .current_dir(builder.src.join("src/bootstrap"))
             .env("RUSTFLAGS", "-Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
+            // HACK: bootstrap's tests want to know the output directory, but there's no way to set
+            // it except through config.toml. Set it through an env variable instead.
             .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out)
             .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo)
             .env("RUSTC_BOOTSTRAP", "1")
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 2ae4d830721..a9ca89bdea1 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -391,7 +391,7 @@ impl ErrorIndex {
         add_dylib_path(
             vec![
                 PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host)),
-                PathBuf::from(builder.rustc_libdir(compiler)),
+                builder.rustc_libdir(compiler),
             ],
             &mut cmd,
         );
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 8e770d4d57f..30d9665dd0f 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -440,3 +440,112 @@ fn fail(s: &str) -> ! {
     println!("\n\n{}\n\n", s);
     std::process::exit(1);
 }
+
+/// Copied from `std::path::absolute` until it stabilizes.
+///
+/// FIXME: this shouldn't exist.
+pub(crate) fn absolute(path: &Path) -> PathBuf {
+    if path.as_os_str().is_empty() {
+        panic!("can't make empty path absolute");
+    }
+    #[cfg(unix)]
+    {
+        t!(absolute_unix(path), format!("could not make path absolute: {}", path.display()))
+    }
+    #[cfg(windows)]
+    {
+        t!(absolute_windows(path), format!("could not make path absolute: {}", path.display()))
+    }
+    #[cfg(not(any(unix, windows)))]
+    {
+        println!("warning: bootstrap is not supported on non-unix platforms");
+        t!(std::fs::canonicalize(t!(std::env::current_dir()))).join(path)
+    }
+}
+
+#[cfg(unix)]
+/// Make a POSIX path absolute without changing its semantics.
+fn absolute_unix(path: &Path) -> io::Result<PathBuf> {
+    // This is mostly a wrapper around collecting `Path::components`, with
+    // exceptions made where this conflicts with the POSIX specification.
+    // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
+    // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+
+    use std::os::unix::prelude::OsStrExt;
+    let mut components = path.components();
+    let path_os = path.as_os_str().as_bytes();
+
+    let mut normalized = if path.is_absolute() {
+        // "If a pathname begins with two successive <slash> characters, the
+        // first component following the leading <slash> characters may be
+        // interpreted in an implementation-defined manner, although more than
+        // two leading <slash> characters shall be treated as a single <slash>
+        // character."
+        if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
+            components.next();
+            PathBuf::from("//")
+        } else {
+            PathBuf::new()
+        }
+    } else {
+        env::current_dir()?
+    };
+    normalized.extend(components);
+
+    // "Interfaces using pathname resolution may specify additional constraints
+    // when a pathname that does not name an existing directory contains at
+    // least one non- <slash> character and contains one or more trailing
+    // <slash> characters".
+    // A trailing <slash> is also meaningful if "a symbolic link is
+    // encountered during pathname resolution".
+
+    if path_os.ends_with(b"/") {
+        normalized.push("");
+    }
+
+    Ok(normalized)
+}
+
+#[cfg(windows)]
+fn absolute_windows(path: &std::path::Path) -> std::io::Result<std::path::PathBuf> {
+    use std::ffi::OsString;
+    use std::io::Error;
+    use std::os::windows::ffi::{OsStrExt, OsStringExt};
+    use std::ptr::null_mut;
+    #[link(name = "kernel32")]
+    extern "system" {
+        fn GetFullPathNameW(
+            lpFileName: *const u16,
+            nBufferLength: u32,
+            lpBuffer: *mut u16,
+            lpFilePart: *mut *const u16,
+        ) -> u32;
+    }
+
+    unsafe {
+        // encode the path as UTF-16
+        let path: Vec<u16> = path.as_os_str().encode_wide().chain([0]).collect();
+        let mut buffer = Vec::new();
+        // Loop until either success or failure.
+        loop {
+            // Try to get the absolute path
+            let len = GetFullPathNameW(
+                path.as_ptr(),
+                buffer.len().try_into().unwrap(),
+                buffer.as_mut_ptr(),
+                null_mut(),
+            );
+            match len as usize {
+                // Failure
+                0 => return Err(Error::last_os_error()),
+                // Buffer is too small, resize.
+                len if len > buffer.len() => buffer.resize(len, 0),
+                // Success!
+                len => {
+                    buffer.truncate(len);
+                    return Ok(OsString::from_wide(&buffer).into());
+                }
+            }
+        }
+    }
+}
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index f1c42b248f4..b0f052e6cf0 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
 # https://github.com/puppeteer/puppeteer/issues/375
 #
 # We also specify the version in case we need to update it to go around cache limitations.
-RUN npm install -g browser-ui-test@0.7.2 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.8.1 --unsafe-perm=true
 
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
diff --git a/src/doc/rustdoc/book.toml b/src/doc/rustdoc/book.toml
index 97e08416d76..45405a11765 100644
--- a/src/doc/rustdoc/book.toml
+++ b/src/doc/rustdoc/book.toml
@@ -4,3 +4,7 @@ title = "The rustdoc book"
 
 [output.html]
 git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustdoc"
+
+[output.html.redirect]
+"/the-doc-attribute.html" = "write-documentation/the-doc-attribute.html"
+"/documentation-tests.html" = "write-documentation/documentation-tests.html"
diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md
index eb181859453..d627f5b0389 100644
--- a/src/doc/rustdoc/src/SUMMARY.md
+++ b/src/doc/rustdoc/src/SUMMARY.md
@@ -1,16 +1,15 @@
 # The Rustdoc Book
 
 - [What is rustdoc?](what-is-rustdoc.md)
+- [Command-line arguments](command-line-arguments.md)
 - [How to read rustdoc output](how-to-read-rustdoc.md)
 - [How to write documentation](how-to-write-documentation.md)
-- [What to include (and exclude)](what-to-include.md)
-- [Command-line arguments](command-line-arguments.md)
-- [The `#[doc]` attribute](the-doc-attribute.md)
-- [Documentation tests](documentation-tests.md)
-- [Linking to items by name](linking-to-items-by-name.md)
-- [Lints](lints.md)
+    - [What to include (and exclude)](write-documentation/what-to-include.md)
+    - [The `#[doc]` attribute](write-documentation/the-doc-attribute.md)
+    - [Linking to items by name](write-documentation/linking-to-items-by-name.md)
+    - [Documentation tests](write-documentation/documentation-tests.md)
+- [Rustdoc-specific lints](lints.md)
 - [Advanced features](advanced-features.md)
 - [Unstable features](unstable-features.md)
-- [Website features](website-features.md)
-- [Passes](passes.md)
+- [Deprecated features](deprecated-features.md)
 - [References](references.md)
diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index 6147bd0a97a..dbf0baec04c 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -88,3 +88,25 @@ You can add multiple aliases at the same time by using a list:
 #[doc(alias("x", "big"))]
 pub struct BigX;
 ```
+
+## Custom search engines
+
+If you find yourself often referencing online Rust docs you might enjoy using a custom search
+engine. This allows you to use the navigation bar directly to search a `rustdoc` website.
+Most browsers support this feature by letting you define a URL template containing `%s`
+which will be substituted for the search term. As an example, for the standard library you could use
+this template:
+
+```text
+https://doc.rust-lang.org/stable/std/?search=%s
+```
+
+Note that this will take you to a results page listing all matches. If you want to navigate to the first
+result right away (which is often the best match) use the following instead:
+
+```text
+https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
+```
+
+This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
+to automatically go to the first result.
diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md
index 3ce57f88938..2a2e51b2f63 100644
--- a/src/doc/rustdoc/src/command-line-arguments.md
+++ b/src/doc/rustdoc/src/command-line-arguments.md
@@ -177,7 +177,7 @@ $ rustdoc src/lib.rs --test
 ```
 
 This flag will run your code examples as tests. For more, see [the chapter
-on documentation tests](documentation-tests.md).
+on documentation tests](write-documentation/documentation-tests.md).
 
 See also `--test-args`.
 
@@ -190,7 +190,7 @@ $ rustdoc src/lib.rs --test --test-args ignored
 ```
 
 This flag will pass options to the test runner when running documentation tests.
-For more, see [the chapter on documentation tests](documentation-tests.md).
+For more, see [the chapter on documentation tests](write-documentation/documentation-tests.md).
 
 See also `--test`.
 
@@ -336,7 +336,7 @@ $ rustdoc src/lib.rs --sysroot /path/to/sysroot
 Similar to `rustc --sysroot`, this lets you change the sysroot `rustdoc` uses
 when compiling your code.
 
-### `--edition`: control the edition of docs and doctests
+## `--edition`: control the edition of docs and doctests
 
 Using this flag looks like this:
 
@@ -403,12 +403,12 @@ encoded as UTF-8.
 ## `--passes`: add more rustdoc passes
 
 This flag is **deprecated**.
-For more details on passes, see [the chapter on them](passes.md).
+For more details on passes, see [the chapter on them](deprecated-features.md#passes).
 
 ## `--no-defaults`: don't run default passes
 
 This flag is **deprecated**.
-For more details on passes, see [the chapter on them](passes.md).
+For more details on passes, see [the chapter on them](deprecated-features.md#passes).
 
 ## `-r`/`--input-format`: input format
 
@@ -417,23 +417,3 @@ This flag is **deprecated** and **has no effect**.
 Rustdoc only supports Rust source code and Markdown input formats. If the
 file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file.
 Otherwise, it assumes that the input file is Rust.
-
-# Unstable command line arguments
-
-## `--nocapture`
-
-When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be
-captured by rustdoc. Instead, the output will be directed to your terminal,
-as if you had run the test executable manually. This is especially useful
-for debugging your tests!
-
-## `--check`
-
-When this flag is supplied, rustdoc will type check and lint your code, but will not generate any
-documentation or run your doctests.
-
-Using this flag looks like:
-
-```bash
-rustdoc -Z unstable-options --check src/lib.rs
-```
diff --git a/src/doc/rustdoc/src/passes.md b/src/doc/rustdoc/src/deprecated-features.md
index c3c3fd3068e..2bc6e8fc8ae 100644
--- a/src/doc/rustdoc/src/passes.md
+++ b/src/doc/rustdoc/src/deprecated-features.md
@@ -1,4 +1,6 @@
-# Passes
+# Deprecated features
+
+## Passes
 
 Rustdoc has a concept called "passes". These are transformations that
 `rustdoc` runs on your documentation before producing its final output.
diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md
index 99724d859ee..098bc1879b5 100644
--- a/src/doc/rustdoc/src/how-to-read-rustdoc.md
+++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md
@@ -26,7 +26,7 @@ At the top is some at-a-glance info and controls:
 - a button to collapse or expand the top-level documentation for that item
   (`[+]` or `[-]`),
 - a link to the source code (`[src]`),
-  if [configured](the-doc-attribute.html#html_no_source),
+  if [configured](write-documentation/the-doc-attribute.html#html_no_source),
   and present (the source may not be available if
   the documentation was created with `cargo doc --no-deps`),
 - and the version in which the item became stable,
@@ -52,7 +52,7 @@ For example, when looking at documentation for the crate root,
 it shows all the crates documented in the documentation bundle,
 and quick links to the modules, structs, traits, functions, and macros available
 from the current crate.
-At the top, it displays a [configurable logo](the-doc-attribute.html#html_logo_url)
+At the top, it displays a [configurable logo](write-documentation/the-doc-attribute.html#html_logo_url)
 alongside the current crate's name and version,
 or the current item whose documentation is being displayed.
 
diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md
index f89495cca3a..38fd1db5c21 100644
--- a/src/doc/rustdoc/src/how-to-write-documentation.md
+++ b/src/doc/rustdoc/src/how-to-write-documentation.md
@@ -126,7 +126,7 @@ use std::env;
 
 // Prints each argument on a separate line
 for argument in env::args() {
-    println!("{}", argument);
+    println!("{argument}");
 }
 ```
 
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index 1773c15464a..bff01d7cb7c 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -13,11 +13,11 @@ Note that, except for `missing_docs`, these lints are only available when runnin
 
 Here is the list of the lints provided by `rustdoc`:
 
-## broken_intra_doc_links
+## `broken_intra_doc_links`
 
 This lint **warns by default**. This lint detects when an [intra-doc link] fails to be resolved. For example:
 
-[intra-doc link]: linking-to-items-by-name.md
+[intra-doc link]: write-documentation/linking-to-items-by-name.md
 
 ```rust
 /// I want to link to [`Nonexistent`] but it doesn't exist!
@@ -64,7 +64,7 @@ help: to link to the function, add parentheses
 
 ```
 
-## private_intra_doc_links
+## `private_intra_doc_links`
 
 This lint **warns by default**. This lint detects when [intra-doc links] from public to private items.
 For example:
@@ -104,9 +104,9 @@ warning: public documentation for `public` links to private item `private`
   = note: this link resolves only because you passed `--document-private-items`, but will break without
 ```
 
-[intra-doc links]: linking-to-items-by-name.html
+[intra-doc links]: write-documentation/linking-to-items-by-name.md
 
-## missing_docs
+## `missing_docs`
 
 This lint is **allowed by default**. It detects items missing documentation.
 For example:
@@ -130,7 +130,7 @@ warning: missing documentation for a function
 
 Note that unlike other rustdoc lints, this lint is also available from `rustc` directly.
 
-## missing_crate_level_docs
+## `missing_crate_level_docs`
 
 This lint is **allowed by default**. It detects if there is no documentation
 at the crate root. For example:
@@ -154,7 +154,7 @@ warning in the future. This is intended as a means to introduce new users on
 get started, without providing overwhelming warnings like `missing_docs`
 might.
 
-## missing_doc_code_examples
+## `missing_doc_code_examples`
 
 This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block
 is missing a code example. For example:
@@ -190,7 +190,7 @@ To fix the lint, you need to add a code example into the documentation block:
 pub fn no_code_example() {}
 ```
 
-## private_doc_tests
+## `private_doc_tests`
 
 This lint is **allowed by default**. It detects documentation tests when they
 are on a private item. For example:
@@ -223,7 +223,7 @@ warning: Documentation test in private item
    | |___________^
 ```
 
-## invalid_codeblock_attributes
+## `invalid_codeblock_attributes`
 
 This lint **warns by default**. It detects code block attributes in
 documentation examples that have potentially mis-typed values. For example:
@@ -259,7 +259,7 @@ warning: unknown attribute `should-panic`. Did you mean `should_panic`?
 In the example above, the correct form is `should_panic`. This helps detect
 typo mistakes for some common attributes.
 
-## invalid_html_tags
+## `invalid_html_tags`
 
 This lint is **allowed by default** and is **nightly-only**. It detects unclosed
 or invalid HTML tags. For example:
@@ -298,7 +298,7 @@ warning: unclosed HTML tag `h1`
 warning: 2 warnings emitted
 ```
 
-## invalid_rust_codeblocks
+## `invalid_rust_codeblocks`
 
 This lint **warns by default**. It detects Rust code blocks in documentation
 examples that are invalid (e.g. empty, not parsable as Rust). For example:
@@ -342,7 +342,7 @@ warning: could not parse code block as Rust code
    = note: error from rustc: unterminated character literal
 ```
 
-## bare_urls
+## `bare_urls`
 
 This lint is **warn-by-default**. It detects URLs which are not links.
 For example:
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 141d5d2d2b2..537ab48bbfc 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -22,7 +22,7 @@ As detailed in [the chapter on documentation tests][doctest-attributes], you can
 nightly, you can optionally add an error number to state that a doctest should emit a specific error
 number:
 
-[doctest-attributes]: documentation-tests.html#attributes
+[doctest-attributes]: write-documentation/documentation-tests.html#attributes
 
 ``````markdown
 ```compile_fail,E0044
@@ -45,6 +45,8 @@ and enabled with a `#![feature(...)]` attribute in your crate.
 
 ### `#[doc(cfg)]`: Recording what platforms or features are required for code to be present
 
+ * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781)
+
 You can use `#[doc(cfg(...))]` to tell Rustdoc exactly which platform items appear on.
 This has two effects:
 
@@ -86,6 +88,8 @@ Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
 
 ### `doc_auto_cfg`: Automatically generate `#[doc(cfg)]`
 
+ * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781)
+
 `doc_auto_cfg` is an extension to the `#[doc(cfg)]` feature. With it, you don't need to add
 `#[doc(cfg(...)]` anymore unless you want to override the default behaviour. So if we take the
 previous source code:
@@ -123,6 +127,8 @@ And `doc` won't show up anymore!
 
 ### Adding your trait to the "Notable traits" dialog
 
+ * Tracking issue: [#45040](https://github.com/rust-lang/rust/issues/45040)
+
 Rustdoc keeps a list of a few traits that are believed to be "fundamental" to
 types that implement them. These traits are intended to be the primary interface
 for their implementers, and are often most of the API available to be documented
@@ -146,6 +152,8 @@ and [its tracking issue][issue-notable_trait].
 
 ### Exclude certain dependencies from documentation
 
+ * Tracking issue: [#44027](https://github.com/rust-lang/rust/issues/44027)
+
 The standard library uses several dependencies which, in turn, use several types and traits from the
 standard library. In addition, there are several compiler-internal crates that are not considered to
 be part of the official standard library, and thus would be a distraction to include in
@@ -164,8 +172,7 @@ Book][unstable-masked] and [its tracking issue][issue-masked].
 [unstable-masked]: ../unstable-book/language-features/doc-masked.html
 [issue-masked]: https://github.com/rust-lang/rust/issues/44027
 
-
-## Document primitives
+### Document primitives
 
 This is for Rust compiler internal use only.
 
@@ -174,7 +181,7 @@ attributes. The `#[doc(primitive)]` attribute is used by the standard library to
 to generate documentation for primitive types, and requires `#![feature(rustdoc_internals)]` to
 enable.
 
-## Document keywords
+### Document keywords
 
 This is for Rust compiler internal use only.
 
@@ -199,6 +206,8 @@ the flag in question to Rustdoc on the command-line. To do this from Cargo, you
 
 ### `--markdown-before-content`: include rendered Markdown before the content
 
+ * Tracking issue: [#44027](https://github.com/rust-lang/rust/issues/44027)
+
 Using this flag looks like this:
 
 ```bash
@@ -241,7 +250,7 @@ attribute][doc-playground]. Please be aware that the official Rust Playground at
 https://play.rust-lang.org does not have every crate available, so if your examples require your
 crate, make sure the playground you provide has your crate available.
 
-[doc-playground]: the-doc-attribute.html#html_playground_url
+[doc-playground]: write-documentation/the-doc-attribute.html#html_playground_url
 
 If both `--playground-url` and `--markdown-playground-url` are present when rendering a standalone
 Markdown file, the URL given to `--markdown-playground-url` will take precedence. If both
@@ -279,6 +288,8 @@ between compilations.
 
 ### `--resource-suffix`: modifying the name of CSS/JavaScript in crate docs
 
+ * Tracking issue: [#54765](https://github.com/rust-lang/rust/issues/54765)
+
 Using this flag looks like this:
 
 ```bash
@@ -331,6 +342,24 @@ Using `index-page` option enables `enable-index-page` option as well.
 
 This feature allows the generation of a default index-page which lists the generated crates.
 
+### `--nocapture`: disable output capture for test
+
+When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be
+captured by rustdoc. Instead, the output will be directed to your terminal,
+as if you had run the test executable manually. This is especially useful
+for debugging your tests!
+
+### `--check`: only checks the documentation
+
+When this flag is supplied, rustdoc will type check and lint your code, but will not generate any
+documentation or run your doctests.
+
+Using this flag looks like:
+
+```bash
+rustdoc -Z unstable-options --check src/lib.rs
+```
+
 ### `--static-root-path`: control how static files are loaded in HTML output
 
 Using this flag looks like this:
@@ -348,6 +377,8 @@ renamed with `--resource-suffix` will load from the given path.
 
 ### `--persist-doctests`: persist doctest executables after running
 
+ * Tracking issue: [#56925](https://github.com/rust-lang/rust/issues/56925)
+
 Using this flag looks like this:
 
 ```bash
@@ -360,6 +391,8 @@ with this option, you can keep those binaries around for farther testing.
 
 ### `--show-coverage`: calculate the percentage of items with documentation
 
+ * Tracking issue: [#58154](https://github.com/rust-lang/rust/issues/58154)
+
 Using this flag looks like this:
 
 ```bash
@@ -438,6 +471,8 @@ information.
 
 ### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
 
+ * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
+
 Using this flag looks like this:
 
 ```bash
@@ -471,6 +506,8 @@ override `ignore`.
 
 ### `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it
 
+ * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
+
 Using these options looks like this:
 
 ```bash
@@ -488,6 +525,8 @@ Another use case would be to run a test inside an emulator, or through a Virtual
 
 ### `--with-examples`: include examples of uses of items as documentation
 
+ * Tracking issue: [#88791](https://github.com/rust-lang/rust/issues/88791)
+
 This option, combined with `--scrape-examples-target-crate` and
 `--scrape-examples-output-path`, is used to implement the functionality in [RFC
 #3123](https://github.com/rust-lang/rfcs/pull/3123). Uses of an item (currently
@@ -515,6 +554,8 @@ add the `--scrape-tests` flag.
 
 ### `--check-cfg`: check configuration flags
 
+ * Tracking issue: [#82450](https://github.com/rust-lang/rust/issues/82450)
+
 This flag accepts the same values as `rustc --check-cfg`, and uses it to check configuration flags.
 
 Using this flag looks like this:
diff --git a/src/doc/rustdoc/src/website-features.md b/src/doc/rustdoc/src/website-features.md
deleted file mode 100644
index 5fade4e84a9..00000000000
--- a/src/doc/rustdoc/src/website-features.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Website features
-
-These features are about using the website generated by `rustdoc`.
-
-## Custom search engines
-
-If you find yourself often referencing online Rust docs you might enjoy using a custom search
-engine. This allows you to use the navigation bar directly to search a `rustdoc` website.
-Most browsers support this feature by letting you define a URL template containing `%s`
-which will be substituted for the search term. As an example, for the standard library you could use
-this template:
-
-```text
-https://doc.rust-lang.org/stable/std/?search=%s
-```
-
-Note that this will take you to a results page listing all matches. If you want to navigate to the first
-result right away (which is often the best match) use the following instead:
-
-```text
-https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
-```
-
-This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
-to automatically go to the first result.
diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
index 534fd19b52e..1cb5b049df4 100644
--- a/src/doc/rustdoc/src/documentation-tests.md
+++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
@@ -269,7 +269,7 @@ By default, this will still hide `unused` warnings, since so many examples use p
 you can add `#![warn(unused)]` to the top of your example if you want to see unused variables or dead code warnings.
 You can also use [`#![doc(test(attr(warn(unused))))]`][test-attr] in the crate root to enable warnings globally.
 
-[test-attr]: ./the-doc-attribute.md#testattr
+[test-attr]: the-doc-attribute.md#testattr
 
 ## Documenting macros
 
diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
index 6ca1d1153b4..36bc312b9c9 100644
--- a/src/doc/rustdoc/src/linking-to-items-by-name.md
+++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
@@ -35,7 +35,7 @@ link to `Option`.
 You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and
 `crate`. Associated items (functions, types, and constants) are supported, but [not for blanket
 trait implementations][#79682]. Rustdoc also supports linking to all primitives listed in
-[the standard library documentation](../std/index.html#primitives).
+[the standard library documentation](../../std/index.html#primitives).
 
 [#79682]: https://github.com/rust-lang/rust/pull/79682
 
diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md
index c5cc84022e3..25ef8b5bb91 100644
--- a/src/doc/rustdoc/src/the-doc-attribute.md
+++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md
@@ -38,7 +38,7 @@ but given that docs are rendered via Markdown, it will remove these newlines.
 Another use case is for including external files as documentation:
 
 ```rust,no_run
-#[doc = include_str!("../README.md")]
+#[doc = include_str!("../../README.md")]
 # fn f() {}
 ```
 
@@ -73,7 +73,7 @@ left hand side of the docs.
 #![doc(html_logo_url = "https://example.com/logo.jpg")]
 ```
 
-This will put `<a href='index.html'><img src='{}' alt='logo' width='100'></a>` into
+This will put `<a href='../index.html'><img src='{}' alt='logo' width='100'></a>` into
 your docs, where the string for the attribute goes into the `{}`.
 
 If you don't use this attribute, there will be no logo.
diff --git a/src/doc/rustdoc/src/what-to-include.md b/src/doc/rustdoc/src/write-documentation/what-to-include.md
index 2a6b62ebfd5..35e6ccbc388 100644
--- a/src/doc/rustdoc/src/what-to-include.md
+++ b/src/doc/rustdoc/src/write-documentation/what-to-include.md
@@ -122,4 +122,4 @@ Here is an example of a new theme, [Ayu].
 [API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html#rustdoc-does-not-show-unhelpful-implementation-details-c-hidden
 [Documentation tests]: documentation-tests.md
 [on this blog]: https://blog.guillaume-gomez.fr/articles/2016-09-16+Generating+doc+with+rustdoc+and+a+custom+theme
-[rustdoc-lints]: lints.md
+[rustdoc-lints]: ../lints.md
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 457851b0cc7..735521e667c 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -240,7 +240,7 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
 fn main() {
     let answer = do_twice(add_one, 5);
 
-    println!("The answer is: {}", answer);
+    println!("The answer is: {answer}");
 
     println!("With CFI enabled, you should not see the next answer");
     let f: fn(i32) -> i32 = unsafe {
@@ -250,7 +250,7 @@ fn main() {
     };
     let next_answer = do_twice(f, 5);
 
-    println!("The next answer is: {}", next_answer);
+    println!("The next answer is: {next_answer}");
 }
 ```
 Fig. 1. Modified example from the [Advanced Functions and
@@ -303,14 +303,14 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
 fn main() {
     let answer = do_twice(add_one, 5);
 
-    println!("The answer is: {}", answer);
+    println!("The answer is: {answer}");
 
     println!("With CFI enabled, you should not see the next answer");
     let f: fn(i32) -> i32 =
         unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
     let next_answer = do_twice(f, 5);
 
-    println!("The next answer is: {}", next_answer);
+    println!("The next answer is: {next_answer}");
 }
 ```
 Fig. 4. Another modified example from the [Advanced Functions and
diff --git a/src/doc/unstable-book/src/language-features/box-patterns.md b/src/doc/unstable-book/src/language-features/box-patterns.md
index bf0819ec920..584f4295cba 100644
--- a/src/doc/unstable-book/src/language-features/box-patterns.md
+++ b/src/doc/unstable-book/src/language-features/box-patterns.md
@@ -18,10 +18,10 @@ fn main() {
     let b = Some(Box::new(5));
     match b {
         Some(box n) if n < 0 => {
-            println!("Box contains negative number {}", n);
+            println!("Box contains negative number {n}");
         },
         Some(box n) if n >= 0 => {
-            println!("Box contains non-negative number {}", n);
+            println!("Box contains non-negative number {n}");
         },
         None => {
             println!("No box");
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 18a3498e34e..cc5c583bea8 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -11,7 +11,7 @@ arrayvec = { version = "0.7", default-features = false }
 askama = { version = "0.11", default-features = false, features = ["config"] }
 atty = "0.2"
 pulldown-cmark = { version = "0.9", default-features = false }
-minifier = "0.0.42"
+minifier = "0.0.43"
 rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 2e66db425d6..ec538f11831 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -244,7 +244,7 @@ fn build_enum(cx: &mut DocContext<'_>, did: DefId) -> clean::Enum {
     clean::Enum {
         generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
         variants_stripped: false,
-        variants: cx.tcx.adt_def(did).variants.iter().map(|v| v.clean(cx)).collect(),
+        variants: cx.tcx.adt_def(did).variants().iter().map(|v| v.clean(cx)).collect(),
     }
 }
 
@@ -327,7 +327,7 @@ fn merge_attrs(
 /// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`.
 crate fn build_impl(
     cx: &mut DocContext<'_>,
-    parent_module: impl Into<Option<DefId>>,
+    parent_module: Option<DefId>,
     did: DefId,
     attrs: Option<Attrs<'_>>,
     ret: &mut Vec<clean::Item>,
@@ -478,7 +478,7 @@ crate fn build_impl(
         record_extern_trait(cx, did);
     }
 
-    let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
+    let (merged_attrs, cfg) = merge_attrs(cx, parent_module, load_attrs(cx, did), attrs);
     trace!("merged_attrs={:?}", merged_attrs);
 
     trace!(
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 29c11c7b28a..52b556ae4b1 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -829,7 +829,7 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib
                             .values
                             .insert(a as _, Argument { name, type_: *ty, is_const: true });
                     } else {
-                        panic!("unexpected non const in position {}", pos);
+                        panic!("unexpected non const in position {pos}");
                     }
                 }
                 _ => panic!("invalid arg index"),
@@ -1551,7 +1551,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 })
             }
             ty::Adt(def, substs) => {
-                let did = def.did;
+                let did = def.did();
                 let kind = match def.adt_kind() {
                     AdtKind::Struct => ItemType::Struct,
                     AdtKind::Union => ItemType::Union,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 63a8e85f7c5..e9efeba0299 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -197,7 +197,7 @@ crate fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
                 .to_string();
             let uext = UnusedExterns { lint_level, unused_extern_names };
             let unused_extern_json = serde_json::to_string(&uext).unwrap();
-            eprintln!("{}", unused_extern_json);
+            eprintln!("{unused_extern_json}");
         }
     }
 
@@ -430,7 +430,7 @@ fn run_test(
                 // We used to check if the output contained "error[{}]: " but since we added the
                 // colored output, we can't anymore because of the color escape characters before
                 // the ":".
-                lang_string.error_codes.retain(|err| !out.contains(&format!("error[{}]", err)));
+                lang_string.error_codes.retain(|err| !out.contains(&format!("error[{err}]")));
 
                 if !lang_string.error_codes.is_empty() {
                     return Err(TestFailure::MissingErrorCodes(lang_string.error_codes));
@@ -510,7 +510,7 @@ crate fn make_test(
 
     // Next, any attributes that came from the crate root via #![doc(test(attr(...)))].
     for attr in &opts.attrs {
-        prog.push_str(&format!("#![{}]\n", attr));
+        prog.push_str(&format!("#![{attr}]\n"));
         line_offset += 1;
     }
 
@@ -647,7 +647,7 @@ crate fn make_test(
             // parse the source, but only has false positives, not false
             // negatives.
             if s.contains(crate_name) {
-                prog.push_str(&format!("extern crate r#{};\n", crate_name));
+                prog.push_str(&format!("extern crate r#{crate_name};\n"));
                 line_offset += 1;
             }
         }
@@ -661,7 +661,7 @@ crate fn make_test(
         // Give each doctest main function a unique name.
         // This is for example needed for the tooling around `-C instrument-coverage`.
         let inner_fn_name = if let Some(test_id) = test_id {
-            format!("_doctest_main_{}", test_id)
+            format!("_doctest_main_{test_id}")
         } else {
             "_inner".into()
         };
@@ -669,15 +669,14 @@ crate fn make_test(
         let (main_pre, main_post) = if returns_result {
             (
                 format!(
-                    "fn main() {{ {}fn {}() -> Result<(), impl core::fmt::Debug> {{\n",
-                    inner_attr, inner_fn_name
+                    "fn main() {{ {inner_attr}fn {inner_fn_name}() -> Result<(), impl core::fmt::Debug> {{\n",
                 ),
-                format!("\n}} {}().unwrap() }}", inner_fn_name),
+                format!("\n}} {inner_fn_name}().unwrap() }}"),
             )
         } else if test_id.is_some() {
             (
-                format!("fn main() {{ {}fn {}() {{\n", inner_attr, inner_fn_name),
-                format!("\n}} {}() }}", inner_fn_name),
+                format!("fn main() {{ {inner_attr}fn {inner_fn_name}() {{\n",),
+                format!("\n}} {inner_fn_name}() }}"),
             )
         } else {
             ("fn main() {\n".into(), "\n}".into())
@@ -695,7 +694,7 @@ crate fn make_test(
         prog.extend([&main_pre, everything_else, &main_post].iter().cloned());
     }
 
-    debug!("final doctest:\n{}", prog);
+    debug!("final doctest:\n{prog}");
 
     (prog, line_offset, supports_color)
 }
@@ -763,9 +762,9 @@ fn partition_source(s: &str) -> (String, String, String) {
         }
     }
 
-    debug!("before:\n{}", before);
-    debug!("crates:\n{}", crates);
-    debug!("after:\n{}", after);
+    debug!("before:\n{before}");
+    debug!("crates:\n{crates}");
+    debug!("after:\n{after}");
 
     (before, after, crates)
 }
@@ -940,7 +939,7 @@ impl Tester for Collector {
             )
         };
 
-        debug!("creating test {}: {}", name, test);
+        debug!("creating test {name}: {test}");
         self.tests.push(test::TestDescAndFn {
             desc: test::TestDesc {
                 name: test::DynTestName(name),
@@ -994,19 +993,19 @@ impl Tester for Collector {
                             eprint!("Some expected error codes were not found: {:?}", codes);
                         }
                         TestFailure::ExecutionError(err) => {
-                            eprint!("Couldn't run the test: {}", err);
+                            eprint!("Couldn't run the test: {err}");
                             if err.kind() == io::ErrorKind::PermissionDenied {
                                 eprint!(" - maybe your tempdir is mounted with noexec?");
                             }
                         }
                         TestFailure::ExecutionFailure(out) => {
                             let reason = if let Some(code) = out.status.code() {
-                                format!("exit code {}", code)
+                                format!("exit code {code}")
                             } else {
                                 String::from("terminated by signal")
                             };
 
-                            eprintln!("Test executable failed ({}).", reason);
+                            eprintln!("Test executable failed ({reason}).");
 
                             // FIXME(#12309): An unfortunate side-effect of capturing the test
                             // executable's output is that the relative ordering between the test's
@@ -1024,11 +1023,11 @@ impl Tester for Collector {
                                 eprintln!();
 
                                 if !stdout.is_empty() {
-                                    eprintln!("stdout:\n{}", stdout);
+                                    eprintln!("stdout:\n{stdout}");
                                 }
 
                                 if !stderr.is_empty() {
-                                    eprintln!("stderr:\n{}", stderr);
+                                    eprintln!("stderr:\n{stderr}");
                                 }
                             }
                         }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index a2f48c16465..5c59609d5b8 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1185,8 +1185,8 @@ impl clean::FnDecl {
         cx: &Context<'_>,
     ) -> fmt::Result {
         let amp = if f.alternate() { "&" } else { "&amp;" };
-        let mut args = String::new();
-        let mut args_plain = String::new();
+        let mut args = Buffer::html();
+        let mut args_plain = Buffer::new();
         for (i, input) in self.inputs.values.iter().enumerate() {
             if i == 0 {
                 args.push_str("<br>");
@@ -1199,59 +1199,51 @@ impl clean::FnDecl {
                         args_plain.push_str("self");
                     }
                     clean::SelfBorrowed(Some(ref lt), mtbl) => {
-                        args.push_str(&format!(
-                            "{}{} {}self",
-                            amp,
-                            lt.print(),
-                            mtbl.print_with_space()
-                        ));
-                        args_plain.push_str(&format!(
-                            "&{} {}self",
-                            lt.print(),
-                            mtbl.print_with_space()
-                        ));
+                        write!(args, "{}{} {}self", amp, lt.print(), mtbl.print_with_space());
+                        write!(args_plain, "&{} {}self", lt.print(), mtbl.print_with_space());
                     }
                     clean::SelfBorrowed(None, mtbl) => {
-                        args.push_str(&format!("{}{}self", amp, mtbl.print_with_space()));
-                        args_plain.push_str(&format!("&{}self", mtbl.print_with_space()));
+                        write!(args, "{}{}self", amp, mtbl.print_with_space());
+                        write!(args_plain, "&{}self", mtbl.print_with_space());
                     }
                     clean::SelfExplicit(ref typ) => {
                         if f.alternate() {
-                            args.push_str(&format!("self: {:#}", typ.print(cx)));
+                            write!(args, "self: {:#}", typ.print(cx));
                         } else {
-                            args.push_str(&format!("self: {}", typ.print(cx)));
+                            write!(args, "self: {}", typ.print(cx));
                         }
-                        args_plain.push_str(&format!("self: {:#}", typ.print(cx)));
+                        write!(args_plain, "self: {:#}", typ.print(cx));
                     }
                 }
             } else {
                 if i > 0 {
                     args.push_str(" <br>");
-                    args_plain.push(' ');
+                    args_plain.push_str(" ");
                 }
                 if input.is_const {
                     args.push_str("const ");
                     args_plain.push_str("const ");
                 }
                 if !input.name.is_empty() {
-                    args.push_str(&format!("{}: ", input.name));
-                    args_plain.push_str(&format!("{}: ", input.name));
+                    write!(args, "{}: ", input.name);
+                    write!(args_plain, "{}: ", input.name);
                 }
 
                 if f.alternate() {
-                    args.push_str(&format!("{:#}", input.type_.print(cx)));
+                    write!(args, "{:#}", input.type_.print(cx));
                 } else {
-                    args.push_str(&input.type_.print(cx).to_string());
+                    write!(args, "{}", input.type_.print(cx));
                 }
-                args_plain.push_str(&format!("{:#}", input.type_.print(cx)));
+                write!(args_plain, "{:#}", input.type_.print(cx));
             }
             if i + 1 < self.inputs.values.len() {
-                args.push(',');
-                args_plain.push(',');
+                args.push_str(",");
+                args_plain.push_str(",");
             }
         }
 
-        let mut args_plain = format!("({})", args_plain);
+        let mut args_plain = format!("({})", args_plain.into_inner());
+        let mut args = args.into_inner();
 
         if self.c_variadic {
             args.push_str(",<br> ...");
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 7061a9674e4..3a3d61b1e67 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1314,7 +1314,7 @@ crate fn markdown_links(md: &str) -> Vec<MarkdownLink> {
 
     for ev in iter {
         if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 {
-            debug!("found link: {}", dest);
+            debug!("found link: {dest}");
             let span = span_for_link(&dest, ev.1);
             links.borrow_mut().push(MarkdownLink { kind, link: dest.into_string(), range: span });
         }
@@ -1460,6 +1460,7 @@ fn init_id_map() -> FxHashMap<String, usize> {
     map.insert("provided-methods".to_owned(), 1);
     map.insert("implementors".to_owned(), 1);
     map.insert("synthetic-implementors".to_owned(), 1);
+    map.insert("implementations-list".to_owned(), 1);
     map.insert("trait-implementations-list".to_owned(), 1);
     map.insert("synthetic-implementations-list".to_owned(), 1);
     map.insert("blanket-implementations-list".to_owned(), 1);
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 558dbb3b396..34d1268a7df 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -699,7 +699,13 @@ fn short_item_info(
 
 // Render the list of items inside one of the sections "Trait Implementations",
 // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
-fn render_impls(cx: &Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_item: &clean::Item) {
+fn render_impls(
+    cx: &Context<'_>,
+    w: &mut Buffer,
+    impls: &[&&Impl],
+    containing_item: &clean::Item,
+    toggle_open_by_default: bool,
+) {
     let tcx = cx.tcx();
     let mut rendered_impls = impls
         .iter()
@@ -722,7 +728,7 @@ fn render_impls(cx: &Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_i
                     is_on_foreign_type: false,
                     show_default_items: true,
                     show_non_assoc_items: true,
-                    toggle_open_by_default: true,
+                    toggle_open_by_default,
                 },
             );
             buffer.into_inner()
@@ -1065,14 +1071,15 @@ fn render_assoc_items_inner(
     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
     if !non_trait.is_empty() {
         let mut tmp_buf = Buffer::empty_from(w);
-        let render_mode = match what {
+        let (render_mode, id) = match what {
             AssocItemRender::All => {
                 tmp_buf.write_str(
                     "<h2 id=\"implementations\" class=\"small-section-header\">\
-                         Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
-                    </h2>",
+                         Implementations\
+                         <a href=\"#implementations\" class=\"anchor\"></a>\
+                     </h2>",
                 );
-                RenderMode::Normal
+                (RenderMode::Normal, "implementations-list".to_owned())
             }
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
                 let id =
@@ -1090,7 +1097,7 @@ fn render_assoc_items_inner(
                     trait_ = trait_.print(cx),
                     type_ = type_.print(cx),
                 );
-                RenderMode::ForDeref { mut_: deref_mut_ }
+                (RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id))
             }
         };
         let mut impls_buf = Buffer::empty_from(w);
@@ -1115,7 +1122,9 @@ fn render_assoc_items_inner(
         }
         if !impls_buf.is_empty() {
             w.push_buffer(tmp_buf);
+            write!(w, "<div id=\"{}\">", id);
             w.push_buffer(impls_buf);
+            w.write_str("</div>");
         }
     }
 
@@ -1140,13 +1149,14 @@ fn render_assoc_items_inner(
             concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
 
         let mut impls = Buffer::empty_from(w);
-        render_impls(cx, &mut impls, &concrete, containing_item);
+        render_impls(cx, &mut impls, &concrete, containing_item, true);
         let impls = impls.into_inner();
         if !impls.is_empty() {
             write!(
                 w,
                 "<h2 id=\"trait-implementations\" class=\"small-section-header\">\
-                     Trait Implementations<a href=\"#trait-implementations\" class=\"anchor\"></a>\
+                     Trait Implementations\
+                     <a href=\"#trait-implementations\" class=\"anchor\"></a>\
                  </h2>\
                  <div id=\"trait-implementations-list\">{}</div>",
                 impls
@@ -1161,7 +1171,7 @@ fn render_assoc_items_inner(
                  </h2>\
                  <div id=\"synthetic-implementations-list\">",
             );
-            render_impls(cx, w, &synthetic, containing_item);
+            render_impls(cx, w, &synthetic, containing_item, false);
             w.write_str("</div>");
         }
 
@@ -1173,7 +1183,7 @@ fn render_assoc_items_inner(
                  </h2>\
                  <div id=\"blanket-implementations-list\">",
             );
-            render_impls(cx, w, &blanket_impl, containing_item);
+            render_impls(cx, w, &blanket_impl, containing_item, false);
             w.write_str("</div>");
         }
     }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index e84dc6c7240..e6c7745c6e1 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1710,11 +1710,11 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
 }
 
 fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
-    fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) {
-        if layout.abi.is_unsized() {
+    fn write_size_of_layout(w: &mut Buffer, layout: Layout<'_>, tag_size: u64) {
+        if layout.abi().is_unsized() {
             write!(w, "(unsized)");
         } else {
-            let bytes = layout.size.bytes() - tag_size;
+            let bytes = layout.size().bytes() - tag_size;
             write!(w, "{size} byte{pl}", size = bytes, pl = if bytes == 1 { "" } else { "s" },);
         }
     }
@@ -1744,7 +1744,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
             write_size_of_layout(w, ty_layout.layout, 0);
             writeln!(w, "</p>");
             if let Variants::Multiple { variants, tag, tag_encoding, .. } =
-                &ty_layout.layout.variants
+                &ty_layout.layout.variants()
             {
                 if !variants.is_empty() {
                     w.write_str(
@@ -1765,9 +1765,9 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
                     };
 
                     for (index, layout) in variants.iter_enumerated() {
-                        let name = adt.variants[index].name;
+                        let name = adt.variant(index).name;
                         write!(w, "<li><code>{name}</code>: ", name = name);
-                        write_size_of_layout(w, layout, tag_size);
+                        write_size_of_layout(w, *layout, tag_size);
                         writeln!(w, "</li>");
                     }
                     w.write_str("</ul>");
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index bae04f2095a..9fba6e91162 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -272,22 +272,16 @@ crate fn print_src(
 ) {
     let lines = s.lines().count();
     let mut line_numbers = Buffer::empty_from(buf);
-    let mut cols = 0;
-    let mut tmp = lines;
-    while tmp > 0 {
-        cols += 1;
-        tmp /= 10;
-    }
     line_numbers.write_str("<pre class=\"line-numbers\">");
     match source_context {
         SourceContext::Standalone => {
             for line in 1..=lines {
-                writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", line, cols)
+                writeln!(line_numbers, "<span id=\"{0}\">{0}</span>", line)
             }
         }
         SourceContext::Embedded { offset } => {
             for line in 1..=lines {
-                writeln!(line_numbers, "<span>{0:1$}</span>", line + offset, cols)
+                writeln!(line_numbers, "<span>{0}</span>", line + offset)
             }
         }
     }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index f1e0a89883a..67adaa8702d 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -397,17 +397,17 @@ nav.sub {
 	overflow-y: hidden;
 }
 
-.source .sidebar > *:not(:first-child) {
-	transition: opacity 0.5s;
+.source .sidebar > *:not(#sidebar-toggle) {
 	opacity: 0;
 	visibility: hidden;
+	transition: opacity 0.5s;
 }
 
 .source .sidebar.expanded {
 	overflow-y: auto;
 }
 
-.source .sidebar.expanded > * {
+.source .sidebar.expanded > *:not(#sidebar-toggle) {
 	opacity: 1;
 	visibility: visible;
 }
@@ -541,6 +541,9 @@ h2.location a {
 	text-decoration: underline;
 }
 
+.line-numbers {
+	text-align: right;
+}
 .rustdoc:not(.source) .example-wrap > pre:not(.line-number) {
 	width: 100%;
 	overflow-x: auto;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 8e1919f75d6..90592335d5d 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -741,7 +741,7 @@ function hideThemeButtonState() {
         } else {
             addClass(innerToggle, "will-expand");
             onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function(e) {
-                if (e.parentNode.id !== MAIN_ID ||
+                if (e.parentNode.id !== "implementations-list" ||
                     (!hasClass(e, "implementors-toggle") &&
                      !hasClass(e, "type-contents-toggle")))
                 {
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 4358dc8980f..7ffcfada5c0 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -340,9 +340,10 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
             Lifetime { outlives } => GenericParamDefKind::Lifetime {
                 outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(),
             },
-            Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type {
+            Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type {
                 bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
                 default: default.map(|x| (*x).into_tcx(tcx)),
+                synthetic,
             },
             Const { did: _, ty, default } => {
                 GenericParamDefKind::Const { ty: (*ty).into_tcx(tcx), default: default.map(|x| *x) }
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 906b8f8a245..a1f92afad46 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -51,7 +51,7 @@ crate fn render<P: AsRef<Path>>(
 
     let mut css = String::new();
     for name in &options.markdown_css {
-        let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n", name);
+        let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{name}\">\n");
         css.push_str(&s)
     }
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index aa771a06f9c..e1ae0a19ef9 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -2,7 +2,7 @@
 //!
 //! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md
 
-use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet};
+use rustc_data_structures::{fx::FxHashMap, intern::Interned, stable_set::FxHashSet};
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::def::{
     DefKind,
@@ -439,7 +439,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                             Err(ResolutionFailure::NotResolved {
                                 item_id,
                                 module_id,
-                                partial_res: Some(Res::Def(DefKind::Enum, def.did)),
+                                partial_res: Some(Res::Def(DefKind::Enum, def.did())),
                                 unresolved: variant_field_name.to_string().into(),
                             }
                             .into())
@@ -686,7 +686,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             ty::FnDef(..) => panic!("type alias to a function definition"),
             ty::FnPtr(_) => Res::Primitive(Fn),
             ty::Never => Res::Primitive(Never),
-            ty::Adt(&ty::AdtDef { did, .. }, _) | ty::Foreign(did) => {
+            ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) | ty::Foreign(did) => {
                 Res::Def(self.cx.tcx.def_kind(did), did)
             }
             ty::Projection(_)
@@ -779,7 +779,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 if ns == TypeNS && def_kind == DefKind::Enum {
                     match tcx.type_of(did).kind() {
                         ty::Adt(adt_def, _) => {
-                            for variant in &adt_def.variants {
+                            for variant in adt_def.variants() {
                                 if variant.name == item_name {
                                     return Some((
                                         root_res,
@@ -1002,8 +1002,8 @@ fn trait_impls_for<'a>(
             let saw_impl = impl_type == ty
                 || match (impl_type.kind(), ty.kind()) {
                     (ty::Adt(impl_def, _), ty::Adt(ty_def, _)) => {
-                        debug!("impl def_id: {:?}, ty def_id: {:?}", impl_def.did, ty_def.did);
-                        impl_def.did == ty_def.did
+                        debug!("impl def_id: {:?}, ty def_id: {:?}", impl_def.did(), ty_def.did());
+                        impl_def.did() == ty_def.did()
                     }
                     _ => false,
                 };
diff --git a/src/llvm-project b/src/llvm-project
-Subproject e29ac13bc97e26f886c3bfe72f9135e994c3cd0
+Subproject c8eccf626fb5bb851b2ade93af8851ca1523807
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 40b0de44829..7df880a4ed8 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -9,7 +9,7 @@ use std::path::PathBuf;
 use serde::{Deserialize, Serialize};
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 12;
+pub const FORMAT_VERSION: u32 = 13;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -346,9 +346,41 @@ pub struct GenericParamDef {
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericParamDefKind {
-    Lifetime { outlives: Vec<String> },
-    Type { bounds: Vec<GenericBound>, default: Option<Type> },
-    Const { ty: Type, default: Option<String> },
+    Lifetime {
+        outlives: Vec<String>,
+    },
+    Type {
+        bounds: Vec<GenericBound>,
+        default: Option<Type>,
+        /// This is normally `false`, which means that this generic parameter is
+        /// declared in the Rust source text.
+        ///
+        /// If it is `true`, this generic parameter has been introduced by the
+        /// compiler behind the scenes.
+        ///
+        /// # Example
+        ///
+        /// Consider
+        ///
+        /// ```ignore (pseudo-rust)
+        /// pub fn f(_: impl Trait) {}
+        /// ```
+        ///
+        /// The compiler will transform this behind the scenes to
+        ///
+        /// ```ignore (pseudo-rust)
+        /// pub fn f<impl Trait: Trait>(_: impl Trait) {}
+        /// ```
+        ///
+        /// In this example, the generic parameter named `impl Trait` (and which
+        /// is bound by `Trait`) is synthetic, because it was not originally in
+        /// the Rust source text.
+        synthetic: bool,
+    },
+    Const {
+        ty: Type,
+        default: Option<String>,
+    },
 }
 
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
diff --git a/src/test/assembly/sparc-struct-abi.rs b/src/test/assembly/sparc-struct-abi.rs
index dd8e6f614df..6a898b2974a 100644
--- a/src/test/assembly/sparc-struct-abi.rs
+++ b/src/test/assembly/sparc-struct-abi.rs
@@ -13,6 +13,7 @@
 pub trait Sized {}
 #[lang = "copy"]
 pub trait Copy {}
+impl Copy for f32 {}
 
 #[repr(C)]
 pub struct Franta {
diff --git a/src/test/assembly/target-feature-multiple.rs b/src/test/assembly/target-feature-multiple.rs
index 4c2073678b8..18d896e86b2 100644
--- a/src/test/assembly/target-feature-multiple.rs
+++ b/src/test/assembly/target-feature-multiple.rs
@@ -23,6 +23,7 @@
 trait Sized {}
 #[lang = "copy"]
 trait Copy {}
+impl Copy for u32 {}
 
 // Use of these requires target features to be enabled
 extern "unadjusted" {
diff --git a/src/test/codegen/abi-sysv64.rs b/src/test/codegen/abi-sysv64.rs
index bb910d573b3..dfc31227908 100644
--- a/src/test/codegen/abi-sysv64.rs
+++ b/src/test/codegen/abi-sysv64.rs
@@ -13,6 +13,7 @@
 trait Sized {}
 #[lang = "copy"]
 trait Copy {}
+impl Copy for i64 {}
 
 // CHECK: define x86_64_sysvcc i64 @has_sysv64_abi
 #[no_mangle]
diff --git a/src/test/codegen/abi-x86-interrupt.rs b/src/test/codegen/abi-x86-interrupt.rs
index 119004d261d..d612f603e4f 100644
--- a/src/test/codegen/abi-x86-interrupt.rs
+++ b/src/test/codegen/abi-x86-interrupt.rs
@@ -13,6 +13,7 @@
 trait Sized {}
 #[lang = "copy"]
 trait Copy {}
+impl Copy for i64 {}
 
 // CHECK: define x86_intrcc i64 @has_x86_interrupt_abi
 #[no_mangle]
diff --git a/src/test/codegen/frame-pointer.rs b/src/test/codegen/frame-pointer.rs
index 367591dcb96..f7c02d47939 100644
--- a/src/test/codegen/frame-pointer.rs
+++ b/src/test/codegen/frame-pointer.rs
@@ -17,7 +17,7 @@
 trait Sized { }
 #[lang="copy"]
 trait Copy { }
-
+impl Copy for u32 {}
 
 
 // CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] {
diff --git a/src/test/codegen/inline-hint.rs b/src/test/codegen/inline-hint.rs
index ad41badf381..d3ea1915a8b 100644
--- a/src/test/codegen/inline-hint.rs
+++ b/src/test/codegen/inline-hint.rs
@@ -6,7 +6,7 @@
 
 pub fn f() {
     let a = A;
-    let b = (0i32, 1i32, 2i32, 3i32);
+    let b = (0i32, 1i32, 2i32, 3 as *const i32);
     let c = || {};
 
     a(String::new(), String::new());
@@ -21,7 +21,7 @@ struct A(String, String);
 // CHECK-NOT:  inlinehint
 // CHECK-SAME: {{$}}
 
-// CHECK:      ; <(i32, i32, i32, i32) as core::clone::Clone>::clone
+// CHECK:      ; <(i32, i32, i32, *const i{{16|32|64}}) as core::clone::Clone>::clone
 // CHECK-NEXT: ; Function Attrs: inlinehint
 
 // CHECK:      ; inline_hint::f::{closure#0}
diff --git a/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
index faf81b5ae76..7f0f678062a 100644
--- a/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
+++ b/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
@@ -10,6 +10,14 @@
 trait Sized {}
 #[lang = "copy"]
 trait Copy {}
+impl Copy for bool {}
+impl Copy for i8 {}
+impl Copy for u8 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for u64 {}
+impl Copy for f32 {}
+impl Copy for f64 {}
 
 // CHECK: define void @f_void()
 #[no_mangle]
diff --git a/src/test/mir-opt/combine_clone_of_primitives.rs b/src/test/mir-opt/combine_clone_of_primitives.rs
new file mode 100644
index 00000000000..0972d2d68a1
--- /dev/null
+++ b/src/test/mir-opt/combine_clone_of_primitives.rs
@@ -0,0 +1,20 @@
+// compile-flags: -C opt-level=0 -Z inline_mir=no
+// ignore-wasm32 compiled with panic=abort by default
+
+// EMIT_MIR combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
+
+#[derive(Clone)]
+struct MyThing<T> {
+    v: T,
+    i: u64,
+    a: [f32; 3],
+}
+
+fn main() {
+    let x = MyThing::<i16> { v: 2, i: 3, a: [0.0; 3] };
+    let y = x.clone();
+
+    assert_eq!(y.v, 2);
+    assert_eq!(y.i, 3);
+    assert_eq!(y.a, [0.0; 3]);
+}
diff --git a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
new file mode 100644
index 00000000000..62e5da4902c
--- /dev/null
+++ b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
@@ -0,0 +1,80 @@
+- // MIR for `<impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone` before InstCombine
++ // MIR for `<impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone` after InstCombine
+  
+  fn <impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone(_1: &MyThing<T>) -> MyThing<T> {
+      debug self => _1;                    // in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+      let mut _0: MyThing<T>;              // return place in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+      let _2: &T;                          // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let _3: &u64;                        // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let _4: &[f32; 3];                   // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      let mut _5: T;                       // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let mut _6: &T;                      // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let _7: &T;                          // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let mut _8: u64;                     // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let mut _9: &u64;                    // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let _10: &u64;                       // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let mut _11: [f32; 3];               // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      let mut _12: &[f32; 3];              // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      let _13: &[f32; 3];                  // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      scope 1 {
+          debug __self_0_0 => _2;          // in scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          debug __self_0_1 => _3;          // in scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          debug __self_0_2 => _4;          // in scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      }
+  
+      bb0: {
+          _2 = &((*_1).0: T);              // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          _3 = &((*_1).1: u64);            // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          _4 = &((*_1).2: [f32; 3]);       // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-         _7 = &(*_2);                     // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+-         _6 = &(*_7);                     // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
++         _7 = _2;                         // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
++         _6 = _7;                         // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          _5 = <T as Clone>::clone(move _6) -> bb1; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+                                           // mir::Constant
+                                           // + span: $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+                                           // + literal: Const { ty: for<'r> fn(&'r T) -> T {<T as Clone>::clone}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+-         _10 = &(*_3);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-         _9 = &(*_10);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-         _8 = <u64 as Clone>::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-                                          // mir::Constant
+-                                          // + span: $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-                                          // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {<u64 as Clone>::clone}, val: Value(Scalar(<ZST>)) }
++         _10 = _3;                        // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++         _9 = _10;                        // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++         _8 = (*_9);                      // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++         goto -> bb2;                     // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      }
+  
+      bb2: {
+-         _13 = &(*_4);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-         _12 = &(*_13);                   // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-         _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-                                          // mir::Constant
+-                                          // + span: $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-                                          // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(Scalar(<ZST>)) }
++         _13 = _4;                        // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++         _12 = _13;                       // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++         _11 = (*_12);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++         goto -> bb3;                     // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      }
+  
+      bb3: {
+          (_0.0: T) = move _5;             // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          (_0.1: u64) = move _8;           // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          (_0.2: [f32; 3]) = move _11;     // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          return;                          // scope 0 at $DIR/combine_clone_of_primitives.rs:6:15: 6:15
+      }
+  
+      bb4 (cleanup): {
+          drop(_5) -> bb5;                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+      }
+  
+      bb5 (cleanup): {
+          resume;                          // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+      }
+  }
+  
diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff
index 1d72b34f83b..831d73045dd 100644
--- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff
+++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff
@@ -46,11 +46,11 @@
 -     bb1: {
 +         discriminant(_4) = 0;            // scope 2 at $DIR/inline-generator.rs:15:5: 15:41
           _3 = &mut _4;                    // scope 0 at $DIR/inline-generator.rs:9:23: 9:31
--         _2 = Pin::<&mut impl Generator<bool>>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32
+-         _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-generator.rs:9:14: 9:22
 -                                          // + user_ty: UserType(0)
--                                          // + literal: Const { ty: fn(&mut impl Generator<bool>) -> Pin<&mut impl Generator<bool>> {Pin::<&mut impl Generator<bool>>::new}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn(&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) -> Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]> {Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new}, val: Value(Scalar(<ZST>)) }
 -     }
 - 
 -     bb2: {
@@ -62,10 +62,10 @@
 +         StorageDead(_6);                 // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         StorageDead(_5);                 // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL
           StorageDead(_3);                 // scope 0 at $DIR/inline-generator.rs:9:31: 9:32
--         _1 = <impl Generator<bool> as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
+-         _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-generator.rs:9:33: 9:39
--                                          // + literal: Const { ty: for<'r> fn(Pin<&'r mut impl Generator<bool>>, bool) -> GeneratorState<<impl Generator<bool> as Generator<bool>>::Yield, <impl Generator<bool> as Generator<bool>>::Return> {<impl Generator<bool> as Generator<bool>>::resume}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> fn(Pin<&'r mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::resume}, val: Value(Scalar(<ZST>)) }
 +         StorageLive(_7);                 // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         _7 = const false;                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         StorageLive(_10);                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
diff --git a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
index 9e92f025b76..ea6b91cba9e 100644
--- a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
+++ b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
@@ -25,10 +25,10 @@
       bb1: {
           _3 = &_4;                        // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
           StorageLive(_5);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
--         _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+-         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
 -                                          // mir::Constant
 -                                          // + span: $DIR/issue-78442.rs:11:5: 11:15
--                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
 +         _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
diff --git a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
index a8ae4008cbc..ba9da7678e7 100644
--- a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
+++ b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
@@ -25,10 +25,12 @@
           _3 = &_4;                        // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
           StorageLive(_5);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
           nop;                             // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
-          _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+-         _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
++         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
                                            // mir::Constant
                                            // + span: $DIR/issue-78442.rs:11:5: 11:15
-                                           // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
++                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
       }
   
       bb2: {
diff --git a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
index 975e2ffbf01..9f235248ca5 100644
--- a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
+++ b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
@@ -42,7 +42,7 @@ fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) ->
     let mut _0: bool;                    // return place in scope 0 at $DIR/named-lifetimes-basic.rs:12:81: 12:85
 
     bb0: {
-        _0 = const Const(Value(Scalar(0x01)): bool); // bb0[0]: scope 0 at $DIR/named-lifetimes-basic.rs:12:88: 12:92
+        _0 = const ConstValue(Scalar(0x01): bool); // bb0[0]: scope 0 at $DIR/named-lifetimes-basic.rs:12:88: 12:92
         return;                          // bb0[1]: scope 0 at $DIR/named-lifetimes-basic.rs:12:94: 12:94
     }
 }
diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
index 3ef7844ce43..ed94a1ecf00 100644
--- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
+++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
@@ -45,11 +45,11 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
-        _1 = [const Const(Value(Scalar(0x00000001)): usize), const Const(Value(Scalar(0x00000002)): usize), const Const(Value(Scalar(0x00000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
+        _1 = [const ConstValue(Scalar(0x00000001): usize), const ConstValue(Scalar(0x00000002): usize), const ConstValue(Scalar(0x00000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
         FakeRead(ForLet(None), _1);      // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
         StorageLive(_2);                 // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
         StorageLive(_3);                 // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
-        _3 = const Const(Value(Scalar(0x00000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
+        _3 = const ConstValue(Scalar(0x00000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
         _4 = Len(_1);                    // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
         _5 = Lt(_3, _4);                 // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
@@ -62,7 +62,7 @@ fn main() -> () {
         _6 = _2;                         // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
         FakeRead(ForLet(None), _6);      // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
         StorageLive(_7);                 // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
-        _7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+        _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
         switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
     }
 
@@ -70,7 +70,7 @@ fn main() -> () {
         StorageLive(_8);                 // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
         StorageLive(_9);                 // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
         _9 = (*_6);                      // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
-        _8 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+        _8 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
@@ -79,13 +79,13 @@ fn main() -> () {
     bb3: {
         StorageDead(_9);                 // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
         StorageDead(_8);                 // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
+        _0 = const ConstValue(Scalar(<ZST>): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
         goto -> bb6;                     // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb4: {
         StorageLive(_10);                // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
-        _10 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x00000016)): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+        _10 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
@@ -93,7 +93,7 @@ fn main() -> () {
 
     bb5: {
         StorageDead(_10);                // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
+        _0 = const ConstValue(Scalar(<ZST>): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
         goto -> bb6;                     // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
index d6b4a0beebd..95997b20701 100644
--- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
+++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
@@ -45,11 +45,11 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
-        _1 = [const Const(Value(Scalar(0x0000000000000001)): usize), const Const(Value(Scalar(0x0000000000000002)): usize), const Const(Value(Scalar(0x0000000000000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
+        _1 = [const ConstValue(Scalar(0x0000000000000001): usize), const ConstValue(Scalar(0x0000000000000002): usize), const ConstValue(Scalar(0x0000000000000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
         FakeRead(ForLet(None), _1);      // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
         StorageLive(_2);                 // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
         StorageLive(_3);                 // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
-        _3 = const Const(Value(Scalar(0x0000000000000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
+        _3 = const ConstValue(Scalar(0x0000000000000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
         _4 = Len(_1);                    // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
         _5 = Lt(_3, _4);                 // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
@@ -62,7 +62,7 @@ fn main() -> () {
         _6 = _2;                         // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
         FakeRead(ForLet(None), _6);      // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
         StorageLive(_7);                 // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
-        _7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+        _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
         switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
     }
 
@@ -70,7 +70,7 @@ fn main() -> () {
         StorageLive(_8);                 // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
         StorageLive(_9);                 // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
         _9 = (*_6);                      // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
-        _8 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+        _8 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
@@ -79,13 +79,13 @@ fn main() -> () {
     bb3: {
         StorageDead(_9);                 // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
         StorageDead(_8);                 // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
+        _0 = const ConstValue(Scalar(<ZST>): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
         goto -> bb6;                     // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb4: {
         StorageLive(_10);                // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
-        _10 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x0000000000000016)): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+        _10 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
@@ -93,7 +93,7 @@ fn main() -> () {
 
     bb5: {
         StorageDead(_10);                // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
+        _0 = const ConstValue(Scalar(<ZST>): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
         goto -> bb6;                     // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
diff --git a/src/test/rustdoc-gui/docblock-table-overflow.goml b/src/test/rustdoc-gui/docblock-table-overflow.goml
index a9af88189a6..af76d2ea427 100644
--- a/src/test/rustdoc-gui/docblock-table-overflow.goml
+++ b/src/test/rustdoc-gui/docblock-table-overflow.goml
@@ -12,10 +12,10 @@ assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"})
 
 // Logically, the ".docblock" and the "<p>" should have the same scroll width.
 compare-elements-property: (
-    "#implementations + details .docblock",
-    "#implementations + details .docblock > p",
+    "#implementations-list > details .docblock",
+    "#implementations-list > details .docblock > p",
     ["scrollWidth"],
 )
-assert-property: ("#implementations + details .docblock", {"scrollWidth": "801"})
+assert-property: ("#implementations-list > details .docblock", {"scrollWidth": "801"})
 // However, since there is overflow in the <table>, its scroll width is bigger.
-assert-property: ("#implementations + details .docblock table", {"scrollWidth": "1573"})
+assert-property: ("#implementations-list > details .docblock table", {"scrollWidth": "1573"})
diff --git a/src/test/rustdoc-gui/hash-item-expansion.goml b/src/test/rustdoc-gui/hash-item-expansion.goml
index a680635ef8a..861f6928362 100644
--- a/src/test/rustdoc-gui/hash-item-expansion.goml
+++ b/src/test/rustdoc-gui/hash-item-expansion.goml
@@ -3,9 +3,9 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.borrow
 // In the blanket implementations list, "Borrow" is the second one, hence the ":nth(2)".
 assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"open": ""})
 // We first check that the impl block is open by default.
-assert-attribute: ("#implementations + details", {"open": ""})
+assert-attribute: ("#implementations-list details", {"open": ""})
 // To ensure that we will click on the currently hidden method.
 assert-text: (".sidebar-elems section .block li > a", "must_use")
 click: ".sidebar-elems section .block li > a"
 // We check that the impl block was opened as expected so that we can see the method.
-assert-attribute: ("#implementations + details", {"open": ""})
+assert-attribute: ("#implementations-list > details", {"open": ""})
diff --git a/src/test/rustdoc-gui/impl-default-expansion.goml b/src/test/rustdoc-gui/impl-default-expansion.goml
index 7c4496dc0ca..6df2661e6c2 100644
--- a/src/test/rustdoc-gui/impl-default-expansion.goml
+++ b/src/test/rustdoc-gui/impl-default-expansion.goml
@@ -1,3 +1,3 @@
 // This test ensures that the impl blocks are open by default.
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
-assert-attribute: ("#main-content > details.implementors-toggle", {"open": ""})
+assert-attribute: ("#implementations-list details.implementors-toggle", {"open": ""})
diff --git a/src/test/rustdoc-gui/mobile.goml b/src/test/rustdoc-gui/mobile.goml
index e70abcb83cf..13b9b563d94 100644
--- a/src/test/rustdoc-gui/mobile.goml
+++ b/src/test/rustdoc-gui/mobile.goml
@@ -3,6 +3,7 @@ goto: file://|DOC_PATH|/staged_api/struct.Foo.html
 size: (400, 600)
 
 font-size: 18
+wait-for: 100 // wait a bit for the resize and the font-size change to be fully taken into account.
 
 // The out-of-band info (source, stable version, collapse) should be below the
 // h1 when the screen gets narrow enough.
@@ -18,10 +19,12 @@ assert-property: (".mobile-topbar h2.location", {"offsetHeight": 36})
 assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" })
 
 size: (1000, 1000)
+wait-for: 100 // wait a bit for the resize to be fully taken into account.
 assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" })
 
 // On the settings page, the theme buttons should not line-wrap. Instead, they should
 // all be placed as a group on a line below the setting name "Theme."
 goto: file://|DOC_PATH|/settings.html
 size: (400, 600)
-compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16})
+// Ignored for now https://github.com/rust-lang/rust/issues/93784.
+// compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16})
diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml
new file mode 100644
index 00000000000..27229705a9f
--- /dev/null
+++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml
@@ -0,0 +1,22 @@
+// This test ensures that the elements in the sidebar are displayed correctly.
+javascript: false
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+// Since the javascript is disabled, there shouldn't be a toggle.
+assert-false: "#sidebar-toggle"
+// For some reason, we need to wait a bit here because it seems like the transition on opacity
+// is being applied whereas it can't be reproduced in a browser...
+wait-for: 500
+assert-css: (".sidebar > *", {"visibility": "hidden", "opacity": 0})
+
+// Let's retry with javascript enabled.
+javascript: true
+reload:
+wait-for: "#sidebar-toggle"
+assert-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
+assert-css: (".sidebar > *:not(#sidebar-toggle)", {"visibility": "hidden", "opacity": 0})
+// Let's expand the sidebar now.
+click: "#sidebar-toggle"
+// Because of the transition CSS, better wait a second before checking.
+wait-for: 1000
+assert-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
+assert-css: (".sidebar > *:not(#sidebar-toggle)", {"visibility": "visible", "opacity": 1})
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
index 375ff4878e5..ad7080c39b8 100644
--- a/src/test/rustdoc-gui/source-code-page.goml
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -14,3 +14,6 @@ assert-attribute: (".line-numbers > span:nth-child(6)", {"class": "line-highligh
 assert-attribute-false: (".line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
 // This is to ensure that the content is correctly align with the line numbers.
 compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
+
+// Assert that the line numbers text is aligned to the right.
+assert-css: (".line-numbers", {"text-align": "right"})
diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml
index b5026923001..ee6bc3cf767 100644
--- a/src/test/rustdoc-gui/toggle-docs-mobile.goml
+++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml
@@ -14,7 +14,7 @@ assert-attribute: (".top-doc", {"open": ""})
 // Assert the position of the toggle on the top doc block.
 assert-position: (".top-doc summary::before", {"x": 4})
 // Assert the position of the toggle on the impl block.
-assert-position: ("#implementations + details > summary::before", {"x": 4})
+assert-position: ("#implementations-list > details > summary::before", {"x": 4})
 // Assert the position of the toggle on a method.
 assert-position: (
     "#trait-implementations-list .impl-items .method-toggle > summary::before",
diff --git a/src/test/rustdoc-gui/toggle-docs.goml b/src/test/rustdoc-gui/toggle-docs.goml
index 477105193d3..bbc85ecd4ad 100644
--- a/src/test/rustdoc-gui/toggle-docs.goml
+++ b/src/test/rustdoc-gui/toggle-docs.goml
@@ -17,14 +17,21 @@ assert-text: ("#toggle-all-docs", "[−]")
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 // We first check that everything is visible.
 assert-text: ("#toggle-all-docs", "[−]")
-assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("#implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("#trait-implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute-false: (
+    "#blanket-implementations-list > details.rustdoc-toggle",
+    {"open": ""},
+    ALL,
+)
+
 // We collapse them all.
 click: "#toggle-all-docs"
 wait-for: 50
 assert-text: ("#toggle-all-docs", "[+]")
 // We check that all <details> are collapsed (except for the impl block ones).
 assert-attribute-false: ("details.rustdoc-toggle:not(.implementors-toggle)", {"open": ""}, ALL)
-assert-attribute: ("details.rustdoc-toggle.implementors-toggle", {"open": ""})
+assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""})
 // We now check that the other impl blocks are collapsed.
 assert-attribute-false: (
     "#blanket-implementations-list > details.rustdoc-toggle.implementors-toggle",
diff --git a/src/test/rustdoc-json/fns/generics.rs b/src/test/rustdoc-json/fns/generics.rs
new file mode 100644
index 00000000000..e777fabaa52
--- /dev/null
+++ b/src/test/rustdoc-json/fns/generics.rs
@@ -0,0 +1,26 @@
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![no_core]
+
+// @set wham_id = generics.json "$.index[*][?(@.name=='Wham')].id"
+pub trait Wham {}
+
+// @is    - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.where_predicates" []
+// @count - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[*]" 1
+// @is    - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].name" '"T"'
+// @has   - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" false
+// @has   - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" $wham_id
+// @is    - "$.index[*][?(@.name=='one_generic_param_fn')].inner.decl.inputs" '[["w", {"inner": "T", "kind": "generic"}]]'
+pub fn one_generic_param_fn<T: Wham>(w: T) {}
+
+// @is    - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.where_predicates" []
+// @count - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[*]" 1
+// @is    - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].name" '"impl Wham"'
+// @has   - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" true
+// @has   - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" $wham_id
+// @count - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[*]" 1
+// @is    - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][0]" '"w"'
+// @is    - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].kind" '"impl_trait"'
+// @is    - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.inner.id" $wham_id
+pub fn one_synthetic_generic_param_fn(w: impl Wham) {}
diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs
index b018dd6cda5..84c9e4ac0cd 100644
--- a/src/test/rustdoc/duplicate_impls/issue-33054.rs
+++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs
@@ -1,8 +1,10 @@
+// ignore-tidy-linelength
+
 // @has issue_33054/impls/struct.Foo.html
 // @has - '//h3[@class="code-header in-band"]' 'impl Foo'
 // @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
 // @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @count - '//*[@id="main-content"]/details/summary/*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1
 // @has issue_33054/impls/bar/trait.Bar.html
 // @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
 // @count - '//*[@class="struct"]' 1
diff --git a/src/test/ui/associated-consts/defaults-cyclic-fail.rs b/src/test/ui/associated-consts/defaults-cyclic-fail.rs
index 9fb1bbebc96..2f1858d39b3 100644
--- a/src/test/ui/associated-consts/defaults-cyclic-fail.rs
+++ b/src/test/ui/associated-consts/defaults-cyclic-fail.rs
@@ -1,5 +1,5 @@
 // build-fail
-//~^ ERROR cycle detected when normalizing `<() as Tr>::A`
+//~^ ERROR cycle detected when normalizing `<() as Tr>::A` [E0391]
 
 // Cyclic assoc. const defaults don't error unless *used*
 trait Tr {
diff --git a/src/test/ui/associated-types/issue-59324.rs b/src/test/ui/associated-types/issue-59324.rs
index 9e68e9e7751..162f9e00edd 100644
--- a/src/test/ui/associated-types/issue-59324.rs
+++ b/src/test/ui/associated-types/issue-59324.rs
@@ -15,9 +15,9 @@ pub trait ThriftService<Bug: NotFoo>:
 {
     fn get_service(
     //~^ ERROR the trait bound `Bug: Foo` is not satisfied
-    //~| ERROR the trait bound `Bug: Foo` is not satisfied
         &self,
     ) -> Self::AssocType;
+    //~^ the trait bound `Bug: Foo` is not satisfied
 }
 
 fn with_factory<H>(factory: dyn ThriftService<()>) {}
diff --git a/src/test/ui/associated-types/issue-59324.stderr b/src/test/ui/associated-types/issue-59324.stderr
index 2f430d3055e..45d2dfb5375 100644
--- a/src/test/ui/associated-types/issue-59324.stderr
+++ b/src/test/ui/associated-types/issue-59324.stderr
@@ -6,7 +6,7 @@ LL | |
 LL | |
 LL | |     Service<AssocType = <Bug as Foo>::OnlyFoo>
 ...  |
-LL | |     ) -> Self::AssocType;
+LL | |
 LL | | }
    | |_^ the trait `Foo` is not implemented for `Bug`
    |
@@ -23,7 +23,7 @@ LL | |
 LL | |
 LL | |     Service<AssocType = <Bug as Foo>::OnlyFoo>
 ...  |
-LL | |     ) -> Self::AssocType;
+LL | |
 LL | | }
    | |_^ the trait `Foo` is not implemented for `Bug`
    |
@@ -37,7 +37,6 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied
    |
 LL | /     fn get_service(
 LL | |
-LL | |
 LL | |         &self,
 LL | |     ) -> Self::AssocType;
    | |_________________________^ the trait `Foo` is not implemented for `Bug`
@@ -48,10 +47,10 @@ LL | pub trait ThriftService<Bug: NotFoo + Foo>:
    |                                     +++++
 
 error[E0277]: the trait bound `Bug: Foo` is not satisfied
-  --> $DIR/issue-59324.rs:16:8
+  --> $DIR/issue-59324.rs:19:10
    |
-LL |     fn get_service(
-   |        ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+LL |     ) -> Self::AssocType;
+   |          ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
    |
 help: consider further restricting this bound
    |
diff --git a/src/test/ui/async-await/await-into-future.rs b/src/test/ui/async-await/await-into-future.rs
index b74b1684440..6e1b155e181 100644
--- a/src/test/ui/async-await/await-into-future.rs
+++ b/src/test/ui/async-await/await-into-future.rs
@@ -10,9 +10,9 @@ struct AwaitMe;
 
 impl IntoFuture for AwaitMe {
     type Output = i32;
-    type Future = Pin<Box<dyn Future<Output = i32>>>;
+    type IntoFuture = Pin<Box<dyn Future<Output = i32>>>;
 
-    fn into_future(self) -> Self::Future {
+    fn into_future(self) -> Self::IntoFuture {
         Box::pin(me())
     }
 }
diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
index 8fb570d6756..35f9c581c7b 100644
--- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
+++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
@@ -4,7 +4,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | async fn foo() {}
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -13,7 +13,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | fn baz() { async fn foo() {} }
    |            ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -22,7 +22,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | async fn async_baz() {
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -31,7 +31,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |     async fn bar() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -40,7 +40,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |     async fn foo() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -49,7 +49,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |     async fn foo() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -58,7 +58,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |         async fn bar() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -67,7 +67,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |         async fn foo() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -76,7 +76,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |             async fn bar() {}
    |             ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0706]: functions in traits cannot be declared `async`
diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.rs b/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.rs
new file mode 100644
index 00000000000..4919e0a051d
--- /dev/null
+++ b/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.rs
@@ -0,0 +1,47 @@
+// rustc-env:CARGO=/usr/bin/cargo
+
+use std::pin::Pin;
+use std::future::Future;
+
+fn main() {}
+
+fn await_on_struct_missing() {
+    struct S;
+    let x = S;
+    x.await;
+    //~^ ERROR no field `await` on type
+    //~| NOTE unknown field
+    //~| NOTE to `.await` a `Future`, switch to Rust 2018
+    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_struct_similar() {
+    struct S {
+        awai: u8,
+    }
+    let x = S { awai: 42 };
+    x.await;
+    //~^ ERROR no field `await` on type
+    //~| HELP a field with a similar name exists
+    //~| NOTE to `.await` a `Future`, switch to Rust 2018
+    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_63533(x: Pin<&mut dyn Future<Output = ()>>) {
+    x.await;
+    //~^ ERROR no field `await` on type
+    //~| NOTE unknown field
+    //~| NOTE to `.await` a `Future`, switch to Rust 2018
+    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_apit(x: impl Future<Output = ()>) {
+    x.await;
+    //~^ ERROR no field `await` on type
+    //~| NOTE to `.await` a `Future`, switch to Rust 2018
+    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.stderr
new file mode 100644
index 00000000000..409eb179e83
--- /dev/null
+++ b/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.stderr
@@ -0,0 +1,43 @@
+error[E0609]: no field `await` on type `await_on_struct_missing::S`
+  --> $DIR/suggest-switching-edition-on-await-cargo.rs:11:7
+   |
+LL |     x.await;
+   |       ^^^^^ unknown field
+   |
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
+   = help: set `edition = "2021"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `await_on_struct_similar::S`
+  --> $DIR/suggest-switching-edition-on-await-cargo.rs:24:7
+   |
+LL |     x.await;
+   |       ^^^^^ help: a field with a similar name exists: `awai`
+   |
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
+   = help: set `edition = "2021"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>`
+  --> $DIR/suggest-switching-edition-on-await-cargo.rs:33:7
+   |
+LL |     x.await;
+   |       ^^^^^ unknown field
+   |
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
+   = help: set `edition = "2021"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `impl Future<Output = ()>`
+  --> $DIR/suggest-switching-edition-on-await-cargo.rs:42:7
+   |
+LL |     x.await;
+   |       ^^^^^
+   |
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
+   = help: set `edition = "2021"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0609`.
diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.rs b/src/test/ui/async-await/suggest-switching-edition-on-await.rs
index f2e0fb19c63..9852e8fc918 100644
--- a/src/test/ui/async-await/suggest-switching-edition-on-await.rs
+++ b/src/test/ui/async-await/suggest-switching-edition-on-await.rs
@@ -10,7 +10,7 @@ fn await_on_struct_missing() {
     //~^ ERROR no field `await` on type
     //~| NOTE unknown field
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP pass `--edition 2021` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -23,7 +23,7 @@ fn await_on_struct_similar() {
     //~^ ERROR no field `await` on type
     //~| HELP a field with a similar name exists
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP pass `--edition 2021` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -32,7 +32,7 @@ fn await_on_63533(x: Pin<&mut dyn Future<Output = ()>>) {
     //~^ ERROR no field `await` on type
     //~| NOTE unknown field
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP pass `--edition 2021` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -40,6 +40,6 @@ fn await_on_apit(x: impl Future<Output = ()>) {
     x.await;
     //~^ ERROR no field `await` on type
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP pass `--edition 2021` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr
index b38c897fc74..ef3334381b7 100644
--- a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr
+++ b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr
@@ -5,7 +5,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0609]: no field `await` on type `await_on_struct_similar::S`
@@ -15,7 +15,7 @@ LL |     x.await;
    |       ^^^^^ help: a field with a similar name exists: `awai`
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>`
@@ -25,7 +25,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0609]: no field `await` on type `impl Future<Output = ()>`
@@ -35,7 +35,7 @@ LL |     x.await;
    |       ^^^^^
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr
index e2c80732414..d88185af778 100644
--- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr
+++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr
@@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard
   --> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:18
    |
 LL |                 (|| { let bar = foo; bar.take() })();
-   |                  ^^             ---
-   |                  |              |
-   |                  |              move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
-   |                  |              move occurs due to use in closure
+   |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                  |
    |                  move out of `foo` occurs here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr
index e2c80732414..d88185af778 100644
--- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr
+++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr
@@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard
   --> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:18
    |
 LL |                 (|| { let bar = foo; bar.take() })();
-   |                  ^^             ---
-   |                  |              |
-   |                  |              move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
-   |                  |              move occurs due to use in closure
+   |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                  |
    |                  move out of `foo` occurs here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr
index 257ec3fbb7f..f81b34a641b 100644
--- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr
+++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr
@@ -8,8 +8,8 @@ LL |       let _g = to_fn_mut(|| {
 LL | |         let _h = to_fn_once(move || -> isize { *bar });
    | |                             ^^^^^^^^^^^^^^^^   ----
    | |                             |                  |
+   | |                             |                  variable moved due to use in closure
    | |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
-   | |                             |                  move occurs due to use in closure
    | |                             move out of `bar` occurs here
 LL | |     });
    | |_____- captured by this `FnMut` closure
diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr
index 79745065070..800f30b34e5 100644
--- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr
@@ -2,7 +2,16 @@ error[E0507]: cannot move out of an `Rc`
   --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14
    |
 LL |     let _x = Rc::new(vec![1, 2]).into_iter();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+   |              ^^^^^^^^^^^^^^^^^^^^-----------
+   |              |                   |
+   |              |                   value moved due to this method call
+   |              move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+   |
+note: this function takes ownership of the receiver `self`, which moves value
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/copy-suggestion-region-vid.rs b/src/test/ui/borrowck/copy-suggestion-region-vid.rs
new file mode 100644
index 00000000000..dff95283459
--- /dev/null
+++ b/src/test/ui/borrowck/copy-suggestion-region-vid.rs
@@ -0,0 +1,17 @@
+pub struct DataStruct();
+
+pub struct HelperStruct<'n> {
+    pub helpers: [Vec<&'n i64>; 2],
+    pub is_empty: bool,
+}
+
+impl DataStruct {
+    pub fn f(&self) -> HelperStruct {
+        let helpers = [vec![], vec![]];
+
+        HelperStruct { helpers, is_empty: helpers[0].is_empty() }
+        //~^ ERROR borrow of moved value
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/copy-suggestion-region-vid.stderr b/src/test/ui/borrowck/copy-suggestion-region-vid.stderr
new file mode 100644
index 00000000000..f03cdd84d75
--- /dev/null
+++ b/src/test/ui/borrowck/copy-suggestion-region-vid.stderr
@@ -0,0 +1,14 @@
+error[E0382]: borrow of moved value: `helpers`
+  --> $DIR/copy-suggestion-region-vid.rs:12:43
+   |
+LL |         let helpers = [vec![], vec![]];
+   |             ------- move occurs because `helpers` has type `[Vec<&i64>; 2]`, which does not implement the `Copy` trait
+LL | 
+LL |         HelperStruct { helpers, is_empty: helpers[0].is_empty() }
+   |                        -------            ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
+   |                        |
+   |                        value moved here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr b/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr
index 540f7f8a484..c4ce7e62fda 100644
--- a/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr
+++ b/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr
@@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard
   --> $DIR/issue-27282-mutation-in-guard.rs:6:18
    |
 LL |                 (|| { let bar = foo; bar.take() })();
-   |                  ^^             ---
-   |                  |              |
-   |                  |              move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
-   |                  |              move occurs due to use in closure
+   |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                  |
    |                  move out of `foo` occurs here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
diff --git a/src/test/ui/borrowck/issue-88434-minimal-example.rs b/src/test/ui/borrowck/issue-88434-minimal-example.rs
index db348a50aa4..632f8dc3ad6 100644
--- a/src/test/ui/borrowck/issue-88434-minimal-example.rs
+++ b/src/test/ui/borrowck/issue-88434-minimal-example.rs
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 // Regression test related to issue 88434
 
 const _CONST: &() = &f(&|_| {});
diff --git a/src/test/ui/borrowck/issue-88434-minimal-example.stderr b/src/test/ui/borrowck/issue-88434-minimal-example.stderr
index 845e1bdba8f..d9635e1ee46 100644
--- a/src/test/ui/borrowck/issue-88434-minimal-example.stderr
+++ b/src/test/ui/borrowck/issue-88434-minimal-example.stderr
@@ -1,14 +1,14 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-88434-minimal-example.rs:10:5
+  --> $DIR/issue-88434-minimal-example.rs:9:5
    |
 LL | const _CONST: &() = &f(&|_| {});
-   |                      ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:4:22
+   |                      ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:3:22
 ...
 LL |     panic!()
    |     ^^^^^^^^
    |     |
-   |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:10:5
-   |     inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:4:25: 4:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+   |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:9:5
+   |     inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.rs b/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.rs
index 4db073c66b1..f0a6dcd4eb3 100644
--- a/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.rs
+++ b/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.rs
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 // Regression test for issue 88434
 
 const _CONST: &[u8] = &f(&[], |_| {});
diff --git a/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr b/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
index 8cbb6a6340c..44e244ae9cc 100644
--- a/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
+++ b/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
@@ -1,14 +1,14 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5
+  --> $DIR/issue-88434-removal-index-should-be-less.rs:9:5
    |
 LL | const _CONST: &[u8] = &f(&[], |_| {});
-   |                        -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:4:24
+   |                        -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:3:24
 ...
 LL |     panic!()
    |     ^^^^^^^^
    |     |
-   |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:10:5
-   |     inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:4:31: 4:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+   |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:9:5
+   |     inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
index 1663ce81d6c..3ea72262003 100644
--- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
+++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
@@ -6,10 +6,18 @@ LL |       let y = vec![format!("World")];
 LL |       call(|| {
    |  __________-
 LL | |         y.into_iter();
-   | |         ^ move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
+   | |         ^ ----------- `y` moved due to this method call
+   | |         |
+   | |         move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
 LL | |
 LL | |     });
    | |_____- captured by this `Fn` closure
+   |
+note: this function takes ownership of the receiver `self`, which moves `y`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/box/large-allocator-ice.rs b/src/test/ui/box/large-allocator-ice.rs
index 3ef1171ff50..b3a882ff089 100644
--- a/src/test/ui/box/large-allocator-ice.rs
+++ b/src/test/ui/box/large-allocator-ice.rs
@@ -1,5 +1,6 @@
 // build-pass
 #![feature(allocator_api)]
+#![allow(unused_must_use)]
 
 use std::alloc::Allocator;
 
@@ -20,4 +21,9 @@ unsafe impl Allocator for BigAllocator {
 fn main() {
     Box::new_in((), &std::alloc::Global);
     Box::new_in((), BigAllocator([0; 2]));
+    generic_function(0);
+}
+
+fn generic_function<T>(val: T) {
+    *Box::new_in(val, &std::alloc::Global);
 }
diff --git a/src/test/ui/cast/fat-ptr-cast.rs b/src/test/ui/cast/fat-ptr-cast.rs
index a0fad583a16..b5276dc619b 100644
--- a/src/test/ui/cast/fat-ptr-cast.rs
+++ b/src/test/ui/cast/fat-ptr-cast.rs
@@ -19,6 +19,15 @@ fn main() {
     q as *const [i32]; //~ ERROR cannot cast
 
     // #21397
-    let t: *mut (dyn Trait + 'static) = 0 as *mut _; //~ ERROR casting
-    let mut fail: *const str = 0 as *const str; //~ ERROR casting
+    let t: *mut (dyn Trait + 'static) = 0 as *mut _;
+    //~^ ERROR cannot cast `usize` to a pointer that is wide
+    let mut fail: *const str = 0 as *const str;
+    //~^ ERROR cannot cast `usize` to a pointer that is wide
+    let mut fail2: *const str = 0isize as *const str;
+    //~^ ERROR cannot cast `isize` to a pointer that is wide
+}
+
+fn foo<T: ?Sized>() {
+    let s = 0 as *const T;
+    //~^ ERROR cannot cast `usize` to a pointer that may be wide
 }
diff --git a/src/test/ui/cast/fat-ptr-cast.stderr b/src/test/ui/cast/fat-ptr-cast.stderr
index 0b0c288fe3b..18e7b68ff3c 100644
--- a/src/test/ui/cast/fat-ptr-cast.stderr
+++ b/src/test/ui/cast/fat-ptr-cast.stderr
@@ -50,19 +50,39 @@ error[E0607]: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]
 LL |     q as *const [i32];
    |     ^^^^^^^^^^^^^^^^^
 
-error[E0606]: casting `usize` as `*mut (dyn Trait + 'static)` is invalid
-  --> $DIR/fat-ptr-cast.rs:22:41
+error[E0606]: cannot cast `usize` to a pointer that is wide
+  --> $DIR/fat-ptr-cast.rs:22:46
    |
 LL |     let t: *mut (dyn Trait + 'static) = 0 as *mut _;
-   |                                         ^^^^^^^^^^^
+   |                                         -    ^^^^^^ creating a `*mut (dyn Trait + 'static)` requires both an address and a vtable
+   |                                         |
+   |                                         consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
 
-error[E0606]: casting `usize` as `*const str` is invalid
-  --> $DIR/fat-ptr-cast.rs:23:32
+error[E0606]: cannot cast `usize` to a pointer that is wide
+  --> $DIR/fat-ptr-cast.rs:24:37
    |
 LL |     let mut fail: *const str = 0 as *const str;
-   |                                ^^^^^^^^^^^^^^^
+   |                                -    ^^^^^^^^^^ creating a `*const str` requires both an address and a length
+   |                                |
+   |                                consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
 
-error: aborting due to 9 previous errors
+error[E0606]: cannot cast `isize` to a pointer that is wide
+  --> $DIR/fat-ptr-cast.rs:26:43
+   |
+LL |     let mut fail2: *const str = 0isize as *const str;
+   |                                 ------    ^^^^^^^^^^ creating a `*const str` requires both an address and a length
+   |                                 |
+   |                                 consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+
+error[E0606]: cannot cast `usize` to a pointer that may be wide
+  --> $DIR/fat-ptr-cast.rs:31:18
+   |
+LL |     let s = 0 as *const T;
+   |             -    ^^^^^^^^ creating a `*const T` requires both an address and type-specific metadata
+   |             |
+   |             consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+
+error: aborting due to 11 previous errors
 
 Some errors have detailed explanations: E0605, E0606, E0607.
 For more information about an error, try `rustc --explain E0605`.
diff --git a/src/test/ui/check-cfg/well-known-names.rs b/src/test/ui/check-cfg/well-known-names.rs
index a66568a2ffd..e57fb69a1e0 100644
--- a/src/test/ui/check-cfg/well-known-names.rs
+++ b/src/test/ui/check-cfg/well-known-names.rs
@@ -24,4 +24,10 @@ fn unix_misspell() {}
 #[cfg(unix)]
 fn unix() {}
 
+#[cfg(miri)]
+fn miri() {}
+
+#[cfg(doc)]
+fn doc() {}
+
 fn main() {}
diff --git a/src/test/ui/check-cfg/well-known-values.rs b/src/test/ui/check-cfg/well-known-values.rs
index 46004be43d8..96375dc8d31 100644
--- a/src/test/ui/check-cfg/well-known-values.rs
+++ b/src/test/ui/check-cfg/well-known-values.rs
@@ -25,4 +25,18 @@ fn unix_with_value() {}
 #[cfg(unix)]
 fn unix() {}
 
+#[cfg(miri = "miri")]
+//~^ WARNING unexpected `cfg` condition value
+fn miri_with_value() {}
+
+#[cfg(miri)]
+fn miri() {}
+
+#[cfg(doc = "linux")]
+//~^ WARNING unexpected `cfg` condition value
+fn doc_with_value() {}
+
+#[cfg(doc)]
+fn doc() {}
+
 fn main() {}
diff --git a/src/test/ui/check-cfg/well-known-values.stderr b/src/test/ui/check-cfg/well-known-values.stderr
index 8eefd6aaf35..8b04c770fb5 100644
--- a/src/test/ui/check-cfg/well-known-values.stderr
+++ b/src/test/ui/check-cfg/well-known-values.stderr
@@ -29,5 +29,25 @@ LL | #[cfg(unix = "aa")]
    |
    = note: no expected value for `unix`
 
-warning: 3 warnings emitted
+warning: unexpected `cfg` condition value
+  --> $DIR/well-known-values.rs:28:7
+   |
+LL | #[cfg(miri = "miri")]
+   |       ^^^^---------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `miri`
+
+warning: unexpected `cfg` condition value
+  --> $DIR/well-known-values.rs:35:7
+   |
+LL | #[cfg(doc = "linux")]
+   |       ^^^----------
+   |          |
+   |          help: remove the value
+   |
+   = note: no expected value for `doc`
+
+warning: 5 warnings emitted
 
diff --git a/src/test/ui/closures/2229_closure_analysis/match/issue-88331.stderr b/src/test/ui/closures/2229_closure_analysis/match/issue-88331.stderr
index f02d23464f1..7e22defa98d 100644
--- a/src/test/ui/closures/2229_closure_analysis/match/issue-88331.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/match/issue-88331.stderr
@@ -1,26 +1,38 @@
 error[E0004]: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
   --> $DIR/issue-88331.rs:11:20
    |
-LL | pub struct Opcode(pub u8);
-   | -------------------------- `Opcode` defined here
-...
 LL |     move |i| match msg_type {
    |                    ^^^^^^^^ patterns `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opcode` defined here
+  --> $DIR/issue-88331.rs:4:12
+   |
+LL | pub struct Opcode(pub u8);
+   |            ^^^^^^
    = note: the matched value is of type `Opcode`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Opcode::OP1 => unimplemented!(),
+LL ~         Opcode(0_u8) | Opcode(2_u8..=u8::MAX) => todo!(),
+   |
 
 error[E0004]: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
   --> $DIR/issue-88331.rs:27:20
    |
-LL | pub struct Opcode2(Opcode);
-   | --------------------------- `Opcode2` defined here
-...
 LL |     move |i| match msg_type {
    |                    ^^^^^^^^ patterns `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opcode2` defined here
+  --> $DIR/issue-88331.rs:18:12
+   |
+LL | pub struct Opcode2(Opcode);
+   |            ^^^^^^^
    = note: the matched value is of type `Opcode2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Opcode2::OP2=> unimplemented!(),
+LL ~         Opcode2(Opcode(0_u8)) | Opcode2(Opcode(2_u8..=u8::MAX)) => todo!(),
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
index 91ffe1a47f4..32d36274ff6 100644
--- a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
@@ -1,17 +1,19 @@
 error[E0004]: non-exhaustive patterns: `B` not covered
   --> $DIR/non-exhaustive-match.rs:26:25
    |
-LL | enum L1 { A, B }
-   | ----------------
-   | |            |
-   | |            not covered
-   | `L1` defined here
-...
 LL |     let _b = || { match l1 { L1::A => () } };
    |                         ^^ pattern `B` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `L1` defined here
+  --> $DIR/non-exhaustive-match.rs:12:14
+   |
+LL | enum L1 { A, B }
+   |      --      ^ not covered
    = note: the matched value is of type `L1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     let _b = || { match l1 { L1::A => (), B => todo!() } };
+   |                                         ++++++++++++++
 
 error[E0004]: non-exhaustive patterns: type `E1` is non-empty
   --> $DIR/non-exhaustive-match.rs:37:25
@@ -19,8 +21,18 @@ error[E0004]: non-exhaustive patterns: type `E1` is non-empty
 LL |     let _d = || { match e1 {} };
    |                         ^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E1` defined here
+  --> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1
+   |
+LL | pub enum E1 {}
+   | ^^^^^^^^^^^^^^
    = note: the matched value is of type `E1`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     let _d = || { match e1 {
+LL +         _ => todo!(),
+LL ~     } };
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/non-exhaustive-match.rs:39:25
@@ -28,8 +40,16 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     let _e = || { match e2 { E2::A => (), E2::B => () } };
    |                         ^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E2` defined here
+  --> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1
+   |
+LL | pub enum E2 { A, B }
+   | ^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `E2`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     let _e = || { match e2 { E2::A => (), E2::B => (), _ => todo!() } };
+   |                                                      ++++++++++++++
 
 error[E0505]: cannot move out of `e3` because it is borrowed
   --> $DIR/non-exhaustive-match.rs:46:22
diff --git a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
index 45641ea3de3..e55fb7ce4bb 100644
--- a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
@@ -4,8 +4,13 @@ error[E0004]: non-exhaustive patterns: type `u8` is non-empty
 LL |     let c1 = || match x { };
    |                       ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     let c1 = || match x {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error[E0381]: use of possibly-uninitialized variable: `x`
   --> $DIR/pattern-matching-should-fail.rs:8:23
diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs
index 9e4521df8c3..bbc039bdf5c 100644
--- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs
+++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs
@@ -7,6 +7,7 @@
 pub trait Sized { }
 #[lang="copy"]
 pub trait Copy { }
+impl Copy for u32 {}
 
 extern "rust-intrinsic" {
     pub fn transmute<T, U>(e: T) -> U;
diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs
index d5c67af2b41..b8112b20a54 100644
--- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs
+++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs
@@ -7,6 +7,7 @@
 pub trait Sized { }
 #[lang="copy"]
 pub trait Copy { }
+impl Copy for u32 {}
 
 extern "rust-intrinsic" {
     pub fn transmute<T, U>(e: T) -> U;
diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs b/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs
index 8cde9ba58b9..5591a8a5864 100644
--- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs
+++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs
@@ -7,6 +7,7 @@
 trait Sized { }
 #[lang="copy"]
 trait Copy { }
+impl Copy for u32 {}
 
 #[no_mangle]
 #[cmse_nonsecure_entry]
diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs b/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs
index 9a1b0a38d5e..39b41dac41f 100644
--- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs
+++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs
@@ -7,6 +7,7 @@
 trait Sized { }
 #[lang="copy"]
 trait Copy { }
+impl Copy for u32 {}
 
 #[no_mangle]
 #[cmse_nonsecure_entry]
diff --git a/src/test/ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs b/src/test/ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs
new file mode 100644
index 00000000000..df454dae725
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs
@@ -0,0 +1,21 @@
+#![feature(generic_const_exprs)]
+
+use std::str::FromStr;
+
+pub struct If<const CONDITION: bool>;
+
+pub trait True {}
+
+impl True for If<true> {}
+
+pub struct FixedI32<const FRAC: u32>;
+
+impl<const FRAC: u32> FromStr for FixedI32<FRAC>
+where
+    If<{ FRAC <= 32 }>: True,
+{
+    type Err = ();
+    fn from_str(_s: &str) -> Result<Self, Self::Err> {
+        unimplemented!()
+    }
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-85848.rs b/src/test/ui/const-generics/generic_const_exprs/issue-85848.rs
index 771e68b0db5..e86ffbf1075 100644
--- a/src/test/ui/const-generics/generic_const_exprs/issue-85848.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-85848.rs
@@ -1,4 +1,4 @@
-#![feature(const_fn_trait_bound, generic_const_exprs)]
+#![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 
 trait _Contains<T> {
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-94287.rs b/src/test/ui/const-generics/generic_const_exprs/issue-94287.rs
new file mode 100644
index 00000000000..643126a4640
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-94287.rs
@@ -0,0 +1,10 @@
+// aux-build:issue-94287-aux.rs
+// build-fail
+
+extern crate issue_94287_aux;
+
+use std::str::FromStr;
+
+fn main() {
+    let _ = <issue_94287_aux::FixedI32<16>>::from_str("");
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr
new file mode 100644
index 00000000000..c918651ba62
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr
@@ -0,0 +1,14 @@
+error: failed to evaluate generic const expression
+  --> $DIR/auxiliary/issue-94287-aux.rs:15:8
+   |
+LL |     If<{ FRAC <= 32 }>: True,
+   |        ^^^^^^^^^^^^^^
+   |
+   = note: the crate this constant originates from uses `#![feature(generic_const_exprs)]`
+help: consider enabling this feature
+   |
+LL | #![feature(generic_const_exprs)]
+   |
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-79674.rs b/src/test/ui/const-generics/issues/issue-79674.rs
index 2f196533dd8..ff141d328e6 100644
--- a/src/test/ui/const-generics/issues/issue-79674.rs
+++ b/src/test/ui/const-generics/issues/issue-79674.rs
@@ -1,4 +1,4 @@
-#![feature(const_fn_trait_bound, generic_const_exprs)]
+#![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 
 trait MiniTypeId {
diff --git a/src/test/ui/consts/auxiliary/const_fn_lib.rs b/src/test/ui/consts/auxiliary/const_fn_lib.rs
index bf0b01a2ecf..88cea60e1b8 100644
--- a/src/test/ui/consts/auxiliary/const_fn_lib.rs
+++ b/src/test/ui/consts/auxiliary/const_fn_lib.rs
@@ -1,6 +1,5 @@
 // Crate that exports a const fn. Used for testing cross-crate.
 
-#![feature(const_fn_fn_ptr_basics)]
 #![crate_type="rlib"]
 
 pub const fn foo() -> usize { 22 }
diff --git a/src/test/ui/consts/const-block-const-bound.rs b/src/test/ui/consts/const-block-const-bound.rs
index f3c82c5f968..1ccd0ee9370 100644
--- a/src/test/ui/consts/const-block-const-bound.rs
+++ b/src/test/ui/consts/const-block-const-bound.rs
@@ -1,5 +1,5 @@
 #![allow(unused)]
-#![feature(const_fn_trait_bound, const_trait_impl, inline_const, negative_impls)]
+#![feature(const_trait_impl, inline_const, negative_impls)]
 
 const fn f<T: ~const Drop>(x: T) {}
 
diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.rs b/src/test/ui/consts/const-eval/const-eval-query-stack.rs
index 8c3959cc11a..e73e54ff5f1 100644
--- a/src/test/ui/consts/const-eval/const-eval-query-stack.rs
+++ b/src/test/ui/consts/const-eval/const-eval-query-stack.rs
@@ -1,5 +1,5 @@
-//~ERROR constructed but no error reported
 // compile-flags: -Ztreat-err-as-bug=2
+//~^ ERROR 1:1: 1:1: ty::ConstKind::Error constructed but no error reported
 // build-fail
 // failure-status: 101
 // rustc-env:RUST_BACKTRACE=1
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.stderr b/src/test/ui/consts/const-eval/const_fn_ptr.stderr
index a16ac7b2a24..ca1585f8837 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr.stderr
@@ -10,23 +10,11 @@ help: skipping check that does not even have a feature gate
    |
 LL |     X_CONST(x)
    |     ^^^^^^^^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr.rs:18:14
-   |
-LL | const fn foo(x: fn(usize) -> usize, y: usize)  -> usize {
-   |              ^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr.rs:19:5
-   |
-LL |     x(y)
-   |     ^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_fn_ptr.rs:19:5
    |
 LL |     x(y)
    |     ^^^^
 
-error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
-
-error: aborting due to previous error; 1 warning emitted
+warning: 1 warning emitted
 
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
index 4f7a771f418..c17166263ba 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
@@ -12,16 +12,6 @@ LL |     assert_eq!(Z, 4);
 
 warning: skipping const checks
    |
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr_fail2.rs:11:14
-   |
-LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
-   |              ^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr_fail2.rs:12:5
-   |
-LL |     x(y)
-   |     ^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_fn_ptr_fail2.rs:12:5
    |
diff --git a/src/test/ui/consts/const-eval/issue-49296.rs b/src/test/ui/consts/const-eval/issue-49296.rs
index 80f6bbec2a1..917777a32ff 100644
--- a/src/test/ui/consts/const-eval/issue-49296.rs
+++ b/src/test/ui/consts/const-eval/issue-49296.rs
@@ -1,7 +1,5 @@
 // issue-49296: Unsafe shenigans in constants can result in missing errors
 
-#![feature(const_fn_trait_bound)]
-
 use std::mem::transmute;
 
 const fn wat(x: u64) -> &'static u64 {
diff --git a/src/test/ui/consts/const-eval/issue-49296.stderr b/src/test/ui/consts/const-eval/issue-49296.stderr
index bc3074b10be..1864a284579 100644
--- a/src/test/ui/consts/const-eval/issue-49296.stderr
+++ b/src/test/ui/consts/const-eval/issue-49296.stderr
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-49296.rs:11:16
+  --> $DIR/issue-49296.rs:9:16
    |
 LL | const X: u64 = *wat(42);
    |                ^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
diff --git a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs
index bf8bae5ea2c..abd1d32abe2 100644
--- a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs
+++ b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs
@@ -1,5 +1,4 @@
 // check-pass
-#![feature(const_fn_fn_ptr_basics)]
 
 const fn nested(x: (for<'a> fn(&'a ()), String)) -> (fn(&'static ()), String) {
     x
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
index 46748673067..c7078e46fa6 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
@@ -2,8 +2,6 @@
 
 const extern "C" fn unsize(x: &[u8; 3]) -> &[u8] { x }
 const unsafe extern "C" fn closure() -> fn() { || {} }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
 const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
 //~^ ERROR floating point arithmetic
 const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
index 2b2d23477f6..4bab466fb95 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
@@ -1,23 +1,5 @@
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/const-extern-fn-min-const-fn.rs:4:41
-   |
-LL | const unsafe extern "C" fn closure() -> fn() { || {} }
-   |                                         ^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/const-extern-fn-min-const-fn.rs:4:48
-   |
-LL | const unsafe extern "C" fn closure() -> fn() { || {} }
-   |                                                ^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
 error[E0658]: floating point arithmetic is not allowed in constant functions
-  --> $DIR/const-extern-fn-min-const-fn.rs:7:42
+  --> $DIR/const-extern-fn-min-const-fn.rs:5:42
    |
 LL | const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
    |                                          ^^^^^^^^^
@@ -26,7 +8,7 @@ LL | const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
    = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable
 
 error: pointers cannot be cast to integers during const eval
-  --> $DIR/const-extern-fn-min-const-fn.rs:9:48
+  --> $DIR/const-extern-fn-min-const-fn.rs:7:48
    |
 LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
    |                                                ^^^^^^^^^^^^
@@ -34,6 +16,6 @@ LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
    = note: at compile-time, pointers do not have an integer value
    = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-fn.rs b/src/test/ui/consts/const-fn.rs
index 1928c51885e..59680e6e4a8 100644
--- a/src/test/ui/consts/const-fn.rs
+++ b/src/test/ui/consts/const-fn.rs
@@ -4,7 +4,6 @@
 // A very basic test of const fn functionality.
 
 #![feature(const_indexing)]
-#![feature(const_fn_trait_bound)]
 
 const fn add(x: u32, y: u32) -> u32 {
     x + y
diff --git a/src/test/ui/consts/const-match-check.eval1.stderr b/src/test/ui/consts/const-match-check.eval1.stderr
index 4141cc4ab1a..6e61dbbd8ee 100644
--- a/src/test/ui/consts/const-match-check.eval1.stderr
+++ b/src/test/ui/consts/const-match-check.eval1.stderr
@@ -7,10 +7,10 @@ LL |     A = { let 0 = 0; 0 },
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     A = { if let 0 = 0 { /* */ } 0 },
-   |           ~~~~~~~~~~~~~~~~~~~~~~
+LL |     A = { if let 0 = 0 { todo!() } 0 },
+   |           ++           ~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-match-check.eval2.stderr b/src/test/ui/consts/const-match-check.eval2.stderr
index af86ba0cc82..1b3b6e06c3d 100644
--- a/src/test/ui/consts/const-match-check.eval2.stderr
+++ b/src/test/ui/consts/const-match-check.eval2.stderr
@@ -7,10 +7,10 @@ LL |     let x: [i32; { let 0 = 0; 0 }] = [];
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     let x: [i32; { if let 0 = 0 { /* */ } 0 }] = [];
-   |                    ~~~~~~~~~~~~~~~~~~~~~~
+LL |     let x: [i32; { if let 0 = 0 { todo!() } 0 }] = [];
+   |                    ++           ~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-match-check.matchck.stderr b/src/test/ui/consts/const-match-check.matchck.stderr
index f71490eba61..bc8edfa7af9 100644
--- a/src/test/ui/consts/const-match-check.matchck.stderr
+++ b/src/test/ui/consts/const-match-check.matchck.stderr
@@ -7,10 +7,10 @@ LL | const X: i32 = { let 0 = 0; 0 };
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
-   |                  ~~~~~~~~~~~~~~~~~~~~~~
+LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
+   |                  ++           ~~~~~~~~~~~
 
 error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:8:23
@@ -21,10 +21,10 @@ LL | static Y: i32 = { let 0 = 0; 0 };
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 };
-   |                   ~~~~~~~~~~~~~~~~~~~~~~
+LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 };
+   |                   ++           ~~~~~~~~~~~
 
 error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:13:26
@@ -35,10 +35,10 @@ LL |     const X: i32 = { let 0 = 0; 0 };
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     const X: i32 = { if let 0 = 0 { /* */ } 0 };
-   |                      ~~~~~~~~~~~~~~~~~~~~~~
+LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
+   |                      ++           ~~~~~~~~~~~
 
 error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:19:26
@@ -49,10 +49,10 @@ LL |     const X: i32 = { let 0 = 0; 0 };
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     const X: i32 = { if let 0 = 0 { /* */ } 0 };
-   |                      ~~~~~~~~~~~~~~~~~~~~~~
+LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
+   |                      ++           ~~~~~~~~~~~
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/consts/const_fn_trait_bound.gated.stderr b/src/test/ui/consts/const_fn_trait_bound.gated.stderr
deleted file mode 100644
index ded05cb17c5..00000000000
--- a/src/test/ui/consts/const_fn_trait_bound.gated.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: fatal error triggered by #[rustc_error]
-  --> $DIR/const_fn_trait_bound.rs:17:1
-   |
-LL | fn main() {}
-   | ^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/consts/const_fn_trait_bound.rs b/src/test/ui/consts/const_fn_trait_bound.rs
deleted file mode 100644
index 19c08b62144..00000000000
--- a/src/test/ui/consts/const_fn_trait_bound.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// gate-test-const_fn_trait_bound
-
-// revisions: stock gated
-
-#![feature(rustc_attrs)]
-#![cfg_attr(gated, feature(const_fn_trait_bound))]
-
-const fn test1<T: std::ops::Add>() {}
-//[stock]~^ trait bounds
-const fn test2(_x: &dyn Send) {}
-//[stock]~^ trait objects in const fn are unstable
-const fn test3() -> &'static dyn Send { loop {} }
-//[stock]~^ trait objects in const fn are unstable
-
-
-#[rustc_error]
-fn main() {} //[gated]~ fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/consts/const_fn_trait_bound.stock.stderr b/src/test/ui/consts/const_fn_trait_bound.stock.stderr
deleted file mode 100644
index 7d9e18cb341..00000000000
--- a/src/test/ui/consts/const_fn_trait_bound.stock.stderr
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/const_fn_trait_bound.rs:8:16
-   |
-LL | const fn test1<T: std::ops::Add>() {}
-   |                ^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/const_fn_trait_bound.rs:10:16
-   |
-LL | const fn test2(_x: &dyn Send) {}
-   |                ^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/const_fn_trait_bound.rs:12:21
-   |
-LL | const fn test3() -> &'static dyn Send { loop {} }
-   |                     ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/drop_box.rs b/src/test/ui/consts/drop_box.rs
new file mode 100644
index 00000000000..58a373a9673
--- /dev/null
+++ b/src/test/ui/consts/drop_box.rs
@@ -0,0 +1,4 @@
+const fn f<T>(_: Box<T>) {}
+//~^ ERROR destructors cannot be evaluated at compile-time
+
+fn main() {}
diff --git a/src/test/ui/consts/drop_box.stderr b/src/test/ui/consts/drop_box.stderr
new file mode 100644
index 00000000000..b9d6581e8ec
--- /dev/null
+++ b/src/test/ui/consts/drop_box.stderr
@@ -0,0 +1,11 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop_box.rs:1:15
+   |
+LL | const fn f<T>(_: Box<T>) {}
+   |               ^           - value is dropped here
+   |               |
+   |               constant functions cannot evaluate destructors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/issue-37550-1.rs b/src/test/ui/consts/issue-37550-1.rs
index 35b63bddca2..4d00ac7fd0d 100644
--- a/src/test/ui/consts/issue-37550-1.rs
+++ b/src/test/ui/consts/issue-37550-1.rs
@@ -1,6 +1,8 @@
+// check-pass
+
 const fn x() {
     let t = true;
-    let x = || t; //~ ERROR function pointer
+    let x = || t;
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/issue-37550-1.stderr b/src/test/ui/consts/issue-37550-1.stderr
deleted file mode 100644
index f66d7067870..00000000000
--- a/src/test/ui/consts/issue-37550-1.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/issue-37550-1.rs:3:9
-   |
-LL |     let x = || t;
-   |         ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/issue-37550.rs b/src/test/ui/consts/issue-37550.rs
index 15877c53747..724eb28291e 100644
--- a/src/test/ui/consts/issue-37550.rs
+++ b/src/test/ui/consts/issue-37550.rs
@@ -2,8 +2,6 @@
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-#![feature(const_fn_fn_ptr_basics)]
-
 const fn x() {
     let t = true;
     let x = || t;
diff --git a/src/test/ui/consts/issue-46553.rs b/src/test/ui/consts/issue-46553.rs
index 0a1e835672d..9438df1937b 100644
--- a/src/test/ui/consts/issue-46553.rs
+++ b/src/test/ui/consts/issue-46553.rs
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(const_fn_fn_ptr_basics)]
 #![deny(const_err)]
 
 pub struct Data<T> {
diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs
index 9c673d20b2a..22ac75514f6 100644
--- a/src/test/ui/consts/issue-56164.rs
+++ b/src/test/ui/consts/issue-56164.rs
@@ -1,5 +1,3 @@
-#![feature(const_fn_fn_ptr_basics)]
-
 const fn foo() { (||{})() }
 //~^ ERROR cannot call non-const closure
 
diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr
index 62a7c7db6b8..803424eedf3 100644
--- a/src/test/ui/consts/issue-56164.stderr
+++ b/src/test/ui/consts/issue-56164.stderr
@@ -1,5 +1,5 @@
 error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/issue-56164.rs:3:18
+  --> $DIR/issue-56164.rs:1:18
    |
 LL | const fn foo() { (||{})() }
    |                  ^^^^^^^^
@@ -8,7 +8,7 @@ LL | const fn foo() { (||{})() }
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: function pointers are not allowed in const fn
-  --> $DIR/issue-56164.rs:7:5
+  --> $DIR/issue-56164.rs:5:5
    |
 LL |     input()
    |     ^^^^^^^
diff --git a/src/test/ui/consts/issue-88071.rs b/src/test/ui/consts/issue-88071.rs
index a2d4a642128..1c38c43e6c0 100644
--- a/src/test/ui/consts/issue-88071.rs
+++ b/src/test/ui/consts/issue-88071.rs
@@ -3,7 +3,6 @@
 // regression test for #88071
 
 #![feature(const_btree_new)]
-#![feature(const_fn_trait_bound)]
 
 use std::collections::BTreeMap;
 
diff --git a/src/test/ui/consts/issue-94675.rs b/src/test/ui/consts/issue-94675.rs
new file mode 100644
index 00000000000..0604aab3bcd
--- /dev/null
+++ b/src/test/ui/consts/issue-94675.rs
@@ -0,0 +1,16 @@
+#![feature(const_trait_impl, const_mut_refs)]
+
+struct Foo<'a> {
+    bar: &'a mut Vec<usize>,
+}
+
+impl<'a> Foo<'a> {
+    const fn spam(&mut self, baz: &mut Vec<u32>) {
+        self.bar[0] = baz.len();
+        //~^ ERROR cannot call non-const fn `Vec::<u32>::len` in constant functions
+        //~| ERROR the trait bound `Vec<usize>: ~const IndexMut<usize>` is not satisfied
+        //~| ERROR cannot call non-const operator in constant functions
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-94675.stderr b/src/test/ui/consts/issue-94675.stderr
new file mode 100644
index 00000000000..6665e42835b
--- /dev/null
+++ b/src/test/ui/consts/issue-94675.stderr
@@ -0,0 +1,38 @@
+error[E0015]: cannot call non-const fn `Vec::<u32>::len` in constant functions
+  --> $DIR/issue-94675.rs:9:27
+   |
+LL |         self.bar[0] = baz.len();
+   |                           ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0277]: the trait bound `Vec<usize>: ~const IndexMut<usize>` is not satisfied
+  --> $DIR/issue-94675.rs:9:9
+   |
+LL |         self.bar[0] = baz.len();
+   |         ^^^^^^^^^^^ vector indices are of type `usize` or ranges of `usize`
+   |
+   = help: the trait `~const IndexMut<usize>` is not implemented for `Vec<usize>`
+note: the trait `IndexMut<usize>` is implemented for `Vec<usize>`, but that implementation is not `const`
+  --> $DIR/issue-94675.rs:9:9
+   |
+LL |         self.bar[0] = baz.len();
+   |         ^^^^^^^^^^^
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/issue-94675.rs:9:9
+   |
+LL |         self.bar[0] = baz.len();
+   |         ^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+   |
+LL | impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
deleted file mode 100644
index a0870ea6de3..00000000000
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(rustc_attrs, staged_api, rustc_allow_const_fn_unstable)]
-#![feature(const_fn_fn_ptr_basics)]
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(since="1.0.0", feature = "mep")]
-const fn error(_: fn()) {}
-//~^ ERROR const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(since="1.0.0", feature = "mep")]
-#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
-const fn compiles(_: fn()) {}
-
-fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
deleted file mode 100644
index 3523cab49fd..00000000000
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
-  --> $DIR/allow_const_fn_ptr.rs:7:16
-   |
-LL | const fn error(_: fn()) {}
-   |                ^
-   |
-help: if it is not part of the public API, make this function unstably const
-   |
-LL | #[rustc_const_unstable(feature = "...", issue = "...")]
-   |
-help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
-   |
-LL | #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
-   |
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
index 430e911aacd..2dbc424d3ba 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
@@ -1,13 +1,11 @@
 // run-pass
 #![feature(rustc_allow_const_fn_unstable)]
-#![feature(const_fn_fn_ptr_basics)]
 
 #![feature(rustc_attrs, staged_api)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(since="1.0.0", feature = "mep")]
-#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
 const fn takes_fn_ptr(_: fn()) {}
 
 const FN: fn() = || ();
diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs
deleted file mode 100644
index b68f47f5cbc..00000000000
--- a/src/test/ui/consts/min_const_fn/cast_errors.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-fn main() {}
-
-const fn unsize(x: &[u8; 3]) -> &[u8] { x }
-const fn closure() -> fn() { || {} }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
-const fn closure2() {
-    (|| {}) as fn();
-//~^ ERROR function pointer
-}
-const fn reify(f: fn()) -> unsafe fn() { f }
-//~^ ERROR function pointer
-//~| ERROR function pointer
-//~| ERROR function pointer cast
-const fn reify2() { main as unsafe fn(); }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
diff --git a/src/test/ui/consts/min_const_fn/cast_errors.stderr b/src/test/ui/consts/min_const_fn/cast_errors.stderr
deleted file mode 100644
index fb962bdf906..00000000000
--- a/src/test/ui/consts/min_const_fn/cast_errors.stderr
+++ /dev/null
@@ -1,75 +0,0 @@
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/cast_errors.rs:4:23
-   |
-LL | const fn closure() -> fn() { || {} }
-   |                       ^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/cast_errors.rs:4:30
-   |
-LL | const fn closure() -> fn() { || {} }
-   |                              ^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/cast_errors.rs:8:5
-   |
-LL |     (|| {}) as fn();
-   |     ^^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/cast_errors.rs:11:16
-   |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
-   |                ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/cast_errors.rs:11:28
-   |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
-   |                            ^^^^^^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/cast_errors.rs:11:42
-   |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
-   |                                          ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/cast_errors.rs:15:21
-   |
-LL | const fn reify2() { main as unsafe fn(); }
-   |                     ^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/cast_errors.rs:15:21
-   |
-LL | const fn reify2() { main as unsafe fn(); }
-   |                     ^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/cast_fn.rs b/src/test/ui/consts/min_const_fn/cast_fn.rs
new file mode 100644
index 00000000000..85802a51490
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/cast_fn.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+fn main() {}
+
+const fn unsize(x: &[u8; 3]) -> &[u8] { x }
+const fn closure() -> fn() { || {} }
+const fn closure2() {
+    (|| {}) as fn();
+}
+const fn reify(f: fn()) -> unsafe fn() { f }
+const fn reify2() { main as unsafe fn(); }
diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
index 638ff1d8b9c..e07b269c386 100644
--- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
+++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
@@ -1,6 +1,4 @@
 const fn cmp(x: fn(), y: fn()) -> bool {
-    //~^ ERROR function pointer
-    //~| ERROR function pointer
     unsafe { x == y }
     //~^ ERROR pointers cannot be reliably compared
 }
diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
index 5d8483cd111..3845068d841 100644
--- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
+++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
@@ -1,29 +1,10 @@
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/cmp_fn_pointers.rs:1:14
-   |
-LL | const fn cmp(x: fn(), y: fn()) -> bool {
-   |              ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/cmp_fn_pointers.rs:1:23
-   |
-LL | const fn cmp(x: fn(), y: fn()) -> bool {
-   |                       ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
 error: pointers cannot be reliably compared during const eval
-  --> $DIR/cmp_fn_pointers.rs:4:14
+  --> $DIR/cmp_fn_pointers.rs:2:14
    |
 LL |     unsafe { x == y }
    |              ^^^^^^
    |
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs
index 10347a02074..0bafaf2e81f 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs
@@ -80,11 +80,10 @@ const unsafe fn ret_i32_no_unsafe() -> i32 { 42 }
 const unsafe fn ret_null_ptr_no_unsafe<T>() -> *const T { core::ptr::null() }
 const unsafe fn ret_null_mut_ptr_no_unsafe<T>() -> *mut T { core::ptr::null_mut() }
 
-// not ok
 const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
 const fn foo11_2<T: Send>(t: T) -> T { t }
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+
+// not ok
 
 static BAR: u32 = 42;
 const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics
@@ -108,41 +107,28 @@ const fn foo37(a: bool, b: bool) -> bool { a || b }
 fn main() {}
 
 impl<T: std::fmt::Debug> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
     const fn foo(&self) {}
 }
 
 impl<T: std::fmt::Debug + Sized> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
     const fn foo2(&self) {}
 }
 
 impl<T: Sync + Sized> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
     const fn foo3(&self) {}
 }
 
 struct AlanTuring<T>(T);
 const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
-//~^ ERROR trait bounds other than `Sized`
-//~| ERROR destructor
+//~^ ERROR destructor
 const fn no_apit(_x: impl std::fmt::Debug) {}
-//~^ ERROR trait bounds other than `Sized`
-//~| ERROR destructor
+//~^ ERROR destructor
 const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
-//~^ ERROR trait objects in const fn are unstable
 const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-//~^ ERROR trait objects in const fn are unstable
 
 const fn no_unsafe() { unsafe {} }
 
-const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-//~^ ERROR trait objects in const fn are unstable
-//~| ERROR trait objects in const fn are unstable
-//~| ERROR trait objects in const fn are unstable
+const fn traits_are_ok_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
 
-const fn no_fn_ptrs(_x: fn()) {}
-//~^ ERROR function pointer
-const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
+const fn fn_ptrs(_x: fn()) {}
+const fn fn_ptrs2() -> fn() { fn foo() {} foo }
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
index 67cb604b6a7..4ad17602c84 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
@@ -130,26 +130,8 @@ LL |     const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:84:16
-   |
-LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
-   |                ^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:86:18
-   |
-LL | const fn foo11_2<T: Send>(t: T) -> T { t }
-   |                  ^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
 error[E0013]: constant functions cannot refer to statics
-  --> $DIR/min_const_fn.rs:90:27
+  --> $DIR/min_const_fn.rs:89:27
    |
 LL | const fn foo25() -> u32 { BAR }
    |                           ^^^
@@ -157,7 +139,7 @@ LL | const fn foo25() -> u32 { BAR }
    = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error[E0013]: constant functions cannot refer to statics
-  --> $DIR/min_const_fn.rs:91:37
+  --> $DIR/min_const_fn.rs:90:37
    |
 LL | const fn foo26() -> &'static u32 { &BAR }
    |                                     ^^^
@@ -165,7 +147,7 @@ LL | const fn foo26() -> &'static u32 { &BAR }
    = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error: pointers cannot be cast to integers during const eval
-  --> $DIR/min_const_fn.rs:92:42
+  --> $DIR/min_const_fn.rs:91:42
    |
 LL | const fn foo30(x: *const u32) -> usize { x as usize }
    |                                          ^^^^^^^^^^
@@ -174,7 +156,7 @@ LL | const fn foo30(x: *const u32) -> usize { x as usize }
    = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
 error: pointers cannot be cast to integers during const eval
-  --> $DIR/min_const_fn.rs:94:63
+  --> $DIR/min_const_fn.rs:93:63
    |
 LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
    |                                                               ^^^^^^^^^^
@@ -183,7 +165,7 @@ LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize }
    = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
 error: pointers cannot be cast to integers during const eval
-  --> $DIR/min_const_fn.rs:96:42
+  --> $DIR/min_const_fn.rs:95:42
    |
 LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
    |                                          ^^^^^^^^^^
@@ -192,7 +174,7 @@ LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
    = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
 error: pointers cannot be cast to integers during const eval
-  --> $DIR/min_const_fn.rs:98:63
+  --> $DIR/min_const_fn.rs:97:63
    |
 LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
    |                                                               ^^^^^^^^^^
@@ -201,7 +183,7 @@ LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize }
    = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/min_const_fn.rs:101:14
+  --> $DIR/min_const_fn.rs:100:14
    |
 LL | const fn inc(x: &mut i32) { *x += 1 }
    |              ^
@@ -209,155 +191,23 @@ LL | const fn inc(x: &mut i32) { *x += 1 }
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:110:6
-   |
-LL | impl<T: std::fmt::Debug> Foo<T> {
-   |      ^
-LL |
-LL |     const fn foo(&self) {}
-   |     ------------------- function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:115:6
-   |
-LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
-   |      ^
-LL |
-LL |     const fn foo2(&self) {}
-   |     -------------------- function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:120:6
-   |
-LL | impl<T: Sync + Sized> Foo<T> {
-   |      ^
-LL |
-LL |     const fn foo3(&self) {}
-   |     -------------------- function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:126:34
-   |
-LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
-   |                                  ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/min_const_fn.rs:126:19
+  --> $DIR/min_const_fn.rs:122:19
    |
 LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    |                   ^^                                     - value is dropped here
    |                   |
    |                   constant functions cannot evaluate destructors
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:129:22
-   |
-LL | const fn no_apit(_x: impl std::fmt::Debug) {}
-   |                      ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/min_const_fn.rs:129:18
+  --> $DIR/min_const_fn.rs:124:18
    |
 LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    |                  ^^                         - value is dropped here
    |                  |
    |                  constant functions cannot evaluate destructors
 
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn.rs:132:23
-   |
-LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
-   |                       ^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn.rs:134:32
-   |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn.rs:139:41
-   |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-   | -------------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | |
-   | function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn.rs:139:42
-   |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-   | -------------------------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | |
-   | function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn.rs:139:42
-   |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-   | -------------------------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | |
-   | function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/min_const_fn.rs:144:21
-   |
-LL | const fn no_fn_ptrs(_x: fn()) {}
-   |                     ^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/min_const_fn.rs:146:27
-   |
-LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
-   |                           ^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/min_const_fn.rs:146:46
-   |
-LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
-   |                                              ^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to 39 previous errors
+error: aborting due to 24 previous errors
 
 Some errors have detailed explanations: E0013, E0493, E0658.
 For more information about an error, try `rustc --explain E0013`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
index 1ab8253b414..36c8880093e 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
@@ -1,3 +1,5 @@
+// check-pass
+
 struct HasDyn {
     field: &'static dyn std::fmt::Debug,
 }
@@ -7,9 +9,7 @@ struct Hide(HasDyn);
 const fn no_inner_dyn_trait(_x: Hide) {}
 const fn no_inner_dyn_trait2(x: Hide) {
     x.0.field;
-//~^ ERROR trait objects in const fn are unstable
 }
 const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
-//~^ ERROR trait objects in const fn are unstable
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
deleted file mode 100644
index 4c2199101d3..00000000000
--- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn_dyn.rs:9:5
-   |
-LL | const fn no_inner_dyn_trait2(x: Hide) {
-   | ------------------------------------- function declared as const here
-LL |     x.0.field;
-   |     ^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn_dyn.rs:12:66
-   |
-LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
-   | -----------------------------------------                        ^^
-   | |
-   | function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs
deleted file mode 100644
index bc6fe89222b..00000000000
--- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// gate-test-const_fn_fn_ptr_basics
-
-struct HasPtr {
-    field: fn(),
-}
-
-struct Hide(HasPtr);
-
-fn field() {}
-
-const fn no_inner_dyn_trait(_x: Hide) {}
-const fn no_inner_dyn_trait2(x: Hide) {
-    x.0.field;
-//~^ ERROR function pointer
-}
-const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
-//~^ ERROR function pointer
-
-fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr
deleted file mode 100644
index 8d82674bbf2..00000000000
--- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/min_const_fn_fn_ptr.rs:13:5
-   |
-LL |     x.0.field;
-   |     ^^^^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/min_const_fn_fn_ptr.rs:16:59
-   |
-LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
-   |                                                           ^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs
deleted file mode 100644
index e062c9f0aa3..00000000000
--- a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// gate-test-const_impl_trait
-
-struct AlanTuring<T>(T);
-const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { //~ `impl Trait`
-    AlanTuring(0)
-}
-
-const fn no_rpit() -> impl std::fmt::Debug {} //~ `impl Trait`
-
-fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr
deleted file mode 100644
index 01c797cd96b..00000000000
--- a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: `impl Trait` is not allowed in constant functions
-  --> $DIR/min_const_fn_impl_trait.rs:4:24
-   |
-LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> {
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
-   = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
-
-error[E0658]: `impl Trait` is not allowed in constant functions
-  --> $DIR/min_const_fn_impl_trait.rs:8:23
-   |
-LL | const fn no_rpit() -> impl std::fmt::Debug {}
-   |                       ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
-   = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
index e2f9708ddcb..aaba19c2c8b 100644
--- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
+++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
@@ -12,16 +12,6 @@ LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "
 
 warning: skipping const checks
    |
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/abi-mismatch.rs:9:23
-   |
-LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) {
-   |                       ^^^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/abi-mismatch.rs:10:5
-   |
-LL |     my_fn();
-   |     ^^^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/abi-mismatch.rs:10:5
    |
diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs
index cbc88bc4d9c..fee61907eb3 100644
--- a/src/test/ui/consts/offset_from_ub.rs
+++ b/src/test/ui/consts/offset_from_ub.rs
@@ -1,4 +1,4 @@
-#![feature(const_ptr_offset_from)]
+#![feature(const_ptr_offset_from, const_ptr_offset)]
 #![feature(core_intrinsics)]
 
 use std::intrinsics::ptr_offset_from;
@@ -44,4 +44,30 @@ pub const DIFFERENT_INT: isize = { // offset_from with two different integers: l
     //~| 0x10 is not a valid pointer
 };
 
+const OUT_OF_BOUNDS_1: isize = {
+    let start_ptr = &4 as *const _ as *const u8;
+    let length = 10;
+    let end_ptr = (start_ptr).wrapping_add(length);
+    // First ptr is out of bounds
+    unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed
+    //~| pointer at offset 10 is out-of-bounds
+};
+
+const OUT_OF_BOUNDS_2: isize = {
+    let start_ptr = &4 as *const _ as *const u8;
+    let length = 10;
+    let end_ptr = (start_ptr).wrapping_add(length);
+    // Second ptr is out of bounds
+    unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed
+    //~| pointer at offset 10 is out-of-bounds
+};
+
+const OUT_OF_BOUNDS_SAME: isize = {
+    let start_ptr = &4 as *const _ as *const u8;
+    let length = 10;
+    let end_ptr = (start_ptr).wrapping_add(length);
+    unsafe { ptr_offset_from(end_ptr, end_ptr) } //~ERROR evaluation of constant value failed
+    //~| pointer at offset 10 is out-of-bounds
+};
+
 fn main() {}
diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr
index ffd6ad58c30..4d60d4df203 100644
--- a/src/test/ui/consts/offset_from_ub.stderr
+++ b/src/test/ui/consts/offset_from_ub.stderr
@@ -10,7 +10,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  0x2a is not a valid pointer
+   |                  out-of-bounds offset_from: 0x2a is not a valid pointer
    |                  inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/offset_from_ub.rs:23:14
@@ -28,14 +28,32 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:36:14
    |
 LL |     unsafe { ptr_offset_from(ptr, ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is not a valid pointer
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:43:14
    |
 LL |     unsafe { ptr_offset_from(ptr2, ptr1) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0x10 is not a valid pointer
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x10 is not a valid pointer
 
-error: aborting due to 5 previous errors
+error[E0080]: evaluation of constant value failed
+  --> $DIR/offset_from_ub.rs:52:14
+   |
+LL |     unsafe { ptr_offset_from(end_ptr, start_ptr) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer at offset 10 is out-of-bounds
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/offset_from_ub.rs:61:14
+   |
+LL |     unsafe { ptr_offset_from(start_ptr, end_ptr) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer at offset 10 is out-of-bounds
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/offset_from_ub.rs:69:14
+   |
+LL |     unsafe { ptr_offset_from(end_ptr, end_ptr) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds
+
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr
index 4c3f373e080..237950a30e8 100644
--- a/src/test/ui/consts/offset_ub.stderr
+++ b/src/test/ui/consts/offset_ub.stderr
@@ -144,7 +144,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: 0x0 is not a valid pointer
+   |                  pointer arithmetic failed: null pointer is not a valid pointer
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/offset_ub.rs:22:50
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.rs b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
index 8ee1270805e..16b36c8d56d 100644
--- a/src/test/ui/consts/unstable-const-fn-in-libcore.rs
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
@@ -5,7 +5,6 @@
 
 #![stable(feature = "core", since = "1.6.0")]
 #![feature(staged_api)]
-#![feature(const_fn_trait_bound)]
 
 enum Opt<T> {
     Some(T),
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
index 3ec9971b8e1..180f9f10cc6 100644
--- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,5 +1,5 @@
 error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/unstable-const-fn-in-libcore.rs:23:26
+  --> $DIR/unstable-const-fn-in-libcore.rs:22:26
    |
 LL |             Opt::None => f(),
    |                          ^^^
@@ -11,7 +11,7 @@ LL |     const fn unwrap_or_else<F: FnOnce() -> T + ~const std::ops::FnOnce<()>>
    |                                              +++++++++++++++++++++++++++++
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/unstable-const-fn-in-libcore.rs:18:53
+  --> $DIR/unstable-const-fn-in-libcore.rs:17:53
    |
 LL |     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    |                                                     ^ constant functions cannot evaluate destructors
@@ -20,7 +20,7 @@ LL |     }
    |     - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/unstable-const-fn-in-libcore.rs:18:47
+  --> $DIR/unstable-const-fn-in-libcore.rs:17:47
    |
 LL |     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    |                                               ^^^^ constant functions cannot evaluate destructors
diff --git a/src/test/ui/debuginfo/debuginfo-box-with-large-allocator.rs b/src/test/ui/debuginfo/debuginfo-box-with-large-allocator.rs
new file mode 100644
index 00000000000..761539227a7
--- /dev/null
+++ b/src/test/ui/debuginfo/debuginfo-box-with-large-allocator.rs
@@ -0,0 +1,23 @@
+// build-pass
+// compile-flags: -Cdebuginfo=2
+// fixes issue #94725
+
+#![feature(allocator_api)]
+
+use std::alloc::{AllocError, Allocator, Layout};
+use std::ptr::NonNull;
+
+struct ZST;
+
+unsafe impl Allocator for &ZST {
+    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+        todo!()
+    }
+    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
+        todo!()
+    }
+}
+
+fn main() {
+    let _ = Box::<i32, &ZST>::new_in(43, &ZST);
+}
diff --git a/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs b/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs
index 833a4726acb..b3f22ecf511 100644
--- a/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs
+++ b/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs
@@ -1,4 +1,4 @@
-// check-pass
+// build-pass
 // compile-flags: -Cdebuginfo=2
 // fixes issue #94149
 
diff --git a/src/test/ui/deprecation/deprecation-in-staged-api.rs b/src/test/ui/deprecation/deprecation-in-staged-api.rs
deleted file mode 100644
index 910bfd1b5e4..00000000000
--- a/src/test/ui/deprecation/deprecation-in-staged-api.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(staged_api)]
-#![stable(feature = "stable_test_feature", since = "1.0.0")]
-#[deprecated] //~ ERROR `#[deprecated]` cannot be used in staged API
-fn main() {}
diff --git a/src/test/ui/deprecation/deprecation-in-staged-api.stderr b/src/test/ui/deprecation/deprecation-in-staged-api.stderr
deleted file mode 100644
index 5c14f5ed356..00000000000
--- a/src/test/ui/deprecation/deprecation-in-staged-api.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `#[deprecated]` cannot be used in staged API
-  --> $DIR/deprecation-in-staged-api.rs:3:1
-   |
-LL | #[deprecated]
-   | ^^^^^^^^^^^^^ use `#[rustc_deprecated]` instead
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/deprecation/feature-gate-deprecated_suggestion.rs b/src/test/ui/deprecation/feature-gate-deprecated_suggestion.rs
new file mode 100644
index 00000000000..a2d0023e3f4
--- /dev/null
+++ b/src/test/ui/deprecation/feature-gate-deprecated_suggestion.rs
@@ -0,0 +1,6 @@
+// compile-flags: --crate-type=lib
+
+#![no_implicit_prelude]
+
+#[deprecated(suggestion = "foo")] //~ ERROR suggestions on deprecated items are unstable
+struct Foo {}
diff --git a/src/test/ui/deprecation/feature-gate-deprecated_suggestion.stderr b/src/test/ui/deprecation/feature-gate-deprecated_suggestion.stderr
new file mode 100644
index 00000000000..3b995fed75c
--- /dev/null
+++ b/src/test/ui/deprecation/feature-gate-deprecated_suggestion.stderr
@@ -0,0 +1,11 @@
+error: suggestions on deprecated items are unstable
+  --> $DIR/feature-gate-deprecated_suggestion.rs:5:14
+   |
+LL | #[deprecated(suggestion = "foo")]
+   |              ^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(deprecated_suggestion)]` to the crate root
+   = note: see #XXX for more details
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.rs b/src/test/ui/deprecation/staged-deprecation-in-future.rs
index 3715f8eb225..87b15ec303c 100644
--- a/src/test/ui/deprecation/rustc_deprecation-in-future.rs
+++ b/src/test/ui/deprecation/staged-deprecation-in-future.rs
@@ -4,11 +4,11 @@
 
 #![stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
 
-#[rustc_deprecated(since = "99.99.99", reason = "effectively never")]
+#[deprecated(since = "99.99.99", note = "effectively never")]
 #[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
 pub struct S1;
 
-#[rustc_deprecated(since = "TBD", reason = "literally never")]
+#[deprecated(since = "TBD", note = "literally never")]
 #[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
 pub struct S2;
 
diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr b/src/test/ui/deprecation/staged-deprecation-in-future.stderr
index 1c3339a8a9d..13d98044a88 100644
--- a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr
+++ b/src/test/ui/deprecation/staged-deprecation-in-future.stderr
@@ -1,17 +1,17 @@
 error: use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never
-  --> $DIR/rustc_deprecation-in-future.rs:16:13
+  --> $DIR/staged-deprecation-in-future.rs:16:13
    |
 LL |     let _ = S1;
    |             ^^
    |
 note: the lint level is defined here
-  --> $DIR/rustc_deprecation-in-future.rs:1:9
+  --> $DIR/staged-deprecation-in-future.rs:1:9
    |
 LL | #![deny(deprecated_in_future)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: use of unit struct `S2` that will be deprecated in a future Rust version: literally never
-  --> $DIR/rustc_deprecation-in-future.rs:17:13
+  --> $DIR/staged-deprecation-in-future.rs:17:13
    |
 LL |     let _ = S2;
    |             ^^
diff --git a/src/test/ui/deprecation/suggestion.fixed b/src/test/ui/deprecation/suggestion.fixed
index 7d662227881..d9fa2b56eee 100644
--- a/src/test/ui/deprecation/suggestion.fixed
+++ b/src/test/ui/deprecation/suggestion.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![feature(staged_api)]
+#![feature(deprecated_suggestion)]
 
 #![stable(since = "1.0.0", feature = "test")]
 
@@ -10,9 +11,9 @@
 struct Foo;
 
 impl Foo {
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.0.0",
-        reason = "replaced by `replacement`",
+        note = "replaced by `replacement`",
         suggestion = "replacement",
     )]
     #[stable(since = "1.0.0", feature = "test")]
@@ -22,9 +23,9 @@ impl Foo {
 }
 
 mod bar {
-    #[rustc_deprecated(
+    #[deprecated(
     since = "1.0.0",
-    reason = "replaced by `replacement`",
+    note = "replaced by `replacement`",
     suggestion = "replacement",
     )]
     #[stable(since = "1.0.0", feature = "test")]
diff --git a/src/test/ui/deprecation/suggestion.rs b/src/test/ui/deprecation/suggestion.rs
index b34dc0eb83a..9dc2eaf2555 100644
--- a/src/test/ui/deprecation/suggestion.rs
+++ b/src/test/ui/deprecation/suggestion.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![feature(staged_api)]
+#![feature(deprecated_suggestion)]
 
 #![stable(since = "1.0.0", feature = "test")]
 
@@ -10,9 +11,9 @@
 struct Foo;
 
 impl Foo {
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.0.0",
-        reason = "replaced by `replacement`",
+        note = "replaced by `replacement`",
         suggestion = "replacement",
     )]
     #[stable(since = "1.0.0", feature = "test")]
@@ -22,9 +23,9 @@ impl Foo {
 }
 
 mod bar {
-    #[rustc_deprecated(
+    #[deprecated(
     since = "1.0.0",
-    reason = "replaced by `replacement`",
+    note = "replaced by `replacement`",
     suggestion = "replacement",
     )]
     #[stable(since = "1.0.0", feature = "test")]
diff --git a/src/test/ui/deprecation/suggestion.stderr b/src/test/ui/deprecation/suggestion.stderr
index 7d78b222244..8d1e108345f 100644
--- a/src/test/ui/deprecation/suggestion.stderr
+++ b/src/test/ui/deprecation/suggestion.stderr
@@ -1,17 +1,17 @@
 error: use of deprecated function `bar::deprecated`: replaced by `replacement`
-  --> $DIR/suggestion.rs:41:10
+  --> $DIR/suggestion.rs:42:10
    |
 LL |     bar::deprecated();
    |          ^^^^^^^^^^ help: replace the use of the deprecated function: `replacement`
    |
 note: the lint level is defined here
-  --> $DIR/suggestion.rs:7:9
+  --> $DIR/suggestion.rs:8:9
    |
 LL | #![deny(deprecated)]
    |         ^^^^^^^^^^
 
 error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement`
-  --> $DIR/suggestion.rs:39:9
+  --> $DIR/suggestion.rs:40:9
    |
 LL |     foo.deprecated();
    |         ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement`
diff --git a/src/test/ui/editions/async-block-2015.rs b/src/test/ui/editions/async-block-2015.rs
index 24112c9855a..3daf4930c5b 100644
--- a/src/test/ui/editions/async-block-2015.rs
+++ b/src/test/ui/editions/async-block-2015.rs
@@ -1,7 +1,7 @@
 async fn foo() {
 //~^ ERROR `async fn` is not permitted in Rust 2015
 //~| NOTE to use `async fn`, switch to Rust 2018 or later
-//~| HELP set `edition = "2021"` in `Cargo.toml`
+//~| HELP pass `--edition 2021` to `rustc`
 //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 
     let x = async {};
@@ -11,7 +11,7 @@ async fn foo() {
         let x = 42;
         //~^ ERROR expected identifier, found keyword `let`
         //~| NOTE expected identifier, found keyword
-        //~| HELP set `edition = "2021"` in `Cargo.toml`
+        //~| HELP pass `--edition 2021` to `rustc`
         //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
         42
     };
@@ -19,7 +19,7 @@ async fn foo() {
         42
         //~^ ERROR expected identifier, found `42`
         //~| NOTE expected identifier
-        //~| HELP set `edition = "2021"` in `Cargo.toml`
+        //~| HELP pass `--edition 2021` to `rustc`
         //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
     };
     y.await;
diff --git a/src/test/ui/editions/async-block-2015.stderr b/src/test/ui/editions/async-block-2015.stderr
index da8412ddcb3..b792b8c1e0d 100644
--- a/src/test/ui/editions/async-block-2015.stderr
+++ b/src/test/ui/editions/async-block-2015.stderr
@@ -4,7 +4,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | async fn foo() {
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected identifier, found keyword `let`
@@ -15,7 +15,7 @@ LL |     let y = async {
 LL |         let x = 42;
    |         ^^^ expected identifier, found keyword
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected identifier, found `42`
@@ -26,7 +26,7 @@ LL |     let z = async {
 LL |         42
    |         ^^ expected identifier
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0422]: cannot find struct, variant or union type `async` in this scope
diff --git a/src/test/ui/empty/empty-attributes.rs b/src/test/ui/empty/empty-attributes.rs
index 7e9b05587b0..d319227b217 100644
--- a/src/test/ui/empty/empty-attributes.rs
+++ b/src/test/ui/empty/empty-attributes.rs
@@ -1,5 +1,8 @@
+#![feature(lint_reasons)]
+
 #![deny(unused_attributes)]
 #![allow()] //~ ERROR unused attribute
+#![expect()] //~ ERROR unused attribute
 #![warn()] //~ ERROR unused attribute
 #![deny()] //~ ERROR unused attribute
 #![forbid()] //~ ERROR unused attribute
diff --git a/src/test/ui/empty/empty-attributes.stderr b/src/test/ui/empty/empty-attributes.stderr
index e0798e4f0c6..8653eaf5ccd 100644
--- a/src/test/ui/empty/empty-attributes.stderr
+++ b/src/test/ui/empty/empty-attributes.stderr
@@ -1,18 +1,18 @@
 error: unused attribute
-  --> $DIR/empty-attributes.rs:8:1
+  --> $DIR/empty-attributes.rs:11:1
    |
 LL | #[repr()]
    | ^^^^^^^^^ help: remove this attribute
    |
 note: the lint level is defined here
-  --> $DIR/empty-attributes.rs:1:9
+  --> $DIR/empty-attributes.rs:3:9
    |
 LL | #![deny(unused_attributes)]
    |         ^^^^^^^^^^^^^^^^^
    = note: attribute `repr` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:11:1
+  --> $DIR/empty-attributes.rs:14:1
    |
 LL | #[target_feature()]
    | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
@@ -20,7 +20,7 @@ LL | #[target_feature()]
    = note: attribute `target_feature` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:2:1
+  --> $DIR/empty-attributes.rs:4:1
    |
 LL | #![allow()]
    | ^^^^^^^^^^^ help: remove this attribute
@@ -28,7 +28,15 @@ LL | #![allow()]
    = note: attribute `allow` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:3:1
+  --> $DIR/empty-attributes.rs:5:1
+   |
+LL | #![expect()]
+   | ^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `expect` with an empty list has no effect
+
+error: unused attribute
+  --> $DIR/empty-attributes.rs:6:1
    |
 LL | #![warn()]
    | ^^^^^^^^^^ help: remove this attribute
@@ -36,7 +44,7 @@ LL | #![warn()]
    = note: attribute `warn` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:4:1
+  --> $DIR/empty-attributes.rs:7:1
    |
 LL | #![deny()]
    | ^^^^^^^^^^ help: remove this attribute
@@ -44,7 +52,7 @@ LL | #![deny()]
    = note: attribute `deny` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:5:1
+  --> $DIR/empty-attributes.rs:8:1
    |
 LL | #![forbid()]
    | ^^^^^^^^^^^^ help: remove this attribute
@@ -52,12 +60,12 @@ LL | #![forbid()]
    = note: attribute `forbid` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:6:1
+  --> $DIR/empty-attributes.rs:9:1
    |
 LL | #![feature()]
    | ^^^^^^^^^^^^^ help: remove this attribute
    |
    = note: attribute `feature` with an empty list has no effect
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr
index 64d640c0e9d..909aa73a74a 100644
--- a/src/test/ui/empty/empty-never-array.stderr
+++ b/src/test/ui/empty/empty-never-array.stderr
@@ -1,24 +1,27 @@
 error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
   --> $DIR/empty-never-array.rs:10:9
    |
-LL | / enum Helper<T, U> {
-LL | |     T(T, [!; 0]),
-   | |     - not covered
-LL | |     #[allow(dead_code)]
-LL | |     U(U),
-LL | | }
-   | |_- `Helper<T, U>` defined here
-...
-LL |       let Helper::U(u) = Helper::T(t, []);
-   |           ^^^^^^^^^^^^ pattern `T(_, _)` not covered
+LL |     let Helper::U(u) = Helper::T(t, []);
+   |         ^^^^^^^^^^^^ pattern `T(_, _)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Helper<T, U>` defined here
+  --> $DIR/empty-never-array.rs:4:5
+   |
+LL | enum Helper<T, U> {
+   |      ------
+LL |     T(T, [!; 0]),
+   |     ^ not covered
    = note: the matched value is of type `Helper<T, U>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Helper::U(u) = Helper::T(t, []) { /* */ }
+LL |     let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() };
+   |     ++++++++++                                     ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
    |
+LL |     let Helper::U(u) = Helper::T(t, []) else { todo!() };
+   |                                         ++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0004-2.stderr b/src/test/ui/error-codes/E0004-2.stderr
index fd0215e72ee..d4519af5408 100644
--- a/src/test/ui/error-codes/E0004-2.stderr
+++ b/src/test/ui/error-codes/E0004-2.stderr
@@ -4,16 +4,27 @@ error[E0004]: non-exhaustive patterns: `None` and `Some(_)` not covered
 LL |     match x { }
    |           ^ patterns `None` and `Some(_)` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<i32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     None,
-   |     ---- not covered
-...
-LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     ---- not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     None,
+   | |     ^^^^ not covered
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   | |     ^^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match x {
+LL +         None | Some(_) => todo!(),
+LL ~     }
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0004.stderr b/src/test/ui/error-codes/E0004.stderr
index 5bf375a6484..8ba151d9e65 100644
--- a/src/test/ui/error-codes/E0004.stderr
+++ b/src/test/ui/error-codes/E0004.stderr
@@ -1,18 +1,22 @@
 error[E0004]: non-exhaustive patterns: `HastaLaVistaBaby` not covered
   --> $DIR/E0004.rs:9:11
    |
-LL | / enum Terminator {
-LL | |     HastaLaVistaBaby,
-   | |     ---------------- not covered
-LL | |     TalkToMyHand,
-LL | | }
-   | |_- `Terminator` defined here
-...
-LL |       match x {
-   |             ^ pattern `HastaLaVistaBaby` not covered
+LL |     match x {
+   |           ^ pattern `HastaLaVistaBaby` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Terminator` defined here
+  --> $DIR/E0004.rs:2:5
+   |
+LL | enum Terminator {
+   |      ----------
+LL |     HastaLaVistaBaby,
+   |     ^^^^^^^^^^^^^^^^ not covered
    = note: the matched value is of type `Terminator`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Terminator::TalkToMyHand => {}
+LL +         HastaLaVistaBaby => todo!()
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0005.stderr b/src/test/ui/error-codes/E0005.stderr
index b95dcbd8935..55b1112b5f8 100644
--- a/src/test/ui/error-codes/E0005.stderr
+++ b/src/test/ui/error-codes/E0005.stderr
@@ -4,18 +4,30 @@ error[E0005]: refutable pattern in local binding: `None` not covered
 LL |     let Some(y) = x;
    |         ^^^^^^^ pattern `None` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
-   |
-LL |     None,
-   |     ---- not covered
-   |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Option<i32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     None,
+   | |     ^^^^ not covered
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+   | |_-
    = note: the matched value is of type `Option<i32>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Some(y) = x { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let y = if let Some(y) = x { y } else { todo!() };
+   |     ++++++++++                 ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+   |
+LL |     let Some(y) = x else { todo!() };
+   |                     ++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0297.stderr b/src/test/ui/error-codes/E0297.stderr
index 957e79a9f39..95d95003c61 100644
--- a/src/test/ui/error-codes/E0297.stderr
+++ b/src/test/ui/error-codes/E0297.stderr
@@ -4,11 +4,19 @@ error[E0005]: refutable pattern in `for` loop binding: `None` not covered
 LL |     for Some(x) in xs {}
    |         ^^^^^^^ pattern `None` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
-   |
-LL |     None,
-   |     ---- not covered
+note: `Option<i32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
    |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     None,
+   | |     ^^^^ not covered
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+   | |_-
    = note: the matched value is of type `Option<i32>`
 
 error: aborting due to previous error
diff --git a/src/test/ui/error-codes/E0507.stderr b/src/test/ui/error-codes/E0507.stderr
index 3837e206169..ce8d1ef0349 100644
--- a/src/test/ui/error-codes/E0507.stderr
+++ b/src/test/ui/error-codes/E0507.stderr
@@ -2,7 +2,16 @@ error[E0507]: cannot move out of dereference of `Ref<'_, TheDarkKnight>`
   --> $DIR/E0507.rs:12:5
    |
 LL |     x.borrow().nothing_is_true();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait
+   |     ^^^^^^^^^^^-----------------
+   |     |          |
+   |     |          value moved due to this method call
+   |     move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait
+   |
+note: this function takes ownership of the receiver `self`, which moves value
+  --> $DIR/E0507.rs:6:24
+   |
+LL |     fn nothing_is_true(self) {}
+   |                        ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
index c5ffa55ebec..21180f31bbd 100644
--- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
+++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
@@ -4,18 +4,29 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
 LL |     let Ok(_x) = foo();
    |         ^^^^^^ pattern `Err(_)` not covered
    |
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
-   |     --- not covered
-   |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, !>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | / pub enum Result<T, E> {
+LL | |     /// Contains the success value
+LL | |     #[lang = "Ok"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+   | |     ^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Result<u32, !>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Ok(_x) = foo() { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let _x = if let Ok(_x) = foo() { _x } else { todo!() };
+   |     +++++++++++                    +++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+   |
+LL |     let Ok(_x) = foo() else { todo!() };
+   |                        ++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
index 2a34ed4d4f6..29a6e1f8a01 100644
--- a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
+++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
@@ -1,9 +1,11 @@
+// check-fail
+
 #![deny(non_exhaustive_omitted_patterns)]
-//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 #![allow(non_exhaustive_omitted_patterns)]
-//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 
 fn main() {
     enum Foo {
@@ -11,14 +13,15 @@ fn main() {
     }
 
     #[allow(non_exhaustive_omitted_patterns)]
+    //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
     match Foo::A {
         Foo::A => {}
         Foo::B => {}
     }
-    //~^^^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+    //~^^^^ ERROR non-exhaustive patterns: `C` not covered
 
     match Foo::A {
         Foo::A => {}
@@ -26,6 +29,6 @@ fn main() {
         #[warn(non_exhaustive_omitted_patterns)]
         _ => {}
     }
-    //~^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+    //~^^^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 }
diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
index 691f64cf0ad..dbeef6c2d2a 100644
--- a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
+++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
@@ -1,93 +1,124 @@
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:1:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
    |
 LL | #![deny(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:4:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1
    |
 LL | #![allow(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:26:9
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9
    |
 LL |         #[warn(non_exhaustive_omitted_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:1:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
    |
 LL | #![deny(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:4:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1
    |
 LL | #![allow(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:26:9
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9
    |
 LL |         #[warn(non_exhaustive_omitted_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error: aborting due to 10 previous errors
+error[E0004]: non-exhaustive patterns: `C` not covered
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11
+   |
+LL |     match Foo::A {
+   |           ^^^^^^ pattern `C` not covered
+   |
+note: `Foo` defined here
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:12:15
+   |
+LL |     enum Foo {
+   |          ---
+LL |         A, B, C,
+   |               ^ not covered
+   = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo::B => {}
+LL +         C => todo!()
+   |
+
+error: aborting due to previous error; 10 warnings emitted
 
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
index 9895646fc2b..b5510683328 100644
--- a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
+++ b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
@@ -4,10 +4,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0usize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         0..=usize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11
@@ -15,10 +19,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0isize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         isize::MIN..=isize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs
index 04f816ea501..667bc9f8ddf 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs
+++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs
@@ -2,6 +2,6 @@
 
 #[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable
 #[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable
-#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable
+#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr
index 822368a5946..45a095903d2 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr
+++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr
@@ -14,7 +14,7 @@ LL | #[rustc_error]
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable
+error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable
   --> $DIR/feature-gate-rustc-attrs-1.rs:5:1
    |
 LL | #[rustc_nonnull_optimization_guaranteed]
diff --git a/src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs b/src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs
new file mode 100644
index 00000000000..c398394cbe1
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+// `test_unstable_lint` is for testing and should never be stabilized.
+#![allow(test_unstable_lint)]
+//~^ WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr b/src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr
new file mode 100644
index 00000000000..a29322443ea
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr
@@ -0,0 +1,30 @@
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.rs b/src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.rs
deleted file mode 100644
index 3acfbd0ca23..00000000000
--- a/src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Testing gating of `#[rustc_deprecated]` in "weird" places.
-//
-// This file sits on its own because these signal errors, making
-// this test incompatible with the "warnings only" nature of
-// issue-43106-gating-of-builtin-attrs.rs
-
-#![rustc_deprecated()]
-//~^ ERROR stability attributes may not be used outside of the standard library
-//~| ERROR missing 'since' [E0542]
-
-#[rustc_deprecated()]
-//~^ ERROR stability attributes may not be used outside of the standard library
-//~| ERROR missing 'since' [E0542]
-mod rustc_deprecated {
-    mod inner {
-        #![rustc_deprecated()]
-        //~^ ERROR stability attributes may not be used outside of the standard library
-        //~| ERROR missing 'since' [E0542]
-    }
-
-    #[rustc_deprecated()]
-    //~^ ERROR stability attributes may not be used outside of the standard library
-    //~| ERROR missing 'since' [E0542]
-    fn f() {}
-
-    #[rustc_deprecated()]
-    //~^ ERROR stability attributes may not be used outside of the standard library
-    //~| ERROR missing 'since' [E0542]
-    //~| ERROR missing 'since' [E0542]
-    struct S;
-
-    #[rustc_deprecated()]
-    //~^ ERROR stability attributes may not be used outside of the standard library
-    //~| ERROR missing 'since' [E0542]
-    type T = S;
-
-    #[rustc_deprecated()]
-    //~^ ERROR stability attributes may not be used outside of the standard library
-    //~| ERROR missing 'since' [E0542]
-    impl S {}
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.stderr
deleted file mode 100644
index 4ec78f318c2..00000000000
--- a/src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.stderr
+++ /dev/null
@@ -1,94 +0,0 @@
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:16:9
-   |
-LL |         #![rustc_deprecated()]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:21:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:32:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:37:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:11:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:7:1
-   |
-LL | #![rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:7:1
-   |
-LL | #![rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:11:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:16:9
-   |
-LL |         #![rustc_deprecated()]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:21:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:32:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:37:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 15 previous errors
-
-Some errors have detailed explanations: E0542, E0734.
-For more information about an error, try `rustc --explain E0542`.
diff --git a/src/test/ui/generic-associated-types/issue-90729.rs b/src/test/ui/generic-associated-types/issue-90729.rs
new file mode 100644
index 00000000000..98295cce8d5
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-90729.rs
@@ -0,0 +1,38 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+use std::marker::PhantomData;
+
+pub trait Type {
+    type Ref<'a>;
+}
+
+pub trait AsBytes {}
+
+impl AsBytes for &str {}
+
+pub struct Utf8;
+
+impl Type for Utf8 {
+    type Ref<'a> = &'a str;
+}
+
+pub struct Bytes<T: Type> {
+    _marker: PhantomData<T>,
+}
+
+impl<T: Type> Bytes<T>
+where
+    for<'a> T::Ref<'a>: AsBytes,
+{
+    pub fn new() -> Self {
+        Self {
+            _marker: PhantomData,
+        }
+    }
+}
+
+fn main() {
+    let _b = Bytes::<Utf8>::new();
+}
diff --git a/src/test/ui/generic-associated-types/issue-91139.migrate.stderr b/src/test/ui/generic-associated-types/issue-91139.migrate.stderr
new file mode 100644
index 00000000000..a27d8110238
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-91139.migrate.stderr
@@ -0,0 +1,10 @@
+error[E0311]: the parameter type `T` may not live long enough
+  --> $DIR/issue-91139.rs:27:12
+   |
+LL | fn foo<T>() {
+   |        - help: consider adding an explicit lifetime bound...: `T: 'a`
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generic-associated-types/issue-91139.rs b/src/test/ui/generic-associated-types/issue-91139.rs
index 5c4a7cf6ffc..78b2b63dadc 100644
--- a/src/test/ui/generic-associated-types/issue-91139.rs
+++ b/src/test/ui/generic-associated-types/issue-91139.rs
@@ -1,4 +1,13 @@
-// check-pass
+// revisions: migrate nll
+//[nll]compile-flags: -Z borrowck=mir
+
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
+//[nll] check-pass
+//[migrate] check-fail
 
 #![feature(generic_associated_types)]
 
@@ -16,6 +25,7 @@ impl<T> Foo<T> for () {
 
 fn foo<T>() {
     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+    //[migrate]~^ the parameter type `T` may not live long enough
 }
 
 pub fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-93341.rs b/src/test/ui/generic-associated-types/issue-93341.rs
new file mode 100644
index 00000000000..e96a768ecda
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-93341.rs
@@ -0,0 +1,55 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+use std::marker::PhantomData;
+
+pub struct Id<'id>(PhantomData<fn(&'id ()) -> &'id ()>);
+
+fn new_id() -> Id<'static> {
+    Id(PhantomData)
+}
+
+pub trait HasLifetime where {
+    type AtLifetime<'a>;
+}
+
+pub struct ExistentialLifetime<S: HasLifetime>(S::AtLifetime<'static>);
+
+impl<S: HasLifetime> ExistentialLifetime<S> {
+    pub fn new<F>(f: F) -> ExistentialLifetime<S>
+        where for<'id> F: FnOnce(Id<'id>) -> S::AtLifetime<'id> {
+        ExistentialLifetime(f(new_id()))
+    }
+}
+
+
+struct ExampleS<'id>(Id<'id>);
+
+struct ExampleMarker;
+
+impl HasLifetime for ExampleMarker {
+    type AtLifetime<'id> = ExampleS<'id>;
+}
+
+
+fn broken0() -> ExistentialLifetime<ExampleMarker> {
+    fn new_helper<'id>(id: Id<'id>) -> ExampleS<'id> {
+        ExampleS(id)
+    }
+
+    ExistentialLifetime::<ExampleMarker>::new(new_helper)
+}
+
+fn broken1() -> ExistentialLifetime<ExampleMarker> {
+    fn new_helper<'id>(id: Id<'id>) -> <ExampleMarker as HasLifetime>::AtLifetime<'id> {
+        ExampleS(id)
+    }
+
+    ExistentialLifetime::<ExampleMarker>::new(new_helper)
+}
+
+fn broken2() -> ExistentialLifetime<ExampleMarker> {
+    ExistentialLifetime::<ExampleMarker>::new(|id| ExampleS(id))
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-93342.rs b/src/test/ui/generic-associated-types/issue-93342.rs
new file mode 100644
index 00000000000..d8d7adac951
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-93342.rs
@@ -0,0 +1,57 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+use std::marker::PhantomData;
+
+pub trait Scalar: 'static {
+    type RefType<'a>: ScalarRef<'a>;
+}
+
+pub trait ScalarRef<'a>: 'a {}
+
+impl Scalar for i32 {
+    type RefType<'a> = i32;
+}
+
+impl Scalar for String {
+    type RefType<'a> = &'a str;
+}
+
+impl Scalar for bool {
+    type RefType<'a> = i32;
+}
+
+impl<'a> ScalarRef<'a> for bool {}
+
+impl<'a> ScalarRef<'a> for i32 {}
+
+impl<'a> ScalarRef<'a> for &'a str {}
+
+fn str_contains(a: &str, b: &str) -> bool {
+    a.contains(b)
+}
+
+pub struct BinaryExpression<A: Scalar, B: Scalar, O: Scalar, F>
+where
+    F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
+{
+    f: F,
+    _phantom: PhantomData<(A, B, O)>,
+}
+
+impl<A: Scalar, B: Scalar, O: Scalar, F> BinaryExpression<A, B, O, F>
+where
+    F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
+{
+    pub fn new(f: F) -> Self {
+        Self {
+            f,
+            _phantom: PhantomData,
+        }
+    }
+}
+
+fn main() {
+    BinaryExpression::<String, String, bool, _>::new(str_contains);
+}
diff --git a/src/test/ui/generics/single-colon-path-not-const-generics.rs b/src/test/ui/generics/single-colon-path-not-const-generics.rs
new file mode 100644
index 00000000000..55a7ae0bb6d
--- /dev/null
+++ b/src/test/ui/generics/single-colon-path-not-const-generics.rs
@@ -0,0 +1,13 @@
+pub mod foo {
+    pub mod bar {
+        pub struct A;
+    }
+}
+
+pub struct Foo {
+  a: Vec<foo::bar:A>,
+  //~^ ERROR expected
+  //~| HELP path separator
+}
+
+fn main() {}
diff --git a/src/test/ui/generics/single-colon-path-not-const-generics.stderr b/src/test/ui/generics/single-colon-path-not-const-generics.stderr
new file mode 100644
index 00000000000..3eafa9fa5a9
--- /dev/null
+++ b/src/test/ui/generics/single-colon-path-not-const-generics.stderr
@@ -0,0 +1,11 @@
+error: expected one of `,` or `>`, found `:`
+  --> $DIR/single-colon-path-not-const-generics.rs:8:18
+   |
+LL |   a: Vec<foo::bar:A>,
+   |                  ^
+   |                  |
+   |                  expected one of `,` or `>`
+   |                  help: write a path separator here: `::`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
index 14dbca60b78..c2c77290c43 100644
--- a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0f32, f32::NEG_INFINITY..);
    |        ^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `f32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:17:8
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0f32, ..f32::INFINITY);
    |        ^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `f32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8
@@ -22,8 +30,12 @@ error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
 LL |     m!('a', ..core::char::MAX);
    |        ^^^ pattern `'\u{10ffff}'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         '\u{10ffff}' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
@@ -31,8 +43,12 @@ error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
 LL |     m!('a', ..ALMOST_MAX);
    |        ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         '\u{10fffe}'..='\u{10ffff}' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'\u{0}'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8
@@ -40,8 +56,12 @@ error[E0004]: non-exhaustive patterns: `'\u{0}'` not covered
 LL |     m!('a', ALMOST_MIN..);
    |        ^^^ pattern `'\u{0}'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         '\u{0}' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8
@@ -49,8 +69,12 @@ error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
 LL |     m!('a', ..=ALMOST_MAX);
    |        ^^^ pattern `'\u{10ffff}'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         '\u{10ffff}' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'b'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:30:8
@@ -58,8 +82,12 @@ error[E0004]: non-exhaustive patterns: `'b'` not covered
 LL |     m!('a', ..=VAL | VAL_2..);
    |        ^^^ pattern `'b'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         'b' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'b'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:31:8
@@ -67,8 +95,12 @@ error[E0004]: non-exhaustive patterns: `'b'` not covered
 LL |     m!('a', ..VAL_1 | VAL_2..);
    |        ^^^ pattern `'b'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         'b' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12
@@ -76,8 +108,12 @@ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
 LL |         m!(0, ..u8::MAX);
    |            ^ pattern `u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
@@ -85,8 +121,12 @@ error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `254_u8..=u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         254_u8..=u8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
@@ -94,8 +134,12 @@ error[E0004]: non-exhaustive patterns: `0_u8` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12
@@ -103,8 +147,12 @@ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12
@@ -112,8 +160,12 @@ error[E0004]: non-exhaustive patterns: `43_u8` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:46:12
@@ -121,8 +173,12 @@ error[E0004]: non-exhaustive patterns: `43_u8` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12
@@ -130,8 +186,12 @@ error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
 LL |         m!(0, ..u16::MAX);
    |            ^ pattern `u16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
@@ -139,8 +199,12 @@ error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `65534_u16..=u16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         65534_u16..=u16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
@@ -148,8 +212,12 @@ error[E0004]: non-exhaustive patterns: `0_u16` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u16` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u16 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12
@@ -157,8 +225,12 @@ error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12
@@ -166,8 +238,12 @@ error[E0004]: non-exhaustive patterns: `43_u16` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u16` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u16 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:59:12
@@ -175,8 +251,12 @@ error[E0004]: non-exhaustive patterns: `43_u16` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u16` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u16 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12
@@ -184,8 +264,12 @@ error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
 LL |         m!(0, ..u32::MAX);
    |            ^ pattern `u32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
@@ -193,8 +277,12 @@ error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `4294967294_u32..=u32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         4294967294_u32..=u32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
@@ -202,8 +290,12 @@ error[E0004]: non-exhaustive patterns: `0_u32` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u32` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u32 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12
@@ -211,8 +303,12 @@ error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12
@@ -220,8 +316,12 @@ error[E0004]: non-exhaustive patterns: `43_u32` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u32` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u32 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:72:12
@@ -229,8 +329,12 @@ error[E0004]: non-exhaustive patterns: `43_u32` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u32` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u32 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12
@@ -238,8 +342,12 @@ error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
 LL |         m!(0, ..u64::MAX);
    |            ^ pattern `u64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
@@ -247,8 +355,12 @@ error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `18446744073709551614_u64..=u64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         18446744073709551614_u64..=u64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
@@ -256,8 +368,12 @@ error[E0004]: non-exhaustive patterns: `0_u64` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u64` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u64 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12
@@ -265,8 +381,12 @@ error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12
@@ -274,8 +394,12 @@ error[E0004]: non-exhaustive patterns: `43_u64` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u64` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u64 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:85:12
@@ -283,8 +407,12 @@ error[E0004]: non-exhaustive patterns: `43_u64` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u64` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u64 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
@@ -292,8 +420,12 @@ error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
 LL |         m!(0, ..u128::MAX);
    |            ^ pattern `u128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
@@ -301,8 +433,12 @@ error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         340282366920938463463374607431768211454_u128..=u128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
@@ -310,8 +446,12 @@ error[E0004]: non-exhaustive patterns: `0_u128` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u128 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12
@@ -319,8 +459,12 @@ error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12
@@ -328,8 +472,12 @@ error[E0004]: non-exhaustive patterns: `43_u128` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u128 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:98:12
@@ -337,8 +485,12 @@ error[E0004]: non-exhaustive patterns: `43_u128` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u128 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12
@@ -346,8 +498,12 @@ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
 LL |         m!(0, ..i8::MAX);
    |            ^ pattern `i8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
@@ -355,8 +511,12 @@ error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `126_i8..=i8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         126_i8..=i8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12
@@ -364,8 +524,12 @@ error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i8::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12
@@ -373,8 +537,12 @@ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12
@@ -382,8 +550,12 @@ error[E0004]: non-exhaustive patterns: `43_i8` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:114:12
@@ -391,8 +563,12 @@ error[E0004]: non-exhaustive patterns: `43_i8` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12
@@ -400,8 +576,12 @@ error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
 LL |         m!(0, ..i16::MAX);
    |            ^ pattern `i16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
@@ -409,8 +589,12 @@ error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `32766_i16..=i16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         32766_i16..=i16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i16::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12
@@ -418,8 +602,12 @@ error[E0004]: non-exhaustive patterns: `i16::MIN` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i16::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i16::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12
@@ -427,8 +615,12 @@ error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12
@@ -436,8 +628,12 @@ error[E0004]: non-exhaustive patterns: `43_i16` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i16` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i16 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:127:12
@@ -445,8 +641,12 @@ error[E0004]: non-exhaustive patterns: `43_i16` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i16` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i16 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12
@@ -454,8 +654,12 @@ error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
 LL |         m!(0, ..i32::MAX);
    |            ^ pattern `i32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
@@ -463,8 +667,12 @@ error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `2147483646_i32..=i32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         2147483646_i32..=i32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i32::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12
@@ -472,8 +680,12 @@ error[E0004]: non-exhaustive patterns: `i32::MIN` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i32::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i32::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12
@@ -481,8 +693,12 @@ error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12
@@ -490,8 +706,12 @@ error[E0004]: non-exhaustive patterns: `43_i32` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i32` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i32 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:140:12
@@ -499,8 +719,12 @@ error[E0004]: non-exhaustive patterns: `43_i32` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i32` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i32 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12
@@ -508,8 +732,12 @@ error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
 LL |         m!(0, ..i64::MAX);
    |            ^ pattern `i64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
@@ -517,8 +745,12 @@ error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `9223372036854775806_i64..=i64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         9223372036854775806_i64..=i64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i64::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12
@@ -526,8 +758,12 @@ error[E0004]: non-exhaustive patterns: `i64::MIN` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i64::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i64::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12
@@ -535,8 +771,12 @@ error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12
@@ -544,8 +784,12 @@ error[E0004]: non-exhaustive patterns: `43_i64` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i64` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i64 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:153:12
@@ -553,8 +797,12 @@ error[E0004]: non-exhaustive patterns: `43_i64` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i64` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i64 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
@@ -562,8 +810,12 @@ error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
 LL |         m!(0, ..i128::MAX);
    |            ^ pattern `i128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
@@ -571,8 +823,12 @@ error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         170141183460469231731687303715884105726_i128..=i128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i128::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12
@@ -580,8 +836,12 @@ error[E0004]: non-exhaustive patterns: `i128::MIN` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i128::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i128::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12
@@ -589,8 +849,12 @@ error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12
@@ -598,8 +862,12 @@ error[E0004]: non-exhaustive patterns: `43_i128` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i128 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:166:12
@@ -607,8 +875,12 @@ error[E0004]: non-exhaustive patterns: `43_i128` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i128 => todo!() }
+   |
 
 error: aborting due to 68 previous errors
 
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs
index 7c3c72e04cb..c6f29fa5908 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs
@@ -1,3 +1,5 @@
+// check-pass
+
 // FamilyType (GAT workaround)
 pub trait FamilyLt<'a> {
     type Out;
@@ -78,8 +80,6 @@ where P: Execute + 'static {
 
 fn main() {
     task(annotate(
-        //~^ the size
-        //~^^ the trait bound
         Annotate::<RefMutFamily<usize>>::new(),
         |value: &mut usize| {
             *value = 2;
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr
deleted file mode 100644
index 01b14660b65..00000000000
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr
+++ /dev/null
@@ -1,52 +0,0 @@
-error[E0277]: the size for values of type `impl Execute` cannot be known at compilation time
-  --> $DIR/issue-62529-1.rs:80:10
-   |
-LL |       task(annotate(
-   |  _____----_^
-   | |     |
-   | |     required by a bound introduced by this call
-LL | |
-LL | |
-LL | |         Annotate::<RefMutFamily<usize>>::new(),
-...  |
-LL | |         }
-LL | |     ));
-   | |_____^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `impl Execute`
-note: required by a bound in `task`
-  --> $DIR/issue-62529-1.rs:69:9
-   |
-LL | fn task<P>(processor: P) -> Task
-   |         ^ required by this bound in `task`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | fn task<P: ?Sized>(processor: P) -> Task
-   |          ++++++++
-
-error[E0277]: the trait bound `impl Execute: Execute` is not satisfied
-  --> $DIR/issue-62529-1.rs:80:10
-   |
-LL |       task(annotate(
-   |  _____----_^
-   | |     |
-   | |     required by a bound introduced by this call
-LL | |
-LL | |
-LL | |         Annotate::<RefMutFamily<usize>>::new(),
-...  |
-LL | |         }
-LL | |     ));
-   | |_____^ the trait `Execute` is not implemented for `impl Execute`
-   |
-note: required by a bound in `task`
-  --> $DIR/issue-62529-1.rs:70:10
-   |
-LL | fn task<P>(processor: P) -> Task
-   |    ---- required by a bound in this
-LL | where P: Execute + 'static {
-   |          ^^^^^^^ required by this bound in `task`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
index 7da6b029c26..e6ffe38ee92 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
@@ -1,5 +1,5 @@
 error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:57:5
+  --> $DIR/issue-71955.rs:54:5
    |
 LL |     foo(bar, "string", |s| s.len() == 5);
    |     ^^^ implementation of `Parser` is not general enough
@@ -8,79 +8,7 @@ LL |     foo(bar, "string", |s| s.len() == 5);
    = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
 
 error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:57:5
-   |
-LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:57:5
-   |
-LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:57:5
-   |
-LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:57:5
-   |
-LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:63:5
-   |
-LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:63:5
-   |
-LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:63:5
-   |
-LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:63:5
-   |
-LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:63:5
+  --> $DIR/issue-71955.rs:58:5
    |
 LL |     foo(baz, "string", |s| s.0.len() == 5);
    |     ^^^ implementation of `Parser` is not general enough
@@ -88,5 +16,5 @@ LL |     foo(baz, "string", |s| s.0.len() == 5);
    = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
    = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
 
-error: aborting due to 10 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr
index c2feaa91280..0f38f8e3283 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr
@@ -1,8 +1,79 @@
-error: fatal error triggered by #[rustc_error]
-  --> $DIR/issue-71955.rs:47:1
+error[E0308]: mismatched types
+  --> $DIR/issue-71955.rs:54:5
    |
-LL | fn main() {
-   | ^^^^^^^^^
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r, 's> FnOnce<(&'r &'s str,)>`
+              found type `for<'r> FnOnce<(&'r &str,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-71955.rs:54:24
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |                        ^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-71955.rs:34:9
+   |
+LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-71955.rs:54:5
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `FnOnce<(&&str,)>`
+              found type `for<'r> FnOnce<(&'r &str,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-71955.rs:54:24
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |                        ^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-71955.rs:34:44
+   |
+LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
+   |                                            ^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-71955.rs:58:5
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
+              found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-71955.rs:58:24
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |                        ^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-71955.rs:34:9
+   |
+LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-71955.rs:58:5
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `FnOnce<(&Wrapper<'_>,)>`
+              found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-71955.rs:58:24
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |                        ^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-71955.rs:34:44
+   |
+LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
+   |                                            ^^^^
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs
index 3d6778b6942..4b7e207b96d 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs
@@ -42,10 +42,7 @@ where
 
 struct Wrapper<'a>(&'a str);
 
-// Because nll currently succeeds and migrate doesn't
-#[rustc_error]
 fn main() {
-    //[nll]~^ fatal
     fn bar<'a>(s: &'a str) -> (&'a str, &'a str) {
         (&s[..1], &s[..])
     }
@@ -56,14 +53,10 @@ fn main() {
 
     foo(bar, "string", |s| s.len() == 5);
     //[migrate]~^ ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    //[nll]~^^ ERROR mismatched types
+    //[nll]~| ERROR mismatched types
     foo(baz, "string", |s| s.0.len() == 5);
     //[migrate]~^ ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    //[nll]~^^ ERROR mismatched types
+    //[nll]~| ERROR mismatched types
 }
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
index 3a4d6c02a15..fe319e6c851 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
@@ -6,7 +6,8 @@ trait SomeTrait<'a> {
 
 fn give_me_ice<T>() {
     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
-    //~^ ERROR: the trait bound `T: SomeTrait<'_>` is not satisfied
+    //~^ ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277]
+    //~| ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277]
 }
 
 fn callee<T: Fn<(&'static (),)>>() {
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
index aaf45dc7ad5..13b68b07240 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
@@ -9,6 +9,17 @@ help: consider restricting type parameter `T`
 LL | fn give_me_ice<T: SomeTrait<'_>>() {
    |                 +++++++++++++++
 
-error: aborting due to previous error
+error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied
+  --> $DIR/issue-85455.rs:8:14
+   |
+LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | fn give_me_ice<T: SomeTrait<'_>>() {
+   |                 +++++++++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/issues/issue-79099.stderr b/src/test/ui/impl-trait/issues/issue-79099.stderr
index 4c9ec2a83ff..362c67dafd2 100644
--- a/src/test/ui/impl-trait/issues/issue-79099.stderr
+++ b/src/test/ui/impl-trait/issues/issue-79099.stderr
@@ -6,7 +6,7 @@ LL |         let f: impl core::future::Future<Output = u8> = async { 1 };
    |                                                         |
    |                                                         `async` blocks are only allowed in Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = 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
diff --git a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs
index 3d8478f06db..6eabd9b1015 100644
--- a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs
+++ b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs
@@ -29,6 +29,11 @@ extern {
 #[rustc_legacy_const_generics(0)] //~ ERROR #[rustc_legacy_const_generics] functions must only have
 fn foo8<X>() {}
 
+impl S {
+    #[rustc_legacy_const_generics(0)] //~ ERROR attribute should be applied to a function
+    fn foo9<const X: usize>() {}
+}
+
 #[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute
 fn bar1() {}
 
diff --git a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr
index 1f55a8e72d2..bfe7bb2e10d 100644
--- a/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr
+++ b/src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr
@@ -7,13 +7,13 @@ LL | #[rustc_legacy_const_generics(0usize)]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: malformed `rustc_legacy_const_generics` attribute input
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:32:1
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:37:1
    |
 LL | #[rustc_legacy_const_generics]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]`
 
 error: malformed `rustc_legacy_const_generics` attribute input
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:35:1
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:40:1
    |
 LL | #[rustc_legacy_const_generics = 1]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]`
@@ -67,6 +67,14 @@ LL | fn foo8<X>() {}
    |         - non-const generic parameter
 
 error: attribute should be applied to a function
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:5
+   |
+LL |     #[rustc_legacy_const_generics(0)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fn foo9<const X: usize>() {}
+   |     ---------------------------- not a function
+
+error: attribute should be applied to a function
   --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:5
    |
 LL |     #[rustc_legacy_const_generics(1)]
@@ -82,6 +90,6 @@ LL |     fn foo7<const X: usize>();
    |
    = help: replace the const parameters with concrete consts
 
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0044`.
diff --git a/src/test/ui/issues/issue-17337.rs b/src/test/ui/issues/issue-17337.rs
index 3fd81401e00..193f89f8378 100644
--- a/src/test/ui/issues/issue-17337.rs
+++ b/src/test/ui/issues/issue-17337.rs
@@ -7,7 +7,7 @@ struct Foo;
 
 impl Foo {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn foo(self) {}
 }
 
diff --git a/src/test/ui/issues/issue-21596.stderr b/src/test/ui/issues/issue-21596.stderr
index b0524f056ef..a336d1b0ed5 100644
--- a/src/test/ui/issues/issue-21596.stderr
+++ b/src/test/ui/issues/issue-21596.stderr
@@ -1,8 +1,8 @@
-error[E0599]: the method `to_string` exists for raw pointer `*const u8`, but its trait bounds were not satisfied
+error[E0599]: `*const u8` doesn't implement `std::fmt::Display`
   --> $DIR/issue-21596.rs:4:22
    |
 LL |     println!("{}", z.to_string());
-   |                      ^^^^^^^^^ method cannot be called on `*const u8` due to unsatisfied trait bounds
+   |                      ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter
    |
    = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
    = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior
diff --git a/src/test/ui/issues/issue-23036.rs b/src/test/ui/issues/issue-23036.rs
index ac24648e49e..d67f184720e 100644
--- a/src/test/ui/issues/issue-23036.rs
+++ b/src/test/ui/issues/issue-23036.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-wasm32-bare FIXME(#93923) llvm miscompilation
 
 use std::collections::HashMap;
 use std::path::Path;
diff --git a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr
index 7895cefb4cb..a0d32616f83 100644
--- a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr
+++ b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr
@@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard
   --> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19
    |
 LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
-   |                   ^^             ---
-   |                   |              |
-   |                   |              move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
-   |                   |              move occurs due to use in closure
+   |                   ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                   |
    |                   move out of `foo` occurs here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr
index 6f345f56d1a..e5b671d7b7a 100644
--- a/src/test/ui/issues/issue-61108.stderr
+++ b/src/test/ui/issues/issue-61108.stderr
@@ -4,10 +4,7 @@ error[E0382]: borrow of moved value: `bad_letters`
 LL |     let mut bad_letters = vec!['e', 't', 'o', 'i'];
    |         --------------- move occurs because `bad_letters` has type `Vec<char>`, which does not implement the `Copy` trait
 LL |     for l in bad_letters {
-   |              -----------
-   |              |
-   |              `bad_letters` moved due to this implicit call to `.into_iter()`
-   |              help: consider borrowing to avoid moving into the for loop: `&bad_letters`
+   |              ----------- `bad_letters` moved due to this implicit call to `.into_iter()`
 ...
 LL |     bad_letters.push('s');
    |     ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
@@ -17,6 +14,10 @@ note: this function takes ownership of the receiver `self`, which moves `bad_let
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider iterating over a slice of the `Vec<char>`'s content to avoid moving into the `for` loop
+   |
+LL |     for l in &bad_letters {
+   |              +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr
index e0da3fd5195..ef178bbd155 100644
--- a/src/test/ui/issues/issue-64559.stderr
+++ b/src/test/ui/issues/issue-64559.stderr
@@ -4,10 +4,7 @@ error[E0382]: use of moved value: `orig`
 LL |     let orig = vec![true];
    |         ---- move occurs because `orig` has type `Vec<bool>`, which does not implement the `Copy` trait
 LL |     for _val in orig {}
-   |                 ----
-   |                 |
-   |                 `orig` moved due to this implicit call to `.into_iter()`
-   |                 help: consider borrowing to avoid moving into the for loop: `&orig`
+   |                 ---- `orig` moved due to this implicit call to `.into_iter()`
 LL |     let _closure = || orig;
    |                    ^^ ---- use occurs due to use in closure
    |                    |
@@ -18,6 +15,10 @@ note: this function takes ownership of the receiver `self`, which moves `orig`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop
+   |
+LL |     for _val in &orig {}
+   |                 +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-87707.rs b/src/test/ui/issues/issue-87707.rs
index d2e9343f86c..26e9e2c8f91 100644
--- a/src/test/ui/issues/issue-87707.rs
+++ b/src/test/ui/issues/issue-87707.rs
@@ -1,6 +1,7 @@
 // test for #87707
 // edition:2018
 // run-fail
+// exec-env:RUST_BACKTRACE=0
 // check-run-results
 
 use std::sync::Once;
diff --git a/src/test/ui/issues/issue-87707.run.stderr b/src/test/ui/issues/issue-87707.run.stderr
index 8f82ccc0c2a..e6c9ea0eb53 100644
--- a/src/test/ui/issues/issue-87707.run.stderr
+++ b/src/test/ui/issues/issue-87707.run.stderr
@@ -1,3 +1,3 @@
-thread 'main' panicked at 'Here Once instance is poisoned.', $DIR/issue-87707.rs:12:24
+thread 'main' panicked at 'Here Once instance is poisoned.', $DIR/issue-87707.rs:13:24
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at 'Once instance has previously been poisoned', $DIR/issue-87707.rs:14:7
+thread 'main' panicked at 'Once instance has previously been poisoned', $DIR/issue-87707.rs:15:7
diff --git a/src/test/ui/lint/auxiliary/inherited_stability.rs b/src/test/ui/lint/auxiliary/inherited_stability.rs
index 1e7eb26fde2..62100e5cc94 100644
--- a/src/test/ui/lint/auxiliary/inherited_stability.rs
+++ b/src/test/ui/lint/auxiliary/inherited_stability.rs
@@ -20,7 +20,7 @@ pub mod stable_mod {
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 pub mod unstable_mod {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated() {}
 
     pub fn unstable() {}
diff --git a/src/test/ui/lint/auxiliary/lint_output_format.rs b/src/test/ui/lint/auxiliary/lint_output_format.rs
index 58cae180196..4e3547250e4 100644
--- a/src/test/ui/lint/auxiliary/lint_output_format.rs
+++ b/src/test/ui/lint/auxiliary/lint_output_format.rs
@@ -4,7 +4,7 @@
 #![unstable(feature = "unstable_test_feature", issue = "none")]
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn foo() -> usize {
     20
 }
diff --git a/src/test/ui/lint/auxiliary/lint_stability.rs b/src/test/ui/lint/auxiliary/lint_stability.rs
index de4058887cf..99c29dcdda6 100644
--- a/src/test/ui/lint/auxiliary/lint_stability.rs
+++ b/src/test/ui/lint/auxiliary/lint_stability.rs
@@ -5,21 +5,21 @@
 #![stable(feature = "lint_stability", since = "1.0.0")]
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated() {}
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_text() {}
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "99.99.99", reason = "text")]
+#[deprecated(since = "99.99.99", note = "text")]
 pub fn deprecated_future() {}
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_unstable() {}
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_unstable_text() {}
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -37,17 +37,17 @@ pub struct MethodTester;
 
 impl MethodTester {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated(&self) {}
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_unstable(&self) {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_unstable_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -64,17 +64,17 @@ impl MethodTester {
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub trait Trait {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated(&self) {}
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_unstable(&self) {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_unstable_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -93,7 +93,7 @@ pub trait TraitWithAssociatedTypes {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     type TypeUnstable = u8;
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     type TypeDeprecated = u8;
 }
 
@@ -104,18 +104,18 @@ impl Trait for MethodTester {}
 pub trait UnstableTrait { fn dummy(&self) { } }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub trait DeprecatedTrait {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] fn dummy(&self) { }
 }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedStruct {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
 }
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableStruct {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
 }
@@ -133,10 +133,10 @@ pub enum UnstableEnum {}
 pub enum StableEnum {}
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnitStruct;
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableUnitStruct;
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 pub struct UnstableUnitStruct;
@@ -146,10 +146,10 @@ pub struct StableUnitStruct;
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub enum Enum {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     DeprecatedVariant,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     DeprecatedUnstableVariant,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     UnstableVariant,
@@ -159,10 +159,10 @@ pub enum Enum {
 }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
diff --git a/src/test/ui/lint/auxiliary/lint_stability_fields.rs b/src/test/ui/lint/auxiliary/lint_stability_fields.rs
index 3cbb48c4a6b..e72a501e11b 100644
--- a/src/test/ui/lint/auxiliary/lint_stability_fields.rs
+++ b/src/test/ui/lint/auxiliary/lint_stability_fields.rs
@@ -6,7 +6,7 @@ pub struct Stable {
     pub inherit: u8,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub override1: u8,
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub override2: u8,
     #[stable(feature = "rust2", since = "2.0.0")]
@@ -17,7 +17,7 @@ pub struct Stable {
 pub struct Stable2(#[stable(feature = "rust2", since = "2.0.0")] pub u8,
                    #[unstable(feature = "unstable_test_feature", issue = "none")] pub u8,
                    #[unstable(feature = "unstable_test_feature", issue = "none")]
-                   #[rustc_deprecated(since = "1.0.0", reason = "text")] pub u8,
+                   #[deprecated(since = "1.0.0", note = "text")] pub u8,
                    pub u8);
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -28,7 +28,7 @@ pub enum Stable3 {
     Override1,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     Override2,
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     Override3,
 }
@@ -38,7 +38,7 @@ pub struct Unstable {
     pub inherit: u8,
     #[stable(feature = "rust1", since = "1.0.0")]
     pub override1: u8,
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub override2: u8,
 }
@@ -47,10 +47,10 @@ pub struct Unstable {
 pub struct Unstable2(pub u8,
                      #[stable(feature = "rust1", since = "1.0.0")] pub u8,
                      #[unstable(feature = "unstable_test_feature", issue = "none")]
-                     #[rustc_deprecated(since = "1.0.0", reason = "text")] pub u8);
+                     #[deprecated(since = "1.0.0", note = "text")] pub u8);
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct Deprecated {
     pub inherit: u8,
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -60,7 +60,7 @@ pub struct Deprecated {
 }
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct Deprecated2(pub u8,
                        #[stable(feature = "rust1", since = "1.0.0")] pub u8,
                        #[unstable(feature = "unstable_test_feature", issue = "none")] pub u8);
diff --git a/src/test/ui/lint/lint-stability-2.rs b/src/test/ui/lint/lint-stability-2.rs
index 2a4f95f555f..94a8d08c8fe 100644
--- a/src/test/ui/lint/lint-stability-2.rs
+++ b/src/test/ui/lint/lint-stability-2.rs
@@ -169,10 +169,10 @@ mod cross_crate {
 
 mod this_crate {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated() {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated_text() {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -190,10 +190,10 @@ mod this_crate {
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -209,10 +209,10 @@ mod this_crate {
 
     pub trait Trait {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -229,7 +229,7 @@ mod this_crate {
     impl Trait for MethodTester {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedStruct {
         #[stable(feature = "stable_test_feature", since = "1.0.0")] i: isize
     }
@@ -243,7 +243,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedUnitStruct;
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableUnitStruct;
@@ -252,7 +252,7 @@ mod this_crate {
 
     pub enum Enum {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         DeprecatedVariant,
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         UnstableVariant,
@@ -262,7 +262,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedTupleStruct(isize);
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableTupleStruct(isize);
@@ -382,7 +382,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn test_fn_body() {
         fn fn_in_body() {}
         fn_in_body();
@@ -390,7 +390,7 @@ mod this_crate {
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn test_method_body(&self) {
             fn fn_in_body() {}
             fn_in_body();
@@ -398,7 +398,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub trait DeprecatedTrait {
         fn dummy(&self) { }
     }
diff --git a/src/test/ui/lint/lint-stability-deprecated.rs b/src/test/ui/lint/lint-stability-deprecated.rs
index 2f600971da1..bdc66e83083 100644
--- a/src/test/ui/lint/lint-stability-deprecated.rs
+++ b/src/test/ui/lint/lint-stability-deprecated.rs
@@ -219,10 +219,10 @@ mod inheritance {
 
 mod this_crate {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated() {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated_text() {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -240,10 +240,10 @@ mod this_crate {
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -259,10 +259,10 @@ mod this_crate {
 
     pub trait Trait {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -279,7 +279,7 @@ mod this_crate {
     impl Trait for MethodTester {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedStruct {
         #[stable(feature = "stable_test_feature", since = "1.0.0")] i: isize
     }
@@ -293,7 +293,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedUnitStruct;
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableUnitStruct;
@@ -302,7 +302,7 @@ mod this_crate {
 
     pub enum Enum {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         DeprecatedVariant,
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         UnstableVariant,
@@ -312,7 +312,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedTupleStruct(isize);
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableTupleStruct(isize);
@@ -433,7 +433,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn test_fn_body() {
         fn fn_in_body() {}
         fn_in_body(); //~ WARN use of deprecated function `this_crate::test_fn_body::fn_in_body`: text
@@ -441,7 +441,7 @@ mod this_crate {
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn test_method_body(&self) {
             fn fn_in_body() {}
             fn_in_body(); //~ WARN use of deprecated function `this_crate::MethodTester::test_method_body::fn_in_body`: text
@@ -449,7 +449,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub trait DeprecatedTrait {
         fn dummy(&self) { }
     }
diff --git a/src/test/ui/lint/lint-stability-fields-deprecated.rs b/src/test/ui/lint/lint-stability-fields-deprecated.rs
index a44eb1ce10a..a5511966d7e 100644
--- a/src/test/ui/lint/lint-stability-fields-deprecated.rs
+++ b/src/test/ui/lint/lint-stability-fields-deprecated.rs
@@ -160,7 +160,7 @@ mod this_crate {
         inherit: u8,
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override1: u8,
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override2: u8,
     }
@@ -169,14 +169,14 @@ mod this_crate {
     struct Stable2(u8,
                    #[stable(feature = "rust1", since = "1.0.0")] u8,
                    #[unstable(feature = "unstable_test_feature", issue = "none")]
-                   #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+                   #[deprecated(since = "1.0.0", note = "text")] u8);
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     struct Unstable {
         inherit: u8,
         #[stable(feature = "rust1", since = "1.0.0")]
         override1: u8,
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override2: u8,
     }
@@ -185,10 +185,10 @@ mod this_crate {
     struct Unstable2(u8,
                      #[stable(feature = "rust1", since = "1.0.0")] u8,
                      #[unstable(feature = "unstable_test_feature", issue = "none")]
-                     #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+                     #[deprecated(since = "1.0.0", note = "text")] u8);
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     struct Deprecated {
         inherit: u8,
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -198,7 +198,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     struct Deprecated2(u8,
                        #[stable(feature = "rust1", since = "1.0.0")] u8,
                        #[unstable(feature = "unstable_test_feature", issue = "none")] u8);
diff --git a/src/test/ui/lint/lint-stability-fields.rs b/src/test/ui/lint/lint-stability-fields.rs
index 40836489848..51990b6eef1 100644
--- a/src/test/ui/lint/lint-stability-fields.rs
+++ b/src/test/ui/lint/lint-stability-fields.rs
@@ -135,7 +135,7 @@ mod this_crate {
         inherit: u8,
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override1: u8,
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override2: u8,
         #[stable(feature = "rust2", since = "2.0.0")]
@@ -146,14 +146,14 @@ mod this_crate {
     struct Stable2(u8,
                    #[stable(feature = "rust2", since = "2.0.0")] u8,
                    #[unstable(feature = "unstable_test_feature", issue = "none")]
-                   #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+                   #[deprecated(since = "1.0.0", note = "text")] u8);
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     struct Unstable {
         inherit: u8,
         #[stable(feature = "rust1", since = "1.0.0")]
         override1: u8,
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override2: u8,
     }
@@ -162,10 +162,10 @@ mod this_crate {
     struct Unstable2(u8,
                      #[stable(feature = "rust1", since = "1.0.0")] u8,
                      #[unstable(feature = "unstable_test_feature", issue = "none")]
-                     #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+                     #[deprecated(since = "1.0.0", note = "text")] u8);
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     struct Deprecated {
         inherit: u8,
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -175,7 +175,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     struct Deprecated2(u8,
                        #[stable(feature = "rust1", since = "1.0.0")] u8,
                        #[unstable(feature = "unstable_test_feature", issue = "none")] u8);
diff --git a/src/test/ui/lint/lint-stability.rs b/src/test/ui/lint/lint-stability.rs
index e5620a9f8e7..464b32c5f43 100644
--- a/src/test/ui/lint/lint-stability.rs
+++ b/src/test/ui/lint/lint-stability.rs
@@ -204,14 +204,14 @@ mod inheritance {
 
 mod this_crate {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated() {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated_text() {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(since = "99.99.99", reason = "text")]
+    #[deprecated(since = "99.99.99", note = "text")]
     pub fn deprecated_future() {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -229,10 +229,10 @@ mod this_crate {
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -248,10 +248,10 @@ mod this_crate {
 
     pub trait Trait {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -268,7 +268,7 @@ mod this_crate {
     impl Trait for MethodTester {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedStruct {
         #[stable(feature = "stable_test_feature", since = "1.0.0")] i: isize
     }
@@ -282,7 +282,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedUnitStruct;
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableUnitStruct;
@@ -291,7 +291,7 @@ mod this_crate {
 
     pub enum Enum {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         DeprecatedVariant,
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         UnstableVariant,
@@ -301,7 +301,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedTupleStruct(isize);
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableTupleStruct(isize);
@@ -423,7 +423,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn test_fn_body() {
         fn fn_in_body() {}
         fn_in_body();
@@ -431,7 +431,7 @@ mod this_crate {
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn test_method_body(&self) {
             fn fn_in_body() {}
             fn_in_body();
@@ -439,7 +439,7 @@ mod this_crate {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub trait DeprecatedTrait {
         fn dummy(&self) { }
     }
diff --git a/src/test/ui/lint/must_not_suspend/gated.rs b/src/test/ui/lint/must_not_suspend/gated.rs
index acb81b0bf9d..b73a7655529 100644
--- a/src/test/ui/lint/must_not_suspend/gated.rs
+++ b/src/test/ui/lint/must_not_suspend/gated.rs
@@ -1,12 +1,15 @@
+// check-pass
+
 // edition:2018
-#![deny(must_not_suspend)]  //~ ERROR the `must_not_suspend`
-//~| ERROR the `must_not_suspend`
-//~| ERROR the `must_not_suspend`
+#![deny(must_not_suspend)]
+//~^ WARNING unknown lint: `must_not_suspend`
+//~| WARNING unknown lint: `must_not_suspend`
+//~| WARNING unknown lint: `must_not_suspend`
 
 async fn other() {}
 
 pub async fn uhoh(m: std::sync::Mutex<()>) {
-    let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across
+    let _guard = m.lock().unwrap();
     other().await;
 }
 
diff --git a/src/test/ui/lint/must_not_suspend/gated.stderr b/src/test/ui/lint/must_not_suspend/gated.stderr
index 0d4319670e6..b58ecb55596 100644
--- a/src/test/ui/lint/must_not_suspend/gated.stderr
+++ b/src/test/ui/lint/must_not_suspend/gated.stderr
@@ -1,54 +1,33 @@
-error[E0658]: the `must_not_suspend` lint is unstable
-  --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+  --> $DIR/gated.rs:4:1
    |
 LL | #![deny(must_not_suspend)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `must_not_suspend` lint is unstable
    = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
    = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
 
-error[E0658]: the `must_not_suspend` lint is unstable
-  --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+  --> $DIR/gated.rs:4:1
    |
 LL | #![deny(must_not_suspend)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `must_not_suspend` lint is unstable
    = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
    = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
 
-error[E0658]: the `must_not_suspend` lint is unstable
-  --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+  --> $DIR/gated.rs:4:1
    |
 LL | #![deny(must_not_suspend)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `must_not_suspend` lint is unstable
    = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
    = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
 
-error: `MutexGuard` held across a suspend point, but should not be
-  --> $DIR/gated.rs:9:9
-   |
-LL |     let _guard = m.lock().unwrap();
-   |         ^^^^^^
-LL |     other().await;
-   |            ------ the value is held across this suspend point
-   |
-note: the lint level is defined here
-  --> $DIR/gated.rs:2:9
-   |
-LL | #![deny(must_not_suspend)]
-   |         ^^^^^^^^^^^^^^^^
-note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send`
-  --> $DIR/gated.rs:9:9
-   |
-LL |     let _guard = m.lock().unwrap();
-   |         ^^^^^^
-help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/gated.rs:9:9
-   |
-LL |     let _guard = m.lock().unwrap();
-   |         ^^^^^^
-
-error: aborting due to 4 previous errors
+warning: 3 warnings emitted
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs b/src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs
new file mode 100644
index 00000000000..bafdea96e08
--- /dev/null
+++ b/src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs
@@ -0,0 +1,14 @@
+#![feature(lint_reasons)]
+
+#![deny(unused_attributes)]
+
+#[allow(reason = "I want to allow something")]//~ ERROR unused attribute
+#[expect(reason = "I don't know what I'm waiting for")]//~ ERROR unused attribute
+#[warn(reason = "This should be warn by default")]//~ ERROR unused attribute
+#[deny(reason = "All listed lints are denied")]//~ ERROR unused attribute
+#[forbid(reason = "Just some reason")]//~ ERROR unused attribute
+
+#[allow(clippy::box_collection, reason = "This is still valid")]
+#[warn(dead_code, reason = "This is also reasonable")]
+
+fn main() {}
diff --git a/src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr b/src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr
new file mode 100644
index 00000000000..3bf8137dc6e
--- /dev/null
+++ b/src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr
@@ -0,0 +1,47 @@
+error: unused attribute
+  --> $DIR/lint-attribute-only-with-reason.rs:5:1
+   |
+LL | #[allow(reason = "I want to allow something")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: the lint level is defined here
+  --> $DIR/lint-attribute-only-with-reason.rs:3:9
+   |
+LL | #![deny(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+   = note: attribute `allow` without any lints has no effect
+
+error: unused attribute
+  --> $DIR/lint-attribute-only-with-reason.rs:6:1
+   |
+LL | #[expect(reason = "I don't know what I'm waiting for")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `expect` without any lints has no effect
+
+error: unused attribute
+  --> $DIR/lint-attribute-only-with-reason.rs:7:1
+   |
+LL | #[warn(reason = "This should be warn by default")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `warn` without any lints has no effect
+
+error: unused attribute
+  --> $DIR/lint-attribute-only-with-reason.rs:8:1
+   |
+LL | #[deny(reason = "All listed lints are denied")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `deny` without any lints has no effect
+
+error: unused attribute
+  --> $DIR/lint-attribute-only-with-reason.rs:9:1
+   |
+LL | #[forbid(reason = "Just some reason")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `forbid` without any lints has no effect
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/loops/issue-82916.stderr b/src/test/ui/loops/issue-82916.stderr
index ad42cce71f6..57d76016c45 100644
--- a/src/test/ui/loops/issue-82916.stderr
+++ b/src/test/ui/loops/issue-82916.stderr
@@ -4,10 +4,7 @@ error[E0382]: use of moved value: `x`
 LL | fn foo(x: Vec<S>) {
    |        - move occurs because `x` has type `Vec<S>`, which does not implement the `Copy` trait
 LL |     for y in x {
-   |              -
-   |              |
-   |              `x` moved due to this implicit call to `.into_iter()`
-   |              help: consider borrowing to avoid moving into the for loop: `&x`
+   |              - `x` moved due to this implicit call to `.into_iter()`
 ...
 LL |     let z = x;
    |             ^ value used here after move
@@ -17,6 +14,10 @@ note: this function takes ownership of the receiver `self`, which moves `x`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider iterating over a slice of the `Vec<S>`'s content to avoid moving into the `for` loop
+   |
+LL |     for y in &x {
+   |              +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/macros/auxiliary/unstable-macros.rs b/src/test/ui/macros/auxiliary/unstable-macros.rs
index 123e244a53e..3aadd4b0ca6 100644
--- a/src/test/ui/macros/auxiliary/unstable-macros.rs
+++ b/src/test/ui/macros/auxiliary/unstable-macros.rs
@@ -7,7 +7,7 @@
 macro_rules! unstable_macro{ () => () }
 
 #[stable(feature = "deprecated_macros", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "deprecation reason")]
+#[deprecated(since = "1.0.0", note = "deprecation note")]
 #[macro_export]
 macro_rules! deprecated_macro{ () => () }
 
diff --git a/src/test/ui/macros/macro-stability.rs b/src/test/ui/macros/macro-stability.rs
index 019f6a874ca..ed7618a672b 100644
--- a/src/test/ui/macros/macro-stability.rs
+++ b/src/test/ui/macros/macro-stability.rs
@@ -14,7 +14,7 @@ macro_rules! local_unstable { () => () }
 macro local_unstable_modern() {}
 
 #[stable(feature = "deprecated_macros", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "local deprecation reason")]
+#[deprecated(since = "1.0.0", note = "local deprecation note")]
 #[macro_export]
 macro_rules! local_deprecated{ () => () }
 
@@ -25,7 +25,7 @@ fn main() {
     // unstable_macro_modern!(); // ERROR use of unstable library feature 'unstable_macros'
 
     deprecated_macro!();
-    //~^ WARN use of deprecated macro `deprecated_macro`: deprecation reason
+    //~^ WARN use of deprecated macro `deprecated_macro`: deprecation note
     local_deprecated!();
-    //~^ WARN use of deprecated macro `local_deprecated`: local deprecation reason
+    //~^ WARN use of deprecated macro `local_deprecated`: local deprecation note
 }
diff --git a/src/test/ui/macros/macro-stability.stderr b/src/test/ui/macros/macro-stability.stderr
index 75da9f47a35..2cfdb52b174 100644
--- a/src/test/ui/macros/macro-stability.stderr
+++ b/src/test/ui/macros/macro-stability.stderr
@@ -22,7 +22,7 @@ LL |     unstable_macro!();
    |
    = help: add `#![feature(unstable_macros)]` to the crate attributes to enable
 
-warning: use of deprecated macro `deprecated_macro`: deprecation reason
+warning: use of deprecated macro `deprecated_macro`: deprecation note
   --> $DIR/macro-stability.rs:27:5
    |
 LL |     deprecated_macro!();
@@ -30,7 +30,7 @@ LL |     deprecated_macro!();
    |
    = note: `#[warn(deprecated)]` on by default
 
-warning: use of deprecated macro `local_deprecated`: local deprecation reason
+warning: use of deprecated macro `local_deprecated`: local deprecation note
   --> $DIR/macro-stability.rs:29:5
    |
 LL |     local_deprecated!();
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs b/src/test/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
new file mode 100644
index 00000000000..ab8d95a41d0
--- /dev/null
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
@@ -0,0 +1,271 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+fn main() {
+    macro_rules! one_nested_count_and_length {
+        ( $( [ $( $l:literal ),* ] ),* ) => {
+            [
+                // outer-most repetition
+                $(
+                    // inner-most repetition
+                    $(
+                        ${ignore(l)} ${index()}, ${length()},
+                    )*
+                    ${count(l)}, ${index()}, ${length()},
+                )*
+                ${count(l)},
+            ]
+        };
+    }
+    assert_eq!(
+        one_nested_count_and_length!(["foo"], ["bar", "baz"]),
+        [
+            // # ["foo"]
+
+            // ## inner-most repetition (first iteration)
+            //
+            // `index` is 0 because this is the first inner-most iteration.
+            // `length` is 1 because there is only one inner-most repetition, "foo".
+            0, 1,
+
+            // ## outer-most repetition (first iteration)
+            //
+            // `count` is 1 because of "foo", i,e, `$l` has only one repetition,
+            // `index` is 0 because this is the first outer-most iteration.
+            // `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+            1, 0, 2,
+
+            // # ["bar", "baz"]
+
+            // ## inner-most repetition (first iteration)
+            //
+            // `index` is 0 because this is the first inner-most iteration
+            // `length` is 2 because there are repetitions, "bar" and "baz"
+            0, 2,
+
+            // ## inner-most repetition (second iteration)
+            //
+            // `index` is 1 because this is the second inner-most iteration
+            // `length` is 2 because there are repetitions, "bar" and "baz"
+            1, 2,
+
+            // ## outer-most repetition (second iteration)
+            //
+            // `count` is 2 because of "bar" and "baz", i,e, `$l` has two repetitions,
+            // `index` is 1 because this is the second outer-most iteration
+            // `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+            2, 1, 2,
+
+            // # last count
+
+            // Because there are a total of 3 repetitions of `$l`, "foo", "bar" and "baz"
+            3,
+        ]
+    );
+
+    // Based on the above explanation, the following macros should be straightforward
+
+    // Grouped from the outer-most to the inner-most
+    macro_rules! three_nested_count {
+        ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
+            &[
+                $( $( $(
+                    &[
+                        ${ignore(i)} ${count(i, 0)},
+                    ][..],
+                )* )* )*
+
+                $( $(
+                    &[
+                        ${ignore(i)} ${count(i, 0)},
+                        ${ignore(i)} ${count(i, 1)},
+                    ][..],
+                )* )*
+
+                $(
+                    &[
+                        ${ignore(i)} ${count(i, 0)},
+                        ${ignore(i)} ${count(i, 1)},
+                        ${ignore(i)} ${count(i, 2)},
+                    ][..],
+                )*
+
+                &[
+                    ${count(i, 0)},
+                    ${count(i, 1)},
+                    ${count(i, 2)},
+                    ${count(i, 3)},
+                ][..]
+            ][..]
+        }
+    }
+    assert_eq!(
+        three_nested_count!(
+            {
+                [ (a b c) (d e f) ]
+                [ (g h) (i j k l m) ]
+                [ (n) ]
+            }
+            {
+                [ (o) (p q) (r s) ]
+                [ (t u v w x y z) ]
+            }
+        ),
+        &[
+            // a b c
+            &[3][..],
+            // d e f
+            &[3][..],
+            // g h
+            &[2][..],
+            // i j k l m
+            &[5][..],
+            // n
+            &[1][..],
+            // o
+            &[1][..],
+            // p q
+            &[2][..],
+            // r s
+            &[2][..],
+            // t u v w x y z
+            &[7][..],
+
+            // (a b c) (d e f)
+            &[2, 6][..],
+            // (g h) (i j k l m)
+            &[2, 7][..],
+            // (n)
+            &[1, 1][..],
+            // (o) (p q) (r s)
+            &[3, 5][..],
+            // (t u v w x y z)
+            &[1, 7][..],
+
+            // [ (a b c) (d e f) ]
+            // [ (g h) (i j k l m) ]
+            // [ (n) ]
+            &[3, 5, 14][..],
+            // [ (o) (p q) (r s) ]
+            // [ (t u v w x y z) ]
+            &[2, 4, 12][..],
+
+            // {
+            //     [ (a b c) (d e f) ]
+            //     [ (g h) (i j k l m) ]
+            //     [ (n) ]
+            // }
+            // {
+            //     [ (o) (p q) (r s) ]
+            //     [ (t u v w x y z) ]
+            // }
+            &[2, 5, 9, 26][..]
+        ][..]
+    );
+
+    // Grouped from the outer-most to the inner-most
+    macro_rules! three_nested_length {
+        ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
+            &[
+                $( $( $( $(
+                    &[
+                        ${ignore(i)} ${length(3)},
+                        ${ignore(i)} ${length(2)},
+                        ${ignore(i)} ${length(1)},
+                        ${ignore(i)} ${length(0)},
+                    ][..],
+                )* )* )* )*
+
+                $( $( $(
+                    &[
+                        ${ignore(i)} ${length(2)},
+                        ${ignore(i)} ${length(1)},
+                        ${ignore(i)} ${length(0)},
+                    ][..],
+                )* )* )*
+
+                $( $(
+                    &[
+                        ${ignore(i)} ${length(1)},
+                        ${ignore(i)} ${length(0)},
+                    ][..],
+                )* )*
+
+                $(
+                    &[
+                        ${ignore(i)} ${length(0)},
+                    ][..],
+                )*
+            ][..]
+        }
+    }
+    assert_eq!(
+        three_nested_length!(
+            {
+                [ (a b c) (d e f) ]
+                [ (g h) (i j k l m) ]
+                [ (n) ]
+            }
+            {
+                [ (o) (p q) (r s) ]
+                [ (t u v w x y z) ]
+            }
+        ),
+        &[
+            // a b c
+            &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..],
+            // d e f
+            &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..],
+            // g h
+            &[2, 3, 2, 2][..], &[2, 3, 2, 2][..],
+            // i j k l m
+            &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..],
+            &[2, 3, 2, 5][..],
+            // n
+            &[2, 3, 1, 1][..],
+            // o
+            &[2, 2, 3, 1][..],
+            // p q
+            &[2, 2, 3, 2][..], &[2, 2, 3, 2][..],
+            // r s
+            &[2, 2, 3, 2][..], &[2, 2, 3, 2][..],
+            // t u v w x y z
+            &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..],
+            &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..],
+
+            // (a b c) (d e f)
+            &[2, 3, 2][..], &[2, 3, 2][..],
+            // (g h) (i j k l m)
+            &[2, 3, 2][..], &[2, 3, 2][..],
+            // (n)
+            &[2, 3, 1][..],
+            // (o) (p q) (r s)
+            &[2, 2, 3][..], &[2, 2, 3][..], &[2, 2, 3][..],
+            // (t u v w x y z)
+            &[2, 2, 1][..],
+
+            // [ (a b c) (d e f) ]
+            // [ (g h) (i j k l m) ]
+            // [ (n) ]
+            &[2, 3][..], &[2, 3][..],  &[2, 3,][..],
+            // [ (o) (p q) (r s) ]
+            // [ (t u v w x y z) ]
+            &[2, 2][..], &[2, 2][..],
+
+            // {
+            //     [ (a b c) (d e f) ]
+            //     [ (g h) (i j k l m) ]
+            //     [ (n) ]
+            // }
+            // {
+            //     [ (o) (p q) (r s) ]
+            //     [ (t u v w x y z) ]
+            // }
+            &[2][..], &[2][..]
+        ][..]
+    );
+
+    // It is possible to say, to some degree, that count is an "amalgamation" of length (see
+    // each length line result and compare them with the count results)
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs b/src/test/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs
new file mode 100644
index 00000000000..ed94c27cf05
--- /dev/null
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+macro_rules! nested {
+    ( $a:ident ) => {
+        macro_rules! $a {
+            ( $$( $b:ident ),* ) => {
+                $$(
+                    macro_rules! $b {
+                        ( $$$$( $c:ident ),* ) => {
+                            $$$$(
+                                fn $c() -> &'static str { stringify!($c) }
+                            ),*
+                        };
+                    }
+                )*
+            };
+        }
+    };
+}
+
+fn main() {
+    nested!(a);
+    a!(b);
+    b!(c);
+    assert_eq!(c(), "c");
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs b/src/test/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs
new file mode 100644
index 00000000000..d05cd1b31bc
--- /dev/null
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs
@@ -0,0 +1,148 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+/// Count the number of idents in a macro repetition.
+macro_rules! count_idents {
+    ( $( $i:ident ),* ) => {
+        ${count(i)}
+    };
+}
+
+/// Count the number of idents in a 2-dimensional macro repetition.
+macro_rules! count_idents_2 {
+    ( $( [ $( $i:ident ),* ] ),* ) => {
+        ${count(i)}
+    };
+}
+
+/// Mostly counts the number of OUTER-MOST repetitions
+macro_rules! count_depth_limits {
+    ( $( { $( [ $( $outer:ident : ( $( $inner:ident )* ) )* ] )* } )* ) => {
+        (
+            (
+                ${count(inner)},
+                ${count(inner, 0)},
+                ${count(inner, 1)},
+                ${count(inner, 2)},
+                ${count(inner, 3)},
+            ),
+            (
+                ${count(outer)},
+                ${count(outer, 0)},
+                ${count(outer, 1)},
+                ${count(outer, 2)},
+            ),
+        )
+    };
+}
+
+/// Produce (index, length) pairs for literals in a macro repetition.
+/// The literal is not included in the output, so this macro uses the
+/// `ignore` meta-variable expression to create a non-expanding
+/// repetition binding.
+macro_rules! enumerate_literals {
+    ( $( ($l:stmt) ),* ) => {
+        [$( ${ignore(l)} (${index()}, ${length()}) ),*]
+    };
+}
+
+/// Produce index and length tuples for literals in a 2-dimensional
+/// macro repetition.
+macro_rules! enumerate_literals_2 {
+    ( $( [ $( ($l:literal) ),* ] ),* ) => {
+        [
+            $(
+                $(
+                    (
+                        ${index(1)},
+                        ${length(1)},
+                        ${index(0)},
+                        ${length(0)},
+                        $l
+                    ),
+                )*
+            )*
+        ]
+    };
+}
+
+/// Generate macros that count idents and then add a constant number
+/// to the count.
+///
+/// This macro uses dollar escaping to make it unambiguous as to which
+/// macro the repetition belongs to.
+macro_rules! make_count_adders {
+    ( $( $i:ident, $b:literal );* ) => {
+        $(
+            macro_rules! $i {
+                ( $$( $$j:ident ),* ) => {
+                    $b + $${count(j)}
+                };
+            }
+        )*
+    };
+}
+
+make_count_adders! { plus_one, 1; plus_five, 5 }
+
+/// Generate a macro that allows selection of a particular literal
+/// from a sequence of inputs by their identifier.
+///
+/// This macro uses dollar escaping to make it unambiguous as to which
+/// macro the repetition belongs to, and to allow expansion of an
+/// identifier the name of which is not known in the definition
+/// of `make_picker`.
+macro_rules! make_picker {
+    ( $m:ident => $( $i:ident ),* ; $p:ident ) => {
+        macro_rules! $m {
+            ( $( $$ $i:literal ),* ) => {
+                $$ $p
+            };
+        }
+    };
+}
+
+make_picker!(first => a, b; a);
+
+make_picker!(second => a, b; b);
+
+fn main() {
+    assert_eq!(count_idents!(a, b, c), 3);
+    assert_eq!(count_idents_2!([a, b, c], [d, e], [f]), 6);
+    assert_eq!(
+        count_depth_limits! {
+            {
+                [ A: (a b c) D: (d e f) ]
+                [ G: (g h) I: (i j k l m) ]
+                [ N: (n) ]
+            }
+            {
+                [ O: (o) P: (p q) R: (r s) ]
+                [ T: (t u v w x y z) ]
+            }
+        },
+        ((26, 2, 5, 9, 26), (9, 2, 5, 9))
+    );
+    assert_eq!(enumerate_literals![("foo"), ("bar")], [(0, 2), (1, 2)]);
+    assert_eq!(
+        enumerate_literals_2![
+            [("foo"), ("bar"), ("baz")],
+            [("qux"), ("quux"), ("quuz"), ("xyzzy")]
+        ],
+        [
+            (0, 2, 0, 3, "foo"),
+            (0, 2, 1, 3, "bar"),
+            (0, 2, 2, 3, "baz"),
+
+            (1, 2, 0, 4, "qux"),
+            (1, 2, 1, 4, "quux"),
+            (1, 2, 2, 4, "quuz"),
+            (1, 2, 3, 4, "xyzzy"),
+        ]
+    );
+    assert_eq!(plus_one!(a, b, c), 4);
+    assert_eq!(plus_five!(a, b), 7);
+    assert_eq!(first!(1, 2), 1);
+    assert_eq!(second!(1, 2), 2);
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs b/src/test/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
new file mode 100644
index 00000000000..b954967c4fe
--- /dev/null
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
@@ -0,0 +1,102 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+#[derive(Debug)]
+struct Example<'a> {
+    _indexes: &'a [(u32, u32)],
+    _counts: &'a [u32],
+    _nested: Vec<Example<'a>>,
+}
+
+macro_rules! example {
+    ( $( [ $( ( $( $x:ident )* ) )* ] )* ) => {
+        Example {
+            _indexes: &[],
+            _counts: &[${count(x, 0)}, ${count(x, 1)}, ${count(x, 2)}],
+            _nested: vec![
+            $(
+                Example {
+                    _indexes: &[(${index()}, ${length()})],
+                    _counts: &[${count(x, 0)}, ${count(x, 1)}],
+                    _nested: vec![
+                    $(
+                        Example {
+                            _indexes: &[(${index(1)}, ${length(1)}), (${index()}, ${length()})],
+                            _counts: &[${count(x)}],
+                            _nested: vec![
+                            $(
+                                Example {
+                                    _indexes: &[
+                                        (${index(2)}, ${length(2)}),
+                                        (${index(1)}, ${length(1)}),
+                                        (${index()}, ${length()})
+                                    ],
+                                    _counts: &[],
+                                    _nested: vec![],
+                                    ${ignore(x)}
+                                }
+                            ),*
+                            ]
+                        }
+                    ),*
+                    ]
+                }
+            ),*
+            ]
+        }
+    };
+}
+
+static EXPECTED: &str = concat!(
+    "Example { _indexes: [], _counts: [2, 4, 13], _nested: [",
+    concat!(
+        "Example { _indexes: [(0, 2)], _counts: [3, 10], _nested: [",
+        concat!(
+            "Example { _indexes: [(0, 2), (0, 3)], _counts: [4], _nested: [",
+            concat!(
+                "Example { _indexes: [(0, 2), (0, 3), (0, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (0, 3), (1, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (0, 3), (2, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (0, 3), (3, 4)], _counts: [], _nested: [] }",
+            ),
+            "] }, ",
+            "Example { _indexes: [(0, 2), (1, 3)], _counts: [4], _nested: [",
+            concat!(
+                "Example { _indexes: [(0, 2), (1, 3), (0, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (1, 3), (1, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (1, 3), (2, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (1, 3), (3, 4)], _counts: [], _nested: [] }",
+            ),
+            "] }, ",
+            "Example { _indexes: [(0, 2), (2, 3)], _counts: [2], _nested: [",
+            concat!(
+                "Example { _indexes: [(0, 2), (2, 3), (0, 2)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (2, 3), (1, 2)], _counts: [], _nested: [] }",
+            ),
+            "] }",
+        ),
+        "] }, ",
+        "Example { _indexes: [(1, 2)], _counts: [1, 3], _nested: [",
+        concat!(
+            "Example { _indexes: [(1, 2), (0, 1)], _counts: [3], _nested: [",
+            concat!(
+                "Example { _indexes: [(1, 2), (0, 1), (0, 3)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(1, 2), (0, 1), (1, 3)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(1, 2), (0, 1), (2, 3)], _counts: [], _nested: [] }",
+            ),
+            "] }",
+        ),
+        "] }",
+    ),
+    "] }",
+);
+
+fn main() {
+    let e = example! {
+        [ ( A B C D ) ( E F G H ) ( I J ) ]
+        [ ( K L M ) ]
+    };
+    let debug = format!("{:?}", e);
+    assert_eq!(debug, EXPECTED);
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
new file mode 100644
index 00000000000..d81c8628bab
--- /dev/null
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
@@ -0,0 +1,44 @@
+#![feature(macro_metavar_expr)]
+
+macro_rules! a {
+    ( $( { $( [ $( ( $( $foo:ident )* ) )* ] )* } )* ) => {
+        (
+            ${count(foo, 0)},
+            ${count(foo, 10)},
+            //~^ ERROR count depth must be less than 4
+        )
+    };
+}
+
+macro_rules! b {
+    ( $( { $( [ $( $foo:ident )* ] )* } )* ) => {
+        (
+            $( $( $(
+                ${ignore(foo)}
+                ${index(0)},
+                ${index(10)},
+                //~^ ERROR index depth must be less than 3
+            )* )* )*
+        )
+    };
+}
+
+macro_rules! c {
+    ( $( { $( $foo:ident )* } )* ) => {
+        (
+            $( $(
+                ${ignore(foo)}
+                ${length(0)}
+                ${length(10)}
+                //~^ ERROR length depth must be less than 2
+            )* )*
+        )
+    };
+}
+
+
+fn main() {
+    a!( { [ (a) ] [ (b c) ] } );
+    b!( { [ a b ] } );
+    c!( { a } );
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
new file mode 100644
index 00000000000..7474c03c0f9
--- /dev/null
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
@@ -0,0 +1,20 @@
+error: count depth must be less than 4
+  --> $DIR/out-of-bounds-arguments.rs:7:14
+   |
+LL |             ${count(foo, 10)},
+   |              ^^^^^^^^^^^^^^^^
+
+error: index depth must be less than 3
+  --> $DIR/out-of-bounds-arguments.rs:19:18
+   |
+LL |                 ${index(10)},
+   |                  ^^^^^^^^^^^
+
+error: length depth must be less than 2
+  --> $DIR/out-of-bounds-arguments.rs:32:18
+   |
+LL |                 ${length(10)}
+   |                  ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs
new file mode 100644
index 00000000000..cff6f29a153
--- /dev/null
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs
@@ -0,0 +1,9 @@
+macro_rules! count {
+    ( $( $e:stmt ),* ) => {
+        ${ count(e) }
+        //~^ ERROR meta-variable expressions are unstable
+    };
+}
+
+fn main() {
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
new file mode 100644
index 00000000000..f5731944793
--- /dev/null
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
@@ -0,0 +1,12 @@
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:3:10
+   |
+LL |         ${ count(e) }
+   |          ^^^^^^^^^^^^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
new file mode 100644
index 00000000000..fdf16442d2a
--- /dev/null
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
@@ -0,0 +1,165 @@
+#![feature(macro_metavar_expr)]
+
+// `curly` = Right hand side curly brackets
+// `no_rhs_dollar` = No dollar sign at the right hand side meta variable "function"
+// `round` = Left hand side round brackets
+
+macro_rules! curly__no_rhs_dollar__round {
+    ( $( $i:ident ),* ) => { ${ count(i) } };
+}
+
+macro_rules! curly__no_rhs_dollar__no_round {
+    ( $i:ident ) => { ${ count(i) } };
+    //~^ ERROR `count` can not be placed inside the inner-most repetition
+}
+
+macro_rules! curly__rhs_dollar__round {
+    ( $( $i:ident ),* ) => { ${ count($i) } };
+    //~^ ERROR expected identifier, found `$`
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! curly__rhs_dollar__no_round {
+    ( $i:ident ) => { ${ count($i) } };
+    //~^ ERROR expected identifier, found `$`
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! no_curly__no_rhs_dollar__round {
+    ( $( $i:ident ),* ) => { count(i) };
+    //~^ ERROR cannot find function `count` in this scope
+    //~| ERROR cannot find value `i` in this scope
+}
+
+macro_rules! no_curly__no_rhs_dollar__no_round {
+    ( $i:ident ) => { count(i) };
+    //~^ ERROR cannot find function `count` in this scope
+    //~| ERROR cannot find value `i` in this scope
+}
+
+macro_rules! no_curly__rhs_dollar__round {
+    ( $( $i:ident ),* ) => { count($i) };
+    //~^ ERROR variable 'i' is still repeating at this depth
+}
+
+macro_rules! no_curly__rhs_dollar__no_round {
+    ( $i:ident ) => { count($i) };
+    //~^ ERROR cannot find function `count` in this scope
+}
+
+// Other scenarios
+
+macro_rules! dollar_dollar_in_the_lhs {
+    ( $$ $a:ident ) => {
+    //~^ ERROR unexpected token: $
+    };
+}
+
+macro_rules! extra_garbage_after_metavar {
+    ( $( $i:ident ),* ) => {
+        ${count() a b c}
+        //~^ ERROR unexpected token: a
+        //~| ERROR expected expression, found `$`
+        ${count(i a b c)}
+        //~^ ERROR unexpected token: a
+        ${count(i, 1 a b c)}
+        //~^ ERROR unexpected token: a
+        ${count(i) a b c}
+        //~^ ERROR unexpected token: a
+
+        ${ignore(i) a b c}
+        //~^ ERROR unexpected token: a
+        ${ignore(i a b c)}
+        //~^ ERROR unexpected token: a
+
+        ${index() a b c}
+        //~^ ERROR unexpected token: a
+        ${index(1 a b c)}
+        //~^ ERROR unexpected token: a
+
+        ${index() a b c}
+        //~^ ERROR unexpected token: a
+        ${index(1 a b c)}
+        //~^ ERROR unexpected token: a
+    };
+}
+
+const IDX: usize = 1;
+macro_rules! metavar_depth_is_not_literal {
+    ( $( $i:ident ),* ) => { ${ index(IDX) } };
+    //~^ ERROR meta-variable expression depth must be a literal
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_in_the_lhs {
+    ( ${ length() } ) => {
+        //~^ ERROR unexpected token: {
+        //~| ERROR expected one of: `*`, `+`, or `?`
+    };
+}
+
+macro_rules! metavar_token_without_ident {
+    ( $( $i:ident ),* ) => { ${ ignore() } };
+    //~^ ERROR expected identifier
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_with_literal_suffix {
+    ( $( $i:ident ),* ) => { ${ index(1u32) } };
+    //~^ ERROR only unsuffixes integer literals are supported in meta-variable expressions
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_without_parens {
+    ( $( $i:ident ),* ) => { ${ count{i} } };
+    //~^ ERROR meta-variable expression parameter must be wrapped in parentheses
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! open_brackets_without_tokens {
+    ( $( $i:ident ),* ) => { ${ {} } };
+    //~^ ERROR expected expression, found `$`
+    //~| ERROR expected identifier
+}
+
+macro_rules! unknown_count_ident {
+    ( $( $i:ident )* ) => {
+        ${count(foo)}
+        //~^ ERROR variable `foo` is not recognized in meta-variable expression
+    };
+}
+
+macro_rules! unknown_ignore_ident {
+    ( $( $i:ident )* ) => {
+        ${ignore(bar)}
+        //~^ ERROR variable `bar` is not recognized in meta-variable expression
+    };
+}
+
+macro_rules! unknown_metavar {
+    ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+    //~^ ERROR unrecognized meta-variable expression
+    //~| ERROR expected expression
+}
+
+fn main() {
+    curly__no_rhs_dollar__round!(a, b, c);
+    curly__no_rhs_dollar__no_round!(a);
+    curly__rhs_dollar__round!(a, b, c);
+    curly__rhs_dollar__no_round!(a);
+    no_curly__no_rhs_dollar__round!(a, b, c);
+    no_curly__no_rhs_dollar__no_round!(a);
+    no_curly__rhs_dollar__round!(a, b, c);
+    no_curly__rhs_dollar__no_round!(a);
+    //~^ ERROR cannot find value `a` in this scope
+
+    extra_garbage_after_metavar!(a);
+    metavar_depth_is_not_literal!(a);
+    metavar_token_without_ident!(a);
+    metavar_with_literal_suffix!(a);
+    metavar_without_parens!(a);
+    open_brackets_without_tokens!(a);
+    unknown_count_ident!(a);
+    unknown_ignore_ident!(a);
+    unknown_metavar!(a);
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
new file mode 100644
index 00000000000..0188938a30e
--- /dev/null
+++ b/src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
@@ -0,0 +1,385 @@
+error: expected identifier, found `$`
+  --> $DIR/syntax-errors.rs:17:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count($i) } };
+   |                                 ^^^^^ - help: try removing `$`
+
+error: expected identifier, found `$`
+  --> $DIR/syntax-errors.rs:23:26
+   |
+LL |     ( $i:ident ) => { ${ count($i) } };
+   |                          ^^^^^ - help: try removing `$`
+
+error: unexpected token: $
+  --> $DIR/syntax-errors.rs:53:8
+   |
+LL |     ( $$ $a:ident ) => {
+   |        ^
+
+note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
+  --> $DIR/syntax-errors.rs:53:8
+   |
+LL |     ( $$ $a:ident ) => {
+   |        ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:60:19
+   |
+LL |         ${count() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:60:19
+   |
+LL |         ${count() a b c}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:63:19
+   |
+LL |         ${count(i a b c)}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:63:19
+   |
+LL |         ${count(i a b c)}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:65:22
+   |
+LL |         ${count(i, 1 a b c)}
+   |                      ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:65:22
+   |
+LL |         ${count(i, 1 a b c)}
+   |                      ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:67:20
+   |
+LL |         ${count(i) a b c}
+   |                    ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:67:20
+   |
+LL |         ${count(i) a b c}
+   |                    ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:70:21
+   |
+LL |         ${ignore(i) a b c}
+   |                     ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:70:21
+   |
+LL |         ${ignore(i) a b c}
+   |                     ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:72:20
+   |
+LL |         ${ignore(i a b c)}
+   |                    ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:72:20
+   |
+LL |         ${ignore(i a b c)}
+   |                    ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:75:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:75:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:77:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:77:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:80:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:80:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:82:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:82:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+
+error: meta-variable expression depth must be a literal
+  --> $DIR/syntax-errors.rs:89:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(IDX) } };
+   |                                 ^^^^^
+
+error: unexpected token: {
+  --> $DIR/syntax-errors.rs:95:8
+   |
+LL |     ( ${ length() } ) => {
+   |        ^^^^^^^^^^^^
+
+note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
+  --> $DIR/syntax-errors.rs:95:8
+   |
+LL |     ( ${ length() } ) => {
+   |        ^^^^^^^^^^^^
+
+error: expected one of: `*`, `+`, or `?`
+  --> $DIR/syntax-errors.rs:95:8
+   |
+LL |     ( ${ length() } ) => {
+   |        ^^^^^^^^^^^^
+
+error: expected identifier
+  --> $DIR/syntax-errors.rs:102:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ ignore() } };
+   |                                 ^^^^^^
+
+error: only unsuffixes integer literals are supported in meta-variable expressions
+  --> $DIR/syntax-errors.rs:108:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(1u32) } };
+   |                                 ^^^^^
+
+error: meta-variable expression parameter must be wrapped in parentheses
+  --> $DIR/syntax-errors.rs:114:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count{i} } };
+   |                                 ^^^^^
+
+error: expected identifier
+  --> $DIR/syntax-errors.rs:120:31
+   |
+LL |     ( $( $i:ident ),* ) => { ${ {} } };
+   |                               ^^^^^^
+
+error: unrecognized meta-variable expression
+  --> $DIR/syntax-errors.rs:140:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+   |                                 ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and length
+
+error: `count` can not be placed inside the inner-most repetition
+  --> $DIR/syntax-errors.rs:12:24
+   |
+LL |     ( $i:ident ) => { ${ count(i) } };
+   |                        ^^^^^^^^^^^^
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:17:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count($i) } };
+   |                              ^ expected expression
+...
+LL |     curly__rhs_dollar__round!(a, b, c);
+   |     ---------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `curly__rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:23:23
+   |
+LL |     ( $i:ident ) => { ${ count($i) } };
+   |                       ^ expected expression
+...
+LL |     curly__rhs_dollar__no_round!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: variable 'i' is still repeating at this depth
+  --> $DIR/syntax-errors.rs:41:36
+   |
+LL |     ( $( $i:ident ),* ) => { count($i) };
+   |                                    ^^
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:60:9
+   |
+LL |         ${count() a b c}
+   |         ^ expected expression
+...
+LL |     extra_garbage_after_metavar!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `extra_garbage_after_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:89:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(IDX) } };
+   |                              ^ expected expression
+...
+LL |     metavar_depth_is_not_literal!(a);
+   |     -------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_depth_is_not_literal` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:102:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ ignore() } };
+   |                              ^ expected expression
+...
+LL |     metavar_token_without_ident!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_token_without_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:108:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(1u32) } };
+   |                              ^ expected expression
+...
+LL |     metavar_with_literal_suffix!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_with_literal_suffix` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:114:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count{i} } };
+   |                              ^ expected expression
+...
+LL |     metavar_without_parens!(a);
+   |     -------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_without_parens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:120:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ {} } };
+   |                              ^ expected expression
+...
+LL |     open_brackets_without_tokens!(a);
+   |     -------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `open_brackets_without_tokens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: variable `foo` is not recognized in meta-variable expression
+  --> $DIR/syntax-errors.rs:127:17
+   |
+LL |         ${count(foo)}
+   |                 ^^^
+
+error: variable `bar` is not recognized in meta-variable expression
+  --> $DIR/syntax-errors.rs:134:18
+   |
+LL |         ${ignore(bar)}
+   |                  ^^^
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:140:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+   |                              ^ expected expression
+...
+LL |     unknown_metavar!(a);
+   |     ------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `unknown_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+  --> $DIR/syntax-errors.rs:29:30
+   |
+LL |     ( $( $i:ident ),* ) => { count(i) };
+   |                              ^^^^^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__round!(a, b, c);
+   |     ---------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+  --> $DIR/syntax-errors.rs:29:36
+   |
+LL |     ( $( $i:ident ),* ) => { count(i) };
+   |                                    ^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__round!(a, b, c);
+   |     ---------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+  --> $DIR/syntax-errors.rs:35:23
+   |
+LL |     ( $i:ident ) => { count(i) };
+   |                       ^^^^^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__no_round!(a);
+   |     ------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+  --> $DIR/syntax-errors.rs:35:29
+   |
+LL |     ( $i:ident ) => { count(i) };
+   |                             ^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__no_round!(a);
+   |     ------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+  --> $DIR/syntax-errors.rs:46:23
+   |
+LL |     ( $i:ident ) => { count($i) };
+   |                       ^^^^^ not found in this scope
+...
+LL |     no_curly__rhs_dollar__no_round!(a);
+   |     ---------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/syntax-errors.rs:153:37
+   |
+LL |     no_curly__rhs_dollar__no_round!(a);
+   |                                     ^ not found in this scope
+
+error: aborting due to 40 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/match/match_non_exhaustive.stderr b/src/test/ui/match/match_non_exhaustive.stderr
index 5debfe1c566..6206dc85ea0 100644
--- a/src/test/ui/match/match_non_exhaustive.stderr
+++ b/src/test/ui/match/match_non_exhaustive.stderr
@@ -1,17 +1,19 @@
 error[E0004]: non-exhaustive patterns: `B` not covered
   --> $DIR/match_non_exhaustive.rs:23:11
    |
-LL | enum L { A, B }
-   | ---------------
-   | |           |
-   | |           not covered
-   | `L` defined here
-...
 LL |     match l { L::A => () };
    |           ^ pattern `B` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `L` defined here
+  --> $DIR/match_non_exhaustive.rs:10:13
+   |
+LL | enum L { A, B }
+   |      -      ^ not covered
    = note: the matched value is of type `L`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     match l { L::A => (), B => todo!() };
+   |                         ++++++++++++++
 
 error[E0004]: non-exhaustive patterns: type `E1` is non-empty
   --> $DIR/match_non_exhaustive.rs:28:11
@@ -19,8 +21,18 @@ error[E0004]: non-exhaustive patterns: type `E1` is non-empty
 LL |     match e1 {};
    |           ^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E1` defined here
+  --> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1
+   |
+LL | pub enum E1 {}
+   | ^^^^^^^^^^^^^^
    = note: the matched value is of type `E1`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match e1 {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/match_non_exhaustive.rs:30:11
@@ -28,8 +40,16 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match e2 { E2::A => (), E2::B => () };
    |           ^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E2` defined here
+  --> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1
+   |
+LL | pub enum E2 { A, B }
+   | ^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `E2`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     match e2 { E2::A => (), E2::B => (), _ => todo!() };
+   |                                        ++++++++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/methods/issues/issue-84495.rs b/src/test/ui/methods/issues/issue-84495.rs
new file mode 100644
index 00000000000..28c094bf2ac
--- /dev/null
+++ b/src/test/ui/methods/issues/issue-84495.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let x: i32 = 1;
+    println!("{:?}", x.count()); //~ ERROR is not an iterator
+}
diff --git a/src/test/ui/methods/issues/issue-84495.stderr b/src/test/ui/methods/issues/issue-84495.stderr
new file mode 100644
index 00000000000..b0217a7c844
--- /dev/null
+++ b/src/test/ui/methods/issues/issue-84495.stderr
@@ -0,0 +1,13 @@
+error[E0599]: `i32` is not an iterator
+  --> $DIR/issue-84495.rs:3:24
+   |
+LL |     println!("{:?}", x.count());
+   |                        ^^^^^ `i32` is not an iterator
+   |
+   = note: the following trait bounds were not satisfied:
+           `i32: Iterator`
+           which is required by `&mut i32: Iterator`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/methods/issues/issue-94581.rs b/src/test/ui/methods/issues/issue-94581.rs
new file mode 100644
index 00000000000..df393e91db0
--- /dev/null
+++ b/src/test/ui/methods/issues/issue-94581.rs
@@ -0,0 +1,7 @@
+fn get_slice() -> &'static [i32] {
+    &[1, 2, 3, 4]
+}
+
+fn main() {
+    let sqsum = get_slice().map(|i| i * i).sum(); //~ ERROR [E0599]
+}
diff --git a/src/test/ui/methods/issues/issue-94581.stderr b/src/test/ui/methods/issues/issue-94581.stderr
new file mode 100644
index 00000000000..d6be29cf582
--- /dev/null
+++ b/src/test/ui/methods/issues/issue-94581.stderr
@@ -0,0 +1,15 @@
+error[E0599]: `&'static [i32]` is not an iterator
+  --> $DIR/issue-94581.rs:6:29
+   |
+LL |     let sqsum = get_slice().map(|i| i * i).sum();
+   |                             ^^^ `&'static [i32]` is not an iterator; try calling `.iter()`
+   |
+   = note: the following trait bounds were not satisfied:
+           `&'static [i32]: Iterator`
+           which is required by `&mut &'static [i32]: Iterator`
+           `[i32]: Iterator`
+           which is required by `&mut [i32]: Iterator`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/methods/method-call-err-msg.rs b/src/test/ui/methods/method-call-err-msg.rs
index 86d00ca3760..d53ef445afc 100644
--- a/src/test/ui/methods/method-call-err-msg.rs
+++ b/src/test/ui/methods/method-call-err-msg.rs
@@ -16,7 +16,7 @@ fn main() {
 
     let y = Foo;
     y.zero()
-     .take()    //~ ERROR the method
+     .take()    //~ ERROR not an iterator
      .one(0);
     y.three::<usize>(); //~ ERROR this function takes 3 arguments but 0 arguments were supplied
 }
diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr
index c1183e053eb..c410e076dde 100644
--- a/src/test/ui/methods/method-call-err-msg.stderr
+++ b/src/test/ui/methods/method-call-err-msg.stderr
@@ -40,7 +40,7 @@ note: associated function defined here
 LL |     fn two(self, _: isize, _: isize) -> Foo { self }
    |        ^^^ ----  --------  --------
 
-error[E0599]: the method `take` exists for struct `Foo`, but its trait bounds were not satisfied
+error[E0599]: `Foo` is not an iterator
   --> $DIR/method-call-err-msg.rs:19:7
    |
 LL | pub struct Foo;
@@ -50,7 +50,7 @@ LL | pub struct Foo;
    | doesn't satisfy `Foo: Iterator`
 ...
 LL |      .take()
-   |       ^^^^ method cannot be called on `Foo` due to unsatisfied trait bounds
+   |       ^^^^ `Foo` is not an iterator
    |
    = note: the following trait bounds were not satisfied:
            `Foo: Iterator`
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.rs b/src/test/ui/mismatched_types/cast-rfc0401.rs
index b8d12fb9809..57222f45947 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.rs
+++ b/src/test/ui/mismatched_types/cast-rfc0401.rs
@@ -48,7 +48,7 @@ fn main()
     let _ = E::A as *const u8; //~ ERROR is invalid
     let _ = 'a' as *const u8; //~ ERROR is invalid
 
-    let _ = 42usize as *const [u8]; //~ ERROR is invalid
+    let _ = 42usize as *const [u8]; //~ ERROR cannot cast `usize` to a pointer that is wide
     let _ = v as *const [u8]; //~ ERROR cannot cast
     let _ = fat_v as *const dyn Foo; //~ ERROR the size for values of type
     let _ = foo as *const str; //~ ERROR is invalid
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
index 6dbf24baf23..5f11e4ded80 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.stderr
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -148,11 +148,13 @@ error[E0606]: casting `char` as `*const u8` is invalid
 LL |     let _ = 'a' as *const u8;
    |             ^^^^^^^^^^^^^^^^
 
-error[E0606]: casting `usize` as `*const [u8]` is invalid
-  --> $DIR/cast-rfc0401.rs:51:13
+error[E0606]: cannot cast `usize` to a pointer that is wide
+  --> $DIR/cast-rfc0401.rs:51:24
    |
 LL |     let _ = 42usize as *const [u8];
-   |             ^^^^^^^^^^^^^^^^^^^^^^
+   |             -------    ^^^^^^^^^^^ creating a `*const [u8]` requires both an address and a length
+   |             |
+   |             consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
 
 error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
   --> $DIR/cast-rfc0401.rs:52:13
diff --git a/src/test/ui/moves/issue-46099-move-in-macro.stderr b/src/test/ui/moves/issue-46099-move-in-macro.stderr
index db4c3979e3a..baa87e3e9fd 100644
--- a/src/test/ui/moves/issue-46099-move-in-macro.stderr
+++ b/src/test/ui/moves/issue-46099-move-in-macro.stderr
@@ -4,10 +4,7 @@ error[E0382]: use of moved value: `b`
 LL |     let b = Box::new(true);
    |         - move occurs because `b` has type `Box<bool>`, which does not implement the `Copy` trait
 LL |     test!({b});
-   |            ^
-   |            |
-   |            value moved here
-   |            value used here after move
+   |            ^ value used here after move
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr
index 57be5fb4d8a..3a686121a92 100644
--- a/src/test/ui/moves/move-fn-self-receiver.stderr
+++ b/src/test/ui/moves/move-fn-self-receiver.stderr
@@ -119,12 +119,14 @@ error[E0382]: use of moved value: `implicit_into_iter`
 LL |     let implicit_into_iter = vec![true];
    |         ------------------ move occurs because `implicit_into_iter` has type `Vec<bool>`, which does not implement the `Copy` trait
 LL |     for _val in implicit_into_iter {}
-   |                 ------------------
-   |                 |
-   |                 `implicit_into_iter` moved due to this implicit call to `.into_iter()`
-   |                 help: consider borrowing to avoid moving into the for loop: `&implicit_into_iter`
+   |                 ------------------ `implicit_into_iter` moved due to this implicit call to `.into_iter()`
 LL |     implicit_into_iter;
    |     ^^^^^^^^^^^^^^^^^^ value used here after move
+   |
+help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop
+   |
+LL |     for _val in &implicit_into_iter {}
+   |                 +
 
 error[E0382]: use of moved value: `explicit_into_iter`
   --> $DIR/move-fn-self-receiver.rs:67:5
diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr
index ea350926b15..8d636c11b78 100644
--- a/src/test/ui/moves/move-in-guard-2.stderr
+++ b/src/test/ui/moves/move-in-guard-2.stderr
@@ -5,10 +5,7 @@ LL |     let x: Box<_> = Box::new(1);
    |         - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
 ...
 LL |         (_, 2) if take(x) => (),
-   |                        ^
-   |                        |
-   |                        value moved here
-   |                        value used here after move
+   |                        ^ value used here after move
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-55825-const-fn.rs b/src/test/ui/nll/issue-55825-const-fn.rs
index c9efccd15b7..17c4a0496b6 100644
--- a/src/test/ui/nll/issue-55825-const-fn.rs
+++ b/src/test/ui/nll/issue-55825-const-fn.rs
@@ -1,8 +1,10 @@
 // Regression test for issue #55825
 // Tests that we don't emit a spurious warning in NLL mode
 
+// check-pass
+
 #![feature(nll)]
 
-const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~ ERROR const
+const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
 
 fn main() { }
diff --git a/src/test/ui/nll/issue-55825-const-fn.stderr b/src/test/ui/nll/issue-55825-const-fn.stderr
deleted file mode 100644
index c834f8bd9c4..00000000000
--- a/src/test/ui/nll/issue-55825-const-fn.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/issue-55825-const-fn.rs:6:32
-   |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/nll/lint-no-err.rs b/src/test/ui/nll/lint-no-err.rs
new file mode 100644
index 00000000000..4b4169faadf
--- /dev/null
+++ b/src/test/ui/nll/lint-no-err.rs
@@ -0,0 +1,28 @@
+// check-pass
+
+// mir borrowck previously incorrectly set `tainted_by_errors`
+// when buffering lints, which resulted in ICE later on,
+// see #94502.
+
+// Errors with `nll` which is already tested in enough other tests,
+// so we ignore it here.
+//
+// ignore-compare-mode-nll
+
+struct Repro;
+impl Repro {
+    fn get(&self) -> &i32 {
+        &3
+    }
+
+    fn insert(&mut self, _: i32) {}
+}
+
+fn main() {
+    let x = &0;
+    let mut conflict = Repro;
+    let prev = conflict.get();
+    conflict.insert(*prev + *x);
+    //~^ WARN cannot borrow `conflict` as mutable because it is also borrowed as immutable
+    //~| WARN this borrowing pattern was not meant to be accepted
+}
diff --git a/src/test/ui/nll/lint-no-err.stderr b/src/test/ui/nll/lint-no-err.stderr
new file mode 100644
index 00000000000..1e7aecfaa64
--- /dev/null
+++ b/src/test/ui/nll/lint-no-err.stderr
@@ -0,0 +1,17 @@
+warning: cannot borrow `conflict` as mutable because it is also borrowed as immutable
+  --> $DIR/lint-no-err.rs:25:5
+   |
+LL |     let prev = conflict.get();
+   |                -------------- immutable borrow occurs here
+LL |     conflict.insert(*prev + *x);
+   |     ^^^^^^^^^^^^^^^^-----^^^^^^
+   |     |               |
+   |     |               immutable borrow later used here
+   |     mutable borrow occurs here
+   |
+   = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
+   = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
+   = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/nll/match-guards-always-borrow.stderr b/src/test/ui/nll/match-guards-always-borrow.stderr
index df6d65056ac..c0fb5f65382 100644
--- a/src/test/ui/nll/match-guards-always-borrow.stderr
+++ b/src/test/ui/nll/match-guards-always-borrow.stderr
@@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard
   --> $DIR/match-guards-always-borrow.rs:8:14
    |
 LL |             (|| { let bar = foo; bar.take() })();
-   |              ^^             ---
-   |              |              |
-   |              |              move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
-   |              |              move occurs due to use in closure
+   |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |              |
    |              move out of `foo` occurs here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
diff --git a/src/test/ui/on-unimplemented/impl-substs.rs b/src/test/ui/on-unimplemented/impl-substs.rs
new file mode 100644
index 00000000000..fe9c50ec3d4
--- /dev/null
+++ b/src/test/ui/on-unimplemented/impl-substs.rs
@@ -0,0 +1,15 @@
+#![feature(rustc_attrs)]
+
+trait Foo<A> {
+    fn foo(self);
+}
+
+#[rustc_on_unimplemented = "an impl did not match: {A} {B} {C}"]
+impl<A, B, C> Foo<A> for (A, B, C) {
+    fn foo(self) {}
+}
+
+fn main() {
+    Foo::<usize>::foo((1i32, 1i32, 1i32));
+    //~^ ERROR the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
+}
diff --git a/src/test/ui/on-unimplemented/impl-substs.stderr b/src/test/ui/on-unimplemented/impl-substs.stderr
new file mode 100644
index 00000000000..db66ab0bfae
--- /dev/null
+++ b/src/test/ui/on-unimplemented/impl-substs.stderr
@@ -0,0 +1,13 @@
+error[E0277]: the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
+  --> $DIR/impl-substs.rs:13:23
+   |
+LL |     Foo::<usize>::foo((1i32, 1i32, 1i32));
+   |     ----------------- ^^^^^^^^^^^^^^^^^^ an impl did not match: usize _ _
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Foo<usize>` is not implemented for `(i32, i32, i32)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
index 44f334eee93..9aa808e6bc9 100644
--- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
+++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(2_u8..=u8::MAX, _)` not covered
 LL |     match (0u8, 0u8) {
    |           ^^^^^^^^^^ pattern `(2_u8..=u8::MAX, _)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(u8, u8)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (0 | 1, 2 | 3) => {}
+LL +         (2_u8..=u8::MAX, _) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
   --> $DIR/exhaustiveness-non-exhaustive.rs:9:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
 LL |     match ((0u8,),) {
    |           ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((u8,),)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         ((0 | 1,) | (2 | 3,),) => {}
+LL +         ((4_u8..=u8::MAX)) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
   --> $DIR/exhaustiveness-non-exhaustive.rs:13:11
@@ -22,8 +30,12 @@ error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
 LL |     match (Some(0u8),) {
    |           ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Option<u8>,)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (None | Some(0 | 1),) => {}
+LL +         (Some(2_u8..=u8::MAX)) => todo!()
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
index 8e6964e3062..95b22ac0594 100644
--- a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
+++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
@@ -7,10 +7,10 @@ LL |     let (0 | (1 | 2)) = 0;
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let (0 | (1 | 2)) = 0 { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     if let (0 | (1 | 2)) = 0 { todo!() }
+   |     ++                       ~~~~~~~~~~~
 
 error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
   --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:3:11
@@ -18,8 +18,12 @@ error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX
 LL |     match 0 {
    |           ^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         0 | (1 | 2) => {}
+LL +         i32::MIN..=-1_i32 | 3_i32..=i32::MAX => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
index 2ca774a48b6..cd5c283f9fd 100644
--- a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
+++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
@@ -4,23 +4,33 @@ error[E0004]: non-exhaustive patterns: type `&!` is non-empty
 LL |     match uninhab_ref() {
    |           ^^^^^^^^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&!`
    = note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match uninhab_ref() {
+LL +         _ => todo!(),
+LL +     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
   --> $DIR/always-inhabited-union-ref.rs:27:11
    |
-LL | / pub union Foo {
-LL | |     foo: !,
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       match uninhab_union() {
-   |             ^^^^^^^^^^^^^^^
+LL |     match uninhab_union() {
+   |           ^^^^^^^^^^^^^^^
+   |
+note: `Foo` defined here
+  --> $DIR/always-inhabited-union-ref.rs:10:11
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | pub union Foo {
+   |           ^^^
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match uninhab_union() {
+LL +         _ => todo!(),
+LL +     }
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/auxiliary/hidden.rs b/src/test/ui/pattern/usefulness/auxiliary/hidden.rs
index 742b7e82c16..364514ba1d3 100644
--- a/src/test/ui/pattern/usefulness/auxiliary/hidden.rs
+++ b/src/test/ui/pattern/usefulness/auxiliary/hidden.rs
@@ -1,6 +1,14 @@
-pub enum Foo {
+pub enum HiddenEnum {
     A,
     B,
     #[doc(hidden)]
     C,
 }
+
+#[derive(Default)]
+pub struct HiddenStruct {
+    pub one: u8,
+    pub two: bool,
+    #[doc(hidden)]
+    pub hide: usize,
+}
diff --git a/src/test/ui/pattern/usefulness/auxiliary/unstable.rs b/src/test/ui/pattern/usefulness/auxiliary/unstable.rs
index 3142489c861..a06b3a6e4e5 100644
--- a/src/test/ui/pattern/usefulness/auxiliary/unstable.rs
+++ b/src/test/ui/pattern/usefulness/auxiliary/unstable.rs
@@ -2,7 +2,7 @@
 #![stable(feature = "stable_test_feature", since = "1.0.0")]
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-pub enum Foo {
+pub enum UnstableEnum {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
     Stable,
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -10,3 +10,14 @@ pub enum Foo {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     Unstable,
 }
+
+#[derive(Default)]
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub struct UnstableStruct {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub stable: bool,
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub stable2: usize,
+    #[unstable(feature = "unstable_test_feature", issue = "none")]
+    pub unstable: u8,
+}
diff --git a/src/test/ui/pattern/usefulness/doc-hidden-fields.rs b/src/test/ui/pattern/usefulness/doc-hidden-fields.rs
new file mode 100644
index 00000000000..4163b87dc85
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/doc-hidden-fields.rs
@@ -0,0 +1,26 @@
+// aux-build:hidden.rs
+
+extern crate hidden;
+
+use hidden::HiddenStruct;
+
+struct InCrate {
+    a: usize,
+    b: bool,
+    #[doc(hidden)]
+    im_hidden: u8
+}
+
+fn main() {
+    let HiddenStruct { one, two } = HiddenStruct::default();
+    //~^ pattern requires `..` due to inaccessible fields
+
+    let HiddenStruct { one } = HiddenStruct::default();
+    //~^ pattern does not mention field `two` and inaccessible fields
+
+    let HiddenStruct { one, hide } = HiddenStruct::default();
+    //~^ pattern does not mention field `two`
+
+    let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 };
+    //~^ pattern does not mention field `im_hidden`
+}
diff --git a/src/test/ui/pattern/usefulness/doc-hidden-fields.stderr b/src/test/ui/pattern/usefulness/doc-hidden-fields.stderr
new file mode 100644
index 00000000000..f277bfbc884
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/doc-hidden-fields.stderr
@@ -0,0 +1,59 @@
+error: pattern requires `..` due to inaccessible fields
+  --> $DIR/doc-hidden-fields.rs:15:9
+   |
+LL |     let HiddenStruct { one, two } = HiddenStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: ignore the inaccessible and unused fields
+   |
+LL |     let HiddenStruct { one, two, .. } = HiddenStruct::default();
+   |                                ++++
+
+error[E0027]: pattern does not mention field `two` and inaccessible fields
+  --> $DIR/doc-hidden-fields.rs:18:9
+   |
+LL |     let HiddenStruct { one } = HiddenStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^ missing field `two` and inaccessible fields
+   |
+help: include the missing field in the pattern and ignore the inaccessible fields
+   |
+LL |     let HiddenStruct { one, two, .. } = HiddenStruct::default();
+   |                           ~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let HiddenStruct { one, .. } = HiddenStruct::default();
+   |                           ~~~~~~
+
+error[E0027]: pattern does not mention field `two`
+  --> $DIR/doc-hidden-fields.rs:21:9
+   |
+LL |     let HiddenStruct { one, hide } = HiddenStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `two`
+   |
+help: include the missing field in the pattern
+   |
+LL |     let HiddenStruct { one, hide, two } = HiddenStruct::default();
+   |                                 ~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let HiddenStruct { one, hide, .. } = HiddenStruct::default();
+   |                                 ~~~~~~
+
+error[E0027]: pattern does not mention field `im_hidden`
+  --> $DIR/doc-hidden-fields.rs:24:9
+   |
+LL |     let InCrate { a, b } = InCrate { a: 0, b: false, im_hidden: 0 };
+   |         ^^^^^^^^^^^^^^^^ missing field `im_hidden`
+   |
+help: include the missing field in the pattern
+   |
+LL |     let InCrate { a, b, im_hidden } = InCrate { a: 0, b: false, im_hidden: 0 };
+   |                       ~~~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let InCrate { a, b, .. } = InCrate { a: 0, b: false, im_hidden: 0 };
+   |                       ~~~~~~
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
index a1dcab09314..d968c48fb1a 100644
--- a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
+++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
@@ -2,29 +2,42 @@
 
 extern crate hidden;
 
-use hidden::Foo;
+use hidden::HiddenEnum;
+
+enum InCrate {
+    A,
+    B,
+    #[doc(hidden)]
+    C,
+}
 
 fn main() {
-    match Foo::A {
-        Foo::A => {}
-        Foo::B => {}
+    match HiddenEnum::A {
+        HiddenEnum::A => {}
+        HiddenEnum::B => {}
     }
     //~^^^^ non-exhaustive patterns: `_` not covered
 
-    match Foo::A {
-        Foo::A => {}
-        Foo::C => {}
+    match HiddenEnum::A {
+        HiddenEnum::A => {}
+        HiddenEnum::C => {}
     }
     //~^^^^ non-exhaustive patterns: `B` not covered
 
-    match Foo::A {
-        Foo::A => {}
+    match HiddenEnum::A {
+        HiddenEnum::A => {}
     }
     //~^^^ non-exhaustive patterns: `B` and `_` not covered
 
     match None {
         None => {}
-        Some(Foo::A) => {}
+        Some(HiddenEnum::A) => {}
     }
     //~^^^^ non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
+
+    match InCrate::A {
+        InCrate::A => {}
+        InCrate::B => {}
+    }
+    //~^^^^ non-exhaustive patterns: `C` not covered
 }
diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
index 6c9539822b3..296465eb818 100644
--- a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
+++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
@@ -1,54 +1,120 @@
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/doc-hidden-non-exhaustive.rs:8:11
+  --> $DIR/doc-hidden-non-exhaustive.rs:15:11
    |
-LL |     match Foo::A {
-   |           ^^^^^^ pattern `_` not covered
+LL |     match HiddenEnum::A {
+   |           ^^^^^^^^^^^^^ pattern `_` not covered
+   |
+note: `HiddenEnum` defined here
+  --> $DIR/auxiliary/hidden.rs:1:1
+   |
+LL | / pub enum HiddenEnum {
+LL | |     A,
+LL | |     B,
+LL | |     #[doc(hidden)]
+LL | |     C,
+LL | | }
+   | |_^
+   = note: the matched value is of type `HiddenEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         HiddenEnum::B => {}
+LL +         _ => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Foo`
 
 error[E0004]: non-exhaustive patterns: `B` not covered
-  --> $DIR/doc-hidden-non-exhaustive.rs:14:11
+  --> $DIR/doc-hidden-non-exhaustive.rs:21:11
    |
-LL |     match Foo::A {
-   |           ^^^^^^ pattern `B` not covered
+LL |     match HiddenEnum::A {
+   |           ^^^^^^^^^^^^^ pattern `B` not covered
    |
-  ::: $DIR/auxiliary/hidden.rs:3:5
+note: `HiddenEnum` defined here
+  --> $DIR/auxiliary/hidden.rs:3:5
    |
-LL |     B,
-   |     - not covered
+LL | / pub enum HiddenEnum {
+LL | |     A,
+LL | |     B,
+   | |     ^ not covered
+LL | |     #[doc(hidden)]
+LL | |     C,
+LL | | }
+   | |_-
+   = note: the matched value is of type `HiddenEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         HiddenEnum::C => {}
+LL +         B => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Foo`
 
 error[E0004]: non-exhaustive patterns: `B` and `_` not covered
-  --> $DIR/doc-hidden-non-exhaustive.rs:20:11
+  --> $DIR/doc-hidden-non-exhaustive.rs:27:11
+   |
+LL |     match HiddenEnum::A {
+   |           ^^^^^^^^^^^^^ patterns `B` and `_` not covered
    |
-LL |     match Foo::A {
-   |           ^^^^^^ patterns `B` and `_` not covered
+note: `HiddenEnum` defined here
+  --> $DIR/auxiliary/hidden.rs:3:5
    |
-  ::: $DIR/auxiliary/hidden.rs:3:5
+LL | / pub enum HiddenEnum {
+LL | |     A,
+LL | |     B,
+   | |     ^ not covered
+LL | |     #[doc(hidden)]
+LL | |     C,
+LL | | }
+   | |_-
+   = note: the matched value is of type `HiddenEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL |     B,
-   |     - not covered
+LL ~         HiddenEnum::A => {}
+LL +         B | _ => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Foo`
 
 error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
-  --> $DIR/doc-hidden-non-exhaustive.rs:25:11
+  --> $DIR/doc-hidden-non-exhaustive.rs:32:11
    |
 LL |     match None {
    |           ^^^^ patterns `Some(B)` and `Some(_)` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<HiddenEnum>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   | |     ^^^^ not covered
+LL | | }
+   | |_-
+   = note: the matched value is of type `Option<HiddenEnum>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Some(HiddenEnum::A) => {}
+LL +         Some(B) | Some(_) => todo!()
+   |
+
+error[E0004]: non-exhaustive patterns: `C` not covered
+  --> $DIR/doc-hidden-non-exhaustive.rs:38:11
+   |
+LL |     match InCrate::A {
+   |           ^^^^^^^^^^ pattern `C` not covered
+   |
+note: `InCrate` defined here
+  --> $DIR/doc-hidden-non-exhaustive.rs:11:5
+   |
+LL | enum InCrate {
+   |      -------
+...
+LL |     C,
+   |     ^ not covered
+   = note: the matched value is of type `InCrate`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     ---- not covered
+LL ~         InCrate::B => {}
+LL +         C => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Option<Foo>`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
index b99386e7402..d31ee0dbd14 100644
--- a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
+++ b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
@@ -46,107 +46,112 @@ error[E0004]: non-exhaustive patterns: type `u8` is non-empty
 LL |     match_no_arms!(0u8);
    |                    ^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
   --> $DIR/empty-match.rs:79:20
    |
-LL | struct NonEmptyStruct1;
-   | ----------------------- `NonEmptyStruct1` defined here
-...
 LL |     match_no_arms!(NonEmptyStruct1);
    |                    ^^^^^^^^^^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+  --> $DIR/empty-match.rs:14:8
+   |
+LL | struct NonEmptyStruct1;
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
   --> $DIR/empty-match.rs:80:20
    |
-LL | struct NonEmptyStruct2(bool);
-   | ----------------------------- `NonEmptyStruct2` defined here
-...
 LL |     match_no_arms!(NonEmptyStruct2(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+  --> $DIR/empty-match.rs:15:8
+   |
+LL | struct NonEmptyStruct2(bool);
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
   --> $DIR/empty-match.rs:81:20
    |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_no_arms!((NonEmptyUnion1 { foo: () }));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     match_no_arms!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `NonEmptyUnion1` defined here
+  --> $DIR/empty-match.rs:16:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
   --> $DIR/empty-match.rs:82:20
    |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_no_arms!((NonEmptyUnion2 { foo: () }));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     match_no_arms!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `NonEmptyUnion2` defined here
+  --> $DIR/empty-match.rs:19:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
   --> $DIR/empty-match.rs:83:20
    |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum1::Foo(true));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+  --> $DIR/empty-match.rs:24:5
+   |
+LL | enum NonEmptyEnum1 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
   --> $DIR/empty-match.rs:84:20
    |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |     Bar,
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum2::Foo(true));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+note: `NonEmptyEnum2` defined here
+  --> $DIR/empty-match.rs:27:5
+   |
+LL | enum NonEmptyEnum2 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
+LL |     Bar,
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
   --> $DIR/empty-match.rs:85:20
    |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum5::V1);
-   |                      ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |     match_no_arms!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+note: `NonEmptyEnum5` defined here
+  --> $DIR/empty-match.rs:30:6
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+   |      ^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyEnum5`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/empty-match.rs:87:24
@@ -154,107 +159,144 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match_guarded_arm!(0u8);
    |                        ^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
   --> $DIR/empty-match.rs:88:24
    |
-LL | struct NonEmptyStruct1;
-   | ----------------------- `NonEmptyStruct1` defined here
-...
 LL |     match_guarded_arm!(NonEmptyStruct1);
    |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+  --> $DIR/empty-match.rs:14:8
+   |
+LL | struct NonEmptyStruct1;
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyStruct1 => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
   --> $DIR/empty-match.rs:89:24
    |
-LL | struct NonEmptyStruct2(bool);
-   | ----------------------------- `NonEmptyStruct2` defined here
-...
 LL |     match_guarded_arm!(NonEmptyStruct2(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+  --> $DIR/empty-match.rs:15:8
+   |
+LL | struct NonEmptyStruct2(bool);
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyStruct2(_) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
   --> $DIR/empty-match.rs:90:24
    |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_guarded_arm!((NonEmptyUnion1 { foo: () }));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+LL |     match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+   |
+note: `NonEmptyUnion1` defined here
+  --> $DIR/empty-match.rs:16:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyUnion1 { .. } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
   --> $DIR/empty-match.rs:91:24
    |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_guarded_arm!((NonEmptyUnion2 { foo: () }));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+LL |     match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+   |
+note: `NonEmptyUnion2` defined here
+  --> $DIR/empty-match.rs:19:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyUnion2 { .. } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
   --> $DIR/empty-match.rs:92:24
    |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum1::Foo(true));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+  --> $DIR/empty-match.rs:24:5
+   |
+LL | enum NonEmptyEnum1 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             Foo(_) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
   --> $DIR/empty-match.rs:93:24
    |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |     Bar,
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum2::Foo(true));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+note: `NonEmptyEnum2` defined here
+  --> $DIR/empty-match.rs:27:5
+   |
+LL | enum NonEmptyEnum2 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
+LL |     Bar,
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~             _ if false => {}
+LL +             Foo(_) | Bar => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
   --> $DIR/empty-match.rs:94:24
    |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum5::V1);
-   |                          ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |     match_guarded_arm!(NonEmptyEnum5::V1);
+   |                        ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+note: `NonEmptyEnum5` defined here
+  --> $DIR/empty-match.rs:30:6
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+   |      ^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyEnum5`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~             _ if false => {}
+LL +             _ => todo!()
+   |
 
 error: aborting due to 22 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/empty-match.normal.stderr b/src/test/ui/pattern/usefulness/empty-match.normal.stderr
index b99386e7402..d31ee0dbd14 100644
--- a/src/test/ui/pattern/usefulness/empty-match.normal.stderr
+++ b/src/test/ui/pattern/usefulness/empty-match.normal.stderr
@@ -46,107 +46,112 @@ error[E0004]: non-exhaustive patterns: type `u8` is non-empty
 LL |     match_no_arms!(0u8);
    |                    ^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
   --> $DIR/empty-match.rs:79:20
    |
-LL | struct NonEmptyStruct1;
-   | ----------------------- `NonEmptyStruct1` defined here
-...
 LL |     match_no_arms!(NonEmptyStruct1);
    |                    ^^^^^^^^^^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+  --> $DIR/empty-match.rs:14:8
+   |
+LL | struct NonEmptyStruct1;
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
   --> $DIR/empty-match.rs:80:20
    |
-LL | struct NonEmptyStruct2(bool);
-   | ----------------------------- `NonEmptyStruct2` defined here
-...
 LL |     match_no_arms!(NonEmptyStruct2(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+  --> $DIR/empty-match.rs:15:8
+   |
+LL | struct NonEmptyStruct2(bool);
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
   --> $DIR/empty-match.rs:81:20
    |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_no_arms!((NonEmptyUnion1 { foo: () }));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     match_no_arms!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `NonEmptyUnion1` defined here
+  --> $DIR/empty-match.rs:16:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
   --> $DIR/empty-match.rs:82:20
    |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_no_arms!((NonEmptyUnion2 { foo: () }));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     match_no_arms!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `NonEmptyUnion2` defined here
+  --> $DIR/empty-match.rs:19:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
   --> $DIR/empty-match.rs:83:20
    |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum1::Foo(true));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+  --> $DIR/empty-match.rs:24:5
+   |
+LL | enum NonEmptyEnum1 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
   --> $DIR/empty-match.rs:84:20
    |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |     Bar,
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum2::Foo(true));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+note: `NonEmptyEnum2` defined here
+  --> $DIR/empty-match.rs:27:5
+   |
+LL | enum NonEmptyEnum2 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
+LL |     Bar,
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
   --> $DIR/empty-match.rs:85:20
    |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum5::V1);
-   |                      ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |     match_no_arms!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+note: `NonEmptyEnum5` defined here
+  --> $DIR/empty-match.rs:30:6
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+   |      ^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyEnum5`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/empty-match.rs:87:24
@@ -154,107 +159,144 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match_guarded_arm!(0u8);
    |                        ^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
   --> $DIR/empty-match.rs:88:24
    |
-LL | struct NonEmptyStruct1;
-   | ----------------------- `NonEmptyStruct1` defined here
-...
 LL |     match_guarded_arm!(NonEmptyStruct1);
    |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+  --> $DIR/empty-match.rs:14:8
+   |
+LL | struct NonEmptyStruct1;
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyStruct1 => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
   --> $DIR/empty-match.rs:89:24
    |
-LL | struct NonEmptyStruct2(bool);
-   | ----------------------------- `NonEmptyStruct2` defined here
-...
 LL |     match_guarded_arm!(NonEmptyStruct2(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+  --> $DIR/empty-match.rs:15:8
+   |
+LL | struct NonEmptyStruct2(bool);
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyStruct2(_) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
   --> $DIR/empty-match.rs:90:24
    |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_guarded_arm!((NonEmptyUnion1 { foo: () }));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+LL |     match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+   |
+note: `NonEmptyUnion1` defined here
+  --> $DIR/empty-match.rs:16:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyUnion1 { .. } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
   --> $DIR/empty-match.rs:91:24
    |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_guarded_arm!((NonEmptyUnion2 { foo: () }));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+LL |     match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+   |
+note: `NonEmptyUnion2` defined here
+  --> $DIR/empty-match.rs:19:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyUnion2 { .. } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
   --> $DIR/empty-match.rs:92:24
    |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum1::Foo(true));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+  --> $DIR/empty-match.rs:24:5
+   |
+LL | enum NonEmptyEnum1 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             Foo(_) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
   --> $DIR/empty-match.rs:93:24
    |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |     Bar,
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum2::Foo(true));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+note: `NonEmptyEnum2` defined here
+  --> $DIR/empty-match.rs:27:5
+   |
+LL | enum NonEmptyEnum2 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
+LL |     Bar,
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~             _ if false => {}
+LL +             Foo(_) | Bar => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
   --> $DIR/empty-match.rs:94:24
    |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum5::V1);
-   |                          ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |     match_guarded_arm!(NonEmptyEnum5::V1);
+   |                        ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+note: `NonEmptyEnum5` defined here
+  --> $DIR/empty-match.rs:30:6
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+   |      ^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyEnum5`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~             _ if false => {}
+LL +             _ => todo!()
+   |
 
 error: aborting due to 22 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/floats.stderr b/src/test/ui/pattern/usefulness/floats.stderr
index 464bfbdb2c3..c926e50b358 100644
--- a/src/test/ui/pattern/usefulness/floats.stderr
+++ b/src/test/ui/pattern/usefulness/floats.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0.0 {
    |           ^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `f64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~       0.0..=1.0 => {}
+LL +       _ => todo!()
+   |
 
 error: unreachable pattern
   --> $DIR/floats.rs:16:7
diff --git a/src/test/ui/pattern/usefulness/guards.stderr b/src/test/ui/pattern/usefulness/guards.stderr
index 61f7facb330..0c1563c160c 100644
--- a/src/test/ui/pattern/usefulness/guards.stderr
+++ b/src/test/ui/pattern/usefulness/guards.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
 LL |     match 0u8 {
    |           ^^^ pattern `128_u8..=u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         128 ..= 255 if true => {}
+LL +         128_u8..=u8::MAX => todo!()
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
index 2e0023348e4..fec54e89d63 100644
--- a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
+++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
 LL |     m!(0u8, 0..255);
    |        ^^^ pattern `u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
   --> $DIR/exhaustiveness.rs:48:8
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
 LL |     m!(0u8, 0..=254);
    |        ^^^ pattern `u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u8` not covered
   --> $DIR/exhaustiveness.rs:49:8
@@ -22,8 +30,12 @@ error[E0004]: non-exhaustive patterns: `0_u8` not covered
 LL |     m!(0u8, 1..=255);
    |        ^^^ pattern `0_u8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `42_u8` not covered
   --> $DIR/exhaustiveness.rs:50:8
@@ -31,8 +43,12 @@ error[E0004]: non-exhaustive patterns: `42_u8` not covered
 LL |     m!(0u8, 0..42 | 43..=255);
    |        ^^^ pattern `42_u8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         42_u8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
   --> $DIR/exhaustiveness.rs:51:8
@@ -40,8 +56,12 @@ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
 LL |     m!(0i8, -128..127);
    |        ^^^ pattern `i8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
   --> $DIR/exhaustiveness.rs:52:8
@@ -49,8 +69,12 @@ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
 LL |     m!(0i8, -128..=126);
    |        ^^^ pattern `i8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
   --> $DIR/exhaustiveness.rs:53:8
@@ -58,8 +82,12 @@ error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
 LL |     m!(0i8, -127..=127);
    |        ^^^ pattern `i8::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_i8` not covered
   --> $DIR/exhaustiveness.rs:54:11
@@ -67,8 +95,12 @@ error[E0004]: non-exhaustive patterns: `0_i8` not covered
 LL |     match 0i8 {
    |           ^^^ pattern `0_i8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         1 ..= i8::MAX => {}
+LL +         0_i8 => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
   --> $DIR/exhaustiveness.rs:59:8
@@ -76,8 +108,12 @@ error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
 LL |     m!(0u128, 0..=ALMOST_MAX);
    |        ^^^^^ pattern `u128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
   --> $DIR/exhaustiveness.rs:60:8
@@ -85,8 +121,12 @@ error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
 LL |     m!(0u128, 0..=4);
    |        ^^^^^ pattern `5_u128..=u128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         5_u128..=u128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u128` not covered
   --> $DIR/exhaustiveness.rs:61:8
@@ -94,8 +134,12 @@ error[E0004]: non-exhaustive patterns: `0_u128` not covered
 LL |     m!(0u128, 1..=u128::MAX);
    |        ^^^^^ pattern `0_u128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u128 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
   --> $DIR/exhaustiveness.rs:69:11
@@ -103,8 +147,12 @@ error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
 LL |     match (0u8, true) {
    |           ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(u8, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (0 ..= 255, true) => {}
+LL +         (126_u8..=127_u8, false) => todo!()
+   |
 
 error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
index 25632934583..9f277fa1e18 100644
--- a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
+++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
@@ -4,8 +4,13 @@ error[E0004]: non-exhaustive patterns: type `usize` is non-empty
 LL |     match 7usize {}
    |           ^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match 7usize {
+LL +         _ => todo!(),
+LL +     }
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
index e8ac9f3cfe1..fa4146a7ad8 100644
--- a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
+++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
@@ -4,10 +4,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0usize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         0 ..= usize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:17:11
@@ -15,10 +19,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0isize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         isize::MIN ..= isize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:22:8
@@ -26,10 +34,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0usize, 0..=usize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:24:8
@@ -37,10 +49,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0usize, 0..5 | 5..=usize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:26:8
@@ -48,10 +64,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0usize, 0..usize::MAX | usize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `(_, _)` not covered
   --> $DIR/pointer-sized-int.rs:28:8
@@ -59,8 +79,12 @@ error[E0004]: non-exhaustive patterns: `(_, _)` not covered
 LL |     m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
    |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(usize, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         (_, _) => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:31:8
@@ -68,10 +92,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0isize, isize::MIN..=isize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:33:8
@@ -79,10 +107,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0isize, isize::MIN..5 | 5..=isize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:35:8
@@ -90,10 +122,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0isize, isize::MIN..isize::MAX | isize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `(_, _)` not covered
   --> $DIR/pointer-sized-int.rs:37:8
@@ -101,8 +137,12 @@ error[E0004]: non-exhaustive patterns: `(_, _)` not covered
 LL |     m!((0isize, true), (isize::MIN..5, true)
    |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(isize, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         (_, _) => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:41:11
@@ -110,10 +150,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0isize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         1 ..= isize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
   --> $DIR/pointer-sized-int.rs:48:11
@@ -121,8 +165,13 @@ error[E0004]: non-exhaustive patterns: type `usize` is non-empty
 LL |     match 7usize {}
    |           ^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match 7usize {
+LL +         _ => todo!(),
+LL +     }
+   |
 
 error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
index 37e73a68f22..30492c98206 100644
--- a/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
+++ b/src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
@@ -4,10 +4,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0usize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         0..=usize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/precise_pointer_matching-message.rs:11:11
@@ -15,10 +19,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0isize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         isize::MIN..=isize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/issue-15129.stderr b/src/test/ui/pattern/usefulness/issue-15129.stderr
index 79a77240937..af60f3ff50b 100644
--- a/src/test/ui/pattern/usefulness/issue-15129.stderr
+++ b/src/test/ui/pattern/usefulness/issue-15129.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` n
 LL |     match (T::T1(()), V::V2(true)) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(T, V)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         (T::T2(()), V::V2(b)) => (),
+LL ~         (T1(()), V2(_)) | (T2(()), V1(_)) => todo!(),
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-2111.stderr b/src/test/ui/pattern/usefulness/issue-2111.stderr
index 60d9b8514b7..01890b73cbd 100644
--- a/src/test/ui/pattern/usefulness/issue-2111.stderr
+++ b/src/test/ui/pattern/usefulness/issue-2111.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` n
 LL |     match (a, b) {
    |           ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Option<usize>, Option<usize>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         (Some(_), None) | (None, Some(_)) => {}
+LL +         (None, None) | (Some(_), Some(_)) => todo!()
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-30240.stderr b/src/test/ui/pattern/usefulness/issue-30240.stderr
index a2c58d6e051..759fdeafe4e 100644
--- a/src/test/ui/pattern/usefulness/issue-30240.stderr
+++ b/src/test/ui/pattern/usefulness/issue-30240.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&_` not covered
 LL |     match "world" {
    |           ^^^^^^^ pattern `&_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&str`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         "hello" => {}
+LL +         &_ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&_` not covered
   --> $DIR/issue-30240.rs:6:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `&_` not covered
 LL |     match "world" {
    |           ^^^^^^^ pattern `&_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&str`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         "hello" => {}
+LL +         &_ => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/issue-3096-1.stderr b/src/test/ui/pattern/usefulness/issue-3096-1.stderr
index 97c34755189..d8884394f8e 100644
--- a/src/test/ui/pattern/usefulness/issue-3096-1.stderr
+++ b/src/test/ui/pattern/usefulness/issue-3096-1.stderr
@@ -4,8 +4,13 @@ error[E0004]: non-exhaustive patterns: type `()` is non-empty
 LL |     match () { }
    |           ^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `()`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match () {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-3096-2.stderr b/src/test/ui/pattern/usefulness/issue-3096-2.stderr
index 472d1a91e6a..2df8911badc 100644
--- a/src/test/ui/pattern/usefulness/issue-3096-2.stderr
+++ b/src/test/ui/pattern/usefulness/issue-3096-2.stderr
@@ -4,8 +4,13 @@ error[E0004]: non-exhaustive patterns: type `*const Bottom` is non-empty
 LL |     match x { }
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `*const Bottom`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-31561.stderr b/src/test/ui/pattern/usefulness/issue-31561.stderr
index 2f562b23692..9da6b5eeead 100644
--- a/src/test/ui/pattern/usefulness/issue-31561.stderr
+++ b/src/test/ui/pattern/usefulness/issue-31561.stderr
@@ -1,25 +1,30 @@
 error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
   --> $DIR/issue-31561.rs:8:9
    |
-LL | / enum Thing {
-LL | |     Foo(u8),
-LL | |     Bar,
-   | |     --- not covered
-LL | |     Baz
-   | |     --- not covered
-LL | | }
-   | |_- `Thing` defined here
-...
-LL |       let Thing::Foo(y) = Thing::Foo(1);
-   |           ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
+LL |     let Thing::Foo(y) = Thing::Foo(1);
+   |         ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Thing` defined here
+  --> $DIR/issue-31561.rs:3:5
+   |
+LL | enum Thing {
+   |      -----
+LL |     Foo(u8),
+LL |     Bar,
+   |     ^^^ not covered
+LL |     Baz
+   |     ^^^ not covered
    = note: the matched value is of type `Thing`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let Thing::Foo(y) = Thing::Foo(1) { /* */ }
+LL |     let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() };
+   |     ++++++++++                                   ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched
    |
+LL |     let Thing::Foo(y) = Thing::Foo(1) else { todo!() };
+   |                                       ++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-35609.stderr b/src/test/ui/pattern/usefulness/issue-35609.stderr
index 0598c8d6f38..717bb53c327 100644
--- a/src/test/ui/pattern/usefulness/issue-35609.stderr
+++ b/src/test/ui/pattern/usefulness/issue-35609.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more n
 LL |     match (A, ()) {
    |           ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Enum, ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         (A, _) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
   --> $DIR/issue-35609.rs:14:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more n
 LL |     match (A, A) {
    |           ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Enum, Enum)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         (_, A) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
   --> $DIR/issue-35609.rs:18:11
@@ -22,8 +30,12 @@ error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _
 LL |     match ((A, ()), ()) {
    |           ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((Enum, ()), ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         ((A, ()), _) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
   --> $DIR/issue-35609.rs:22:11
@@ -31,8 +43,12 @@ error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _
 LL |     match ((A, ()), A) {
    |           ^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((Enum, ()), Enum)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         ((A, ()), _) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
   --> $DIR/issue-35609.rs:26:11
@@ -40,32 +56,48 @@ error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _
 LL |     match ((A, ()), ()) {
    |           ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((Enum, ()), ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         ((A, _), _) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
   --> $DIR/issue-35609.rs:31:11
    |
-LL | struct S(Enum, ());
-   | ------------------- `S` defined here
-...
 LL |     match S(A, ()) {
    |           ^^^^^^^^ patterns `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `S` defined here
+  --> $DIR/issue-35609.rs:6:8
+   |
+LL | struct S(Enum, ());
+   |        ^
    = note: the matched value is of type `S`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         S(A, _) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
   --> $DIR/issue-35609.rs:35:11
    |
-LL | struct Sd { x: Enum, y: () }
-   | ---------------------------- `Sd` defined here
-...
 LL |     match (Sd { x: A, y: () }) {
    |           ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Sd` defined here
+  --> $DIR/issue-35609.rs:7:8
+   |
+LL | struct Sd { x: Enum, y: () }
+   |        ^^
    = note: the matched value is of type `Sd`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         Sd { x: A, y: _ } => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
   --> $DIR/issue-35609.rs:39:11
@@ -73,8 +105,23 @@ error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 mor
 LL |     match Some(A) {
    |           ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Option<Enum>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+   | |_^
    = note: the matched value is of type `Option<Enum>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         None => (),
+LL +         _ => todo!()
+   |
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/issue-3601.stderr b/src/test/ui/pattern/usefulness/issue-3601.stderr
index 48ed1491508..4e0adcc1ba2 100644
--- a/src/test/ui/pattern/usefulness/issue-3601.stderr
+++ b/src/test/ui/pattern/usefulness/issue-3601.stderr
@@ -4,8 +4,20 @@ error[E0004]: non-exhaustive patterns: `box _` not covered
 LL |         box NodeKind::Element(ed) => match ed.kind {
    |                                            ^^^^^^^ pattern `box _` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Box<ElementKind>` defined here
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+   |
+LL | / pub struct Box<
+LL | |     T: ?Sized,
+LL | |     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+LL | | >(Unique<T>, A);
+   | |________________^
    = note: the matched value is of type `Box<ElementKind>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
+LL +             box _ => todo!()
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-39362.stderr b/src/test/ui/pattern/usefulness/issue-39362.stderr
index 8c162e55619..ca37af6fb80 100644
--- a/src/test/ui/pattern/usefulness/issue-39362.stderr
+++ b/src/test/ui/pattern/usefulness/issue-39362.stderr
@@ -1,16 +1,22 @@
 error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
   --> $DIR/issue-39362.rs:10:11
    |
-LL | / enum Foo {
-LL | |     Bar { bar: Bar, id: usize }
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       match f {
-   |             ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
+LL |     match f {
+   |           ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+  --> $DIR/issue-39362.rs:2:5
+   |
+LL | enum Foo {
+   |      ---
+LL |     Bar { bar: Bar, id: usize }
+   |     ^^^ not covered
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         Foo::Bar { bar: Bar::B, .. } => (),
+LL ~         _ => todo!(),
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-40221.stderr b/src/test/ui/pattern/usefulness/issue-40221.stderr
index 98efe805a0b..c477e435335 100644
--- a/src/test/ui/pattern/usefulness/issue-40221.stderr
+++ b/src/test/ui/pattern/usefulness/issue-40221.stderr
@@ -1,17 +1,22 @@
 error[E0004]: non-exhaustive patterns: `C(QA)` not covered
   --> $DIR/issue-40221.rs:11:11
    |
-LL | / enum P {
-LL | |     C(PC),
-   | |     - not covered
-LL | | }
-   | |_- `P` defined here
-...
-LL |       match proto {
-   |             ^^^^^ pattern `C(QA)` not covered
+LL |     match proto {
+   |           ^^^^^ pattern `C(QA)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `P` defined here
+  --> $DIR/issue-40221.rs:2:5
+   |
+LL | enum P {
+   |      -
+LL |     C(PC),
+   |     ^ not covered
    = note: the matched value is of type `P`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         P::C(PC::Q) => (),
+LL ~         C(QA) => todo!(),
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-4321.stderr b/src/test/ui/pattern/usefulness/issue-4321.stderr
index 1e8852556b1..29327317410 100644
--- a/src/test/ui/pattern/usefulness/issue-4321.stderr
+++ b/src/test/ui/pattern/usefulness/issue-4321.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered
 LL |     println!("foo {:}", match tup {
    |                               ^^^ pattern `(true, false)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(bool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (true, true) => "baz",
+LL +         (true, false) => todo!()
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-50900.stderr b/src/test/ui/pattern/usefulness/issue-50900.stderr
index d378b6e8efe..2bdbecabbbe 100644
--- a/src/test/ui/pattern/usefulness/issue-50900.stderr
+++ b/src/test/ui/pattern/usefulness/issue-50900.stderr
@@ -1,14 +1,20 @@
 error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered
   --> $DIR/issue-50900.rs:15:11
    |
-LL | pub struct Tag(pub Context, pub u16);
-   | ------------------------------------- `Tag` defined here
-...
 LL |     match Tag::ExifIFDPointer {
    |           ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Tag` defined here
+  --> $DIR/issue-50900.rs:2:12
+   |
+LL | pub struct Tag(pub Context, pub u16);
+   |            ^^^
    = note: the matched value is of type `Tag`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Tag::ExifIFDPointer => {}
+LL +         Tag(Exif, _) => todo!()
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-56379.stderr b/src/test/ui/pattern/usefulness/issue-56379.stderr
index 6a231b868c8..f6261001c5e 100644
--- a/src/test/ui/pattern/usefulness/issue-56379.stderr
+++ b/src/test/ui/pattern/usefulness/issue-56379.stderr
@@ -1,21 +1,26 @@
 error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered
   --> $DIR/issue-56379.rs:8:11
    |
-LL | / enum Foo {
-LL | |     A(bool),
-   | |     - not covered
-LL | |     B(bool),
-   | |     - not covered
-LL | |     C(bool),
-   | |     - not covered
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       match Foo::A(true) {
-   |             ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
+LL |     match Foo::A(true) {
+   |           ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+  --> $DIR/issue-56379.rs:2:5
+   |
+LL | enum Foo {
+   |      ---
+LL |     A(bool),
+   |     ^ not covered
+LL |     B(bool),
+   |     ^ not covered
+LL |     C(bool),
+   |     ^ not covered
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Foo::C(true) => {}
+LL +         A(false) | B(false) | C(false) => todo!()
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-72377.stderr b/src/test/ui/pattern/usefulness/issue-72377.stderr
index b4a68333967..20f002dd3db 100644
--- a/src/test/ui/pattern/usefulness/issue-72377.stderr
+++ b/src/test/ui/pattern/usefulness/issue-72377.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(A, Some(A))`, `(A, Some(B))`, `(B, Some
 LL |     match (x, y) {
    |           ^^^^^^ patterns `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(X, Option<X>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         (X::A, Some(X::C)) | (X::C, Some(X::A)) => false,
+LL ~         _ => todo!(),
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs b/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs
index 6c5a331b4b5..cbfcf0eafd4 100644
--- a/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs
+++ b/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs
@@ -1,5 +1,6 @@
 enum A {}
     //~^ NOTE `A` defined here
+    //~| NOTE
 
 fn f(a: &A) {
     match a {}
diff --git a/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr b/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr
index e992632a91f..bf05d616d6e 100644
--- a/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr
+++ b/src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr
@@ -1,15 +1,22 @@
 error[E0004]: non-exhaustive patterns: type `&A` is non-empty
-  --> $DIR/issue-78123-non-exhaustive-reference.rs:5:11
+  --> $DIR/issue-78123-non-exhaustive-reference.rs:6:11
    |
-LL | enum A {}
-   | --------- `A` defined here
-...
 LL |     match a {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `A` defined here
+  --> $DIR/issue-78123-non-exhaustive-reference.rs:1:6
+   |
+LL | enum A {}
+   |      ^
    = note: the matched value is of type `&A`
    = note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match a {
+LL +         _ => todo!(),
+LL +     }
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr
index 4a987cb6c03..3326e6b85a4 100644
--- a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr
+++ b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered
 LL |     match (true, false) {
    |           ^^^^^^^^^^^^^ pattern `(true, false)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(bool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (false, true) => (),
+LL +         (true, false) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered
   --> $DIR/match-arm-statics-2.rs:29:11
@@ -13,31 +17,45 @@ error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered
 LL |     match Some(Some(North)) {
    |           ^^^^^^^^^^^^^^^^^ pattern `Some(Some(West))` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Option<Direction>>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   | |     ^^^^
+   | |     |
+   | |     not covered
+   | |     not covered
+LL | | }
+   | |_-
+   = note: the matched value is of type `Option<Option<Direction>>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     ----
-   |     |
-   |     not covered
-   |     not covered
+LL ~         None => (),
+LL +         Some(Some(West)) => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Option<Option<Direction>>`
 
 error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered
   --> $DIR/match-arm-statics-2.rs:48:11
    |
-LL | / struct Foo {
-LL | |     bar: Option<Direction>,
-LL | |     baz: NewBool
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       match (Foo { bar: Some(North), baz: NewBool(true) }) {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered
+LL |     match (Foo { bar: Some(North), baz: NewBool(true) }) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered
+   |
+note: `Foo` defined here
+  --> $DIR/match-arm-statics-2.rs:40:8
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | struct Foo {
+   |        ^^^
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo { bar: Some(EAST), .. } => (),
+LL +         Foo { bar: Some(North), baz: NewBool(true) } => todo!()
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
index ffc8433403f..a90f32f7aeb 100644
--- a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
+++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..
 LL |     match buf {
    |           ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8; 4]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         b"AAAA" => {}
+LL +         &[0_u8..=64_u8, _, _, _] | &[66_u8..=u8::MAX, _, _, _] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
   --> $DIR/match-byte-array-patterns-2.rs:10:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not c
 LL |     match buf {
    |           ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         b"AAAA" => {}
+LL +         _ => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr
index a35d61e4b71..08dde523a15 100644
--- a/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr
+++ b/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr
@@ -4,8 +4,11 @@ error[E0004]: non-exhaustive patterns: `i32::MIN..=0_i32` and `2_i32..=i32::MAX`
 LL |     match 0 { 1 => () }
    |           ^ patterns `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL |     match 0 { 1 => (), i32::MIN..=0_i32 | 2_i32..=i32::MAX => todo!() }
+   |                      ++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/match-non-exhaustive.rs:3:11
@@ -13,8 +16,11 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0 { 0 if false => () }
    |           ^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     match 0 { 0 if false => (), _ => todo!() }
+   |                               ++++++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.stderr b/src/test/ui/pattern/usefulness/match-privately-empty.stderr
index 4efb41978a2..88178d64291 100644
--- a/src/test/ui/pattern/usefulness/match-privately-empty.stderr
+++ b/src/test/ui/pattern/usefulness/match-privately-empty.stderr
@@ -4,13 +4,24 @@ error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not co
 LL |     match private::DATA {
    |           ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Private>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     ---- not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   | |     ^^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Option<Private>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         }) => {}
+LL +         Some(Private { misc: true, .. }) => todo!()
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/match-slice-patterns.stderr b/src/test/ui/pattern/usefulness/match-slice-patterns.stderr
index 88f27be0412..961dd590119 100644
--- a/src/test/ui/pattern/usefulness/match-slice-patterns.stderr
+++ b/src/test/ui/pattern/usefulness/match-slice-patterns.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&[_, Some(_), .., None, _]` not covered
 LL |     match list {
    |           ^^^^ pattern `&[_, Some(_), .., None, _]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[Option<()>]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         &[.., Some(_), _] => {}
+LL ~         &[_, Some(_), .., None, _] => todo!(),
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs
index 6f009acbdfe..2e15bc2d2a5 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs
@@ -4,20 +4,26 @@
 
 #[derive(Clone)]
 enum E {
-//~^ `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
+    //~^ NOTE
+    //~| NOTE
+    //~| NOTE
+    //~| NOTE
+    //~| NOTE
+    //~| NOTE
     A,
     B,
-    //~^ not covered
-    //~| not covered
-    //~| not covered
-    //~| not covered
-    //~| not covered
-    //~| not covered
+    //~^ NOTE `E` defined here
+    //~| NOTE `E` defined here
+    //~| NOTE `E` defined here
+    //~| NOTE `E` defined here
+    //~| NOTE `E` defined here
+    //~| NOTE `E` defined here
+    //~| NOTE  not covered
+    //~| NOTE  not covered
+    //~| NOTE  not covered
+    //~| NOTE  not covered
+    //~| NOTE  not covered
+    //~| NOTE  not covered
     C
     //~^ not covered
     //~| not covered
@@ -30,43 +36,70 @@ enum E {
 fn by_val(e: E) {
     let e1 = e.clone();
     match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered
+        //~^ NOTE patterns `B` and `C` not covered
+        //~| NOTE the matched value is of type `E`
         E::A => {}
     }
 
     let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered
+    //~^ NOTE patterns `B` and `C` not covered
+    //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+    //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+    //~| NOTE the matched value is of type `E`
 }
 
 fn by_ref_once(e: &E) {
     match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered
+    //~^ NOTE patterns `&B` and `&C` not covered
+    //~| NOTE the matched value is of type `&E`
         E::A => {}
     }
 
     let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
+    //~^ NOTE patterns `&B` and `&C` not covered
+    //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+    //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+    //~| NOTE the matched value is of type `&E`
 }
 
 fn by_ref_thrice(e: & &mut &E) {
     match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
+    //~^ NOTE patterns `&&mut &B` and `&&mut &C` not covered
+    //~| NOTE the matched value is of type `&&mut &E`
         E::A => {}
     }
 
     let E::A = e;
     //~^ ERROR refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
+    //~| NOTE patterns `&&mut &B` and `&&mut &C` not covered
+    //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+    //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+    //~| NOTE the matched value is of type `&&mut &E`
 }
 
 enum Opt {
-//~^ `Opt` defined here
-//~| `Opt` defined here
+    //~^ NOTE
+    //~| NOTE
     Some(u8),
     None,
-    //~^ not covered
+    //~^ NOTE `Opt` defined here
+    //~| NOTE `Opt` defined here
+    //~| NOTE not covered
+    //~| NOTE not covered
 }
 
 fn ref_pat(e: Opt) {
     match e {//~ ERROR non-exhaustive patterns: `None` not covered
+        //~^ NOTE pattern `None` not covered
+        //~| NOTE the matched value is of type `Opt`
         Opt::Some(ref _x) => {}
     }
 
     let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered
+    //~^ NOTE the matched value is of type `Opt`
+    //~| NOTE pattern `None` not covered
+    //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+    //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 }
 
 fn main() {}
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
index 02eff28015d..0f06c31c468 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
@@ -1,204 +1,196 @@
 error[E0004]: non-exhaustive patterns: `B` and `C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:32:11
-   |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       match e1 {
-   |             ^^ patterns `B` and `C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:38:11
+   |
+LL |     match e1 {
+   |           ^^ patterns `B` and `C` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
+   |
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
    = note: the matched value is of type `E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         E::A => {}
+LL +         B | C => todo!()
+   |
 
 error[E0005]: refutable pattern in local binding: `B` and `C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:36:9
-   |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       let E::A = e;
-   |           ^^^^ patterns `B` and `C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:44:9
+   |
+LL |     let E::A = e;
+   |         ^^^^ patterns `B` and `C` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
+   |
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
    = note: the matched value is of type `E`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let E::A = e { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     if let E::A = e { todo!() }
+   |     ++              ~~~~~~~~~~~
 
 error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:40:11
-   |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       match e {
-   |             ^ patterns `&B` and `&C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:52:11
+   |
+LL |     match e {
+   |           ^ patterns `&B` and `&C` not covered
+   |
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
    = note: the matched value is of type `&E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         E::A => {}
+LL +         &B | &C => todo!()
+   |
 
 error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:44:9
+  --> $DIR/non-exhaustive-defined-here.rs:58:9
    |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       let E::A = e;
-   |           ^^^^ patterns `&B` and `&C` not covered
+LL |     let E::A = e;
+   |         ^^^^ patterns `&B` and `&C` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
+   |
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
    = note: the matched value is of type `&E`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let E::A = e { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     if let E::A = e { todo!() }
+   |     ++              ~~~~~~~~~~~
 
 error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:48:11
-   |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       match e {
-   |             ^ patterns `&&mut &B` and `&&mut &C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:66:11
+   |
+LL |     match e {
+   |           ^ patterns `&&mut &B` and `&&mut &C` not covered
+   |
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
    = note: the matched value is of type `&&mut &E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         E::A => {}
+LL +         &&mut &B | &&mut &C => todo!()
+   |
 
 error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:52:9
-   |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       let E::A = e;
-   |           ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:72:9
+   |
+LL |     let E::A = e;
+   |         ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `&&mut &E`
-help: you might want to use `if let` to ignore the variant that isn't matched
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
    |
-LL |     if let E::A = e { /* */ }
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
+   = note: the matched value is of type `&&mut &E`
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
+LL |     if let E::A = e { todo!() }
+   |     ++              ~~~~~~~~~~~
 
 error[E0004]: non-exhaustive patterns: `None` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:65:11
-   |
-LL | / enum Opt {
-LL | |
-LL | |
-LL | |     Some(u8),
-LL | |     None,
-   | |     ---- not covered
-LL | |
-LL | | }
-   | |_- `Opt` defined here
-...
-LL |       match e {
-   |             ^ pattern `None` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:92:11
+   |
+LL |     match e {
+   |           ^ pattern `None` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opt` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:84:5
+   |
+LL | enum Opt {
+   |      ---
+...
+LL |     None,
+   |     ^^^^ not covered
    = note: the matched value is of type `Opt`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Opt::Some(ref _x) => {}
+LL +         None => todo!()
+   |
 
 error[E0005]: refutable pattern in local binding: `None` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:69:9
-   |
-LL | / enum Opt {
-LL | |
-LL | |
-LL | |     Some(u8),
-LL | |     None,
-   | |     ---- not covered
-LL | |
-LL | | }
-   | |_- `Opt` defined here
-...
-LL |       let Opt::Some(ref _x) = e;
-   |           ^^^^^^^^^^^^^^^^^ pattern `None` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:98:9
+   |
+LL |     let Opt::Some(ref _x) = e;
+   |         ^^^^^^^^^^^^^^^^^ pattern `None` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Opt` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:84:5
+   |
+LL | enum Opt {
+   |      ---
+...
+LL |     None,
+   |     ^^^^ not covered
    = note: the matched value is of type `Opt`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Opt::Some(ref _x) = e { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() };
+   |     +++++++++++                           +++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+   |
+LL |     let Opt::Some(ref _x) = e else { todo!() };
+   |                               ++++++++++++++++
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
index 928e9068266..cbbd544f943 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
@@ -4,23 +4,30 @@ error[E0004]: non-exhaustive patterns: `(Some(&[]), Err(_))` not covered
 LL |     match (l1, l2) {
    |           ^^^^^^^^ pattern `(Some(&[]), Err(_))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Option<&[T]>, Result<&[T], ()>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)",
+LL +         (Some(&[]), Err(_)) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `A(C)` not covered
   --> $DIR/non-exhaustive-match-nested.rs:15:11
    |
-LL | enum T { A(U), B }
-   | ------------------
-   | |        |
-   | |        not covered
-   | `T` defined here
-...
 LL |     match x {
    |           ^ pattern `A(C)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+  --> $DIR/non-exhaustive-match-nested.rs:1:10
+   |
+LL | enum T { A(U), B }
+   |      -   ^ not covered
    = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         T::B => { panic!("goodbye"); }
+LL +         A(C) => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
index 1ca0a33bf37..e7fa6a7814f 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
@@ -1,17 +1,19 @@
 error[E0004]: non-exhaustive patterns: `A` not covered
   --> $DIR/non-exhaustive-match.rs:7:11
    |
-LL | enum T { A, B }
-   | ---------------
-   | |        |
-   | |        not covered
-   | `T` defined here
-...
 LL |     match x { T::B => { } }
    |           ^ pattern `A` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+  --> $DIR/non-exhaustive-match.rs:3:10
+   |
+LL | enum T { A, B }
+   |      -   ^ not covered
    = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     match x { T::B => { } A => todo!() }
+   |                           ++++++++++++
 
 error[E0004]: non-exhaustive patterns: `false` not covered
   --> $DIR/non-exhaustive-match.rs:8:11
@@ -19,8 +21,12 @@ error[E0004]: non-exhaustive patterns: `false` not covered
 LL |     match true {
    |           ^^^^ pattern `false` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `bool`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~       true => {}
+LL +       false => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
   --> $DIR/non-exhaustive-match.rs:11:11
@@ -28,13 +34,24 @@ error[E0004]: non-exhaustive patterns: `Some(_)` not covered
 LL |     match Some(10) {
    |           ^^^^^^^^ pattern `Some(_)` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<i32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   | |     ^^^^ not covered
+LL | | }
+   | |_-
+   = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     ---- not covered
+LL ~       None => {}
+LL +       Some(_) => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Option<i32>`
 
 error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
   --> $DIR/non-exhaustive-match.rs:14:11
@@ -42,8 +59,12 @@ error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_
 LL |     match (2, 3, 4) {
    |           ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(i32, i32, i32)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~       (_, _, 4) => {}
+LL +       (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
   --> $DIR/non-exhaustive-match.rs:18:11
@@ -51,23 +72,30 @@ error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
 LL |     match (T::A, T::A) {
    |           ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(T, T)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~       (T::B, T::A) => {}
+LL +       (A, A) | (B, B) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `B` not covered
   --> $DIR/non-exhaustive-match.rs:22:11
    |
-LL | enum T { A, B }
-   | ---------------
-   | |           |
-   | |           not covered
-   | `T` defined here
-...
 LL |     match T::A {
    |           ^^^^ pattern `B` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+  --> $DIR/non-exhaustive-match.rs:3:13
+   |
+LL | enum T { A, B }
+   |      -      ^ not covered
    = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~       T::A => {}
+LL +       B => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
   --> $DIR/non-exhaustive-match.rs:33:11
@@ -75,8 +103,12 @@ error[E0004]: non-exhaustive patterns: `[]` not covered
 LL |     match *vec {
    |           ^^^^ pattern `[]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `[Option<isize>]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [None] => {}
+LL +         [] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
   --> $DIR/non-exhaustive-match.rs:46:11
@@ -84,8 +116,12 @@ error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
 LL |     match *vec {
    |           ^^^^ pattern `[_, _, _, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `[f32]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [] => (),
+LL +         [_, _, _, _, ..] => todo!()
+   |
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
index c9ed12aae5f..b0cfd631fb0 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
@@ -1,83 +1,102 @@
 error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:7:11
    |
-LL | / struct Foo {
-LL | |     first: bool,
-LL | |     second: Option<[usize; 4]>
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       match (Foo { first: true, second: None }) {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+LL |     match (Foo { first: true, second: None }) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+   |
+note: `Foo` defined here
+  --> $DIR/non-exhaustive-pattern-witness.rs:1:8
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | struct Foo {
+   |        ^^^
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
+LL +         Foo { first: false, second: Some([_, _, _, _]) } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Red` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:23:11
    |
-LL | / enum Color {
-LL | |     Red,
-   | |     --- not covered
-LL | |     Green,
-LL | |     CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
-LL | | }
-   | |_- `Color` defined here
-...
-LL |       match Color::Red {
-   |             ^^^^^^^^^^ pattern `Red` not covered
+LL |     match Color::Red {
+   |           ^^^^^^^^^^ pattern `Red` not covered
+   |
+note: `Color` defined here
+  --> $DIR/non-exhaustive-pattern-witness.rs:17:5
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Color {
+   |      -----
+LL |     Red,
+   |     ^^^ not covered
    = note: the matched value is of type `Color`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Color::Green => (),
+LL +         Red => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `East`, `South` and `West` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:35:11
    |
-LL | / enum Direction {
-LL | |     North, East, South, West
-   | |            ----  -----  ---- not covered
-   | |            |     |
-   | |            |     not covered
-   | |            not covered
-LL | | }
-   | |_- `Direction` defined here
-...
-LL |       match Direction::North {
-   |             ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered
+LL |     match Direction::North {
+   |           ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered
+   |
+note: `Direction` defined here
+  --> $DIR/non-exhaustive-pattern-witness.rs:31:12
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Direction {
+   |      ---------
+LL |     North, East, South, West
+   |            ^^^^  ^^^^^  ^^^^ not covered
+   |            |     |
+   |            |     not covered
+   |            not covered
    = note: the matched value is of type `Direction`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Direction::North => (),
+LL +         East | South | West => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Second`, `Third`, `Fourth` and 8 more not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:46:11
    |
-LL | / enum ExcessiveEnum {
-LL | |     First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth
-LL | | }
-   | |_- `ExcessiveEnum` defined here
-...
-LL |       match ExcessiveEnum::First {
-   |             ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered
+LL |     match ExcessiveEnum::First {
+   |           ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `ExcessiveEnum` defined here
+  --> $DIR/non-exhaustive-pattern-witness.rs:41:6
+   |
+LL | enum ExcessiveEnum {
+   |      ^^^^^^^^^^^^^
    = note: the matched value is of type `ExcessiveEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         ExcessiveEnum::First => (),
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:54:11
    |
-LL | / enum Color {
-LL | |     Red,
-LL | |     Green,
-LL | |     CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
-   | |     ---------- not covered
-LL | | }
-   | |_- `Color` defined here
-...
-LL |       match Color::Red {
-   |             ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered
+LL |     match Color::Red {
+   |           ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered
+   |
+note: `Color` defined here
+  --> $DIR/non-exhaustive-pattern-witness.rs:19:5
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Color {
+   |      -----
+...
+LL |     CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+   |     ^^^^^^^^^^ not covered
    = note: the matched value is of type `Color`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (),
+LL +         CustomRGBA { a: true, .. } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:70:11
@@ -85,8 +104,12 @@ error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not cover
 LL |     match *x {
    |           ^^ pattern `[Second(true), Second(false)]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `[Enum]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [_, _, ref tail @ .., _] => (),
+LL +         [Second(true), Second(false)] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `((), false)` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:83:11
@@ -94,8 +117,12 @@ error[E0004]: non-exhaustive patterns: `((), false)` not covered
 LL |     match ((), false) {
    |           ^^^^^^^^^^^ pattern `((), false)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((), bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         ((), true) => (),
+LL +         ((), false) => todo!()
+   |
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr
index 74ec646e31c..d1dacc822e9 100644
--- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr
+++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr
@@ -15,10 +15,10 @@ LL |     let (1, (Some(1), 2..=3)) = (1, (None, 2));
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `(i32, (Option<i32>, i32))`
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |     if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { /* */ }
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
+LL |     if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() }
+   |     ++                                            ~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
index e34770fb912..5d1e170ae6c 100644
--- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
+++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&[false, _]` not covered
 LL |     match s2 {
    |           ^^ pattern `&[false, _]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 2]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [true, .., true] => {}
+LL +         &[false, _] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:12:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
 LL |     match s3 {
    |           ^^ pattern `&[false, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 3]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [true, .., true] => {}
+LL +         &[false, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:16:11
@@ -22,8 +30,12 @@ error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
 LL |     match s10 {
    |           ^^^ pattern `&[false, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 10]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [true, .., true] => {}
+LL +         &[false, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:25:11
@@ -31,8 +43,12 @@ error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
 LL |     match s2 {
    |           ^^ pattern `&[false, true]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 2]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [.., false] => {}
+LL +         &[false, true] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:30:11
@@ -40,8 +56,12 @@ error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
 LL |     match s3 {
    |           ^^ pattern `&[false, .., true]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 3]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [.., false] => {}
+LL +         &[false, .., true] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:35:11
@@ -49,8 +69,12 @@ error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
 LL |     match s {
    |           ^ pattern `&[false, .., true]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [.., false] => {}
+LL +         &[false, .., true] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:42:11
@@ -58,8 +82,12 @@ error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
 LL |     match s {
    |           ^ pattern `&[_, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [] => {}
+LL +         &[_, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:46:11
@@ -67,8 +95,12 @@ error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ pattern `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [_] => {}
+LL +         &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:51:11
@@ -76,8 +108,12 @@ error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
 LL |     match s {
    |           ^ pattern `&[false, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [true, ..] => {}
+LL +         &[false, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:56:11
@@ -85,8 +121,12 @@ error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
 LL |     match s {
    |           ^ pattern `&[false, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [true, ..] => {}
+LL +         &[false, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:62:11
@@ -94,8 +134,12 @@ error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
 LL |     match s {
    |           ^ pattern `&[_, .., false]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [.., true] => {}
+LL +         &[_, .., false] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:69:11
@@ -103,8 +147,12 @@ error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
 LL |     match s {
    |           ^ pattern `&[_, _, .., true]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [.., false] => {}
+LL +         &[_, _, .., true] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:76:11
@@ -112,8 +160,12 @@ error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
 LL |     match s {
    |           ^ pattern `&[true, _, .., _]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [false, .., false] => {}
+LL +         &[true, _, .., _] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:85:11
@@ -121,8 +173,12 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         &[true] => {}
+LL +         &[] | &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:89:11
@@ -130,8 +186,12 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         CONST => {}
+LL +         &[] | &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:93:11
@@ -139,8 +199,12 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         &[false] => {}
+LL +         &[] | &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:98:11
@@ -148,8 +212,12 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         CONST => {}
+LL +         &[] | &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:103:11
@@ -157,8 +225,12 @@ error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ pattern `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         CONST => {}
+LL +         &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:108:11
@@ -166,8 +238,12 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
 LL |     match s {
    |           ^ pattern `&[false]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         &[_, _, ..] => {}
+LL +         &[false] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:121:11
@@ -175,8 +251,12 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
 LL |     match s1 {
    |           ^^ pattern `&[false]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 1]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         CONST1 => {}
+LL +         &[false] => todo!()
+   |
 
 error: aborting due to 20 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/stable-gated-fields.rs b/src/test/ui/pattern/usefulness/stable-gated-fields.rs
new file mode 100644
index 00000000000..90f40a8d629
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/stable-gated-fields.rs
@@ -0,0 +1,16 @@
+// aux-build:unstable.rs
+
+extern crate unstable;
+
+use unstable::UnstableStruct;
+
+fn main() {
+    let UnstableStruct { stable } = UnstableStruct::default();
+    //~^ pattern does not mention field `stable2` and inaccessible fields
+
+    let UnstableStruct { stable, stable2 } = UnstableStruct::default();
+    //~^ pattern requires `..` due to inaccessible fields
+
+    // OK: stable field is matched
+    let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+}
diff --git a/src/test/ui/pattern/usefulness/stable-gated-fields.stderr b/src/test/ui/pattern/usefulness/stable-gated-fields.stderr
new file mode 100644
index 00000000000..cf98c51a2b4
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/stable-gated-fields.stderr
@@ -0,0 +1,29 @@
+error[E0027]: pattern does not mention field `stable2` and inaccessible fields
+  --> $DIR/stable-gated-fields.rs:8:9
+   |
+LL |     let UnstableStruct { stable } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `stable2` and inaccessible fields
+   |
+help: include the missing field in the pattern and ignore the inaccessible fields
+   |
+LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+   |                                ~~~~~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let UnstableStruct { stable, .. } = UnstableStruct::default();
+   |                                ~~~~~~
+
+error: pattern requires `..` due to inaccessible fields
+  --> $DIR/stable-gated-fields.rs:11:9
+   |
+LL |     let UnstableStruct { stable, stable2 } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: ignore the inaccessible and unused fields
+   |
+LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+   |                                         ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.rs b/src/test/ui/pattern/usefulness/stable-gated-patterns.rs
index 2e023a3be4a..ff1c472e24f 100644
--- a/src/test/ui/pattern/usefulness/stable-gated-patterns.rs
+++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.rs
@@ -2,17 +2,17 @@
 
 extern crate unstable;
 
-use unstable::Foo;
+use unstable::UnstableEnum;
 
 fn main() {
-    match Foo::Stable {
-        Foo::Stable => {}
+    match UnstableEnum::Stable {
+        UnstableEnum::Stable => {}
     }
     //~^^^ non-exhaustive patterns: `Stable2` and `_` not covered
 
-    match Foo::Stable {
-        Foo::Stable => {}
-        Foo::Stable2 => {}
+    match UnstableEnum::Stable {
+        UnstableEnum::Stable => {}
+        UnstableEnum::Stable2 => {}
     }
     //~^^^^ non-exhaustive patterns: `_` not covered
 }
diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr
index 9b42565ac73..559539178cb 100644
--- a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr
+++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr
@@ -1,25 +1,52 @@
 error[E0004]: non-exhaustive patterns: `Stable2` and `_` not covered
   --> $DIR/stable-gated-patterns.rs:8:11
    |
-LL |     match Foo::Stable {
-   |           ^^^^^^^^^^^ patterns `Stable2` and `_` not covered
+LL |     match UnstableEnum::Stable {
+   |           ^^^^^^^^^^^^^^^^^^^^ patterns `Stable2` and `_` not covered
    |
-  ::: $DIR/auxiliary/unstable.rs:9:5
+note: `UnstableEnum` defined here
+  --> $DIR/auxiliary/unstable.rs:9:5
    |
-LL |     Stable2,
-   |     ------- not covered
+LL | / pub enum UnstableEnum {
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | |     Stable,
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | |     Stable2,
+   | |     ^^^^^^^ not covered
+LL | |     #[unstable(feature = "unstable_test_feature", issue = "none")]
+LL | |     Unstable,
+LL | | }
+   | |_-
+   = note: the matched value is of type `UnstableEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         UnstableEnum::Stable => {}
+LL +         Stable2 | _ => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Foo`
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/stable-gated-patterns.rs:13:11
    |
-LL |     match Foo::Stable {
-   |           ^^^^^^^^^^^ pattern `_` not covered
+LL |     match UnstableEnum::Stable {
+   |           ^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
+   |
+note: `UnstableEnum` defined here
+  --> $DIR/auxiliary/unstable.rs:5:1
+   |
+LL | / pub enum UnstableEnum {
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | |     Stable,
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+...  |
+LL | |     Unstable,
+LL | | }
+   | |_^
+   = note: the matched value is of type `UnstableEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         UnstableEnum::Stable2 => {}
+LL +         _ => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Foo`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr b/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
index 23ff6c626f7..6127fad3f7d 100644
--- a/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
+++ b/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
@@ -1,18 +1,22 @@
 error[E0004]: non-exhaustive patterns: `B { x: Some(_) }` not covered
   --> $DIR/struct-like-enum-nonexhaustive.rs:8:11
    |
-LL | / enum A {
-LL | |     B { x: Option<isize> },
-   | |     - not covered
-LL | |     C
-LL | | }
-   | |_- `A` defined here
-...
-LL |       match x {
-   |             ^ pattern `B { x: Some(_) }` not covered
+LL |     match x {
+   |           ^ pattern `B { x: Some(_) }` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `A` defined here
+  --> $DIR/struct-like-enum-nonexhaustive.rs:2:5
+   |
+LL | enum A {
+   |      -
+LL |     B { x: Option<isize> },
+   |     ^ not covered
    = note: the matched value is of type `A`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         A::B { x: None } => {}
+LL +         B { x: Some(_) } => todo!()
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr b/src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr
index ca8f67f3c8d..fc0430d06fa 100644
--- a/src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr
+++ b/src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr
@@ -1,14 +1,20 @@
 error[E0004]: non-exhaustive patterns: `Foo(_, _)` not covered
   --> $DIR/tuple-struct-nonexhaustive.rs:5:11
    |
-LL | struct Foo(isize, isize);
-   | ------------------------- `Foo` defined here
-...
 LL |     match x {
    |           ^ pattern `Foo(_, _)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+  --> $DIR/tuple-struct-nonexhaustive.rs:1:8
+   |
+LL | struct Foo(isize, isize);
+   |        ^^^
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo(2, b) => println!("{}", b)
+LL +         Foo(_, _) => todo!()
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr
index 6ce53a4f21e..acae605dae3 100644
--- a/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr
+++ b/src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
 LL |     match data {
    |           ^^^^ pattern `&[_, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         b"" => 1,
+LL ~         &[_, ..] => todo!(),
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
   --> $DIR/type_polymorphic_byte_str_literals.rs:23:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not c
 LL |     match data {
    |           ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         [_, _, _] => 1,
+LL ~         _ => todo!(),
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/pattern/usefulness/unstable-gated-fields.rs b/src/test/ui/pattern/usefulness/unstable-gated-fields.rs
new file mode 100644
index 00000000000..2b473ae989b
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/unstable-gated-fields.rs
@@ -0,0 +1,18 @@
+#![feature(unstable_test_feature)]
+
+// aux-build:unstable.rs
+
+extern crate unstable;
+
+use unstable::UnstableStruct;
+
+fn main() {
+    let UnstableStruct { stable, stable2, } = UnstableStruct::default();
+    //~^ pattern does not mention field `unstable`
+
+    let UnstableStruct { stable, unstable, } = UnstableStruct::default();
+    //~^ pattern does not mention field `stable2`
+
+    // OK: stable field is matched
+    let UnstableStruct { stable, stable2, unstable } = UnstableStruct::default();
+}
diff --git a/src/test/ui/pattern/usefulness/unstable-gated-fields.stderr b/src/test/ui/pattern/usefulness/unstable-gated-fields.stderr
new file mode 100644
index 00000000000..e4f5fa06b3f
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/unstable-gated-fields.stderr
@@ -0,0 +1,33 @@
+error[E0027]: pattern does not mention field `unstable`
+  --> $DIR/unstable-gated-fields.rs:10:9
+   |
+LL |     let UnstableStruct { stable, stable2, } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `unstable`
+   |
+help: include the missing field in the pattern
+   |
+LL |     let UnstableStruct { stable, stable2, unstable } = UnstableStruct::default();
+   |                                         ~~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+   |                                         ~~~~~~
+
+error[E0027]: pattern does not mention field `stable2`
+  --> $DIR/unstable-gated-fields.rs:13:9
+   |
+LL |     let UnstableStruct { stable, unstable, } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `stable2`
+   |
+help: include the missing field in the pattern
+   |
+LL |     let UnstableStruct { stable, unstable, stable2 } = UnstableStruct::default();
+   |                                          ~~~~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     let UnstableStruct { stable, unstable, .. } = UnstableStruct::default();
+   |                                          ~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0027`.
diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs b/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs
index b9804b0ffe7..bdab327fd57 100644
--- a/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs
+++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs
@@ -4,19 +4,19 @@
 
 extern crate unstable;
 
-use unstable::Foo;
+use unstable::UnstableEnum;
 
 fn main() {
-    match Foo::Stable {
-        Foo::Stable => {}
-        Foo::Stable2 => {}
+    match UnstableEnum::Stable {
+        UnstableEnum::Stable => {}
+        UnstableEnum::Stable2 => {}
     }
     //~^^^^ non-exhaustive patterns: `Unstable` not covered
 
     // Ok: all variants are explicitly matched
-    match Foo::Stable {
-        Foo::Stable => {}
-        Foo::Stable2 => {}
-        Foo::Unstable => {}
+    match UnstableEnum::Stable {
+        UnstableEnum::Stable => {}
+        UnstableEnum::Stable2 => {}
+        UnstableEnum::Unstable => {}
     }
 }
diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr
index f9c0196b765..b5f1805deef 100644
--- a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr
+++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr
@@ -1,16 +1,27 @@
 error[E0004]: non-exhaustive patterns: `Unstable` not covered
   --> $DIR/unstable-gated-patterns.rs:10:11
    |
-LL |     match Foo::Stable {
-   |           ^^^^^^^^^^^ pattern `Unstable` not covered
+LL |     match UnstableEnum::Stable {
+   |           ^^^^^^^^^^^^^^^^^^^^ pattern `Unstable` not covered
    |
-  ::: $DIR/auxiliary/unstable.rs:11:5
+note: `UnstableEnum` defined here
+  --> $DIR/auxiliary/unstable.rs:11:5
    |
-LL |     Unstable,
-   |     -------- not covered
+LL | / pub enum UnstableEnum {
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | |     Stable,
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+...  |
+LL | |     Unstable,
+   | |     ^^^^^^^^ not covered
+LL | | }
+   | |_-
+   = note: the matched value is of type `UnstableEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         UnstableEnum::Stable2 => {}
+LL +         Unstable => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr
index f904a0ecd11..a9159562d9d 100644
--- a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr
+++ b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr
@@ -4,18 +4,29 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
 LL |     let Ok(x) = res;
    |         ^^^^^ pattern `Err(_)` not covered
    |
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
-   |     --- not covered
-   |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, &R>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | / pub enum Result<T, E> {
+LL | |     /// Contains the success value
+LL | |     #[lang = "Ok"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+   | |     ^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Result<u32, &R>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Ok(x) = res { /* */ }
+LL |     let x = if let Ok(x) = res { x } else { todo!() };
+   |     ++++++++++                 ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
    |
+LL |     let Ok(x) = res else { todo!() };
+   |                     ++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2005-default-binding-mode/slice.stderr b/src/test/ui/rfc-2005-default-binding-mode/slice.stderr
index 18d8f5481c9..60c1f5420f6 100644
--- a/src/test/ui/rfc-2005-default-binding-mode/slice.stderr
+++ b/src/test/ui/rfc-2005-default-binding-mode/slice.stderr
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&[]` not covered
 LL |     match sl {
    |           ^^ pattern `&[]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [first, remainder @ ..] => {}
+LL ~         &[] => todo!(),
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs
index de9d6f65945..11df44461e3 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/unstable.rs
@@ -27,3 +27,34 @@ impl OnlyUnstableEnum {
         Self::Unstable
     }
 }
+
+#[derive(Default)]
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+#[non_exhaustive]
+pub struct UnstableStruct {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub stable: bool,
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub stable2: usize,
+    #[unstable(feature = "unstable_test_feature", issue = "none")]
+    pub unstable: u8,
+}
+
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+#[non_exhaustive]
+pub struct OnlyUnstableStruct {
+    #[unstable(feature = "unstable_test_feature", issue = "none")]
+    pub unstable: u8,
+    #[unstable(feature = "unstable_test_feature", issue = "none")]
+    pub unstable2: bool,
+}
+
+impl OnlyUnstableStruct {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub fn new() -> Self {
+        Self {
+            unstable: 0,
+            unstable2: false,
+        }
+    }
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
index cd9ded81e6a..5ef078c2005 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
@@ -4,8 +4,18 @@ error[E0004]: non-exhaustive patterns: type `EmptyNonExhaustiveEnum` is non-empt
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `EmptyNonExhaustiveEnum` defined here
+  --> $DIR/auxiliary/enums.rs:18:1
+   |
+LL | pub enum EmptyNonExhaustiveEnum {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `EmptyNonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/enum.rs:16:11
@@ -13,8 +23,21 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match enum_unit {
    |           ^^^^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonExhaustiveEnum` defined here
+  --> $DIR/auxiliary/enums.rs:4:1
+   |
+LL | / pub enum NonExhaustiveEnum {
+LL | |     Unit,
+LL | |     Tuple(u32),
+LL | |     Struct { field: u32 },
+LL | | }
+   | |_^
    = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         NonExhaustiveEnum::Struct { .. } => "third",
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/enum.rs:23:11
@@ -22,8 +45,22 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match enum_unit {};
    |           ^^^^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonExhaustiveEnum` defined here
+  --> $DIR/auxiliary/enums.rs:4:1
+   |
+LL | / pub enum NonExhaustiveEnum {
+LL | |     Unit,
+LL | |     Tuple(u32),
+LL | |     Struct { field: u32 },
+LL | | }
+   | |_^
    = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~     match enum_unit {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
index 966f3a2e414..1f20904483f 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
@@ -13,46 +13,56 @@ LL | #![deny(unreachable_patterns)]
 error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/enum_same_crate_empty_match.rs:33:11
    |
-LL | / pub enum NonExhaustiveEnum {
-LL | |     Unit,
-   | |     ---- not covered
-LL | |
-LL | |     Tuple(u32),
-   | |     ----- not covered
-LL | |
-LL | |     Struct { field: u32 }
-   | |     ------ not covered
-LL | |
-LL | | }
-   | |_- `NonExhaustiveEnum` defined here
-...
-LL |       match NonExhaustiveEnum::Unit {}
-   |             ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match NonExhaustiveEnum::Unit {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+   |
+note: `NonExhaustiveEnum` defined here
+  --> $DIR/enum_same_crate_empty_match.rs:5:5
+   |
+LL | pub enum NonExhaustiveEnum {
+   |          -----------------
+LL |     Unit,
+   |     ^^^^ not covered
+LL |
+LL |     Tuple(u32),
+   |     ^^^^^ not covered
+LL |
+LL |     Struct { field: u32 }
+   |     ^^^^^^ not covered
    = note: the matched value is of type `NonExhaustiveEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match NonExhaustiveEnum::Unit {
+LL +         Unit | Tuple(_) | Struct { .. } => todo!(),
+LL +     }
+   |
 
 error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/enum_same_crate_empty_match.rs:35:11
    |
-LL | / pub enum NormalEnum {
-LL | |     Unit,
-   | |     ---- not covered
-LL | |
-LL | |     Tuple(u32),
-   | |     ----- not covered
-LL | |
-LL | |     Struct { field: u32 }
-   | |     ------ not covered
-LL | |
-LL | | }
-   | |_- `NormalEnum` defined here
-...
-LL |       match NormalEnum::Unit {}
-   |             ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match NormalEnum::Unit {}
+   |           ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+   |
+note: `NormalEnum` defined here
+  --> $DIR/enum_same_crate_empty_match.rs:14:5
+   |
+LL | pub enum NormalEnum {
+   |          ----------
+LL |     Unit,
+   |     ^^^^ not covered
+LL |
+LL |     Tuple(u32),
+   |     ^^^^^ not covered
+LL |
+LL |     Struct { field: u32 }
+   |     ^^^^^^ not covered
    = note: the matched value is of type `NormalEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match NormalEnum::Unit {
+LL +         Unit | Tuple(_) | Struct { .. } => todo!(),
+LL +     }
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs
index fe9734fdc08..d8f07bb8f24 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.rs
@@ -13,7 +13,7 @@ use enums::{
     EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant,
     VariantNonExhaustive,
 };
-use unstable::{UnstableEnum, OnlyUnstableEnum};
+use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct};
 use structs::{FunctionalRecord, MixedVisFields, NestedStruct, NormalStruct};
 
 #[non_exhaustive]
@@ -145,6 +145,7 @@ fn main() {
     }
     //~^^ some variants are not matched explicitly
 
+    // Ok: the feature is on and all variants are matched
     #[deny(non_exhaustive_omitted_patterns)]
     match UnstableEnum::Stable {
         UnstableEnum::Stable => {}
@@ -167,4 +168,20 @@ fn main() {
         _ => {}
     }
     //~^^ some variants are not matched explicitly
+
+    #[warn(non_exhaustive_omitted_patterns)]
+    let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
+    //~^ some fields are not explicitly listed
+
+    // OK: both unstable fields are matched with feature on
+    #[warn(non_exhaustive_omitted_patterns)]
+    let OnlyUnstableStruct { unstable, unstable2, .. } = OnlyUnstableStruct::new();
+
+    #[warn(non_exhaustive_omitted_patterns)]
+    let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+    //~^ some fields are not explicitly listed
+
+    // OK: both unstable and stable fields are matched with feature on
+    #[warn(non_exhaustive_omitted_patterns)]
+    let UnstableStruct { stable, stable2, unstable, .. } = UnstableStruct::default();
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
index 30f3f88ad91..a9885449f3f 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
@@ -49,6 +49,34 @@ LL |     let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found
 
+warning: some fields are not explicitly listed
+  --> $DIR/omitted-patterns.rs:173:9
+   |
+LL |     let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed
+   |
+note: the lint level is defined here
+  --> $DIR/omitted-patterns.rs:172:12
+   |
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: ensure that all fields are mentioned explicitly by adding the suggested fields
+   = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
+
+warning: some fields are not explicitly listed
+  --> $DIR/omitted-patterns.rs:181:9
+   |
+LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed
+   |
+note: the lint level is defined here
+  --> $DIR/omitted-patterns.rs:180:12
+   |
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: ensure that all fields are mentioned explicitly by adding the suggested fields
+   = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
+
 error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:58:9
    |
@@ -143,18 +171,18 @@ LL |         #[deny(non_exhaustive_omitted_patterns)]
    = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:167:9
+  --> $DIR/omitted-patterns.rs:168:9
    |
 LL |         _ => {}
    |         ^ pattern `Unstable2` not covered
    |
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:164:12
+  --> $DIR/omitted-patterns.rs:165:12
    |
 LL |     #[deny(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 
-error: aborting due to 8 previous errors; 4 warnings emitted
+error: aborting due to 8 previous errors; 6 warnings emitted
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs
index 9621d28f8e2..82ee68687ed 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.rs
@@ -6,7 +6,7 @@
 // aux-build:unstable.rs
 extern crate unstable;
 
-use unstable::{UnstableEnum, OnlyUnstableEnum};
+use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct};
 
 fn main() {
     // OK: this matches all the stable variants
@@ -30,4 +30,16 @@ fn main() {
     match OnlyUnstableEnum::new() {
         _ => {}
     }
+
+    // Ok: Same as the above enum (no fields can be matched on)
+    #[warn(non_exhaustive_omitted_patterns)]
+    let OnlyUnstableStruct { .. } = OnlyUnstableStruct::new();
+
+    #[warn(non_exhaustive_omitted_patterns)]
+    let UnstableStruct { stable, .. } = UnstableStruct::default();
+    //~^ some fields are not explicitly listed
+
+    // OK: stable field is matched
+    #[warn(non_exhaustive_omitted_patterns)]
+    let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
index b9a281974fa..7cce178988a 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
@@ -1,3 +1,17 @@
+warning: some fields are not explicitly listed
+  --> $DIR/stable-omitted-patterns.rs:39:9
+   |
+LL |     let UnstableStruct { stable, .. } = UnstableStruct::default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `stable2` not listed
+   |
+note: the lint level is defined here
+  --> $DIR/stable-omitted-patterns.rs:38:12
+   |
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: ensure that all fields are mentioned explicitly by adding the suggested fields
+   = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
+
 error: some variants are not matched explicitly
   --> $DIR/stable-omitted-patterns.rs:23:9
    |
@@ -12,5 +26,5 @@ LL |         #[deny(non_exhaustive_omitted_patterns)]
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
index c461302a366..2dc4eabb863 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
@@ -4,8 +4,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-emp
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+  --> $DIR/auxiliary/uninhabited.rs:26:1
+   |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
   --> $DIR/indirect_match.rs:23:11
@@ -13,8 +23,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-e
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:28:1
+   |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
   --> $DIR/indirect_match.rs:27:11
@@ -22,8 +42,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:30:1
+   |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
   --> $DIR/indirect_match.rs:33:11
@@ -31,8 +61,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+  --> $DIR/auxiliary/uninhabited.rs:32:1
+   |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
index 42bf67c0a45..c1219054140 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
@@ -1,50 +1,78 @@
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
   --> $DIR/indirect_match_same_crate.rs:34:11
    |
-LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
-   | ---------------------------------------------------- `IndirectUninhabitedEnum` defined here
-...
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+  --> $DIR/indirect_match_same_crate.rs:20:12
+   |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
   --> $DIR/indirect_match_same_crate.rs:38:11
    |
-LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
-   | -------------------------------------------------------- `IndirectUninhabitedStruct` defined here
-...
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+  --> $DIR/indirect_match_same_crate.rs:22:12
+   |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
   --> $DIR/indirect_match_same_crate.rs:42:11
    |
-LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
-   | ------------------------------------------------------------------ `IndirectUninhabitedTupleStruct` defined here
-...
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+  --> $DIR/indirect_match_same_crate.rs:24:12
+   |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
   --> $DIR/indirect_match_same_crate.rs:48:11
    |
-LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
-   | ------------------------------------------------------------ `IndirectUninhabitedVariants` defined here
-...
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+  --> $DIR/indirect_match_same_crate.rs:26:12
+   |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
index c397158c024..f0cb13de3f7 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
@@ -4,8 +4,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-emp
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+  --> $DIR/auxiliary/uninhabited.rs:26:1
+   |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
   --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11
@@ -13,8 +23,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-e
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:28:1
+   |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
   --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11
@@ -22,8 +42,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:30:1
+   |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
   --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11
@@ -31,8 +61,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+  --> $DIR/auxiliary/uninhabited.rs:32:1
+   |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
index d21a94a0d64..49febd9241d 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
@@ -4,8 +4,19 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedEnum` defined here
+  --> $DIR/auxiliary/uninhabited.rs:5:1
+   |
+LL | / pub enum UninhabitedEnum {
+LL | | }
+   | |_^
    = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
   --> $DIR/match.rs:23:11
@@ -13,8 +24,20 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:9:1
+   |
+LL | / pub struct UninhabitedStruct {
+LL | |     _priv: !,
+LL | | }
+   | |_^
    = note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
   --> $DIR/match.rs:27:11
@@ -22,8 +45,18 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empt
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:14:1
+   |
+LL | pub struct UninhabitedTupleStruct(!);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/match.rs:31:11
@@ -31,15 +64,23 @@ error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covere
 LL |     match x {}
    |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
    |
-  ::: $DIR/auxiliary/uninhabited.rs:17:23
+note: `UninhabitedVariants` defined here
+  --> $DIR/auxiliary/uninhabited.rs:17:23
    |
-LL |     #[non_exhaustive] Tuple(!),
-   |                       ----- not covered
-LL |     #[non_exhaustive] Struct { x: ! }
-   |                       ------ not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum UninhabitedVariants {
+LL | |     #[non_exhaustive] Tuple(!),
+   | |                       ^^^^^ not covered
+LL | |     #[non_exhaustive] Struct { x: ! }
+   | |                       ^^^^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match x {
+LL +         Tuple(_) | Struct { .. } => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
index e4d0c7022f3..c89c70ae6cc 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
@@ -1,45 +1,63 @@
 error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
   --> $DIR/match_same_crate.rs:30:11
    |
-LL | / pub struct UninhabitedStruct {
-LL | |     _priv: !,
-LL | | }
-   | |_- `UninhabitedStruct` defined here
-...
-LL |       match x {}
-   |             ^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match x {}
+   |           ^
+   |
+note: `UninhabitedStruct` defined here
+  --> $DIR/match_same_crate.rs:8:12
+   |
+LL | pub struct UninhabitedStruct {
+   |            ^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
   --> $DIR/match_same_crate.rs:34:11
    |
-LL | pub struct UninhabitedTupleStruct(!);
-   | ------------------------------------- `UninhabitedTupleStruct` defined here
-...
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+  --> $DIR/match_same_crate.rs:13:12
+   |
+LL | pub struct UninhabitedTupleStruct(!);
+   |            ^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/match_same_crate.rs:38:11
    |
-LL | / pub enum UninhabitedVariants {
-LL | |     #[non_exhaustive] Tuple(!),
-   | |                       ----- not covered
-LL | |     #[non_exhaustive] Struct { x: ! }
-   | |                       ------ not covered
-LL | | }
-   | |_- `UninhabitedVariants` defined here
-...
-LL |       match x {}
-   |             ^ patterns `Tuple(_)` and `Struct { .. }` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match x {}
+   |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
+   |
+note: `UninhabitedVariants` defined here
+  --> $DIR/match_same_crate.rs:16:23
+   |
+LL | pub enum UninhabitedVariants {
+   |          -------------------
+LL |     #[non_exhaustive] Tuple(!),
+   |                       ^^^^^ not covered
+LL |     #[non_exhaustive] Struct { x: ! }
+   |                       ^^^^^^ not covered
    = note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match x {
+LL +         Tuple(_) | Struct { .. } => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
index cc3dc6c29b9..e18c2678d32 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
@@ -4,8 +4,19 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedEnum` defined here
+  --> $DIR/auxiliary/uninhabited.rs:5:1
+   |
+LL | / pub enum UninhabitedEnum {
+LL | | }
+   | |_^
    = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
   --> $DIR/match_with_exhaustive_patterns.rs:26:11
@@ -13,8 +24,20 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:9:1
+   |
+LL | / pub struct UninhabitedStruct {
+LL | |     _priv: !,
+LL | | }
+   | |_^
    = note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
   --> $DIR/match_with_exhaustive_patterns.rs:30:11
@@ -22,8 +45,18 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empt
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:14:1
+   |
+LL | pub struct UninhabitedTupleStruct(!);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/match_with_exhaustive_patterns.rs:34:11
@@ -31,15 +64,23 @@ error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covere
 LL |     match x {}
    |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
    |
-  ::: $DIR/auxiliary/uninhabited.rs:17:23
+note: `UninhabitedVariants` defined here
+  --> $DIR/auxiliary/uninhabited.rs:17:23
    |
-LL |     #[non_exhaustive] Tuple(!),
-   |                       ----- not covered
-LL |     #[non_exhaustive] Struct { x: ! }
-   |                       ------ not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum UninhabitedVariants {
+LL | |     #[non_exhaustive] Tuple(!),
+   | |                       ^^^^^ not covered
+LL | |     #[non_exhaustive] Struct { x: ! }
+   | |                       ^^^^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match x {
+LL +         Tuple(_) | Struct { .. } => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr
index 0291a526333..cf8ca57714c 100644
--- a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr
+++ b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr
@@ -1,27 +1,10 @@
 warning: skipping const checks
    |
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:9
-   |
-LL |     let ptr: fn() -> L = attributed;
-   |         ^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
-   |
-LL |     ptr()
-   |     ^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:26
-   |
-LL |     let ptr: fn() -> L = attributed;
-   |                          ^^^^^^^^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
    |
 LL |     ptr()
    |     ^^^^^
 
-error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
-
-error: aborting due to previous error; 1 warning emitted
+warning: 1 warning emitted
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 897de54a7bf..dd090a3a548 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -15,7 +15,7 @@ error: `let` expressions are not supported here
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -24,7 +24,7 @@ error: `let` expressions are not supported here
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -33,7 +33,7 @@ error: `let` expressions are not supported here
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -42,7 +42,7 @@ error: `let` expressions are not supported here
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -51,7 +51,7 @@ error: `let` expressions are not supported here
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -60,8 +60,13 @@ error: `let` expressions are not supported here
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:47:13
+   |
+LL |     if true || let 0 = 0 {}
+   |             ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:48:17
@@ -69,8 +74,13 @@ error: `let` expressions are not supported here
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:48:14
+   |
+LL |     if (true || let 0 = 0) {}
+   |              ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:49:25
@@ -78,8 +88,13 @@ error: `let` expressions are not supported here
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:49:22
+   |
+LL |     if true && (true || let 0 = 0) {}
+   |                      ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:50:25
@@ -87,8 +102,13 @@ error: `let` expressions are not supported here
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:50:13
+   |
+LL |     if true || (true && let 0 = 0) {}
+   |             ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:53:12
@@ -96,7 +116,7 @@ error: `let` expressions are not supported here
 LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -105,7 +125,7 @@ error: `let` expressions are not supported here
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -114,7 +134,7 @@ error: `let` expressions are not supported here
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -123,7 +143,7 @@ error: `let` expressions are not supported here
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -132,7 +152,7 @@ error: `let` expressions are not supported here
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -141,7 +161,7 @@ error: `let` expressions are not supported here
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -150,7 +170,7 @@ error: `let` expressions are not supported here
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -159,7 +179,7 @@ error: `let` expressions are not supported here
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -168,7 +188,7 @@ error: `let` expressions are not supported here
 LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -177,7 +197,7 @@ error: `let` expressions are not supported here
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -186,7 +206,7 @@ error: `let` expressions are not supported here
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -195,7 +215,7 @@ error: `let` expressions are not supported here
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -204,7 +224,7 @@ error: `let` expressions are not supported here
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -213,7 +233,7 @@ error: `let` expressions are not supported here
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -222,8 +242,13 @@ error: `let` expressions are not supported here
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:111:16
+   |
+LL |     while true || let 0 = 0 {}
+   |                ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:112:20
@@ -231,8 +256,13 @@ error: `let` expressions are not supported here
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:112:17
+   |
+LL |     while (true || let 0 = 0) {}
+   |                 ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:113:28
@@ -240,8 +270,13 @@ error: `let` expressions are not supported here
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:113:25
+   |
+LL |     while true && (true || let 0 = 0) {}
+   |                         ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:114:28
@@ -249,8 +284,13 @@ error: `let` expressions are not supported here
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:114:16
+   |
+LL |     while true || (true && let 0 = 0) {}
+   |                ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:117:15
@@ -258,7 +298,7 @@ error: `let` expressions are not supported here
 LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -267,7 +307,7 @@ error: `let` expressions are not supported here
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -276,7 +316,7 @@ error: `let` expressions are not supported here
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -285,7 +325,7 @@ error: `let` expressions are not supported here
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -294,7 +334,7 @@ error: `let` expressions are not supported here
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -303,7 +343,7 @@ error: `let` expressions are not supported here
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -312,7 +352,7 @@ error: `let` expressions are not supported here
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -321,7 +361,7 @@ error: `let` expressions are not supported here
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -330,7 +370,7 @@ error: `let` expressions are not supported here
 LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -339,7 +379,7 @@ error: `let` expressions are not supported here
 LL |     &let 0 = 0;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -348,7 +388,7 @@ error: `let` expressions are not supported here
 LL |     !let 0 = 0;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -357,7 +397,7 @@ error: `let` expressions are not supported here
 LL |     *let 0 = 0;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -366,7 +406,7 @@ error: `let` expressions are not supported here
 LL |     -let 0 = 0;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -375,7 +415,7 @@ error: `let` expressions are not supported here
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -384,8 +424,13 @@ error: `let` expressions are not supported here
 LL |     true || let 0 = 0;
    |             ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:184:10
+   |
+LL |     true || let 0 = 0;
+   |          ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:185:14
@@ -393,8 +438,13 @@ error: `let` expressions are not supported here
 LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:185:11
+   |
+LL |     (true || let 0 = 0);
+   |           ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:186:22
@@ -402,8 +452,13 @@ error: `let` expressions are not supported here
 LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:186:19
+   |
+LL |     true && (true || let 0 = 0);
+   |                   ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:189:9
@@ -411,7 +466,7 @@ error: `let` expressions are not supported here
 LL |     x = let 0 = 0;
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -420,7 +475,7 @@ error: `let` expressions are not supported here
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -429,7 +484,7 @@ error: `let` expressions are not supported here
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -438,7 +493,7 @@ error: `let` expressions are not supported here
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -447,7 +502,7 @@ error: `let` expressions are not supported here
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -456,7 +511,7 @@ error: `let` expressions are not supported here
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -465,7 +520,7 @@ error: `let` expressions are not supported here
 LL |     &let 0 = 0
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -474,7 +529,7 @@ error: `let` expressions are not supported here
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -483,7 +538,7 @@ error: `let` expressions are not supported here
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -492,7 +547,7 @@ error: `let` expressions are not supported here
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -501,7 +556,7 @@ error: `let` expressions are not supported here
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error[E0308]: mismatched types
diff --git a/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs b/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs
index 2d049277d7f..34934d1e01d 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 pub trait MyTrait {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs
index 4b706a190e6..89dc47aad3d 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs
@@ -1,5 +1,4 @@
 // check-pass
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 trait MyPartialEq {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs
index adf8d4f9ea5..b00ff1f2fac 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs
@@ -3,7 +3,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 struct S;
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs
index cc24dbd96d2..c8ded0fa7ea 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 struct S;
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
index e81e0d1e571..8df68225d44 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
index 3963f64ad32..cf114334cc3 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
@@ -1,17 +1,17 @@
 error[E0277]: can't compare `T` with `T` in const contexts
-  --> $DIR/call-generic-method-fail.rs:5:5
+  --> $DIR/call-generic-method-fail.rs:4:5
    |
 LL |     *t == *t
    |     ^^^^^^^^ no implementation for `T == T`
    |
 note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const`
-  --> $DIR/call-generic-method-fail.rs:5:5
+  --> $DIR/call-generic-method-fail.rs:4:5
    |
 LL |     *t == *t
    |     ^^^^^^^^
 
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/call-generic-method-fail.rs:5:5
+  --> $DIR/call-generic-method-fail.rs:4:5
    |
 LL |     *t == *t
    |     ^^^^^^^^
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs
index 585b65988f3..e197c8b73c5 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(const_fn_trait_bound)]
-
 struct S;
 
 impl PartialEq for S {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
index 6881db0aa02..d3e14a53a2f 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
@@ -1,5 +1,4 @@
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 struct S;
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
index 35b7fe8e401..b0af45acda1 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
@@ -1,5 +1,5 @@
 error[E0277]: can't compare `S` with `S` in const contexts
-  --> $DIR/call-generic-method-nonconst.rs:19:34
+  --> $DIR/call-generic-method-nonconst.rs:18:34
    |
 LL | pub const EQ: bool = equals_self(&S);
    |                      ----------- ^^ no implementation for `S == S`
@@ -8,12 +8,12 @@ LL | pub const EQ: bool = equals_self(&S);
    |
    = help: the trait `~const PartialEq` is not implemented for `S`
 note: the trait `PartialEq` is implemented for `S`, but that implementation is not `const`
-  --> $DIR/call-generic-method-nonconst.rs:19:34
+  --> $DIR/call-generic-method-nonconst.rs:18:34
    |
 LL | pub const EQ: bool = equals_self(&S);
    |                                  ^^
 note: required by a bound in `equals_self`
-  --> $DIR/call-generic-method-nonconst.rs:12:25
+  --> $DIR/call-generic-method-nonconst.rs:11:25
    |
 LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
    |                         ^^^^^^^^^^^^^^^^ required by this bound in `equals_self`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs
index aa9bd4d824e..40565d1b76a 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs
@@ -3,7 +3,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 struct S;
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs b/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs
index 99e608797ff..755d8539839 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 const fn answer_p1<F>(f: &F) -> u8
     where
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs
index 3e87787a091..3c82fe1ad6c 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs
@@ -1,5 +1,4 @@
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)] // FIXME is this needed?
 
 trait ConstDefaultFn: Sized {
     fn b(self);
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
index 948830d6def..fe788b43a54 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
@@ -1,17 +1,17 @@
 error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
-  --> $DIR/const-default-method-bodies.rs:25:18
+  --> $DIR/const-default-method-bodies.rs:24:18
    |
 LL |     NonConstImpl.a();
    |                  ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
    |
 note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const`
-  --> $DIR/const-default-method-bodies.rs:25:18
+  --> $DIR/const-default-method-bodies.rs:24:18
    |
 LL |     NonConstImpl.a();
    |                  ^^^
 
 error[E0015]: cannot call non-const fn `<NonConstImpl as ConstDefaultFn>::a` in constant functions
-  --> $DIR/const-default-method-bodies.rs:25:18
+  --> $DIR/const-default-method-bodies.rs:24:18
    |
 LL |     NonConstImpl.a();
    |                  ^^^
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs
index 83fa32bf092..a1cfee6b6e7 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 #![feature(const_precise_live_drops)]
 
 const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Drop {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
index d280cd2556f..d88bcdc89ad 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:44:5
+  --> $DIR/const-drop-fail.rs:43:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -8,7 +8,7 @@ LL |     NonTrivialDrop,
    |     ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
@@ -20,7 +20,7 @@ LL |     &mut NonTrivialDrop,
    |     ++++
 
 error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue`
-  --> $DIR/const-drop-fail.rs:46:5
+  --> $DIR/const-drop-fail.rs:45:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -29,23 +29,23 @@ LL |     ConstImplWithDropGlue(NonTrivialDrop),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop`
    |
 note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const`
-  --> $DIR/const-drop-fail.rs:46:5
+  --> $DIR/const-drop-fail.rs:45:5
    |
 LL |     ConstImplWithDropGlue(NonTrivialDrop),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required because it appears within the type `ConstImplWithDropGlue`
-  --> $DIR/const-drop-fail.rs:17:8
+  --> $DIR/const-drop-fail.rs:16:8
    |
 LL | struct ConstImplWithDropGlue(NonTrivialDrop);
    |        ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
 
 error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:48:5
+  --> $DIR/const-drop-fail.rs:47:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -54,12 +54,12 @@ LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
 note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>`
-  --> $DIR/const-drop-fail.rs:29:25
+  --> $DIR/const-drop-fail.rs:28:25
    |
 LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
    |                         ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
index 4622723c189..49968b47dbe 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
@@ -1,7 +1,6 @@
 // revisions: stock precise
 #![feature(const_trait_impl)]
 #![feature(const_mut_refs)]
-#![feature(const_fn_trait_bound)]
 #![cfg_attr(precise, feature(const_precise_live_drops))]
 
 use std::marker::PhantomData;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
index d280cd2556f..d88bcdc89ad 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:44:5
+  --> $DIR/const-drop-fail.rs:43:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -8,7 +8,7 @@ LL |     NonTrivialDrop,
    |     ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
@@ -20,7 +20,7 @@ LL |     &mut NonTrivialDrop,
    |     ++++
 
 error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue`
-  --> $DIR/const-drop-fail.rs:46:5
+  --> $DIR/const-drop-fail.rs:45:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -29,23 +29,23 @@ LL |     ConstImplWithDropGlue(NonTrivialDrop),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop`
    |
 note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const`
-  --> $DIR/const-drop-fail.rs:46:5
+  --> $DIR/const-drop-fail.rs:45:5
    |
 LL |     ConstImplWithDropGlue(NonTrivialDrop),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required because it appears within the type `ConstImplWithDropGlue`
-  --> $DIR/const-drop-fail.rs:17:8
+  --> $DIR/const-drop-fail.rs:16:8
    |
 LL | struct ConstImplWithDropGlue(NonTrivialDrop);
    |        ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
 
 error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:48:5
+  --> $DIR/const-drop-fail.rs:47:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -54,12 +54,12 @@ LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
 note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>`
-  --> $DIR/const-drop-fail.rs:29:25
+  --> $DIR/const-drop-fail.rs:28:25
    |
 LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
    |                         ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
index 13363c506d5..20b9d772147 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
@@ -1,7 +1,6 @@
 // run-pass
 // revisions: stock precise
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 #![feature(const_mut_refs)]
 #![feature(never_type)]
 #![cfg_attr(precise, feature(const_precise_live_drops))]
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
index 76ea17159ac..17c88e44296 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 trait Tr {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
index bc807507fd6..668e166c298 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
@@ -1,16 +1,16 @@
 error[E0277]: the trait bound `(): ~const Tr` is not satisfied
-  --> $DIR/default-method-body-is-const-body-checking.rs:12:15
+  --> $DIR/default-method-body-is-const-body-checking.rs:11:15
    |
 LL |         foo::<()>();
    |               ^^ the trait `~const Tr` is not implemented for `()`
    |
 note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
-  --> $DIR/default-method-body-is-const-body-checking.rs:12:15
+  --> $DIR/default-method-body-is-const-body-checking.rs:11:15
    |
 LL |         foo::<()>();
    |               ^^
 note: required by a bound in `foo`
-  --> $DIR/default-method-body-is-const-body-checking.rs:7:28
+  --> $DIR/default-method-body-is-const-body-checking.rs:6:28
    |
 LL | const fn foo<T>() where T: ~const Tr {}
    |                            ^^^^^^^^^ required by this bound in `foo`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
index 4d087b5180b..be2f3f6d623 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 pub trait Tr {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
index db4d61f88ab..cf357971951 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
@@ -1,17 +1,17 @@
 error[E0277]: the trait bound `(): ~const Tr` is not satisfied
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
    |
 LL |         ().a()
    |            ^^^ the trait `~const Tr` is not implemented for `()`
    |
 note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
    |
 LL |         ().a()
    |            ^^^
 
 error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
    |
 LL |         ().a()
    |            ^^^
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
index d5b1a9073ac..7f6d86d3375 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
@@ -7,7 +7,6 @@
 
 #![feature(staged_api)]
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 #![stable(since = "1", feature = "foo")]
 
 trait Tr {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/generic-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/generic-bound.rs
index 91c3d2d5920..5495b531cff 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/generic-bound.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/generic-bound.rs
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 use std::marker::PhantomData;
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs
index 8eefb375b8c..eba8b665ceb 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs
@@ -1,5 +1,4 @@
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 trait Tr {
     fn req(&self);
diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr
index a0916797041..4ec6f929ffc 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr
@@ -1,5 +1,5 @@
 error: const trait implementations may not use non-const default functions
-  --> $DIR/impl-with-default-fn-fail.rs:18:1
+  --> $DIR/impl-with-default-fn-fail.rs:17:1
    |
 LL | / impl const Tr for S {
 LL | |     fn req(&self) {}
@@ -9,7 +9,7 @@ LL | | }
    = note: `prov` not implemented
 
 error: const trait implementations may not use non-const default functions
-  --> $DIR/impl-with-default-fn-fail.rs:28:1
+  --> $DIR/impl-with-default-fn-fail.rs:27:1
    |
 LL | / impl const Tr for u32 {
 LL | |     fn req(&self) {}
@@ -20,7 +20,7 @@ LL | | }
    = note: `prov` not implemented
 
 error[E0046]: not all trait items implemented, missing: `req`
-  --> $DIR/impl-with-default-fn-fail.rs:22:1
+  --> $DIR/impl-with-default-fn-fail.rs:21:1
    |
 LL |     fn req(&self);
    |     -------------- `req` from trait
diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs
index ba3fec0882b..2e4664714a7 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 trait Tr {
     fn req(&self);
diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs
index fe1015b3bf7..2cef803a90e 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs
@@ -1,6 +1,5 @@
 // check-pass
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 struct S;
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
index cbe3fe0ce5f..b132c395ac7 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 pub trait A {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
index 931c0b3658f..95592350520 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
@@ -1,17 +1,17 @@
 error[E0277]: the trait bound `T: ~const A` is not satisfied
-  --> $DIR/issue-88155.rs:9:5
+  --> $DIR/issue-88155.rs:8:5
    |
 LL |     T::assoc()
    |     ^^^^^^^^^^ the trait `~const A` is not implemented for `T`
    |
 note: the trait `A` is implemented for `T`, but that implementation is not `const`
-  --> $DIR/issue-88155.rs:9:5
+  --> $DIR/issue-88155.rs:8:5
    |
 LL |     T::assoc()
    |     ^^^^^^^^^^
 
 error[E0015]: cannot call non-const fn `<T as A>::assoc` in constant functions
-  --> $DIR/issue-88155.rs:9:5
+  --> $DIR/issue-88155.rs:8:5
    |
 LL |     T::assoc()
    |     ^^^^^^^^^^
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-92111.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-92111.rs
index 9bf0886084f..da7147acdd7 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/issue-92111.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-92111.rs
@@ -10,7 +10,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 pub trait Tr {}
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs
index 158c628c3e0..97c27ce1a1c 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs
@@ -2,7 +2,6 @@
 //
 // check-pass
 
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 pub trait Super {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs b/src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs
index ef74ef8e426..defef9e0409 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 trait Convert<T> {
     fn to(self) -> T;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs
index cbfdf89b7bd..f4a5d0133ce 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs
@@ -2,7 +2,6 @@
 
 #![feature(staged_api)]
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 #![feature(const_t_try)]
 #![feature(const_try)]
 #![feature(try_trait_v2)]
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs
index 0cde5b6f842..e47c5c7bd66 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 trait Bar {
     fn bar() -> u8;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs
index ae9ab26cdc0..acea58eaecb 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 trait Foo {
     fn bar() where Self: ~const Foo;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs
index d64822d7ce8..d37ed3bb8dd 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 trait Bar {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
index f9b5d81c63b..d5b2d269730 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
@@ -1,16 +1,16 @@
 error[E0277]: the trait bound `T: ~const Bar` is not satisfied
-  --> $DIR/trait-where-clause.rs:14:5
+  --> $DIR/trait-where-clause.rs:13:5
    |
 LL |     T::b();
    |     ^^^^ the trait `~const Bar` is not implemented for `T`
    |
 note: the trait `Bar` is implemented for `T`, but that implementation is not `const`
-  --> $DIR/trait-where-clause.rs:14:5
+  --> $DIR/trait-where-clause.rs:13:5
    |
 LL |     T::b();
    |     ^^^^
 note: required by a bound in `Foo::b`
-  --> $DIR/trait-where-clause.rs:8:24
+  --> $DIR/trait-where-clause.rs:7:24
    |
 LL |     fn b() where Self: ~const Bar;
    |                        ^^^^^^^^^^ required by this bound in `Foo::b`
@@ -20,18 +20,18 @@ LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() {
    |                                    ++++++++++++
 
 error[E0277]: the trait bound `T: ~const Bar` is not satisfied
-  --> $DIR/trait-where-clause.rs:16:5
+  --> $DIR/trait-where-clause.rs:15:5
    |
 LL |     T::c::<T>();
    |     ^^^^^^^^^ the trait `~const Bar` is not implemented for `T`
    |
 note: the trait `Bar` is implemented for `T`, but that implementation is not `const`
-  --> $DIR/trait-where-clause.rs:16:5
+  --> $DIR/trait-where-clause.rs:15:5
    |
 LL |     T::c::<T>();
    |     ^^^^^^^^^
 note: required by a bound in `Foo::c`
-  --> $DIR/trait-where-clause.rs:9:13
+  --> $DIR/trait-where-clause.rs:8:13
    |
 LL |     fn c<T: ~const Bar>();
    |             ^^^^^^^^^^ required by this bound in `Foo::c`
@@ -41,13 +41,13 @@ LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() {
    |                                    ++++++++++++
 
 error[E0277]: the trait bound `T: Bar` is not satisfied
-  --> $DIR/trait-where-clause.rs:28:5
+  --> $DIR/trait-where-clause.rs:27:5
    |
 LL |     T::b();
    |     ^^^^ the trait `Bar` is not implemented for `T`
    |
 note: required by a bound in `Foo::b`
-  --> $DIR/trait-where-clause.rs:8:24
+  --> $DIR/trait-where-clause.rs:7:24
    |
 LL |     fn b() where Self: ~const Bar;
    |                        ^^^^^^^^^^ required by this bound in `Foo::b`
@@ -57,13 +57,13 @@ LL | fn test3<T: Foo + Bar>() {
    |                 +++++
 
 error[E0277]: the trait bound `T: Bar` is not satisfied
-  --> $DIR/trait-where-clause.rs:30:5
+  --> $DIR/trait-where-clause.rs:29:5
    |
 LL |     T::c::<T>();
    |     ^^^^^^^^^ the trait `Bar` is not implemented for `T`
    |
 note: required by a bound in `Foo::c`
-  --> $DIR/trait-where-clause.rs:9:13
+  --> $DIR/trait-where-clause.rs:8:13
    |
 LL |     fn c<T: ~const Bar>();
    |             ^^^^^^^^^^ required by this bound in `Foo::c`
diff --git a/src/test/ui/stability-attribute/auxiliary/lint-stability.rs b/src/test/ui/stability-attribute/auxiliary/lint-stability.rs
index de4058887cf..99c29dcdda6 100644
--- a/src/test/ui/stability-attribute/auxiliary/lint-stability.rs
+++ b/src/test/ui/stability-attribute/auxiliary/lint-stability.rs
@@ -5,21 +5,21 @@
 #![stable(feature = "lint_stability", since = "1.0.0")]
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated() {}
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_text() {}
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "99.99.99", reason = "text")]
+#[deprecated(since = "99.99.99", note = "text")]
 pub fn deprecated_future() {}
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_unstable() {}
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_unstable_text() {}
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -37,17 +37,17 @@ pub struct MethodTester;
 
 impl MethodTester {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated(&self) {}
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_unstable(&self) {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_unstable_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -64,17 +64,17 @@ impl MethodTester {
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub trait Trait {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated(&self) {}
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_unstable(&self) {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_unstable_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -93,7 +93,7 @@ pub trait TraitWithAssociatedTypes {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     type TypeUnstable = u8;
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     type TypeDeprecated = u8;
 }
 
@@ -104,18 +104,18 @@ impl Trait for MethodTester {}
 pub trait UnstableTrait { fn dummy(&self) { } }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub trait DeprecatedTrait {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] fn dummy(&self) { }
 }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedStruct {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
 }
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableStruct {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
 }
@@ -133,10 +133,10 @@ pub enum UnstableEnum {}
 pub enum StableEnum {}
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnitStruct;
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableUnitStruct;
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 pub struct UnstableUnitStruct;
@@ -146,10 +146,10 @@ pub struct StableUnitStruct;
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub enum Enum {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     DeprecatedVariant,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     DeprecatedUnstableVariant,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     UnstableVariant,
@@ -159,10 +159,10 @@ pub enum Enum {
 }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs
index 231ab966558..1d6a6bd4e13 100644
--- a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs
+++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs
@@ -40,14 +40,14 @@ pub struct Struct3<A = isize, #[unstable(feature = "unstable_default", issue = "
     pub field2: B,
 }
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub struct Struct4<A = usize> {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
     pub field: A,
 }
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub struct Struct5<#[unstable(feature = "unstable_default", issue = "none")] A = usize> {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -99,7 +99,7 @@ pub enum Enum3<T = isize, #[unstable(feature = "unstable_default", issue = "none
     Err(#[stable(feature = "stable_test_feature", since = "1.0.0")] E),
 }
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub enum Enum4<T = usize> {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -108,7 +108,7 @@ pub enum Enum4<T = usize> {
     None,
 }
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub enum Enum5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -152,11 +152,11 @@ pub type Alias2<T = usize> = Option<T>;
 pub type Alias3<T = isize, #[unstable(feature = "unstable_default", issue = "none")] E = usize> =
     Result<T, E>;
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub type Alias4<T = usize> = Option<T>;
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub type Alias5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> = Option<T>;
 
diff --git a/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.rs b/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.rs
index 1627d1d3f9f..f61acc8aac5 100644
--- a/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.rs
+++ b/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.rs
@@ -2,6 +2,4 @@
 
 #[unstable()] //~ ERROR: stability attributes may not be used
 #[stable()] //~ ERROR: stability attributes may not be used
-#[rustc_deprecated()] //~ ERROR: stability attributes may not be used
-//~^ ERROR missing 'since'
 fn main() {}
diff --git a/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.stderr b/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.stderr
index a2b2d3cbe59..45d965ea0a0 100644
--- a/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.stderr
@@ -10,19 +10,6 @@ error[E0734]: stability attributes may not be used outside of the standard libra
 LL | #[stable()]
    | ^^^^^^^^^^^
 
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/stability-attribute-non-staged-force-unstable.rs:5:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/stability-attribute-non-staged-force-unstable.rs:5:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0542, E0734.
-For more information about an error, try `rustc --explain E0542`.
+For more information about this error, try `rustc --explain E0734`.
diff --git a/src/test/ui/stability-attribute/stability-attribute-non-staged.rs b/src/test/ui/stability-attribute/stability-attribute-non-staged.rs
index dfbd9ea5ebf..4015f2f971e 100644
--- a/src/test/ui/stability-attribute/stability-attribute-non-staged.rs
+++ b/src/test/ui/stability-attribute/stability-attribute-non-staged.rs
@@ -1,5 +1,3 @@
 #[unstable()] //~ ERROR: stability attributes may not be used
 #[stable()] //~ ERROR: stability attributes may not be used
-#[rustc_deprecated()] //~ ERROR: stability attributes may not be used
-//~^ ERROR missing 'since'
 fn main() {}
diff --git a/src/test/ui/stability-attribute/stability-attribute-non-staged.stderr b/src/test/ui/stability-attribute/stability-attribute-non-staged.stderr
index 9af8d1df4ea..391f3c2744d 100644
--- a/src/test/ui/stability-attribute/stability-attribute-non-staged.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-non-staged.stderr
@@ -10,19 +10,6 @@ error[E0734]: stability attributes may not be used outside of the standard libra
 LL | #[stable()]
    | ^^^^^^^^^^^
 
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/stability-attribute-non-staged.rs:3:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/stability-attribute-non-staged.rs:3:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0542, E0734.
-For more information about an error, try `rustc --explain E0542`.
+For more information about this error, try `rustc --explain E0734`.
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-4.rs b/src/test/ui/stability-attribute/stability-attribute-sanity-4.rs
index b85f9342045..64f99635219 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity-4.rs
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity-4.rs
@@ -18,13 +18,11 @@ mod bogus_attribute_types_2 {
     fn f4() { }
 
     #[stable(feature = "a", since = "b")]
-    #[rustc_deprecated] //~ ERROR malformed `rustc_deprecated` attribute
-                        //~^ ERROR missing 'since'
+    #[deprecated] //~ ERROR missing 'since'
     fn f5() { }
 
     #[stable(feature = "a", since = "b")]
-    #[rustc_deprecated = "a"] //~ ERROR malformed `rustc_deprecated` attribute
-                              //~^ ERROR missing 'since'
+    #[deprecated = "a"] //~ ERROR missing 'since'
     fn f6() { }
 }
 
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-4.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity-4.stderr
index 651f293ff51..a76f5be1e3d 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity-4.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity-4.stderr
@@ -22,30 +22,18 @@ error: malformed `stable` attribute input
 LL |     #[stable = "a"]
    |     ^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]`
 
-error: malformed `rustc_deprecated` attribute input
-  --> $DIR/stability-attribute-sanity-4.rs:21:5
-   |
-LL |     #[rustc_deprecated]
-   |     ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]`
-
-error: malformed `rustc_deprecated` attribute input
-  --> $DIR/stability-attribute-sanity-4.rs:26:5
-   |
-LL |     #[rustc_deprecated = "a"]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]`
-
 error[E0542]: missing 'since'
   --> $DIR/stability-attribute-sanity-4.rs:21:5
    |
-LL |     #[rustc_deprecated]
-   |     ^^^^^^^^^^^^^^^^^^^
+LL |     #[deprecated]
+   |     ^^^^^^^^^^^^^
 
 error[E0542]: missing 'since'
-  --> $DIR/stability-attribute-sanity-4.rs:26:5
+  --> $DIR/stability-attribute-sanity-4.rs:25:5
    |
-LL |     #[rustc_deprecated = "a"]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deprecated = "a"]
+   |     ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0542`.
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.rs b/src/test/ui/stability-attribute/stability-attribute-sanity.rs
index fe8079dbc37..f37a8f328a7 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity.rs
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity.rs
@@ -37,11 +37,11 @@ mod missing_version {
     fn f1() { }
 
     #[stable(feature = "a", since = "b")]
-    #[rustc_deprecated(reason = "a")] //~ ERROR missing 'since' [E0542]
+    #[deprecated(note = "a")] //~ ERROR missing 'since' [E0542]
     fn f2() { }
 
     #[stable(feature = "a", since = "b")]
-    #[rustc_deprecated(since = "a")] //~ ERROR missing 'reason' [E0543]
+    #[deprecated(since = "a")] //~ ERROR missing 'note' [E0543]
     fn f3() { }
 }
 
@@ -58,19 +58,19 @@ fn multiple2() { }
 fn multiple3() { }
 
 #[stable(feature = "a", since = "b")] //~ ERROR invalid stability version found
-#[rustc_deprecated(since = "b", reason = "text")]
-#[rustc_deprecated(since = "b", reason = "text")] //~ ERROR multiple deprecated attributes
+#[deprecated(since = "b", note = "text")]
+#[deprecated(since = "b", note = "text")] //~ ERROR multiple deprecated attributes
 #[rustc_const_unstable(feature = "c", issue = "none")]
 #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
 pub const fn multiple4() { }
 
 #[stable(feature = "a", since = "1.0.0")] //~ ERROR invalid deprecation version found
 //~^ ERROR feature `a` is declared stable since 1.0.0
-#[rustc_deprecated(since = "invalid", reason = "text")]
+#[deprecated(since = "invalid", note = "text")]
 fn invalid_deprecation_version() {}
 
-#[rustc_deprecated(since = "a", reason = "text")]
+#[deprecated(since = "a", note = "text")]
 fn deprecated_without_unstable_or_stable() { }
-//~^^ ERROR rustc_deprecated attribute must be paired with either stable or unstable attribute
+//~^^ ERROR deprecated attribute must be paired with either stable or unstable attribute
 
 fn main() { }
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
index b4e8fc78815..9e2d9f27084 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -55,14 +55,14 @@ LL |     #[stable(feature = "a")]
 error[E0542]: missing 'since'
   --> $DIR/stability-attribute-sanity.rs:40:5
    |
-LL |     #[rustc_deprecated(reason = "a")]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deprecated(note = "a")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0543]: missing 'reason'
+error[E0543]: missing 'note'
   --> $DIR/stability-attribute-sanity.rs:44:5
    |
-LL |     #[rustc_deprecated(since = "a")]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deprecated(since = "a")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:49:1
@@ -85,10 +85,10 @@ LL | #[stable(feature = "a", since = "b")]
 error[E0550]: multiple deprecated attributes
   --> $DIR/stability-attribute-sanity.rs:62:1
    |
-LL | #[rustc_deprecated(since = "b", reason = "text")]
-   | ------------------------------------------------- first deprecation attribute
-LL | #[rustc_deprecated(since = "b", reason = "text")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ repeated deprecation attribute
+LL | #[deprecated(since = "b", note = "text")]
+   | ----------------------------------------- first deprecation attribute
+LL | #[deprecated(since = "b", note = "text")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ repeated deprecation attribute
 
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:64:1
@@ -114,11 +114,11 @@ LL | #[stable(feature = "a", since = "1.0.0")]
 LL | fn invalid_deprecation_version() {}
    | ----------------------------------- the stability attribute annotates this item
 
-error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute
+error[E0549]: deprecated attribute must be paired with either stable or unstable attribute
   --> $DIR/stability-attribute-sanity.rs:72:1
    |
-LL | #[rustc_deprecated(since = "a", reason = "text")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[deprecated(since = "a", note = "text")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since b
   --> $DIR/stability-attribute-sanity.rs:67:1
diff --git a/src/test/ui/str/str-idx.stderr b/src/test/ui/str/str-idx.stderr
index 9c3c3646139..9ab409bbdcd 100644
--- a/src/test/ui/str/str-idx.stderr
+++ b/src/test/ui/str/str-idx.stderr
@@ -23,8 +23,8 @@ LL |     let _ = s.get(4);
 note: required by a bound in `core::str::<impl str>::get`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
    |
-LL |     pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
-   |                   ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get`
+LL |     pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
+   |                         ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get`
 
 error[E0277]: the type `str` cannot be indexed by `{integer}`
   --> $DIR/str-idx.rs:5:29
@@ -40,8 +40,8 @@ LL |     let _ = s.get_unchecked(4);
 note: required by a bound in `core::str::<impl str>::get_unchecked`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
    |
-LL |     pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
-   |                                    ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked`
+LL |     pub const unsafe fn get_unchecked<I: ~const SliceIndex<str>>(&self, i: I) -> &I::Output {
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked`
 
 error[E0277]: the type `str` cannot be indexed by `char`
   --> $DIR/str-idx.rs:6:17
diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr
index 2559ee9eb49..5956e363b0c 100644
--- a/src/test/ui/str/str-mut-idx.stderr
+++ b/src/test/ui/str/str-mut-idx.stderr
@@ -47,8 +47,8 @@ LL |     s.get_mut(1);
 note: required by a bound in `core::str::<impl str>::get_mut`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
    |
-LL |     pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
-   |                       ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_mut`
+LL |     pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
+   |                             ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_mut`
 
 error[E0277]: the type `str` cannot be indexed by `{integer}`
   --> $DIR/str-mut-idx.rs:11:25
@@ -64,8 +64,8 @@ LL |     s.get_unchecked_mut(1);
 note: required by a bound in `core::str::<impl str>::get_unchecked_mut`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
    |
-LL |     pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
-   |                                        ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked_mut`
+LL |     pub const unsafe fn get_unchecked_mut<I: ~const SliceIndex<str>>(
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked_mut`
 
 error[E0277]: the type `str` cannot be indexed by `char`
   --> $DIR/str-mut-idx.rs:13:5
diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr
index 28c319b6597..1059e3d1525 100644
--- a/src/test/ui/suggestions/borrow-for-loop-head.stderr
+++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr
@@ -13,16 +13,17 @@ LL |     let a = vec![1, 2, 3];
    |         - move occurs because `a` has type `Vec<i32>`, which does not implement the `Copy` trait
 LL |     for i in &a {
 LL |         for j in a {
-   |                  ^
-   |                  |
-   |                  `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
-   |                  help: consider borrowing to avoid moving into the for loop: `&a`
+   |                  ^ `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
    |
 note: this function takes ownership of the receiver `self`, which moves `a`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider iterating over a slice of the `Vec<i32>`'s content to avoid moving into the `for` loop
+   |
+LL |         for j in &a {
+   |                  +
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/constrain-suggest-ice.rs b/src/test/ui/suggestions/constrain-suggest-ice.rs
new file mode 100644
index 00000000000..69b874bed1b
--- /dev/null
+++ b/src/test/ui/suggestions/constrain-suggest-ice.rs
@@ -0,0 +1,11 @@
+struct Bug<S>{ //~ ERROR parameter `S` is never used [E0392]
+    A: [(); {
+        let x: [u8; Self::W] = [0; Self::W]; //~ ERROR generic `Self` types are currently not permitted in anonymous constants
+        //~^ ERROR generic `Self` types are currently not permitted in anonymous constants
+        //~^^ ERROR the size for values of type `S` cannot be known at compilation time [E0277]
+        F //~ ERROR cannot find value `F` in this scope [E0425]
+    }
+} //~ ERROR mismatched closing delimiter: `}`
+//~^ ERROR mismatched closing delimiter: `}`
+
+fn main() {}
diff --git a/src/test/ui/suggestions/constrain-suggest-ice.stderr b/src/test/ui/suggestions/constrain-suggest-ice.stderr
new file mode 100644
index 00000000000..477eb278679
--- /dev/null
+++ b/src/test/ui/suggestions/constrain-suggest-ice.stderr
@@ -0,0 +1,81 @@
+error: mismatched closing delimiter: `}`
+  --> $DIR/constrain-suggest-ice.rs:2:8
+   |
+LL | struct Bug<S>{
+   |              - closing delimiter possibly meant for this
+LL |     A: [(); {
+   |        ^ unclosed delimiter
+...
+LL | }
+   | ^ mismatched closing delimiter
+
+error: mismatched closing delimiter: `}`
+  --> $DIR/constrain-suggest-ice.rs:2:8
+   |
+LL | struct Bug<S>{
+   |              - closing delimiter possibly meant for this
+LL |     A: [(); {
+   |        ^ unclosed delimiter
+...
+LL | }
+   | ^ mismatched closing delimiter
+
+error[E0425]: cannot find value `F` in this scope
+  --> $DIR/constrain-suggest-ice.rs:6:9
+   |
+LL |         F
+   |         ^
+   |
+help: a local variable with a similar name exists
+   |
+LL |         x
+   |         ~
+help: you might be missing a type parameter
+   |
+LL | struct Bug<S, F>{
+   |             +++
+
+error: generic `Self` types are currently not permitted in anonymous constants
+  --> $DIR/constrain-suggest-ice.rs:3:21
+   |
+LL |         let x: [u8; Self::W] = [0; Self::W];
+   |                     ^^^^
+
+error: generic `Self` types are currently not permitted in anonymous constants
+  --> $DIR/constrain-suggest-ice.rs:3:36
+   |
+LL |         let x: [u8; Self::W] = [0; Self::W];
+   |                                    ^^^^
+
+error[E0277]: the size for values of type `S` cannot be known at compilation time
+  --> $DIR/constrain-suggest-ice.rs:3:36
+   |
+LL | struct Bug<S>{
+   |            - this type parameter needs to be `std::marker::Sized`
+LL |     A: [(); {
+LL |         let x: [u8; Self::W] = [0; Self::W];
+   |                                    ^^^^^^^ doesn't have a size known at compile-time
+   |
+note: required by a bound in `Bug`
+  --> $DIR/constrain-suggest-ice.rs:1:12
+   |
+LL | struct Bug<S>{
+   |            ^ required by this bound in `Bug`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | struct Bug<S: ?Sized>{
+   |             ++++++++
+
+error[E0392]: parameter `S` is never used
+  --> $DIR/constrain-suggest-ice.rs:1:12
+   |
+LL | struct Bug<S>{
+   |            ^ unused parameter
+   |
+   = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0277, E0392, E0425.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/for-i-in-vec.stderr b/src/test/ui/suggestions/for-i-in-vec.stderr
index c39363f762b..88be9e30a76 100644
--- a/src/test/ui/suggestions/for-i-in-vec.stderr
+++ b/src/test/ui/suggestions/for-i-in-vec.stderr
@@ -2,9 +2,17 @@ error[E0507]: cannot move out of `self.v` which is behind a shared reference
   --> $DIR/for-i-in-vec.rs:11:18
    |
 LL |         for _ in self.v {
-   |                  ^^^^^^ move occurs because `self.v` has type `Vec<u32>`, which does not implement the `Copy` trait
+   |                  ^^^^^^
+   |                  |
+   |                  `self.v` moved due to this implicit call to `.into_iter()`
+   |                  move occurs because `self.v` has type `Vec<u32>`, which does not implement the `Copy` trait
    |
-help: consider iterating over a slice of the `Vec<u32>`'s content
+note: this function takes ownership of the receiver `self`, which moves `self.v`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
+help: consider iterating over a slice of the `Vec<u32>`'s content to avoid moving into the `for` loop
    |
 LL |         for _ in &self.v {
    |                  +
@@ -13,9 +21,12 @@ error[E0507]: cannot move out of `self.h` which is behind a shared reference
   --> $DIR/for-i-in-vec.rs:13:18
    |
 LL |         for _ in self.h {
-   |                  ^^^^^^ move occurs because `self.h` has type `HashMap<i32, i32>`, which does not implement the `Copy` trait
+   |                  ^^^^^^
+   |                  |
+   |                  `self.h` moved due to this implicit call to `.into_iter()`
+   |                  move occurs because `self.h` has type `HashMap<i32, i32>`, which does not implement the `Copy` trait
    |
-help: consider iterating over a slice of the `HashMap<i32, i32>`'s content
+help: consider iterating over a slice of the `HashMap<i32, i32>`'s content to avoid moving into the `for` loop
    |
 LL |         for _ in &self.h {
    |                  +
@@ -24,9 +35,17 @@ error[E0507]: cannot move out of a shared reference
   --> $DIR/for-i-in-vec.rs:21:19
    |
 LL |     for loader in *LOADERS {
-   |                   ^^^^^^^^ move occurs because value has type `Vec<&u8>`, which does not implement the `Copy` trait
+   |                   ^^^^^^^^
+   |                   |
+   |                   value moved due to this implicit call to `.into_iter()`
+   |                   move occurs because value has type `Vec<&u8>`, which does not implement the `Copy` trait
+   |
+note: this function takes ownership of the receiver `self`, which moves value
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
-help: consider iterating over a slice of the `Vec<&u8>`'s content
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
+help: consider iterating over a slice of the `Vec<&u8>`'s content to avoid moving into the `for` loop
    |
 LL |     for loader in &*LOADERS {
    |                   +
diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr
index a0ce7d05b4d..16cbbaba512 100644
--- a/src/test/ui/suggestions/option-content-move2.stderr
+++ b/src/test/ui/suggestions/option-content-move2.stderr
@@ -12,8 +12,8 @@ LL | |
 LL | |             var = Some(NotCopyable);
    | |             ---
    | |             |
+   | |             variable moved due to use in closure
    | |             move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
-   | |             move occurs due to use in closure
 LL | |         }
 LL | |     });
    | |_____- captured by this `FnMut` closure
diff --git a/src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.rs b/src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.rs
new file mode 100644
index 00000000000..56aed77c10e
--- /dev/null
+++ b/src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.rs
@@ -0,0 +1,30 @@
+struct Wrapper<T>(T);
+
+fn foo<T>(foo: Wrapper<T>)
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
+where
+    T
+    :
+    ?
+    Sized
+{
+    //
+}
+
+fn bar<T>(foo: Wrapper<T>)
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
+where T: ?Sized
+{
+    //
+}
+
+fn qux<T>(foo: Wrapper<T>)
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
+where
+    T: ?Sized
+{
+    //
+}
+
+
+fn main() {}
diff --git a/src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr b/src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr
new file mode 100644
index 00000000000..3df17056ef4
--- /dev/null
+++ b/src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr
@@ -0,0 +1,83 @@
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:3:16
+   |
+LL | fn foo<T>(foo: Wrapper<T>)
+   |        -       ^^^^^^^^^^ doesn't have a size known at compile-time
+   |        |
+   |        this type parameter needs to be `std::marker::Sized`
+   |
+note: required by a bound in `Wrapper`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^ required by this bound in `Wrapper`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^  - ...if indirection were used here: `Box<T>`
+   |                |
+   |                this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - where
+LL -     T
+LL -     :
+LL -     ?
+LL -     Sized
+   | 
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:14:16
+   |
+LL | fn bar<T>(foo: Wrapper<T>)
+   |        -       ^^^^^^^^^^ doesn't have a size known at compile-time
+   |        |
+   |        this type parameter needs to be `std::marker::Sized`
+   |
+note: required by a bound in `Wrapper`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^ required by this bound in `Wrapper`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^  - ...if indirection were used here: `Box<T>`
+   |                |
+   |                this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - where T: ?Sized
+   | 
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:21:16
+   |
+LL | fn qux<T>(foo: Wrapper<T>)
+   |        -       ^^^^^^^^^^ doesn't have a size known at compile-time
+   |        |
+   |        this type parameter needs to be `std::marker::Sized`
+   |
+note: required by a bound in `Wrapper`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^ required by this bound in `Wrapper`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^  - ...if indirection were used here: `Box<T>`
+   |                |
+   |                this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - where
+LL -     T: ?Sized
+   | 
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/struct-field-type-including-single-colon.rs b/src/test/ui/suggestions/struct-field-type-including-single-colon.rs
new file mode 100644
index 00000000000..b7ad6d996f1
--- /dev/null
+++ b/src/test/ui/suggestions/struct-field-type-including-single-colon.rs
@@ -0,0 +1,20 @@
+mod foo {
+    struct A;
+    mod bar {
+        struct B;
+    }
+}
+
+struct Foo {
+    a: foo:A,
+    //~^ ERROR found single colon in a struct field type path
+    //~| expected `,`, or `}`, found `:`
+}
+
+struct Bar {
+    b: foo::bar:B,
+    //~^ ERROR found single colon in a struct field type path
+    //~| expected `,`, or `}`, found `:`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/struct-field-type-including-single-colon.stderr b/src/test/ui/suggestions/struct-field-type-including-single-colon.stderr
new file mode 100644
index 00000000000..189759d64fc
--- /dev/null
+++ b/src/test/ui/suggestions/struct-field-type-including-single-colon.stderr
@@ -0,0 +1,36 @@
+error: found single colon in a struct field type path
+  --> $DIR/struct-field-type-including-single-colon.rs:9:11
+   |
+LL |     a: foo:A,
+   |           ^
+   |
+help: write a path separator here
+   |
+LL |     a: foo::A,
+   |           ~~
+
+error: expected `,`, or `}`, found `:`
+  --> $DIR/struct-field-type-including-single-colon.rs:9:11
+   |
+LL |     a: foo:A,
+   |           ^
+
+error: found single colon in a struct field type path
+  --> $DIR/struct-field-type-including-single-colon.rs:15:16
+   |
+LL |     b: foo::bar:B,
+   |                ^
+   |
+help: write a path separator here
+   |
+LL |     b: foo::bar::B,
+   |                ~~
+
+error: expected `,`, or `}`, found `:`
+  --> $DIR/struct-field-type-including-single-colon.rs:15:16
+   |
+LL |     b: foo::bar:B,
+   |                ^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
index 74708193317..4baf198b12f 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
@@ -5,7 +5,7 @@ use std::fmt::Debug;
 fn main() {}
 
 type Two<A, B> = impl Debug;
-//~^ ERROR the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+//~^ ERROR the trait bound `A: Foo` is not satisfied
 //~| ERROR `A` doesn't implement `Debug`
 //~| ERROR `B` doesn't implement `Debug`
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
index a8eb53a50e3..43471f980b2 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
@@ -10,13 +10,12 @@ note: previous use here
 LL | fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+error[E0277]: the trait bound `A: Foo` is not satisfied
   --> $DIR/generic_duplicate_param_use9.rs:7:18
    |
 LL | type Two<A, B> = impl Debug;
-   |                  ^^^^^^^^^^ within `(A, B, <A as Foo>::Bar)`, the trait `Foo` is not implemented for `A`
+   |                  ^^^^^^^^^^ the trait `Foo` is not implemented for `A`
    |
-   = note: required because it appears within the type `(A, B, <A as Foo>::Bar)`
 help: consider restricting type parameter `A`
    |
 LL | type Two<A: Foo, B> = impl Debug;
@@ -28,7 +27,7 @@ error[E0277]: `A` doesn't implement `Debug`
 LL | type Two<A, B> = impl Debug;
    |                  ^^^^^^^^^^ `A` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
-   = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
+   = note: required because of the requirements on the impl of `Debug` for `(A, B, _)`
 help: consider restricting type parameter `A`
    |
 LL | type Two<A: std::fmt::Debug, B> = impl Debug;
@@ -40,7 +39,7 @@ error[E0277]: `B` doesn't implement `Debug`
 LL | type Two<A, B> = impl Debug;
    |                  ^^^^^^^^^^ `B` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
-   = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
+   = note: required because of the requirements on the impl of `Debug` for `(A, B, _)`
 help: consider restricting type parameter `B`
    |
 LL | type Two<A, B: std::fmt::Debug> = impl Debug;
diff --git a/src/test/ui/type-alias-impl-trait/issue-53096.rs b/src/test/ui/type-alias-impl-trait/issue-53096.rs
index 792bd16527b..007dcf3bcb6 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53096.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53096.rs
@@ -1,4 +1,4 @@
-#![feature(const_impl_trait, const_fn_fn_ptr_basics, rustc_attrs)]
+#![feature(rustc_attrs)]
 #![feature(type_alias_impl_trait)]
 
 type Foo = impl Fn() -> usize;
diff --git a/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs b/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs
index 176118200e5..a3f126d56cf 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs
@@ -1,4 +1,4 @@
-#![feature(const_impl_trait, generators, generator_trait, rustc_attrs)]
+#![feature(generators, generator_trait, rustc_attrs)]
 #![feature(type_alias_impl_trait)]
 
 use std::ops::Generator;
diff --git a/src/test/ui/type-alias-impl-trait/issue-89686.rs b/src/test/ui/type-alias-impl-trait/issue-89686.rs
index 5878b26fddb..f058653dde3 100644
--- a/src/test/ui/type-alias-impl-trait/issue-89686.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-89686.rs
@@ -5,8 +5,7 @@
 use std::future::Future;
 
 type G<'a, T> = impl Future<Output = ()>;
-//~^ ERROR: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
-//~| ERROR: the trait bound `T: Trait` is not satisfied
+//~^ ERROR: the trait bound `T: Trait` is not satisfied
 
 trait Trait {
     type F: Future<Output = ()>;
diff --git a/src/test/ui/type-alias-impl-trait/issue-89686.stderr b/src/test/ui/type-alias-impl-trait/issue-89686.stderr
index 19ed9a7476c..0df5a809ebb 100644
--- a/src/test/ui/type-alias-impl-trait/issue-89686.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-89686.stderr
@@ -1,22 +1,3 @@
-error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
-  --> $DIR/issue-89686.rs:7:17
-   |
-LL | type G<'a, T> = impl Future<Output = ()>;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
-...
-LL |         async move { self.f().await }
-   |                    ------------------ the found `async` block
-   |
-  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
-   |
-LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
-   |                                           ------------------------------- the found opaque type
-   |
-   = note:    expected unit type `()`
-           found associated type `<impl Future<Output = [async output]> as Future>::Output`
-   = help: consider constraining the associated type `<impl Future<Output = [async output]> as Future>::Output` to `()`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
 error[E0277]: the trait bound `T: Trait` is not satisfied
   --> $DIR/issue-89686.rs:7:17
    |
@@ -28,7 +9,6 @@ help: consider restricting type parameter `T`
 LL | type G<'a, T: Trait> = impl Future<Output = ()>;
    |             +++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
index 51a7b6454c3..219837aa04b 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
+++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
@@ -1,4 +1,3 @@
-#![feature(const_impl_trait)]
 #![feature(type_alias_impl_trait)]
 
 type Bar = impl Send;
diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr
index 7e41b374452..889c4fd4b04 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr
+++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr
@@ -1,5 +1,5 @@
 error: `impl Send` cannot be used in patterns
-  --> $DIR/structural-match-no-leak.rs:15:9
+  --> $DIR/structural-match-no-leak.rs:14:9
    |
 LL |         LEAK_FREE => (),
    |         ^^^^^^^^^
diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs
index 73558d39ad5..c9e669cad60 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match.rs
+++ b/src/test/ui/type-alias-impl-trait/structural-match.rs
@@ -1,4 +1,3 @@
-#![feature(const_impl_trait)]
 #![feature(type_alias_impl_trait)]
 
 type Foo = impl Send;
diff --git a/src/test/ui/type-alias-impl-trait/structural-match.stderr b/src/test/ui/type-alias-impl-trait/structural-match.stderr
index b43f2148dea..262fd072613 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match.stderr
+++ b/src/test/ui/type-alias-impl-trait/structural-match.stderr
@@ -1,5 +1,5 @@
 error: `impl Send` cannot be used in patterns
-  --> $DIR/structural-match.rs:16:9
+  --> $DIR/structural-match.rs:15:9
    |
 LL |         VALUE => (),
    |         ^^^^^
diff --git a/src/test/ui/unboxed-closures/issue-53448.rs b/src/test/ui/unboxed-closures/issue-53448.rs
index 5c82a56e77e..ea1edf7d450 100644
--- a/src/test/ui/unboxed-closures/issue-53448.rs
+++ b/src/test/ui/unboxed-closures/issue-53448.rs
@@ -1,3 +1,5 @@
+// check-pass
+
 #![feature(unboxed_closures)]
 
 trait Lt<'a> {
@@ -10,6 +12,5 @@ impl<'a> Lt<'a> for () {
 fn main() {
     let v: <() as Lt<'_>>::T = ();
     let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
-    //~^ ERROR: the size for values of type `<() as Lt<'_>>::T` cannot be known
     f(v);
 }
diff --git a/src/test/ui/unboxed-closures/issue-53448.stderr b/src/test/ui/unboxed-closures/issue-53448.stderr
deleted file mode 100644
index 8f9d918fdba..00000000000
--- a/src/test/ui/unboxed-closures/issue-53448.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0277]: the size for values of type `<() as Lt<'_>>::T` cannot be known at compilation time
-  --> $DIR/issue-53448.rs:12:54
-   |
-LL |     let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
-   |                                                      ^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `<() as Lt<'_>>::T`
-   = help: unsized fn params are gated as an unstable feature
-help: consider further restricting the associated type
-   |
-LL | fn main() where <() as Lt<'_>>::T: Sized {
-   |           ++++++++++++++++++++++++++++++
-help: function arguments must have a statically known size, borrowed types always have a known size
-   |
-LL |     let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: &<() as Lt<'_>>::T| {};
-   |                                                         +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.rs b/src/test/ui/uninhabited/uninhabited-irrefutable.rs
index 48cd92719b4..661b5486adc 100644
--- a/src/test/ui/uninhabited/uninhabited-irrefutable.rs
+++ b/src/test/ui/uninhabited/uninhabited-irrefutable.rs
@@ -19,10 +19,10 @@ enum Foo {
     A(foo::SecretlyEmpty),
     B(foo::NotSoSecretlyEmpty),
     C(NotSoSecretlyEmpty),
-    D(u32),
+    D(u32, u32),
 }
 
 fn main() {
-    let x: Foo = Foo::D(123);
-    let Foo::D(_y) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
+    let x: Foo = Foo::D(123, 456);
+    let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
 }
diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
index 3cb99556748..c571e17a7b3 100644
--- a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
+++ b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
@@ -1,25 +1,27 @@
 error[E0005]: refutable pattern in local binding: `A(_)` not covered
   --> $DIR/uninhabited-irrefutable.rs:27:9
    |
-LL | / enum Foo {
-LL | |     A(foo::SecretlyEmpty),
-   | |     - not covered
-LL | |     B(foo::NotSoSecretlyEmpty),
-LL | |     C(NotSoSecretlyEmpty),
-LL | |     D(u32),
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       let Foo::D(_y) = x;
-   |           ^^^^^^^^^^ pattern `A(_)` not covered
+LL |     let Foo::D(_y, _z) = x;
+   |         ^^^^^^^^^^^^^^ pattern `A(_)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Foo` defined here
+  --> $DIR/uninhabited-irrefutable.rs:19:5
+   |
+LL | enum Foo {
+   |      ---
+LL |     A(foo::SecretlyEmpty),
+   |     ^ not covered
    = note: the matched value is of type `Foo`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Foo::D(_y) = x { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() };
+   |     +++++++++++++++++                        +++++++++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+   |
+LL |     let Foo::D(_y, _z) = x else { todo!() };
+   |                            ++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
index b92ceb479bd..74216d265d0 100644
--- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
+++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
@@ -4,26 +4,44 @@ error[E0004]: non-exhaustive patterns: `Err(_)` not covered
 LL |     let _ = match x {
    |                   ^ pattern `Err(_)` not covered
    |
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+note: `Result<u32, &Void>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | / pub enum Result<T, E> {
+LL | |     /// Contains the success value
+LL | |     #[lang = "Ok"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+   | |     ^^^ not covered
+LL | | }
+   | |_-
+   = note: the matched value is of type `Result<u32, &Void>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
-   |     --- not covered
+LL ~         Ok(n) => n,
+LL ~         Err(_) => todo!(),
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Result<u32, &Void>`
 
 error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
   --> $DIR/uninhabited-matches-feature-gated.rs:15:19
    |
-LL | enum Void {}
-   | ------------ `Void` defined here
-...
 LL |     let _ = match x {};
    |                   ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Void` defined here
+  --> $DIR/uninhabited-matches-feature-gated.rs:2:6
+   |
+LL | enum Void {}
+   |      ^^^^
    = note: the matched value is of type `&Void`
    = note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     let _ = match x {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
   --> $DIR/uninhabited-matches-feature-gated.rs:18:19
@@ -31,8 +49,13 @@ error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
 LL |     let _ = match x {};
    |                   ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Void,)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     let _ = match x {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
   --> $DIR/uninhabited-matches-feature-gated.rs:21:19
@@ -40,8 +63,13 @@ error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
 LL |     let _ = match x {};
    |                   ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `[Void; 1]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     let _ = match x {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
   --> $DIR/uninhabited-matches-feature-gated.rs:24:19
@@ -49,8 +77,12 @@ error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
 LL |     let _ = match x {
    |                   ^ pattern `&[_, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[Void]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         &[] => (),
+LL ~         &[_, ..] => todo!(),
+   |
 
 error[E0004]: non-exhaustive patterns: `Err(_)` not covered
   --> $DIR/uninhabited-matches-feature-gated.rs:32:19
@@ -58,13 +90,24 @@ error[E0004]: non-exhaustive patterns: `Err(_)` not covered
 LL |     let _ = match x {
    |                   ^ pattern `Err(_)` not covered
    |
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+note: `Result<u32, Void>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | / pub enum Result<T, E> {
+LL | |     /// Contains the success value
+LL | |     #[lang = "Ok"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+   | |     ^^^ not covered
+LL | | }
+   | |_-
+   = note: the matched value is of type `Result<u32, Void>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
-   |     --- not covered
+LL ~         Ok(x) => x,
+LL ~         Err(_) => todo!(),
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Result<u32, Void>`
 
 error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   --> $DIR/uninhabited-matches-feature-gated.rs:37:9
@@ -72,18 +115,29 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
 LL |     let Ok(x) = x;
    |         ^^^^^ pattern `Err(_)` not covered
    |
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
-   |     --- not covered
-   |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, Void>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | / pub enum Result<T, E> {
+LL | |     /// Contains the success value
+LL | |     #[lang = "Ok"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+   | |     ^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Result<u32, Void>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Ok(x) = x { /* */ }
+LL |     let x = if let Ok(x) = x { x } else { todo!() };
+   |     ++++++++++               ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
    |
+LL |     let Ok(x) = x else { todo!() };
+   |                   ++++++++++++++++
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs
new file mode 100644
index 00000000000..80e30f23993
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs
@@ -0,0 +1,4 @@
+// check-pass
+// compile-flags: -Aunknown_lints -Atest_unstable_lint
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs
new file mode 100644
index 00000000000..992472c894a
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs
@@ -0,0 +1,5 @@
+// check-pass
+
+#![allow(unknown_lints, test_unstable_lint)]
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs
new file mode 100644
index 00000000000..dcc06850de1
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs
@@ -0,0 +1,6 @@
+// check-fail
+// compile-flags: -Dunknown_lints -Atest_unstable_lint
+// error-pattern: unknown lint: `test_unstable_lint`
+// error-pattern: the `test_unstable_lint` lint is unstable
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr
new file mode 100644
index 00000000000..7e6885bd706
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr
@@ -0,0 +1,18 @@
+error: unknown lint: `test_unstable_lint`
+   |
+   = note: requested on the command line with `-D unknown-lints`
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs
new file mode 100644
index 00000000000..c6c60b12d83
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs
@@ -0,0 +1,9 @@
+// check-fail
+
+#![deny(unknown_lints)]
+#![allow(test_unstable_lint)]
+//~^ ERROR unknown lint: `test_unstable_lint`
+//~| ERROR unknown lint: `test_unstable_lint`
+//~| ERROR unknown lint: `test_unstable_lint`
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr
new file mode 100644
index 00000000000..2d1027dd0e0
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr
@@ -0,0 +1,34 @@
+error: unknown lint: `test_unstable_lint`
+  --> $DIR/deny-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/deny-unstable-lint-inline.rs:3:9
+   |
+LL | #![deny(unknown_lints)]
+   |         ^^^^^^^^^^^^^
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+  --> $DIR/deny-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+  --> $DIR/deny-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs
new file mode 100644
index 00000000000..3778291ebb4
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs
@@ -0,0 +1,6 @@
+// check-pass
+// compile-flags: -Wunknown_lints -Atest_unstable_lint
+// error-pattern: unknown lint: `test_unstable_lint`
+// error-pattern: the `test_unstable_lint` lint is unstable
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr
new file mode 100644
index 00000000000..799d740b00e
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr
@@ -0,0 +1,18 @@
+warning: unknown lint: `test_unstable_lint`
+   |
+   = note: requested on the command line with `-W unknown-lints`
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs
new file mode 100644
index 00000000000..f4247e4569e
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+#![warn(unknown_lints)]
+#![allow(test_unstable_lint)]
+//~^ WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr
new file mode 100644
index 00000000000..142558b471b
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr
@@ -0,0 +1,34 @@
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:3:9
+   |
+LL | #![warn(unknown_lints)]
+   |         ^^^^^^^^^^^^^
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 3d6970d50e30e797b8e26b2b9b1bdf92dc381f3
+Subproject 65c82664263feddc5fe2d424be0993c28d46377
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index f0979840ff8..4592ca72748 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -149,7 +149,7 @@ impl LateLintPass<'_> for AwaitHolding {
 fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) {
     for ty_cause in ty_causes {
         if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
-            if is_mutex_guard(cx, adt.did) {
+            if is_mutex_guard(cx, adt.did()) {
                 span_lint_and_then(
                     cx,
                     AWAIT_HOLDING_LOCK,
@@ -167,7 +167,7 @@ fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorType
                     },
                 );
             }
-            if is_refcell_ref(cx, adt.did) {
+            if is_refcell_ref(cx, adt.did()) {
                 span_lint_and_then(
                     cx,
                     AWAIT_HOLDING_REFCELL_REF,
diff --git a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
index 7637666d059..df780747a0c 100644
--- a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
+use rustc_data_structures::intern::Interned;
 use rustc_hir::{Expr, ExprKind, PathSegment};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
@@ -55,7 +56,7 @@ fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &
                 ty::Str => {
                     return Some(span);
                 },
-                ty::Adt(&ty::AdtDef { did, .. }, _) => {
+                ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) => {
                     if ctx.tcx.is_diagnostic_item(sym::String, did) {
                         return Some(span);
                     }
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 9b189ea1ef8..421bd6f53f7 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
@@ -116,15 +116,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
                 && let Res::Def(DefKind::Ctor(..), id) = cx.qpath_res(p, cast_expr.hir_id)
             {
                 let i = def.variant_index_with_ctor_id(id);
-                let variant = &def.variants[i];
-                let nbits = utils::enum_value_nbits(get_discriminant_value(cx.tcx, def, i));
+                let variant = def.variant(i);
+                let nbits = utils::enum_value_nbits(get_discriminant_value(cx.tcx, *def, i));
                 (nbits, Some(variant))
             } else {
-                (utils::enum_ty_to_nbits(def, cx.tcx), None)
+                (utils::enum_ty_to_nbits(*def, cx.tcx), None)
             };
             let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
 
-            let cast_from_ptr_size = def.repr.int.map_or(true, |ty| {
+            let cast_from_ptr_size = def.repr().int.map_or(true, |ty| {
                 matches!(
                     ty,
                     IntType::SignedInt(ast::IntTy::Isize) | IntType::UnsignedInt(ast::UintTy::Usize)
diff --git a/src/tools/clippy/clippy_lints/src/casts/utils.rs b/src/tools/clippy/clippy_lints/src/casts/utils.rs
index bbed766c47a..5a4f20f0990 100644
--- a/src/tools/clippy/clippy_lints/src/casts/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/utils.rs
@@ -34,10 +34,10 @@ pub(super) fn enum_value_nbits(value: EnumValue) -> u64 {
     .into()
 }
 
-pub(super) fn enum_ty_to_nbits(adt: &AdtDef, tcx: TyCtxt<'_>) -> u64 {
+pub(super) fn enum_ty_to_nbits(adt: AdtDef<'_>, tcx: TyCtxt<'_>) -> u64 {
     let mut explicit = 0i128;
     let (start, end) = adt
-        .variants
+        .variants()
         .iter()
         .fold((0, i128::MIN), |(start, end), variant| match variant.discr {
             VariantDiscr::Relative(x) => match explicit.checked_add(i128::from(x)) {
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 06e6bf986c2..f7e4bc24321 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
             then {
                 // TODO: Work out a way to put "whatever the imported way of referencing
                 // this type in this file" rather than a fully-qualified type.
-                let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
+                let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did()));
                 span_lint_and_sugg(
                     cx,
                     DEFAULT_TRAIT_ACCESS,
@@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                 if let Some(adt) = binding_type.ty_adt_def();
                 if adt.is_struct();
                 let variant = adt.non_enum_variant();
-                if adt.did.is_local() || !variant.is_field_list_non_exhaustive();
+                if adt.did().is_local() || !variant.is_field_list_non_exhaustive();
                 let module_did = cx.tcx.parent_module(stmt.hir_id).to_def_id();
                 if variant
                     .fields
@@ -216,7 +216,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                     if let ty::Adt(adt_def, substs) = binding_type.kind();
                     if !substs.is_empty();
                     then {
-                        let adt_def_ty_name = cx.tcx.item_name(adt_def.did);
+                        let adt_def_ty_name = cx.tcx.item_name(adt_def.did());
                         let generic_args = substs.iter().collect::<Vec<_>>();
                         let tys_str = generic_args
                             .iter()
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index b80d55dd192..f3996e5b44d 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -148,7 +148,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                 if_chain! {
                     if let Some(adt_def) = ty.ty_adt_def();
                     if adt_def.is_struct();
-                    if let Some(variant) = adt_def.variants.iter().next();
+                    if let Some(variant) = adt_def.variants().iter().next();
                     then {
                         let fields_def = &variant.fields;
 
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index eccb18982f3..14098340745 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
                     _ => false,
                 };
                 if should_emit {
-                    let path_string = cx.tcx.def_path_str(adt_def.did);
+                    let path_string = cx.tcx.def_path_str(adt_def.did());
                     span_lint_and_help(
                         cx,
                         DERIVABLE_IMPLS,
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 7277e4080c5..557e101494e 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -315,7 +315,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &T
             let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).map_or(false, |impls| {
                 impls
                     .iter()
-                    .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did))
+                    .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()))
             });
             if !has_copy_impl {
                 return;
@@ -357,10 +357,10 @@ fn check_unsafe_derive_deserialize<'tcx>(
         if let Some(trait_def_id) = trait_ref.trait_def_id();
         if match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE);
         if let ty::Adt(def, _) = ty.kind();
-        if let Some(local_def_id) = def.did.as_local();
+        if let Some(local_def_id) = def.did().as_local();
         let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
         if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id);
-        if cx.tcx.inherent_impls(def.did)
+        if cx.tcx.inherent_impls(def.did())
             .iter()
             .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
             .any(|imp| has_unsafe(cx, imp));
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index af9e65e6361..b5d6b3c7524 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
         if let ItemKind::Enum(..) = item.kind {
             let ty = cx.tcx.type_of(item.def_id);
             let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
-            if adt.variants.is_empty() {
+            if adt.variants().is_empty() {
                 span_lint_and_help(
                     cx,
                     EMPTY_ENUM,
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index 3b6661c817b..e2a5430da08 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
                     if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) {
                         if let ty::Adt(adt, _) = ty.kind() {
                             if adt.is_enum() {
-                                ty = adt.repr.discr_type().to_ty(cx.tcx);
+                                ty = adt.repr().discr_type().to_ty(cx.tcx);
                             }
                         }
                         match ty.kind() {
diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs
index 6490231fed8..51c811b304c 100644
--- a/src/tools/clippy/clippy_lints/src/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/eq_op.rs
@@ -306,7 +306,7 @@ fn in_impl<'tcx>(
 fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool {
     if_chain! {
         if let ty::Adt(adt_def, _) = middle_ty.kind();
-        if let Some(local_did) = adt_def.did.as_local();
+        if let Some(local_did) = adt_def.did().as_local();
         let item = cx.tcx.hir().expect_item(local_did);
         let middle_ty_id = item.def_id.to_def_id();
         if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index d23c0c225e1..845863bd209 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -224,7 +224,7 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
         ty::ImplContainer(def_id) => {
             let ty = cx.tcx.type_of(def_id);
             match ty.kind() {
-                ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did),
+                ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
                 _ => ty.to_string(),
             }
         },
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 395c920c997..64c41b56587 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
             if_chain! {
                 if format_args.format_string_parts == [kw::Empty];
                 if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
-                    ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did),
+                    ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()),
                     ty::Str => true,
                     _ => false,
                 };
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index ea9b68d1a40..0709580c8ad 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -189,8 +189,8 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m
         // primitive types are never mutable
         ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
         ty::Adt(adt, substs) => {
-            tys.insert(adt.did) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
-                || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did, path))
+            tys.insert(adt.did()) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
+                || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did(), path))
                     && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
         },
         ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, span, tys)),
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 3d44a669d8f..c8ec2f45137 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
             let ty = cx.typeck_results().expr_ty(expr);
             if let Some(adt_def) = ty.ty_adt_def();
             if adt_def.is_struct();
-            if let Some(variant) = adt_def.variants.iter().next();
+            if let Some(variant) = adt_def.variants().iter().next();
             if fields.iter().all(|f| f.is_shorthand);
             then {
                 let mut def_order_map = FxHashMap::default();
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index d1dc6b775c5..0f3889a2936 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -81,11 +81,11 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
         if let ItemKind::Enum(ref def, _) = item.kind {
             let ty = cx.tcx.type_of(item.def_id);
             let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
-            if adt.variants.len() <= 1 {
+            if adt.variants().len() <= 1 {
                 return;
             }
             let mut variants_size: Vec<VariantInfo> = Vec::new();
-            for (i, variant) in adt.variants.iter().enumerate() {
+            for (i, variant) in adt.variants().iter().enumerate() {
                 let mut fields_size = Vec::new();
                 for (i, f) in variant.fields.iter().enumerate() {
                     let ty = cx.tcx.type_of(f.did);
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 35d10d53112..dabbb8375f0 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -248,13 +248,13 @@ enum LenOutput<'tcx> {
 fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
     match *sig.output().kind() {
         ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
-        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) => {
-            subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did))
+        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) => {
+            subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did()))
         },
-        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did) => subs
+        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => subs
             .type_at(0)
             .is_integral()
-            .then(|| LenOutput::Result(adt.did, subs.type_at(1))),
+            .then(|| LenOutput::Result(adt.did(), subs.type_at(1))),
         _ => None,
     }
 }
@@ -263,8 +263,8 @@ impl LenOutput<'_> {
     fn matches_is_empty_output(self, ty: Ty<'_>) -> bool {
         match (self, ty.kind()) {
             (_, &ty::Bool) => true,
-            (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did => subs.type_at(0).is_bool(),
-            (Self::Result(id, err_ty), &ty::Adt(adt, subs)) if id == adt.did => {
+            (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(),
+            (Self::Result(id, err_ty), &ty::Adt(adt, subs)) if id == adt.did() => {
                 subs.type_at(0).is_bool() && subs.type_at(1) == err_ty
             },
             _ => false,
@@ -488,7 +488,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
                 .any(|item| is_is_empty(cx, item))
         }),
         ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
-        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
+        ty::Adt(id, _) => has_is_empty_impl(cx, id.did()),
         ty::Array(..) | ty::Slice(..) | ty::Str => true,
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index f6ef87264c0..b31015d195b 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -334,7 +334,7 @@ struct Start<'hir> {
 
 fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     match ty.kind() {
-        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Vec, adt.did) => Some(subs.type_at(0)),
+        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Vec, adt.did()) => Some(subs.type_at(0)),
         ty::Ref(_, subty, _) => get_slice_like_element_ty(cx, *subty),
         ty::Slice(ty) | ty::Array(ty, _) => Some(*ty),
         _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 3515286d5b4..93bf0dc62e0 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -45,8 +45,8 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
 
     // Accumulate the variants which should be put in place of the wildcard because they're not
     // already covered.
-    let has_hidden = adt_def.variants.iter().any(|x| is_hidden(cx, x));
-    let mut missing_variants: Vec<_> = adt_def.variants.iter().filter(|x| !is_hidden(cx, x)).collect();
+    let has_hidden = adt_def.variants().iter().any(|x| is_hidden(cx, x));
+    let mut missing_variants: Vec<_> = adt_def.variants().iter().filter(|x| !is_hidden(cx, x)).collect();
 
     let mut path_prefix = CommonPrefixSearcher::None;
     for arm in arms {
@@ -118,7 +118,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
                 }
                 s
             } else {
-                let mut s = cx.tcx.def_path_str(adt_def.did);
+                let mut s = cx.tcx.def_path_str(adt_def.did());
                 s.push_str("::");
                 s
             },
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index ce958b8ac9f..eec232e6d09 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -145,7 +145,7 @@ pub(crate) trait BindInsteadOfMap {
         if_chain! {
             if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def();
             if let Ok(vid) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM);
-            if Some(adt.did) == cx.tcx.parent(vid);
+            if Some(adt.did()) == cx.tcx.parent(vid);
             then {} else { return false; }
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
index 67a585edc25..6d30bb5a278 100644
--- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
@@ -15,7 +15,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span,
     let inner_ty = match recv_ty.kind() {
         // `Option<T>` -> `T`
         ty::Adt(adt, subst)
-            if cx.tcx.is_diagnostic_item(sym::Option, adt.did) && meets_msrv(msrv, &msrvs::OPTION_COPIED) =>
+            if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, &msrvs::OPTION_COPIED) =>
         {
             subst.type_at(0)
         },
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 30c68186b3a..558cb6bd64e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -119,9 +119,9 @@ pub(super) fn check<'tcx>(
             if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
             if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind;
             if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def();
-            if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did) {
+            if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
                 Some(false)
-            } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did) {
+            } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) {
                 Some(true)
             } else {
                 None
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 7a255baffd7..6e64e7f6222 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -17,7 +17,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
         let return_type = cx.typeck_results().expr_ty(expr);
         let input_type = cx.typeck_results().expr_ty(recv);
         let (input_type, ref_count) = peel_mid_ty_refs(input_type);
-        if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did));
+        if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()));
         if return_type == input_type;
         then {
             let mut app = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index c0f66feb48a..06ead144afa 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -60,7 +60,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     }
 
     if let ty::Adt(adt, substs) = ty.kind() {
-        match_def_path(cx, adt.did, &paths::COW) && substs.type_at(1).is_str()
+        match_def_path(cx, adt.did(), &paths::COW) && substs.type_at(1).is_str()
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
index 6782f64f2ca..e1212c31cfb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -55,9 +55,9 @@ pub(super) fn check<'tcx>(
     // lint if caller of `.map().flatten()` is an Option or Result
     let caller_type = match cx.typeck_results().expr_ty(recv).kind() {
         ty::Adt(adt, _) => {
-            if cx.tcx.is_diagnostic_item(sym::Option, adt.did) {
+            if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) {
                 "Option"
-            } else if cx.tcx.is_diagnostic_item(sym::Result, adt.did) {
+            } else if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) {
                 "Result"
             } else {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 926c25b4b40..8125930b304 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -152,7 +152,7 @@ fn parse_iter_usage<'tcx>(
                     return if_chain! {
                         if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE);
                         if let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind();
-                        if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did);
+                        if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did());
                         if let ty::Tuple(subs) = subs.type_at(0).kind();
                         if subs.len() == 2;
                         then {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index 12ad3d8d690..a307e33875e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -33,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
         } else if !found_mapping && !mutates_arg {
             let in_ty = cx.typeck_results().node_type(body.params[0].hir_id);
             match cx.typeck_results().expr_ty(&body.value).kind() {
-                ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) && in_ty == subst.type_at(0) => {
+                ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) => {
                     "filter"
                 },
                 _ => return,
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index bad9e0be82e..ecc9acf4445 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -3,6 +3,7 @@ use clippy_utils::qualify_min_const_fn::is_min_const_fn;
 use clippy_utils::ty::has_drop;
 use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method};
 use rustc_hir as hir;
+use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
@@ -131,6 +132,18 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             FnKind::Closure => return,
         }
 
+        // Const fns are not allowed as methods in a trait.
+        {
+            let parent = cx.tcx.hir().get_parent_item(hir_id);
+            if parent != CRATE_DEF_ID {
+                if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent) {
+                    if let hir::ItemKind::Trait(..) = &item.kind {
+                        return;
+                    }
+                }
+            }
+        }
+
         let mir = cx.tcx.optimized_mir(def_id);
 
         if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) {
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index ce9ca15430e..cba54e14212 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -125,7 +125,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
     if let Adt(def, substs) = ty.kind() {
         let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
             .iter()
-            .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did));
+            .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
         if is_keyed_type && is_interior_mutable_type(cx, substs.type_at(0), span) {
             span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
         }
@@ -159,8 +159,8 @@ fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Sp
                 sym::Arc,
             ]
             .iter()
-            .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did));
-            let is_box = Some(def.did) == cx.tcx.lang_items().owned_box();
+            .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
+            let is_box = Some(def.did()) == cx.tcx.lang_items().owned_box();
             if is_std_collection || is_box {
                 // The type is mutable if any of its type parameters are
                 substs.types().any(|ty| is_interior_mutable_type(cx, ty, span))
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 ebfd908a6fb..a57dc2b2798 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
@@ -198,7 +198,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                     // Dereference suggestion
                     let sugg = |diag: &mut Diagnostic| {
                         if let ty::Adt(def, ..) = ty.kind() {
-                            if let Some(span) = cx.tcx.hir().span_if_local(def.did) {
+                            if let Some(span) = cx.tcx.hir().span_if_local(def.did()) {
                                 if can_type_implement_copy(cx.tcx, cx.param_env, ty, traits::ObligationCause::dummy_with_span(span)).is_ok() {
                                     diag.span_help(span, "consider marking this type as `Copy`");
                                 }
diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs
index ed315efaa2f..c87c174ef73 100644
--- a/src/tools/clippy/clippy_lints/src/needless_update.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_update.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate {
             let ty = cx.typeck_results().expr_ty(expr);
             if let ty::Adt(def, _) = ty.kind() {
                 if fields.len() == def.non_enum_variant().fields.len()
-                    && !def.variants[0_usize.into()].is_field_list_non_exhaustive()
+                    && !def.variant(0_usize.into()).is_field_list_non_exhaustive()
                 {
                     span_lint(
                         cx,
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 6c68c1bc48d..9419056be14 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                                     let mut impls = HirIdSet::default();
                                     cx.tcx.for_each_impl(default_trait_id, |d| {
                                         if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
-                                            if let Some(local_def_id) = ty_def.did.as_local() {
+                                            if let Some(local_def_id) = ty_def.did().as_local() {
                                                 impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id));
                                             }
                                         }
@@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                                 if_chain! {
                                     if let Some(ref impling_types) = self.impling_types;
                                     if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def();
-                                    if let Some(self_local_did) = self_def.did.as_local();
+                                    if let Some(self_local_did) = self_def.did().as_local();
                                     let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
                                     if impling_types.contains(&self_id);
                                     then {
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 3ba99403f06..8db41ba6ee2 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -140,7 +140,7 @@ fn is_value_unfrozen_raw<'tcx>(
         match val.ty().kind() {
             // the fact that we have to dig into every structs to search enums
             // leads us to the point checking `UnsafeCell` directly is the only option.
-            ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true,
+            ty::Adt(ty_def, ..) if Some(ty_def.did()) == cx.tcx.lang_items().unsafe_cell_type() => true,
             ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => {
                 let val = cx.tcx.destructure_const(cx.param_env.and(val));
                 val.fields.iter().any(|field| inner(cx, *field))
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index 5168ca67b6a..ddef7352de8 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
                 let mut non_send_fields = Vec::new();
 
                 let hir_map = cx.tcx.hir();
-                for variant in &adt_def.variants {
+                for variant in adt_def.variants() {
                     for field in &variant.fields {
                         if_chain! {
                             if let Some(field_hir_id) = field
@@ -233,7 +233,7 @@ fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> b
                     return true;
                 },
                 ty::Adt(adt_def, _) => {
-                    if match_def_path(cx, adt_def.did, &paths::PTR_NON_NULL) {
+                    if match_def_path(cx, adt_def.did(), &paths::PTR_NON_NULL) {
                         return true;
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 2c328195f24..9c776437d7f 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -405,13 +405,13 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                 // Check that the name as typed matches the actual name of the type.
                 // e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec`
                 if let [.., name] = path.segments;
-                if cx.tcx.item_name(adt.did) == name.ident.name;
+                if cx.tcx.item_name(adt.did()) == name.ident.name;
 
                 if !is_lint_allowed(cx, PTR_ARG, hir_ty.hir_id);
                 if params.get(i).map_or(true, |p| !is_lint_allowed(cx, PTR_ARG, p.hir_id));
 
                 then {
-                    let (method_renames, deref_ty, deref_impl_id) = match cx.tcx.get_diagnostic_name(adt.did) {
+                    let (method_renames, deref_ty, deref_impl_id) = match cx.tcx.get_diagnostic_name(adt.did()) {
                         Some(sym::Vec) => (
                             [("clone", ".to_owned()")].as_slice(),
                             DerefTy::Slice(
@@ -462,7 +462,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                     return Some(PtrArg {
                         idx: i,
                         span: hir_ty.span,
-                        ty_did: adt.did,
+                        ty_did: adt.did(),
                         ty_name: name.ident.name,
                         method_renames,
                         ref_prefix: RefPrefix {
@@ -570,7 +570,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                             .map(|sig| sig.input(i).skip_binder().peel_refs())
                             .map_or(true, |ty| match *ty.kind() {
                                 ty::Param(_) => true,
-                                ty::Adt(def, _) => def.did == args.ty_did,
+                                ty::Adt(def, _) => def.did() == args.ty_did,
                                 _ => false,
                             })
                         {
@@ -607,7 +607,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                             // If the types match check for methods which exist on both types. e.g. `Vec::len` and
                             // `slice::len`
                             ty::Adt(def, _)
-                                if def.did == args.ty_did
+                                if def.did() == args.ty_did
                                     && (i != 0
                                         || self.cx.tcx.trait_of_item(id).is_some()
                                         || !args.deref_assoc_items.map_or(false, |(id, items)| {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index b3988973256..1f134be2cbc 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -543,10 +543,10 @@ impl<'a, 'tcx> PossibleBorrowerVisitor<'a, 'tcx> {
                 continue;
             }
 
-            let borrowers = self.possible_borrower.reachable_from(&row);
+            let borrowers = self.possible_borrower.reachable_from(row);
             if !borrowers.is_empty() {
                 let mut bs = HybridBitSet::new_empty(self.body.local_decls.len());
-                for &c in borrowers {
+                for c in borrowers {
                     if c != mir::Local::from_usize(0) {
                         bs.insert(c);
                     }
@@ -663,10 +663,10 @@ impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
                 continue;
             }
 
-            let borrowers = self.possible_origin.reachable_from(&row);
+            let borrowers = self.possible_origin.reachable_from(row);
             if !borrowers.is_empty() {
                 let mut bs = HybridBitSet::new_empty(self.body.local_decls.len());
-                for &c in borrowers {
+                for c in borrowers {
                     if c != mir::Local::from_usize(0) {
                         bs.insert(c);
                     }
diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
index 123d0ad0457..d07c26d7c89 100644
--- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
+++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
@@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
 
         if_chain! {
             if let Some(self_def) = self_ty.ty_adt_def();
-            if let Some(self_local_did) = self_def.did.as_local();
+            if let Some(self_local_did) = self_def.did().as_local();
             let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
             if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id);
             let type_name = x.ident.name.as_str().to_lowercase();
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 05eadab3e6c..6edff224092 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -141,7 +141,7 @@ pub(super) fn check<'tcx>(
                                 then {
                                     diag.note(&format!(
                                         "two instances of the same generic type (`{}`) may have different layouts",
-                                        cx.tcx.item_name(from_def.did)
+                                        cx.tcx.item_name(from_def.did())
                                     ));
                                 } else {
                                     if from_ty_orig.peel_refs() != from_ty {
@@ -304,13 +304,13 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
                     ty = sized_ty;
                     continue;
                 }
-                if def.repr.inhibit_struct_field_reordering_opt() {
+                if def.repr().inhibit_struct_field_reordering_opt() {
                     ReducedTy::OrderedFields(ty)
                 } else {
                     ReducedTy::UnorderedFields(ty)
                 }
             },
-            ty::Adt(def, _) if def.is_enum() && (def.variants.is_empty() || is_c_void(cx, ty)) => {
+            ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => {
                 ReducedTy::TypeErasure
             },
             ty::Foreign(_) => ReducedTy::TypeErasure,
@@ -326,7 +326,7 @@ fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty);
         if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
         then {
-            layout.layout.size.bytes() == 0
+            layout.layout.size().bytes() == 0
         } else {
             false
         }
diff --git a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
index 2d67401a15f..831b0d450d2 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
@@ -11,11 +11,11 @@ use rustc_span::symbol::sym;
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
         (ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => {
-            if from_adt.did != to_adt.did {
+            if from_adt.did() != to_adt.did() {
                 return false;
             }
             if !matches!(
-                cx.tcx.get_diagnostic_name(to_adt.did),
+                cx.tcx.get_diagnostic_name(to_adt.did()),
                 Some(
                     sym::BTreeMap
                         | sym::BTreeSet
diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs
index 4da32c52e75..80d6f3c6336 100644
--- a/src/tools/clippy/clippy_lints/src/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/try_err.rs
@@ -151,11 +151,11 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
 fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     if_chain! {
         if let ty::Adt(def, subst) = ty.kind();
-        if match_def_path(cx, def.did, &paths::POLL);
+        if match_def_path(cx, def.did(), &paths::POLL);
         let ready_ty = subst.type_at(0);
 
         if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
-        if cx.tcx.is_diagnostic_item(sym::Result, ready_def.did);
+        if cx.tcx.is_diagnostic_item(sym::Result, ready_def.did());
         then {
             Some(ready_subst.type_at(1))
         } else {
@@ -168,15 +168,15 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<
 fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     if_chain! {
         if let ty::Adt(def, subst) = ty.kind();
-        if match_def_path(cx, def.did, &paths::POLL);
+        if match_def_path(cx, def.did(), &paths::POLL);
         let ready_ty = subst.type_at(0);
 
         if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
-        if cx.tcx.is_diagnostic_item(sym::Option, ready_def.did);
+        if cx.tcx.is_diagnostic_item(sym::Option, ready_def.did());
         let some_ty = ready_subst.type_at(0);
 
         if let ty::Adt(some_def, some_subst) = some_ty.kind();
-        if cx.tcx.is_diagnostic_item(sym::Result, some_def.did);
+        if cx.tcx.is_diagnostic_item(sym::Result, some_def.did());
         then {
             Some(some_subst.type_at(1))
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index 1728533f18b..f4f5a4336a3 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -102,9 +102,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
 
         // Get the wrapper and inner types, if can't, abort.
         let (return_type_label, lang_item, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id).kind() {
-            if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did) {
+            if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) {
                 ("Option", OptionSome, subst.type_at(0))
-            } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did) {
+            } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) {
                 ("Result", ResultOk, subst.type_at(0))
             } else {
                 return;
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 eb9efec3f16..a6ef6d79fc0 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -73,7 +73,7 @@ fn fn_eagerness<'tcx>(
         // than marker traits.
         // Due to the limited operations on these types functions should be fairly cheap.
         if def
-            .variants
+            .variants()
             .iter()
             .flat_map(|v| v.fields.iter())
             .any(|x| matches!(cx.tcx.type_of(x.did).peel_refs().kind(), ty::Param(_)))
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 397783e309e..cd20abd94ed 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -268,7 +268,7 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str])
 pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
     if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
         if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
-            return cx.tcx.is_diagnostic_item(diag_item, adt.did);
+            return cx.tcx.is_diagnostic_item(diag_item, adt.did());
         }
     }
     false
@@ -489,7 +489,8 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
     fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
         tcx.crates(())
             .iter()
-            .find(|&&num| tcx.crate_name(num).as_str() == name)
+            .copied()
+            .find(|&num| tcx.crate_name(num).as_str() == name)
             .map(CrateNum::as_def_id)
     }
 
@@ -656,7 +657,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
                 if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
                     return std_types_symbols
                         .iter()
-                        .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did));
+                        .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did()));
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index c039fec955d..891531951c1 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -32,32 +32,12 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv:
                 | ty::PredicateKind::Projection(_)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::Trait(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
                 ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
                 ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
                 ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
                 ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate),
-                ty::PredicateKind::Trait(pred) => {
-                    if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
-                        continue;
-                    }
-                    match pred.self_ty().kind() {
-                        ty::Param(ref p) => {
-                            let generics = tcx.generics_of(current);
-                            let def = generics.type_param(p, tcx);
-                            let span = tcx.def_span(def.def_id);
-                            return Err((
-                                span,
-                                "trait bounds other than `Sized` \
-                                 on const fn parameters are unstable"
-                                    .into(),
-                            ));
-                        },
-                        // other kinds of bounds are either tautologies
-                        // or cause errors in other passes
-                        _ => continue,
-                    }
-                },
             }
         }
         match predicates.parent {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 0646d1524a7..3645a9a5228 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -51,7 +51,7 @@ pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool {
 
 /// Walks into `ty` and returns `true` if any inner type is an instance of the given adt
 /// constructor.
-pub fn contains_adt_constructor(ty: Ty<'_>, adt: &AdtDef) -> bool {
+pub fn contains_adt_constructor(ty: Ty<'_>, adt: AdtDef<'_>) -> bool {
     ty.walk().any(|inner| match inner.unpack() {
         GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt),
         GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
@@ -112,7 +112,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<
     let def_id = match ty_to_check.kind() {
         ty::Array(..) => return Some(sym::array),
         ty::Slice(..) => return Some(sym::slice),
-        ty::Adt(adt, _) => adt.did,
+        ty::Adt(adt, _) => adt.did(),
         _ => return None,
     };
 
@@ -164,7 +164,7 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 // Returns whether the type has #[must_use] attribute
 pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
-        ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(),
+        ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did())).is_some(),
         ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
         ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
             // for the Array case we don't need to care for the len == 0 case
@@ -220,7 +220,7 @@ fn is_normalizable_helper<'tcx>(
         let cause = rustc_middle::traits::ObligationCause::dummy();
         if infcx.at(&cause, param_env).normalize(ty).is_ok() {
             match ty.kind() {
-                ty::Adt(def, substs) => def.variants.iter().all(|variant| {
+                ty::Adt(def, substs) => def.variants().iter().all(|variant| {
                     variant
                         .fields
                         .iter()
@@ -264,7 +264,7 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
 pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
     match ty.kind() {
         ty::Ref(_, ref_ty, _) => match ref_ty.kind() {
-            ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
+            ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did()),
             _ => false,
         },
         _ => false,
@@ -284,7 +284,7 @@ pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_ite
 /// [Diagnostic Items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
 pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
     match ty.kind() {
-        ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
+        ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did()),
         _ => false,
     }
 }
@@ -294,7 +294,7 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb
 /// Returns `false` if the `LangItem` is not defined.
 pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
     match ty.kind() {
-        ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did),
+        ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did()),
         _ => false,
     }
 }
@@ -310,7 +310,7 @@ pub fn is_isize_or_usize(typ: Ty<'_>) -> bool {
 /// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
 pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
     match ty.kind() {
-        ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
+        ty::Adt(adt, _) => match_def_path(cx, adt.did(), path),
         _ => false,
     }
 }
@@ -398,7 +398,7 @@ pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     match *ty.kind() {
         ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
         ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
-        ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did),
+        ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did()),
         _ => false,
     }
 }
@@ -562,11 +562,11 @@ pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue>
 }
 
 /// Gets the value of the given variant.
-pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: &'_ AdtDef, i: VariantIdx) -> EnumValue {
-    let variant = &adt.variants[i];
+pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: AdtDef<'_>, i: VariantIdx) -> EnumValue {
+    let variant = &adt.variant(i);
     match variant.discr {
         VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap(),
-        VariantDiscr::Relative(x) => match adt.variants[(i.as_usize() - x as usize).into()].discr {
+        VariantDiscr::Relative(x) => match adt.variant((i.as_usize() - x as usize).into()).discr {
             VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap() + x,
             VariantDiscr::Relative(_) => EnumValue::Unsigned(x.into()),
         },
@@ -577,7 +577,7 @@ pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: &'_ AdtDef, i: VariantIdx) -
 /// platform specific `libc::<platform>::c_void` types in libc.
 pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     if let ty::Adt(adt, _) = ty.kind()
-        && let &[krate, .., name] = &*cx.get_def_path(adt.did)
+        && let &[krate, .., name] = &*cx.get_def_path(adt.did())
         && let sym::libc | sym::core | sym::std = krate
         && name.as_str() == "c_void"
     {
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index baa7eec0546..88f6935d224 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -49,8 +49,6 @@ fn sub(x: u32) -> usize {
     unsafe { transmute(&x) }
 }
 
-// NOTE: This is currently not yet allowed to be const
-// Once implemented, Clippy should be able to suggest this as const, too.
 fn generic_arr<T: Copy>(t: [T; 1]) -> T {
     t[0]
 }
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index b89cc6451bb..3eb52b68274 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -58,7 +58,15 @@ LL | | }
    | |_^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:67:9
+  --> $DIR/could_be_const.rs:52:1
+   |
+LL | / fn generic_arr<T: Copy>(t: [T; 1]) -> T {
+LL | |     t[0]
+LL | | }
+   | |_^
+
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:65:9
    |
 LL | /         pub fn b(self, a: &A) -> B {
 LL | |             B
@@ -66,12 +74,12 @@ LL | |         }
    | |_________^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:77:5
+  --> $DIR/could_be_const.rs:75:5
    |
 LL | /     fn const_fn_stabilized_before_msrv(byte: u8) {
 LL | |         byte.is_ascii_digit();
 LL | |     }
    | |_____^
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 46daaf42883..c9b1649200d 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -489,16 +489,22 @@ fn is_exception(file: &Path, link: &str) -> bool {
 /// If the given HTML file contents is an HTML redirect, this returns the
 /// destination path given in the redirect.
 fn maybe_redirect(source: &str) -> Option<String> {
-    const REDIRECT: &str = "<p>Redirecting to <a href=";
+    const REDIRECT_RUSTDOC: (usize, &str) = (7, "<p>Redirecting to <a href=");
+    const REDIRECT_MDBOOK: (usize, &str) = (8 - 7, "<p>Redirecting to... <a href=");
 
     let mut lines = source.lines();
-    let redirect_line = lines.nth(7)?;
 
-    redirect_line.find(REDIRECT).map(|i| {
-        let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
-        let pos_quote = rest.find('"').unwrap();
-        rest[..pos_quote].to_owned()
-    })
+    let mut find_redirect = |(line_rel, redirect_pattern): (usize, &str)| {
+        let redirect_line = lines.nth(line_rel)?;
+
+        redirect_line.find(redirect_pattern).map(|i| {
+            let rest = &redirect_line[(i + redirect_pattern.len() + 1)..];
+            let pos_quote = rest.find('"').unwrap();
+            rest[..pos_quote].to_owned()
+        })
+    };
+
+    find_redirect(REDIRECT_RUSTDOC).or_else(|| find_redirect(REDIRECT_MDBOOK))
 }
 
 fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, mut f: F) {
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 54b14b7f0110133477e7459a327a0a5cbd18fd4
+Subproject a12a48bf723e0e13f043979a7f79861d975e718
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject 4e72700e38421a12993fe5fa5c33d712652bc6c
+Subproject 5fae65dd28b450a437ebc800a410164c3af1d51
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index 32340ec7eec..841c0f2b939 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -138,7 +138,7 @@ async function main(argv) {
     try {
         // This is more convenient that setting fields one by one.
         let args = [
-            "--no-screenshot",
+            "--no-screenshot-comparison",
             "--variable", "DOC_PATH", opts["doc_folder"],
         ];
         if (opts["debug"]) {
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index 1d5ec5c31c6..503df537047 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -117,7 +117,7 @@ mod os_impl {
                         .stderr(Stdio::null())
                         .output()
                         .unwrap_or_else(|e| {
-                            panic!("could not run git ls-files: {}", e);
+                            panic!("could not run git ls-files: {e}");
                         });
                     let path_bytes = rel_path.as_os_str().as_bytes();
                     if output.status.success() && output.stdout.starts_with(path_bytes) {
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 52429fee461..d6e36c2e7db 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -340,8 +340,8 @@ fn check_exceptions(
                 }
                 Some(pkg_license) => {
                     if pkg_license.as_str() != *license {
-                        println!("dependency exception `{}` license has changed", name);
-                        println!("    previously `{}` now `{}`", license, pkg_license);
+                        println!("dependency exception `{name}` license has changed");
+                        println!("    previously `{license}` now `{pkg_license}`");
                         println!("    update EXCEPTIONS for the new license");
                         *bad = true;
                     }
@@ -418,7 +418,7 @@ fn check_dependencies(
     if !unapproved.is_empty() {
         tidy_error!(bad, "Dependencies not explicitly permitted:");
         for dep in unapproved {
-            println!("* {}", dep);
+            println!("* {dep}");
         }
     }
 }
@@ -501,7 +501,7 @@ fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package
         .nodes
         .iter()
         .find(|n| &n.id == pkg_id)
-        .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
+        .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
     node.deps
         .iter()
         .map(|dep| {
@@ -516,8 +516,8 @@ fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package
 fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
     let mut i = metadata.packages.iter().filter(|p| p.name == name);
     let result =
-        i.next().unwrap_or_else(|| panic!("could not find package `{}` in package list", name));
-    assert!(i.next().is_none(), "more than one package found for `{}`", name);
+        i.next().unwrap_or_else(|| panic!("could not find package `{name}` in package list"));
+    assert!(i.next().is_none(), "more than one package found for `{name}`");
     result
 }
 
@@ -545,7 +545,7 @@ fn normal_deps_of_r<'a>(
         .nodes
         .iter()
         .find(|n| &n.id == pkg_id)
-        .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
+        .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
     for dep in &node.deps {
         normal_deps_of_r(resolve, &dep.pkg, result);
     }
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index f6be550283a..281773b0569 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -260,7 +260,7 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
 
         for (err_code, error_status) in &error_codes {
             if !error_status.has_test && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
-                errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
+                errors.push(format!("Error code {err_code} needs to have at least one UI test!"));
             } else if error_status.has_test && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                 errors.push(format!(
                     "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
@@ -309,7 +309,7 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
     }
     errors.sort();
     for err in &errors {
-        eprintln!("{}", err);
+        eprintln!("{err}");
     }
     println!("Found {} error(s) in error codes", errors.len());
     if !errors.is_empty() {
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 9b6037c6a4b..2f22c081a54 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -157,7 +157,7 @@ pub fn check(
         .collect::<Vec<_>>();
 
     for &(name, _) in gate_untested.iter() {
-        println!("Expected a gate test for the feature '{}'.", name);
+        println!("Expected a gate test for the feature '{name}'.");
         println!(
             "Hint: create a failing test file named 'feature-gate-{}.rs'\
                 \n      in the 'ui' test suite, with its failures due to\
@@ -186,7 +186,7 @@ pub fn check(
 
         lines.sort();
         for line in lines {
-            println!("* {}", line);
+            println!("* {line}");
         }
     } else {
         println!("* {} features", features.len());
@@ -221,7 +221,7 @@ fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
         "issue" => &*ISSUE,
         "feature" => &*FEATURE,
         "since" => &*SINCE,
-        _ => unimplemented!("{} not handled", attr),
+        _ => unimplemented!("{attr} not handled"),
     };
 
     r.captures(line).and_then(|c| c.get(1)).map(|m| m.as_str())
@@ -231,7 +231,7 @@ fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
     let prefix = "feature_gate_";
     if filen_underscore.starts_with(prefix) {
         for (n, f) in features.iter_mut() {
-            // Equivalent to filen_underscore == format!("feature_gate_{}", n)
+            // Equivalent to filen_underscore == format!("feature_gate_{n}")
             if &filen_underscore[prefix.len()..] == n {
                 f.has_gate_test = true;
                 return true;
diff --git a/src/tools/tidy/src/primitive_docs.rs b/src/tools/tidy/src/primitive_docs.rs
index 8476650d9b5..f3200e0afd7 100644
--- a/src/tools/tidy/src/primitive_docs.rs
+++ b/src/tools/tidy/src/primitive_docs.rs
@@ -8,10 +8,10 @@ pub fn check(library_path: &Path, bad: &mut bool) {
     let std_name = "std/src/primitive_docs.rs";
     let core_name = "core/src/primitive_docs.rs";
     let std_contents = std::fs::read_to_string(library_path.join(std_name))
-        .unwrap_or_else(|e| panic!("failed to read library/{}: {}", std_name, e));
+        .unwrap_or_else(|e| panic!("failed to read library/{std_name}: {e}"));
     let core_contents = std::fs::read_to_string(library_path.join(core_name))
-        .unwrap_or_else(|e| panic!("failed to read library/{}: {}", core_name, e));
+        .unwrap_or_else(|e| panic!("failed to read library/{core_name}: {e}"));
     if std_contents != core_contents {
-        tidy_error!(bad, "library/{} and library/{} have different contents", core_name, std_name);
+        tidy_error!(bad, "library/{core_name} and library/{std_name} have different contents");
     }
 }
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index c197acd4828..9861cba410d 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -153,9 +153,9 @@ fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) ->
         return Directive::Deny;
     }
     // Update `can_contain` when changing this
-    if contents.contains(&format!("// ignore-tidy-{}", check))
-        || contents.contains(&format!("# ignore-tidy-{}", check))
-        || contents.contains(&format!("/* ignore-tidy-{} */", check))
+    if contents.contains(&format!("// ignore-tidy-{check}"))
+        || contents.contains(&format!("# ignore-tidy-{check}"))
+        || contents.contains(&format!("/* ignore-tidy-{check} */"))
     {
         Directive::Ignore(false)
     } else {
@@ -294,7 +294,7 @@ pub fn check(path: &Path, bad: &mut bool) {
                 suppressible_tidy_err!(
                     err,
                     skip_line_length,
-                    &format!("line longer than {} chars", max_columns)
+                    &format!("line longer than {max_columns} chars")
                 );
             }
             if !is_style_file && line.contains('\t') {
@@ -381,7 +381,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             n => suppressible_tidy_err!(
                 err,
                 skip_trailing_newlines,
-                &format!("too many trailing newlines ({})", n)
+                &format!("too many trailing newlines ({n})")
             ),
         };
         if lines > LINES {
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index 8e1749196d2..723684bfa4c 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -20,7 +20,7 @@ fn iter_header<'a>(contents: &'a str, it: &mut dyn FnMut(Option<&'a str>, &'a st
                 let lncfg = &ln[open_brace + 1..close_brace];
                 it(Some(lncfg), ln[(close_brace + 1)..].trim_start());
             } else {
-                panic!("malformed condition directive: expected `//[foo]`, found `{}`", ln)
+                panic!("malformed condition directive: expected `//[foo]`, found `{ln}`")
             }
         } else if ln.starts_with(COMMENT) {
             it(None, ln[COMMENT.len()..].trim_start());
@@ -61,7 +61,7 @@ pub fn check(path: &Path, bad: &mut bool) {
                             let info = header_map.entry(cfg).or_insert(RevisionInfo::default());
                             info.target_arch.replace(arch);
                         } else {
-                            eprintln!("{}: seems to have a malformed --target value", file);
+                            eprintln!("{file}: seems to have a malformed --target value");
                             *bad = true;
                         }
                     }
diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs
index 218e9668df4..4720ee7020f 100644
--- a/src/tools/unicode-table-generator/src/main.rs
+++ b/src/tools/unicode-table-generator/src/main.rs
@@ -277,7 +277,7 @@ fn main() {
 
     for (name, contents) in modules {
         table_file.push_str("#[rustfmt::skip]\n");
-        table_file.push_str(&format!("pub mod {} {{\n", name));
+        table_file.push_str(&format!("pub mod {name} {{\n"));
         for line in contents.lines() {
             if !line.trim().is_empty() {
                 table_file.push_str("    ");
@@ -290,7 +290,7 @@ fn main() {
 
     std::fs::write(&write_location, format!("{}\n", table_file.trim_end())).unwrap();
 
-    println!("Total table sizes: {} bytes", total_bytes);
+    println!("Total table sizes: {total_bytes} bytes");
 }
 
 fn version() -> String {
@@ -308,7 +308,7 @@ fn version() -> String {
         readme[start..end].split('.').map(|v| v.parse::<u32>().expect(&v)).collect::<Vec<_>>();
     let [major, minor, micro] = [version[0], version[1], version[2]];
 
-    out.push_str(&format!("({}, {}, {});\n", major, minor, micro));
+    out.push_str(&format!("({major}, {minor}, {micro});\n"));
     out
 }
 
@@ -322,7 +322,7 @@ fn fmt_list<V: std::fmt::Debug>(values: impl IntoIterator<Item = V>) -> String {
         } else {
             out.push_str(line.trim_end());
             out.push('\n');
-            line = format!("    {}", piece);
+            line = format!("    {piece}");
         }
     }
     out.push_str(line.trim_end());
@@ -335,7 +335,7 @@ fn generate_tests(data_path: &str, ranges: &[(&str, Vec<Range<u32>>)]) -> String
     s.push_str("#![allow(incomplete_features, unused)]\n");
     s.push_str("#![feature(const_generics)]\n\n");
     s.push_str("\n#[allow(unused)]\nuse std::hint;\n");
-    s.push_str(&format!("#[path = \"{}\"]\n", data_path));
+    s.push_str(&format!("#[path = \"{data_path}\"]\n"));
     s.push_str("mod unicode_data;\n\n");
 
     s.push_str("\nfn main() {\n");
diff --git a/src/tools/unicode-table-generator/src/unicode_download.rs b/src/tools/unicode-table-generator/src/unicode_download.rs
index fa57f650ac0..9b2e0a25891 100644
--- a/src/tools/unicode-table-generator/src/unicode_download.rs
+++ b/src/tools/unicode-table-generator/src/unicode_download.rs
@@ -13,13 +13,12 @@ pub fn fetch_latest() {
     let directory = Path::new(UNICODE_DIRECTORY);
     if directory.exists() {
         eprintln!(
-            "Not refetching unicode data, already exists, please delete {:?} to regenerate",
-            directory
+            "Not refetching unicode data, already exists, please delete {directory:?} to regenerate",
         );
         return;
     }
     if let Err(e) = std::fs::create_dir_all(directory) {
-        panic!("Failed to create {:?}: {}", UNICODE_DIRECTORY, e);
+        panic!("Failed to create {UNICODE_DIRECTORY:?}: {e}");
     }
     let output = Command::new("curl").arg(URL_PREFIX.to_owned() + README).output().unwrap();
     if !output.status.success() {
diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs
index e10f72a47b2..5a0477b4b94 100644
--- a/src/tools/unstable-book-gen/src/main.rs
+++ b/src/tools/unstable-book-gen/src/main.rs
@@ -67,7 +67,7 @@ fn generate_unstable_book_files(src: &Path, out: &Path, features: &Features) {
     t!(fs::create_dir_all(&out));
     for feature_name in &unstable_features - &unstable_section_file_names {
         let feature_name_underscore = feature_name.replace('-', "_");
-        let file_name = format!("{}.md", feature_name);
+        let file_name = format!("{feature_name}.md");
         let out_file_path = out.join(&file_name);
         let feature = &features[&feature_name_underscore];
 
diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs
index 6c0311433d6..8c47559b369 100644
--- a/src/tools/x/src/main.rs
+++ b/src/tools/x/src/main.rs
@@ -58,7 +58,7 @@ fn main() {
     let current = match env::current_dir() {
         Ok(dir) => dir,
         Err(err) => {
-            eprintln!("Failed to get current directory: {}", err);
+            eprintln!("Failed to get current directory: {err}");
             process::exit(1);
         }
     };
diff --git a/triagebot.toml b/triagebot.toml
index 276587e7f13..f6f1b918f06 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -73,6 +73,13 @@ Thanks! <3
 """
 label = "O-riscv"
 
+[ping.fuchsia]
+message = """\
+Hey friends of Fuchsia! This issue could use some guidance on how this should be
+resolved/implemented on Fuchsia. Could one of you weigh in?
+"""
+label = "O-fuchsia"
+
 [prioritize]
 label = "I-prioritize"