about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml10
-rw-r--r--Cargo.lock9
-rw-r--r--RELEASES.md1
-rw-r--r--compiler/rustc_abi/src/layout.rs43
-rw-r--r--compiler/rustc_abi/src/lib.rs39
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs16
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock48
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml8
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs30
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/config.txt3
-rw-r--r--compiler/rustc_codegen_cranelift/example/alloc_example.rs44
-rw-r--r--compiler/rustc_codegen_cranelift/example/alloc_system.rs124
-rw-r--r--compiler/rustc_codegen_cranelift/example/mod_bench.rs37
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs46
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/mod.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs54
-rw-r--r--compiler/rustc_codegen_gcc/src/attributes.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs42
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs28
-rw-r--r--compiler/rustc_const_eval/messages.ftl59
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs14
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs423
-rw-r--r--compiler/rustc_const_eval/src/errors.rs39
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs34
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs19
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs10
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs11
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs7
-rw-r--r--compiler/rustc_middle/src/query/erase.rs9
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/error.rs3
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs1
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs12
-rw-r--r--compiler/rustc_mir_build/Cargo.toml1
-rw-r--r--compiler/rustc_mir_build/messages.ftl6
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_constant.rs52
-rw-r--r--compiler/rustc_mir_build/src/builder/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/check_inline.rs81
-rw-r--r--compiler/rustc_mir_build/src/errors.rs12
-rw-r--r--compiler/rustc_mir_build/src/lib.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/constant.rs22
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs9
-rw-r--r--compiler/rustc_mir_transform/messages.ftl11
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mappings.rs5
-rw-r--r--compiler/rustc_mir_transform/src/cross_crate_inline.rs7
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs28
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs1489
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs8
-rw-r--r--compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs2
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs10
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs4
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs11
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs17
-rw-r--r--compiler/rustc_passes/messages.ftl8
-rw-r--r--compiler/rustc_passes/src/check_attr.rs42
-rw-r--r--compiler/rustc_passes/src/errors.rs18
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs56
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs55
-rw-r--r--compiler/rustc_trait_selection/messages.ftl4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs11
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs10
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs10
-rw-r--r--compiler/rustc_type_ir/src/error.rs4
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/raw_vec.rs46
-rw-r--r--library/alloc/src/vec/is_zero.rs15
-rw-r--r--library/alloc/tests/vec.rs10
-rw-r--r--library/core/src/num/mod.rs4
-rw-r--r--library/core/src/num/niche_types.rs168
-rw-r--r--library/core/src/num/nonzero.rs31
-rw-r--r--library/core/src/ptr/mod.rs4
-rw-r--r--library/core/src/slice/iter.rs42
-rw-r--r--library/core/src/time.rs96
-rw-r--r--library/proc_macro/src/lib.rs2
-rw-r--r--library/proc_macro/src/quote.rs149
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/fd/owned.rs34
-rw-r--r--library/std/src/os/solid/io.rs27
-rw-r--r--library/std/src/os/windows/io/socket.rs39
-rw-r--r--library/std/src/sys/pal/solid/fs.rs14
-rw-r--r--library/std/src/sys/pal/unix/thread.rs24
-rw-r--r--library/std/src/sys/pal/unix/time.rs33
-rw-r--r--src/bootstrap/src/utils/helpers.rs5
-rw-r--r--src/ci/docker/README.md27
-rwxr-xr-xsrc/ci/github-actions/ci.py (renamed from src/ci/github-actions/calculate-job-matrix.py)146
-rw-r--r--src/ci/github-actions/jobs.yml146
-rw-r--r--src/doc/rustc-dev-guide/src/building/optimized-build.md2
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ci.md7
-rw-r--r--src/doc/rustc-dev-guide/src/tests/docker.md9
-rw-r--r--src/doc/unstable-book/src/language-features/default-field-values.md93
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/workflows/clippy_dev.yml3
-rw-r--r--src/tools/clippy/.github/workflows/clippy_mq.yml27
-rw-r--r--src/tools/clippy/.github/workflows/clippy_pr.yml7
-rw-r--r--src/tools/clippy/.github/workflows/deploy.yml10
-rw-r--r--src/tools/clippy/.github/workflows/lintcheck.yml8
-rw-r--r--src/tools/clippy/.github/workflows/remark.yml3
-rw-r--r--src/tools/clippy/CHANGELOG.md47
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/book/src/development/infrastructure/changelog_update.md5
-rw-r--r--src/tools/clippy/book/src/development/method_checking.md2
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md27
-rw-r--r--src/tools/clippy/clippy.toml2
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs20
-rw-r--r--src/tools/clippy/clippy_dev/src/fmt.rs6
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/missing_headers.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs127
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_div_ceil.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_flatten.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs139
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_else.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/zombie_processes.rs2
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/output.rs2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/compile-test.rs2
-rw-r--r--src/tools/clippy/tests/missing-test-files.rs2
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed79
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs79
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr77
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr3
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.fixed8
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.rs8
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.stderr14
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs11
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr28
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs9
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-13862.rs19
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.fixed53
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.rs53
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.stderr17
-rw-r--r--src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed6
-rw-r--r--src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr19
-rw-r--r--src/tools/clippy/tests/ui/infinite_iter.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.fixed7
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.rs7
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.stderr38
-rw-r--r--src/tools/clippy/tests/ui/len_zero.fixed22
-rw-r--r--src/tools/clippy/tests/ui/len_zero.rs22
-rw-r--r--src/tools/clippy/tests/ui/len_zero.stderr42
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.fixed22
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.rs22
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.stderr56
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed27
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs27
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr68
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.fixed5
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.rs5
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.stderr24
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.rs12
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.stderr11
-rw-r--r--src/tools/clippy/tests/ui/map_identity.fixed15
-rw-r--r--src/tools/clippy/tests/ui/map_identity.rs15
-rw-r--r--src/tools/clippy/tests/ui/map_identity.stderr14
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs29
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed5
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs5
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr14
-rw-r--r--src/tools/clippy/tests/ui/needless_continue.rs65
-rw-r--r--src/tools/clippy/tests/ui/needless_continue.stderr80
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed8
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs8
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr8
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.rs26
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.stderr143
-rw-r--r--src/tools/clippy/tests/ui/starts_ends_with.fixed2
-rw-r--r--src/tools/clippy/tests/ui/starts_ends_with.rs2
-rw-r--r--src/tools/clippy/tests/ui/trailing_empty_array.rs14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_map_or.fixed14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_map_or.rs4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_map_or.stderr66
-rw-r--r--src/tools/clippy/tests/ui/useless_vec.rs15
-rw-r--r--src/tools/clippy/tests/ui/useless_vec.stderr21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs4
-rw-r--r--src/tools/rustfmt/src/patterns.rs37
-rw-r--r--src/tools/rustfmt/tests/source/pattern.rs10
-rw-r--r--src/tools/rustfmt/tests/target/pattern.rs8
-rw-r--r--tests/codegen/slice-init.rs26
-rw-r--r--tests/codegen/vec-in-place.rs54
-rw-r--r--tests/codegen/vec_pop_push_noop.rs3
-rw-r--r--tests/coverage/generic-unused-impl.cov-map18
-rw-r--r--tests/coverage/generic-unused-impl.coverage18
-rw-r--r--tests/coverage/generic-unused-impl.rs17
-rw-r--r--tests/crashes/114317.rs6
-rw-r--r--tests/crashes/126182.rs10
-rw-r--r--tests/debuginfo/strings-and-strs.rs2
-rw-r--r--tests/mir-opt/inline/forced.caller.ForceInline.panic-abort.diff21
-rw-r--r--tests/mir-opt/inline/forced.caller.ForceInline.panic-unwind.diff21
-rw-r--r--tests/mir-opt/inline/forced.rs13
-rw-r--r--tests/mir-opt/inline/forced_async.caller.ForceInline.panic-abort.diff12
-rw-r--r--tests/mir-opt/inline/forced_async.caller.ForceInline.panic-unwind.diff12
-rw-r--r--tests/mir-opt/inline/forced_async.rs14
-rw-r--r--tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-abort.diff21
-rw-r--r--tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-unwind.diff21
-rw-r--r--tests/mir-opt/inline/forced_closure.rs15
-rw-r--r--tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-abort.diff21
-rw-r--r--tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-unwind.diff21
-rw-r--r--tests/mir-opt/inline/forced_dead_code.rs17
-rw-r--r--tests/ui/abi/c-zst.aarch64-darwin.stderr2
-rw-r--r--tests/ui/abi/c-zst.powerpc-linux.stderr2
-rw-r--r--tests/ui/abi/c-zst.s390x-linux.stderr2
-rw-r--r--tests/ui/abi/c-zst.sparc64-linux.stderr2
-rw-r--r--tests/ui/abi/c-zst.x86_64-linux.stderr2
-rw-r--r--tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr2
-rw-r--r--tests/ui/abi/debug.rs1
-rw-r--r--tests/ui/abi/debug.stderr46
-rw-r--r--tests/ui/abi/sysv64-zst.stderr2
-rw-r--r--tests/ui/abi/win64-zst.x86_64-linux.stderr2
-rw-r--r--tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr2
-rw-r--r--tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr2
-rw-r--r--tests/ui/coherence/auxiliary/pr_review_132289_2_lib.rs37
-rw-r--r--tests/ui/coherence/auxiliary/pr_review_132289_3_lib.rs12
-rw-r--r--tests/ui/coherence/pr-review-132289-1.rs52
-rw-r--r--tests/ui/coherence/pr-review-132289-2.rs26
-rw-r--r--tests/ui/coherence/pr-review-132289-3.rs50
-rw-r--r--tests/ui/coherence/pr-review-132289-3.run.stdout1
-rw-r--r--tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs22
-rw-r--r--tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr21
-rw-r--r--tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr48
-rw-r--r--tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr48
-rw-r--r--tests/ui/coroutine/gen_block.e2024.stderr4
-rw-r--r--tests/ui/coroutine/gen_block.none.stderr4
-rw-r--r--tests/ui/coroutine/gen_block.rs4
-rw-r--r--tests/ui/force-inlining/asm.rs68
-rw-r--r--tests/ui/force-inlining/asm.stderr34
-rw-r--r--tests/ui/force-inlining/auxiliary/callees.rs10
-rw-r--r--tests/ui/force-inlining/cast.rs25
-rw-r--r--tests/ui/force-inlining/cast.stderr40
-rw-r--r--tests/ui/force-inlining/cross-crate.rs13
-rw-r--r--tests/ui/force-inlining/deny-async.rs24
-rw-r--r--tests/ui/force-inlining/deny-async.stderr24
-rw-r--r--tests/ui/force-inlining/deny-closure.rs25
-rw-r--r--tests/ui/force-inlining/deny-closure.stderr24
-rw-r--r--tests/ui/force-inlining/deny.rs23
-rw-r--r--tests/ui/force-inlining/deny.stderr24
-rw-r--r--tests/ui/force-inlining/early-deny.rs21
-rw-r--r--tests/ui/force-inlining/early-deny.stderr35
-rw-r--r--tests/ui/force-inlining/gate.rs12
-rw-r--r--tests/ui/force-inlining/gate.stderr21
-rw-r--r--tests/ui/force-inlining/invalid.rs164
-rw-r--r--tests/ui/force-inlining/invalid.stderr377
-rw-r--r--tests/ui/force-inlining/shims.rs9
-rw-r--r--tests/ui/inline-const/collect-scopes-in-pat.rs16
-rw-r--r--tests/ui/issues/issue-25901.rs2
-rw-r--r--tests/ui/issues/issue-25901.stderr9
-rw-r--r--tests/ui/layout/debug.rs1
-rw-r--r--tests/ui/layout/debug.stderr56
-rw-r--r--tests/ui/layout/hexagon-enum.rs1
-rw-r--r--tests/ui/layout/hexagon-enum.stderr20
-rw-r--r--tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs1
-rw-r--r--tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr27
-rw-r--r--tests/ui/layout/issue-96185-overaligned-enum.rs1
-rw-r--r--tests/ui/layout/issue-96185-overaligned-enum.stderr10
-rw-r--r--tests/ui/layout/randomize.rs62
-rw-r--r--tests/ui/layout/thumb-enum.rs1
-rw-r--r--tests/ui/layout/thumb-enum.stderr20
-rw-r--r--tests/ui/layout/zero-sized-array-enum-niche.rs1
-rw-r--r--tests/ui/layout/zero-sized-array-enum-niche.stderr21
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs2
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr14
-rw-r--r--tests/ui/lint/invalid_value.stderr10
-rw-r--r--tests/ui/methods/bad-wf-when-selecting-method.rs18
-rw-r--r--tests/ui/methods/bad-wf-when-selecting-method.stderr54
-rw-r--r--tests/ui/print_type_sizes/niche-filling.stdout2
-rw-r--r--tests/ui/proc-macro/quote-debug.stdout49
-rw-r--r--tests/ui/proc-macro/quote/auxiliary/basic.rs361
-rw-r--r--tests/ui/proc-macro/quote/basic.rs8
-rw-r--r--tests/ui/proc-macro/quote/debug.rs (renamed from tests/ui/proc-macro/quote-debug.rs)1
-rw-r--r--tests/ui/proc-macro/quote/debug.stdout72
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs17
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr10
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs17
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr10
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-separated.rs13
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr10
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter.rs13
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter.stderr10
-rw-r--r--tests/ui/proc-macro/quote/not-quotable.rs12
-rw-r--r--tests/ui/proc-macro/quote/not-quotable.stderr24
-rw-r--r--tests/ui/proc-macro/quote/not-repeatable.rs16
-rw-r--r--tests/ui/proc-macro/quote/not-repeatable.stderr10
-rw-r--r--tests/ui/repeat-expr/repeat_count.stderr12
-rw-r--r--tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr14
-rw-r--r--tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr14
-rw-r--r--tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr14
-rw-r--r--tests/ui/repr/repr-c-dead-variants.rs1
-rw-r--r--tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr14
-rw-r--r--tests/ui/repr/repr-c-int-dead-variants.rs1
-rw-r--r--tests/ui/repr/repr-c-int-dead-variants.stderr14
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs-ice.stderr1
-rw-r--r--tests/ui/traits/const-traits/cross-crate.stock.stderr5
-rw-r--r--tests/ui/traits/const-traits/cross-crate.stocknc.stderr10
-rw-r--r--tests/ui/traits/const-traits/staged-api-user-crate.stderr1
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr5
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr5
-rw-r--r--tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs2
-rw-r--r--tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr12
-rw-r--r--tests/ui/type/pattern_types/range_patterns.rs1
-rw-r--r--tests/ui/type/pattern_types/range_patterns.stderr19
375 files changed, 7331 insertions, 2527 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f0e151d2577..c650df6a0ec 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,7 +2,7 @@
 # and also on pushes to special branches (auto, try).
 #
 # The actual definition of the executed jobs is calculated by a Python
-# script located at src/ci/github-actions/calculate-job-matrix.py, which
+# script located at src/ci/github-actions/ci.py, which
 # uses job definition data from src/ci/github-actions/jobs.yml.
 # You should primarily modify the `jobs.yml` file if you want to modify
 # what jobs are executed in CI.
@@ -56,10 +56,10 @@ jobs:
       - name: Calculate the CI job matrix
         env:
           COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
-        run: python3 src/ci/github-actions/calculate-job-matrix.py >> $GITHUB_OUTPUT
+        run: python3 src/ci/github-actions/ci.py calculate-job-matrix >> $GITHUB_OUTPUT
         id: jobs
   job:
-    name: ${{ matrix.name }}
+    name: ${{ matrix.full_name }}
     needs: [ calculate_matrix ]
     runs-on: "${{ matrix.os }}"
     defaults:
@@ -67,7 +67,7 @@ jobs:
         shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}
     timeout-minutes: 360
     env:
-      CI_JOB_NAME: ${{ matrix.image }}
+      CI_JOB_NAME: ${{ matrix.name }}
       CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
       # commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs.
       HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
@@ -233,7 +233,7 @@ jobs:
         env:
           DATADOG_SITE: datadoghq.com
           DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
-          DD_GITHUB_JOB_NAME: ${{ matrix.name }}
+          DD_GITHUB_JOB_NAME: ${{ matrix.full_name }}
         run: |
           cd src/ci
           npm ci
diff --git a/Cargo.lock b/Cargo.lock
index 26971e8a120..117f1475e00 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -541,7 +541,7 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
 
 [[package]]
 name = "clippy"
-version = "0.1.85"
+version = "0.1.86"
 dependencies = [
  "anstream",
  "cargo_metadata 0.18.1",
@@ -572,7 +572,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_config"
-version = "0.1.85"
+version = "0.1.86"
 dependencies = [
  "clippy_utils",
  "itertools",
@@ -597,7 +597,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.85"
+version = "0.1.86"
 dependencies = [
  "arrayvec",
  "cargo_metadata 0.18.1",
@@ -620,7 +620,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.85"
+version = "0.1.86"
 dependencies = [
  "arrayvec",
  "itertools",
@@ -4158,6 +4158,7 @@ dependencies = [
  "rustc_apfloat",
  "rustc_arena",
  "rustc_ast",
+ "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fluent_macro",
diff --git a/RELEASES.md b/RELEASES.md
index 7c2c2406e90..13102734a8c 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -60,6 +60,7 @@ Stabilized APIs
 - [`core::ptr::without_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance_mut.html)
 - [`core::ptr::dangling`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling.html)
 - [`core::ptr::dangling_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling_mut.html)
+- [`Pin::as_deref_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.as_deref_mut)
 
 These APIs are now stable in const contexts
 
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 226a46f605c..b8773f9ff38 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -119,6 +119,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             .chain(Niche::from_scalar(dl, Size::ZERO, a))
             .max_by_key(|niche| niche.available(dl));
 
+        let combined_seed = a.size(&self.cx).bytes().wrapping_add(b.size(&self.cx).bytes());
+
         LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary {
@@ -131,6 +133,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             size,
             max_repr_align: None,
             unadjusted_abi_align: align.abi,
+            randomization_seed: combined_seed,
         }
     }
 
@@ -223,6 +226,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             size: Size::ZERO,
             max_repr_align: None,
             unadjusted_abi_align: dl.i8_align.abi,
+            randomization_seed: 0,
         }
     }
 
@@ -385,6 +389,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             return Err(LayoutCalculatorError::EmptyUnion);
         };
 
+        let combined_seed = only_variant
+            .iter()
+            .map(|v| v.randomization_seed)
+            .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
+
         Ok(LayoutData {
             variants: Variants::Single { index: only_variant_idx },
             fields: FieldsShape::Union(union_field_count),
@@ -394,6 +403,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             size: size.align_to(align.abi),
             max_repr_align,
             unadjusted_abi_align,
+            randomization_seed: combined_seed,
         })
     }
 
@@ -650,6 +660,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
                 BackendRepr::Memory { sized: true }
             };
 
+            let combined_seed = variant_layouts
+                .iter()
+                .map(|v| v.randomization_seed)
+                .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
+
             let layout = LayoutData {
                 variants: Variants::Multiple {
                     tag: niche_scalar,
@@ -671,6 +686,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
                 align,
                 max_repr_align,
                 unadjusted_abi_align,
+                randomization_seed: combined_seed,
             };
 
             Some(TmpLayout { layout, variants: variant_layouts })
@@ -961,6 +977,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
 
         let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
 
+        let combined_seed = layout_variants
+            .iter()
+            .map(|v| v.randomization_seed)
+            .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
+
         let tagged_layout = LayoutData {
             variants: Variants::Multiple {
                 tag,
@@ -978,6 +999,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             size,
             max_repr_align,
             unadjusted_abi_align,
+            randomization_seed: combined_seed,
         };
 
         let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants };
@@ -1030,12 +1052,15 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         let mut max_repr_align = repr.align;
         let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
         let optimize_field_order = !repr.inhibit_struct_field_reordering();
-        if optimize_field_order && fields.len() > 1 {
-            let end =
-                if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
-            let optimizing = &mut inverse_memory_index.raw[..end];
-            let fields_excluding_tail = &fields.raw[..end];
+        let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
+        let optimizing = &mut inverse_memory_index.raw[..end];
+        let fields_excluding_tail = &fields.raw[..end];
+        // unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts.
+        let field_seed = fields_excluding_tail
+            .iter()
+            .fold(0u64, |acc, f| acc.wrapping_add(f.randomization_seed));
 
+        if optimize_field_order && fields.len() > 1 {
             // If `-Z randomize-layout` was enabled for the type definition we can shuffle
             // the field ordering to try and catch some code making assumptions about layouts
             // we don't guarantee.
@@ -1046,8 +1071,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
                     use rand::seq::SliceRandom;
                     // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field
                     // ordering.
-                    let mut rng =
-                        rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
+                    let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64(
+                        field_seed.wrapping_add(repr.field_shuffle_seed),
+                    );
 
                     // Shuffle the ordering of the fields.
                     optimizing.shuffle(&mut rng);
@@ -1344,6 +1370,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             unadjusted_abi_align
         };
 
+        let seed = field_seed.wrapping_add(repr.field_shuffle_seed);
+
         Ok(LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary { offsets, memory_index },
@@ -1353,6 +1381,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             size,
             max_repr_align,
             unadjusted_abi_align,
+            randomization_seed: seed,
         })
     }
 
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 7fa869a509c..8ad33749f34 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1719,6 +1719,18 @@ pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> {
     /// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment
     /// in some cases.
     pub unadjusted_abi_align: Align,
+
+    /// The randomization seed based on this type's own repr and its fields.
+    ///
+    /// Since randomization is toggled on a per-crate basis even crates that do not have randomization
+    /// enabled should still calculate a seed so that downstream uses can use it to distinguish different
+    /// types.
+    ///
+    /// For every T and U for which we do not guarantee that a repr(Rust) `Foo<T>` can be coerced or
+    /// transmuted to `Foo<U>` we aim to create probalistically distinct seeds so that Foo can choose
+    /// to reorder its fields based on that information. The current implementation is a conservative
+    /// approximation of this goal.
+    pub randomization_seed: u64,
 }
 
 impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
@@ -1739,6 +1751,30 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
         let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
         let size = scalar.size(cx);
         let align = scalar.align(cx);
+
+        let range = scalar.valid_range(cx);
+
+        // All primitive types for which we don't have subtype coercions should get a distinct seed,
+        // so that types wrapping them can use randomization to arrive at distinct layouts.
+        //
+        // Some type information is already lost at this point, so as an approximation we derive
+        // the seed from what remains. For example on 64-bit targets usize and u64 can no longer
+        // be distinguished.
+        let randomization_seed = size
+            .bytes()
+            .wrapping_add(
+                match scalar.primitive() {
+                    Primitive::Int(_, true) => 1,
+                    Primitive::Int(_, false) => 2,
+                    Primitive::Float(_) => 3,
+                    Primitive::Pointer(_) => 4,
+                } << 32,
+            )
+            // distinguishes references from pointers
+            .wrapping_add((range.start as u64).rotate_right(16))
+            // distinguishes char from u32 and bool from u8
+            .wrapping_add((range.end as u64).rotate_right(16));
+
         LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Primitive,
@@ -1748,6 +1784,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
             align,
             max_repr_align: None,
             unadjusted_abi_align: align.abi,
+            randomization_seed,
         }
     }
 }
@@ -1770,6 +1807,7 @@ where
             variants,
             max_repr_align,
             unadjusted_abi_align,
+            ref randomization_seed,
         } = self;
         f.debug_struct("Layout")
             .field("size", size)
@@ -1780,6 +1818,7 @@ where
             .field("variants", variants)
             .field("max_repr_align", max_repr_align)
             .field("unadjusted_abi_align", unadjusted_abi_align)
+            .field("randomization_seed", randomization_seed)
             .finish()
     }
 }
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 8986bec57de..def6b16ee8a 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -11,6 +11,22 @@ pub enum InlineAttr {
     Hint,
     Always,
     Never,
+    /// `#[rustc_force_inline]` forces inlining to happen in the MIR inliner - it reports an error
+    /// if the inlining cannot happen. It is limited to only free functions so that the calls
+    /// can always be resolved.
+    Force {
+        attr_span: Span,
+        reason: Option<Symbol>,
+    },
+}
+
+impl InlineAttr {
+    pub fn always(&self) -> bool {
+        match self {
+            InlineAttr::Always | InlineAttr::Force { .. } => true,
+            InlineAttr::None | InlineAttr::Hint | InlineAttr::Never => false,
+        }
+    }
 }
 
 #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)]
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 889b5684a21..a1979c8b8ab 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -892,19 +892,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     Some(l) if !body.local_decls[l].is_user_variable() => {
                         ConstraintCategory::Boring
                     }
-                    Some(_)
-                        if let Some(body_id) = tcx
-                            .hir_node_by_def_id(body.source.def_id().expect_local())
-                            .body_id()
-                            && let params = tcx.hir().body(body_id).params
-                            && params
-                                .iter()
-                                .any(|param| param.span.contains(stmt.source_info.span)) =>
-                    {
-                        // Assignments generated from lowering argument patterns shouldn't be called
-                        // "assignments" in diagnostics and aren't interesting to blame for errors.
-                        ConstraintCategory::Boring
-                    }
                     _ => ConstraintCategory::Assignment,
                 };
                 debug!(
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index ec71370ef9e..b5aba86079f 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -10,15 +10,15 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
 [[package]]
 name = "anyhow"
-version = "1.0.94"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
+checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
 
 [[package]]
 name = "arbitrary"
-version = "1.3.2"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
+checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
 
 [[package]]
 name = "bitflags"
@@ -211,9 +211,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
 
 [[package]]
 name = "foldhash"
-version = "0.1.3"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
+checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
 
 [[package]]
 name = "gimli"
@@ -253,15 +253,15 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.155"
+version = "0.2.169"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
 
 [[package]]
 name = "libloading"
-version = "0.8.4"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
+checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
 dependencies = [
  "cfg-if",
  "windows-targets",
@@ -290,9 +290,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "object"
-version = "0.36.5"
+version = "0.36.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
 dependencies = [
  "crc32fast",
  "hashbrown 0.15.2",
@@ -311,9 +311,9 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.36"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
 dependencies = [
  "proc-macro2",
 ]
@@ -346,9 +346,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-hash"
-version = "2.0.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
+checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
 
 [[package]]
 name = "rustc_codegen_cranelift"
@@ -370,18 +370,18 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.215"
+version = "1.0.217"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.215"
+version = "1.0.217"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -402,9 +402,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
 [[package]]
 name = "syn"
-version = "2.0.90"
+version = "2.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
+checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -419,9 +419,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 82d2b6cb2c4..bfdbc3e768a 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -23,6 +23,14 @@ libloading = { version = "0.8.0", optional = true }
 smallvec = "1.8.1"
 
 [patch.crates-io]
+# Uncomment to use an unreleased version of cranelift
+#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
+#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
+#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
+#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
+#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
+#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
+
 # Uncomment to use local checkout of cranelift
 #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
 #cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index e47e9829916..a73e3c87d43 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -33,14 +33,7 @@ pub(crate) fn build_sysroot(
     let cg_clif_dylib_path = match cg_clif_dylib_src {
         CodegenBackend::Local(src_path) => {
             // Copy the backend
-            let cg_clif_dylib_path = if cfg!(windows) {
-                // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
-                // binaries.
-                dist_dir.join("bin")
-            } else {
-                dist_dir.join("lib")
-            }
-            .join(src_path.file_name().unwrap());
+            let cg_clif_dylib_path = dist_dir.join("lib").join(src_path.file_name().unwrap());
             try_hard_link(src_path, &cg_clif_dylib_path);
             CodegenBackend::Local(cg_clif_dylib_path)
         }
@@ -102,19 +95,14 @@ pub(crate) fn build_sysroot(
         .install_into_sysroot(dist_dir);
     }
 
-    let mut target_compiler = {
-        let rustc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustc-clif"));
-        let rustdoc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustdoc-clif"));
-
-        Compiler {
-            cargo: bootstrap_host_compiler.cargo.clone(),
-            rustc: rustc_clif.clone(),
-            rustdoc: rustdoc_clif.clone(),
-            rustflags: vec![],
-            rustdocflags: vec![],
-            triple: target_triple,
-            runner: vec![],
-        }
+    let mut target_compiler = Compiler {
+        cargo: bootstrap_host_compiler.cargo.clone(),
+        rustc: dist_dir.join(wrapper_base_name.replace("____", "rustc-clif")),
+        rustdoc: dist_dir.join(wrapper_base_name.replace("____", "rustdoc-clif")),
+        rustflags: vec![],
+        rustdocflags: vec![],
+        triple: target_triple,
+        runner: vec![],
     };
     if !is_native {
         target_compiler.set_cross_linker_and_runner();
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index 08736db8ba0..8de419a0c4e 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -73,8 +73,6 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
         "example/arbitrary_self_types_pointers_and_wrappers.rs",
         &[],
     ),
-    TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"),
-    TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]),
     TestCase::jit_bin("jit.std_example", "example/std_example.rs", "arg"),
     TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]),
     TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]),
@@ -89,7 +87,6 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
         &[],
     ),
     TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]),
-    TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
     TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
     TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"),
     TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]),
diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt
index 9808ad624e1..f578cbef35e 100644
--- a/compiler/rustc_codegen_cranelift/config.txt
+++ b/compiler/rustc_codegen_cranelift/config.txt
@@ -21,15 +21,12 @@ aot.mini_core_hello_world
 testsuite.base_sysroot
 aot.arbitrary_self_types_pointers_and_wrappers
 aot.issue_91827_extern_types
-build.alloc_system
-aot.alloc_example
 jit.std_example
 aot.std_example
 aot.dst_field_align
 aot.subslice-patterns-const-eval
 aot.track-caller-attribute
 aot.float-minmax-pass
-aot.mod_bench
 aot.issue-72793
 aot.issue-59326
 aot.neon
diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
deleted file mode 100644
index da70ca79439..00000000000
--- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-#![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
-#![allow(internal_features)]
-#![no_std]
-
-extern crate alloc;
-extern crate alloc_system;
-
-use alloc::boxed::Box;
-
-use alloc_system::System;
-
-#[global_allocator]
-static ALLOC: System = System;
-
-#[cfg_attr(unix, link(name = "c"))]
-#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
-extern "C" {
-    fn puts(s: *const u8) -> i32;
-}
-
-#[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
-    core::intrinsics::abort();
-}
-
-#[alloc_error_handler]
-fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
-    core::intrinsics::abort();
-}
-
-#[lang = "eh_personality"]
-fn eh_personality() -> ! {
-    loop {}
-}
-
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
-    let world: Box<&str> = Box::new("Hello World!\0");
-    unsafe {
-        puts(*world as *const str as *const u8);
-    }
-
-    0
-}
diff --git a/compiler/rustc_codegen_cranelift/example/alloc_system.rs b/compiler/rustc_codegen_cranelift/example/alloc_system.rs
deleted file mode 100644
index 2884c9c32ae..00000000000
--- a/compiler/rustc_codegen_cranelift/example/alloc_system.rs
+++ /dev/null
@@ -1,124 +0,0 @@
-// SPDX-License-Identifier: MIT OR Apache-2.0
-// SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org)
-
-#![no_std]
-
-pub struct System;
-
-#[cfg(any(windows, unix, target_os = "redox"))]
-mod realloc_fallback {
-    use core::alloc::{GlobalAlloc, Layout};
-    use core::{cmp, ptr};
-    impl super::System {
-        pub(crate) unsafe fn realloc_fallback(
-            &self,
-            ptr: *mut u8,
-            old_layout: Layout,
-            new_size: usize,
-        ) -> *mut u8 {
-            // Docs for GlobalAlloc::realloc require this to be valid:
-            let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
-            let new_ptr = GlobalAlloc::alloc(self, new_layout);
-            if !new_ptr.is_null() {
-                let size = cmp::min(old_layout.size(), new_size);
-                ptr::copy_nonoverlapping(ptr, new_ptr, size);
-                GlobalAlloc::dealloc(self, ptr, old_layout);
-            }
-            new_ptr
-        }
-    }
-}
-#[cfg(any(unix, target_os = "redox"))]
-mod platform {
-    use core::alloc::{GlobalAlloc, Layout};
-    use core::ffi::c_void;
-    use core::ptr;
-
-    use System;
-    extern "C" {
-        fn posix_memalign(memptr: *mut *mut c_void, align: usize, size: usize) -> i32;
-        fn free(p: *mut c_void);
-    }
-    unsafe impl GlobalAlloc for System {
-        #[inline]
-        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-            aligned_malloc(&layout)
-        }
-        #[inline]
-        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-            let ptr = self.alloc(layout.clone());
-            if !ptr.is_null() {
-                ptr::write_bytes(ptr, 0, layout.size());
-            }
-            ptr
-        }
-        #[inline]
-        unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
-            free(ptr as *mut c_void)
-        }
-        #[inline]
-        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-            self.realloc_fallback(ptr, layout, new_size)
-        }
-    }
-    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
-        let mut out = ptr::null_mut();
-        let ret = posix_memalign(&mut out, layout.align(), layout.size());
-        if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
-    }
-}
-#[cfg(windows)]
-#[allow(nonstandard_style)]
-mod platform {
-    use core::alloc::{GlobalAlloc, Layout};
-
-    use System;
-    type LPVOID = *mut u8;
-    type HANDLE = LPVOID;
-    type SIZE_T = usize;
-    type DWORD = u32;
-    type BOOL = i32;
-    extern "system" {
-        fn GetProcessHeap() -> HANDLE;
-        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
-        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
-        fn GetLastError() -> DWORD;
-    }
-    #[repr(C)]
-    struct Header(*mut u8);
-    const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
-    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
-        &mut *(ptr as *mut Header).sub(1)
-    }
-    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
-        let aligned = ptr.add(align - (ptr as usize & (align - 1)));
-        *get_header(aligned) = Header(ptr);
-        aligned
-    }
-    #[inline]
-    unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
-        let size = layout.size() + layout.align();
-        let ptr = HeapAlloc(GetProcessHeap(), flags, size);
-        (if ptr.is_null() { ptr } else { align_ptr(ptr, layout.align()) }) as *mut u8
-    }
-    unsafe impl GlobalAlloc for System {
-        #[inline]
-        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-            allocate_with_flags(layout, 0)
-        }
-        #[inline]
-        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-            allocate_with_flags(layout, HEAP_ZERO_MEMORY)
-        }
-        #[inline]
-        unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
-            let header = get_header(ptr);
-            let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
-            debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
-        }
-        #[inline]
-        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-            self.realloc_fallback(ptr, layout, new_size)
-        }
-    }
-}
diff --git a/compiler/rustc_codegen_cranelift/example/mod_bench.rs b/compiler/rustc_codegen_cranelift/example/mod_bench.rs
deleted file mode 100644
index 11a3e8fc72d..00000000000
--- a/compiler/rustc_codegen_cranelift/example/mod_bench.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-#![feature(start, core_intrinsics, lang_items)]
-#![allow(internal_features)]
-#![no_std]
-
-#[cfg_attr(unix, link(name = "c"))]
-#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
-extern "C" {}
-
-#[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
-    core::intrinsics::abort();
-}
-
-#[lang = "eh_personality"]
-fn eh_personality() {}
-
-// Required for rustc_codegen_llvm
-#[no_mangle]
-unsafe extern "C" fn _Unwind_Resume() {
-    core::intrinsics::unreachable();
-}
-
-#[start]
-fn main(_argc: isize, _argv: *const *const u8) -> isize {
-    for i in 2..10_000_000 {
-        black_box((i + 1) % i);
-    }
-
-    0
-}
-
-#[inline(never)]
-fn black_box(i: u32) {
-    if i != 1 {
-        core::intrinsics::abort();
-    }
-}
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 4b97f210579..e4c3dd708fd 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,4 +1,4 @@
 [toolchain]
-channel = "nightly-2025-01-05"
+channel = "nightly-2025-01-10"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
 profile = "minimal"
diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
index 1e14f41d4a2..ebbb6879610 100644
--- a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
@@ -16,7 +16,7 @@ fn main() {
     if let Some(name) = option_env!("BUILTIN_BACKEND") {
         rustflags.push(format!("-Zcodegen-backend={name}"));
     } else {
-        let dylib = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
+        let dylib = sysroot.join("lib").join(
             env::consts::DLL_PREFIX.to_string()
                 + "rustc_codegen_cranelift"
                 + env::consts::DLL_SUFFIX,
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
index a27b9983bf1..528031af82a 100644
--- a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
@@ -11,7 +11,7 @@ fn main() {
         sysroot = sysroot.parent().unwrap();
     }
 
-    let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
+    let cg_clif_dylib_path = sysroot.join("lib").join(
         env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
     );
 
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
index 1cad312bb79..6ebe060d8bb 100644
--- a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
@@ -11,7 +11,7 @@ fn main() {
         sysroot = sysroot.parent().unwrap();
     }
 
-    let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
+    let cg_clif_dylib_path = sysroot.join("lib").join(
         env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
     );
 
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index 734574338d0..025667e66b2 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -62,9 +62,8 @@ pub(crate) fn maybe_codegen<'tcx>(
     }
 }
 
-pub(crate) fn maybe_codegen_checked<'tcx>(
+pub(crate) fn maybe_codegen_mul_checked<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
-    bin_op: BinOp,
     lhs: CValue<'tcx>,
     rhs: CValue<'tcx>,
 ) -> Option<CValue<'tcx>> {
@@ -78,32 +77,19 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
 
     let is_signed = type_sign(lhs.layout().ty);
 
-    match bin_op {
-        BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(),
-        BinOp::Add | BinOp::Sub => None,
-        BinOp::Mul => {
-            let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
-            let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
-            let param_types = vec![
-                AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
-                AbiParam::new(types::I128),
-                AbiParam::new(types::I128),
-            ];
-            let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
-            fx.lib_call(
-                if is_signed { "__rust_i128_mulo" } else { "__rust_u128_mulo" },
-                param_types,
-                vec![],
-                &args,
-            );
-            Some(out_place.to_cvalue(fx))
-        }
-        BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
-        BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(),
-        BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
-        BinOp::Div | BinOp::Rem => unreachable!(),
-        BinOp::Cmp => unreachable!(),
-        BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(),
-        BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(),
-    }
+    let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
+    let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
+    let param_types = vec![
+        AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
+        AbiParam::new(types::I128),
+        AbiParam::new(types::I128),
+    ];
+    let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
+    fx.lib_call(
+        if is_signed { "__rust_i128_mulo" } else { "__rust_u128_mulo" },
+        param_types,
+        vec![],
+        &args,
+    );
+    Some(out_place.to_cvalue(fx))
 }
diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
index fb0eed07c19..ffd47cace38 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
@@ -73,12 +73,14 @@ impl Drop for TimingGuard {
 
 impl cranelift_codegen::timing::Profiler for MeasuremeProfiler {
     fn start_pass(&self, pass: cranelift_codegen::timing::Pass) -> Box<dyn std::any::Any> {
-        let mut timing_guard =
-            TimingGuard { profiler: std::mem::ManuallyDrop::new(self.0.clone()), inner: None };
+        let mut timing_guard = Box::new(TimingGuard {
+            profiler: std::mem::ManuallyDrop::new(self.0.clone()),
+            inner: None,
+        });
         timing_guard.inner = Some(
             unsafe { &*(&*timing_guard.profiler as &SelfProfilerRef as *const SelfProfilerRef) }
                 .generic_activity(pass.description()),
         );
-        Box::new(timing_guard)
+        timing_guard
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index fb18f45d7dc..f44e2459a78 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -2,10 +2,10 @@
 
 use crate::prelude::*;
 
-pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
+pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> IntCC {
     use BinOp::*;
     use IntCC::*;
-    Some(match bin_op {
+    match bin_op {
         Eq => Equal,
         Lt => {
             if signed {
@@ -36,8 +36,8 @@ pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
                 UnsignedGreaterThan
             }
         }
-        _ => return None,
-    })
+        _ => unreachable!(),
+    }
 }
 
 fn codegen_three_way_compare<'tcx>(
@@ -48,8 +48,8 @@ fn codegen_three_way_compare<'tcx>(
 ) -> CValue<'tcx> {
     // This emits `(lhs > rhs) - (lhs < rhs)`, which is cranelift's preferred form per
     // <https://github.com/bytecodealliance/wasmtime/blob/8052bb9e3b792503b225f2a5b2ba3bc023bff462/cranelift/codegen/src/prelude_opt.isle#L41-L47>
-    let gt_cc = crate::num::bin_op_to_intcc(BinOp::Gt, signed).unwrap();
-    let lt_cc = crate::num::bin_op_to_intcc(BinOp::Lt, signed).unwrap();
+    let gt_cc = crate::num::bin_op_to_intcc(BinOp::Gt, signed);
+    let lt_cc = crate::num::bin_op_to_intcc(BinOp::Lt, signed);
     let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs);
     let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs);
     let val = fx.bcx.ins().isub(gt, lt);
@@ -63,11 +63,7 @@ fn codegen_compare_bin_op<'tcx>(
     lhs: Value,
     rhs: Value,
 ) -> CValue<'tcx> {
-    if bin_op == BinOp::Cmp {
-        return codegen_three_way_compare(fx, signed, lhs, rhs);
-    }
-
-    let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
+    let intcc = crate::num::bin_op_to_intcc(bin_op, signed);
     let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
     CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
 }
@@ -79,7 +75,7 @@ pub(crate) fn codegen_binop<'tcx>(
     in_rhs: CValue<'tcx>,
 ) -> CValue<'tcx> {
     match bin_op {
-        BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt | BinOp::Cmp => {
+        BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
             match in_lhs.layout().ty.kind() {
                 ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
                     let signed = type_sign(in_lhs.layout().ty);
@@ -91,6 +87,16 @@ pub(crate) fn codegen_binop<'tcx>(
                 _ => {}
             }
         }
+        BinOp::Cmp => match in_lhs.layout().ty.kind() {
+            ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
+                let signed = type_sign(in_lhs.layout().ty);
+                let lhs = in_lhs.load_scalar(fx);
+                let rhs = in_rhs.load_scalar(fx);
+
+                return codegen_three_way_compare(fx, signed, lhs, rhs);
+            }
+            _ => {}
+        },
         _ => {}
     }
 
@@ -200,10 +206,6 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
     let lhs = in_lhs.load_scalar(fx);
     let rhs = in_rhs.load_scalar(fx);
 
-    if let Some(res) = crate::codegen_i128::maybe_codegen_checked(fx, bin_op, in_lhs, in_rhs) {
-        return res;
-    }
-
     let signed = type_sign(in_lhs.layout().ty);
 
     let (res, has_overflow) = match bin_op {
@@ -236,6 +238,10 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
             (val, has_overflow)
         }
         BinOp::Mul => {
+            if let Some(res) = crate::codegen_i128::maybe_codegen_mul_checked(fx, in_lhs, in_rhs) {
+                return res;
+            }
+
             let ty = fx.bcx.func.dfg.value_type(lhs);
             match ty {
                 types::I8 | types::I16 | types::I32 if !signed => {
@@ -357,14 +363,12 @@ pub(crate) fn codegen_float_binop<'tcx>(
                 _ => bug!(),
             };
 
-            let ret_val = fx.lib_call(
+            fx.lib_call(
                 name,
                 vec![AbiParam::new(ty), AbiParam::new(ty)],
                 vec![AbiParam::new(ty)],
                 &[lhs, rhs],
-            )[0];
-
-            return CValue::by_val(ret_val, in_lhs.layout());
+            )[0]
         }
         BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
             let fltcc = match bin_op {
@@ -431,13 +435,9 @@ pub(crate) fn codegen_ptr_binop<'tcx>(
             BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => {
                 let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
 
-                let ptr_cmp =
-                    fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr);
-                let extra_cmp = fx.bcx.ins().icmp(
-                    bin_op_to_intcc(bin_op, false).unwrap(),
-                    lhs_extra,
-                    rhs_extra,
-                );
+                let ptr_cmp = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false), lhs_ptr, rhs_ptr);
+                let extra_cmp =
+                    fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false), lhs_extra, rhs_extra);
 
                 fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp)
             }
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index 028a5ab5f71..69b04dd5796 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -20,7 +20,7 @@ fn inline_attr<'gcc, 'tcx>(
 ) -> Option<FnAttribute<'gcc>> {
     match inline {
         InlineAttr::Hint => Some(FnAttribute::Inline),
-        InlineAttr::Always => Some(FnAttribute::AlwaysInline),
+        InlineAttr::Always | InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline),
         InlineAttr::Never => {
             if cx.sess().target.arch != "amdgpu" {
                 Some(FnAttribute::NoInline)
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index f8454fd9960..0250064e55f 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -37,7 +37,9 @@ fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll
     }
     match inline {
         InlineAttr::Hint => Some(AttributeKind::InlineHint.create_attr(cx.llcx)),
-        InlineAttr::Always => Some(AttributeKind::AlwaysInline.create_attr(cx.llcx)),
+        InlineAttr::Always | InlineAttr::Force { .. } => {
+            Some(AttributeKind::AlwaysInline.create_attr(cx.llcx))
+        }
         InlineAttr::Never => {
             if cx.sess().target.arch != "amdgpu" {
                 Some(AttributeKind::NoInline.create_attr(cx.llcx))
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index cdb72aba36f..37b53bb5bea 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -18,6 +18,7 @@ use rustc_session::parse::feature_err;
 use rustc_session::{Session, lint};
 use rustc_span::{Ident, Span, sym};
 use rustc_target::spec::{SanitizerSet, abi};
+use tracing::debug;
 
 use crate::errors;
 use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr};
@@ -525,6 +526,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         if !attr.has_name(sym::inline) {
             return ia;
         }
+
         if attr.is_word() {
             InlineAttr::Hint
         } else if let Some(ref items) = attr.meta_item_list() {
@@ -547,6 +549,20 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             ia
         }
     });
+    codegen_fn_attrs.inline = attrs.iter().fold(codegen_fn_attrs.inline, |ia, attr| {
+        if !attr.has_name(sym::rustc_force_inline) || !tcx.features().rustc_attrs() {
+            return ia;
+        }
+
+        if attr.is_word() {
+            InlineAttr::Force { attr_span: attr.span, reason: None }
+        } else if let Some(val) = attr.value_str() {
+            InlineAttr::Force { attr_span: attr.span, reason: Some(val) }
+        } else {
+            debug!("`rustc_force_inline` not checked by attribute validation");
+            ia
+        }
+    });
 
     // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
     // but not for the code generation backend because at that point the naked function will just be
@@ -596,7 +612,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
     // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
     if tcx.features().target_feature_11()
         && tcx.is_closure_like(did.to_def_id())
-        && codegen_fn_attrs.inline != InlineAttr::Always
+        && !codegen_fn_attrs.inline.always()
     {
         let owner_id = tcx.parent(did.to_def_id());
         if tcx.def_kind(owner_id).has_codegen_attrs() {
@@ -606,22 +622,28 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         }
     }
 
-    // If a function uses #[target_feature] it can't be inlined into general
+    // If a function uses `#[target_feature]` it can't be inlined into general
     // purpose functions as they wouldn't have the right target features
-    // enabled. For that reason we also forbid #[inline(always)] as it can't be
+    // enabled. For that reason we also forbid `#[inline(always)]` as it can't be
     // respected.
-    if !codegen_fn_attrs.target_features.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always
+    //
+    // `#[rustc_force_inline]` doesn't need to be prohibited here, only
+    // `#[inline(always)]`, as forced inlining is implemented entirely within
+    // rustc (and so the MIR inliner can do any necessary checks for compatible target
+    // features).
+    //
+    // This sidesteps the LLVM blockers in enabling `target_features` +
+    // `inline(always)` to be used together (see rust-lang/rust#116573 and
+    // llvm/llvm-project#70563).
+    if !codegen_fn_attrs.target_features.is_empty()
+        && matches!(codegen_fn_attrs.inline, InlineAttr::Always)
     {
         if let Some(span) = inline_span {
-            tcx.dcx().span_err(
-                span,
-                "cannot use `#[inline(always)]` with \
-                     `#[target_feature]`",
-            );
+            tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`");
         }
     }
 
-    if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always {
+    if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline.always() {
         if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
             let hir_id = tcx.local_def_id_to_hir_id(did);
             tcx.node_span_lint(
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 3b62148abb7..31793641d75 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -93,23 +93,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     return;
                 }
 
-                if let OperandValue::Immediate(v) = cg_elem.val {
+                let try_init_all_same = |bx: &mut Bx, v| {
                     let start = dest.val.llval;
                     let size = bx.const_usize(dest.layout.size.bytes());
 
-                    // Use llvm.memset.p0i8.* to initialize all zero arrays
-                    if bx.cx().const_to_opt_u128(v, false) == Some(0) {
-                        let fill = bx.cx().const_u8(0);
-                        bx.memset(start, fill, size, dest.val.align, MemFlags::empty());
-                        return;
+                    // Use llvm.memset.p0i8.* to initialize all same byte arrays
+                    if let Some(int) = bx.cx().const_to_opt_u128(v, false) {
+                        let bytes = &int.to_le_bytes()[..cg_elem.layout.size.bytes_usize()];
+                        let first = bytes[0];
+                        if bytes[1..].iter().all(|&b| b == first) {
+                            let fill = bx.cx().const_u8(first);
+                            bx.memset(start, fill, size, dest.val.align, MemFlags::empty());
+                            return true;
+                        }
                     }
 
                     // Use llvm.memset.p0i8.* to initialize byte arrays
                     let v = bx.from_immediate(v);
                     if bx.cx().val_ty(v) == bx.cx().type_i8() {
                         bx.memset(start, v, size, dest.val.align, MemFlags::empty());
-                        return;
+                        return true;
+                    }
+                    false
+                };
+
+                match cg_elem.val {
+                    OperandValue::Immediate(v) => {
+                        if try_init_all_same(bx, v) {
+                            return;
+                        }
                     }
+                    _ => (),
                 }
 
                 let count = self
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 0c2242b810b..4861b7a4430 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -12,8 +12,6 @@ const_eval_already_reported =
 const_eval_assume_false =
     `assume` called with `false`
 
-const_eval_await_non_const =
-    cannot convert `{$ty}` into a future in {const_eval_const_context}s
 const_eval_bounds_check_failed =
     indexing out of bounds: the len is {$len} but the index is {$index}
 const_eval_call_nonzero_intrinsic =
@@ -23,11 +21,6 @@ const_eval_closure_call =
     closures need an RFC before allowed to be called in {const_eval_const_context}s
 const_eval_closure_fndef_not_const =
     function defined here, but it is not `const`
-const_eval_closure_non_const =
-    cannot call non-const closure in {const_eval_const_context}s
-
-const_eval_conditionally_const_call =
-    cannot call conditionally-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s
 
 const_eval_consider_dereferencing =
     consider dereferencing here
@@ -62,10 +55,6 @@ const_eval_dealloc_incorrect_layout =
 const_eval_dealloc_kind_mismatch =
     deallocating {$alloc}, which is {$alloc_kind} memory, using {$kind} deallocation operation
 
-const_eval_deref_coercion_non_const =
-    cannot perform deref coercion on `{$ty}` in {const_eval_const_context}s
-    .note = attempting to deref into `{$target_ty}`
-    .target_note = deref defined here
 const_eval_deref_function_pointer =
     accessing {$allocation} which contains a function
 const_eval_deref_vtable_pointer =
@@ -109,9 +98,6 @@ const_eval_extern_type_field = `extern type` field does not have a known offset
 
 const_eval_fn_ptr_call =
     function pointers need an RFC before allowed to be called in {const_eval_const_context}s
-const_eval_for_loop_into_iter_non_const =
-    cannot use `for` loop on `{$ty}` in {const_eval_const_context}s
-
 const_eval_frame_note = {$times ->
     [0] {const_eval_frame_note_inner}
     *[other] [... {$times} additional calls {const_eval_frame_note_inner} ...]
@@ -216,9 +202,6 @@ const_eval_long_running =
     .label = the const evaluator is currently interpreting this expression
     .help = the constant being evaluated
 
-const_eval_match_eq_non_const = cannot match on `{$ty}` in {const_eval_const_context}s
-    .note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es
-
 const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
 
 const_eval_memory_access_test = memory access failed
@@ -249,11 +232,26 @@ const_eval_mutable_ref_escaping =
         If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
 
 const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
+
+const_eval_non_const_await =
+    cannot convert `{$ty}` into a future in {const_eval_const_context}s
+
+const_eval_non_const_closure =
+    cannot call {$non_or_conditionally}-const closure in {const_eval_const_context}s
+
+const_eval_non_const_deref_coercion =
+    cannot perform {$non_or_conditionally}-const deref coercion on `{$ty}` in {const_eval_const_context}s
+    .note = attempting to deref into `{$target_ty}`
+    .target_note = deref defined here
+
 const_eval_non_const_fmt_macro_call =
-    cannot call non-const formatting macro in {const_eval_const_context}s
+    cannot call {$non_or_conditionally}-const formatting macro in {const_eval_const_context}s
 
 const_eval_non_const_fn_call =
-    cannot call non-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s
+    cannot call {$non_or_conditionally}-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s
+
+const_eval_non_const_for_loop_into_iter =
+    cannot use `for` loop on `{$ty}` in {const_eval_const_context}s
 
 const_eval_non_const_impl =
     impl defined here, but it is not `const`
@@ -261,6 +259,20 @@ const_eval_non_const_impl =
 const_eval_non_const_intrinsic =
     cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s
 
+const_eval_non_const_match_eq = cannot match on `{$ty}` in {const_eval_const_context}s
+    .note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es
+
+const_eval_non_const_operator =
+    cannot call {$non_or_conditionally}-const operator in {const_eval_const_context}s
+
+const_eval_non_const_question_branch =
+    `?` is not allowed on `{$ty}` in {const_eval_const_context}s
+const_eval_non_const_question_from_residual =
+    `?` is not allowed on `{$ty}` in {const_eval_const_context}s
+
+const_eval_non_const_try_block_from_output =
+    `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s
+
 const_eval_not_enough_caller_args =
     calling a function with fewer arguments than it requires
 
@@ -281,8 +293,6 @@ const_eval_offset_from_unsigned_overflow =
         *[false] offset
     } than second: {$a_offset} < {$b_offset}
 
-const_eval_operator_non_const =
-    cannot call non-const operator in {const_eval_const_context}s
 const_eval_overflow_arith =
     arithmetic overflow in `{$intrinsic}`
 const_eval_overflow_shift =
@@ -325,11 +335,6 @@ const_eval_ptr_as_bytes_1 =
 const_eval_ptr_as_bytes_2 =
     the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
-const_eval_question_branch_non_const =
-    `?` is not allowed on `{$ty}` in {const_eval_const_context}s
-const_eval_question_from_residual_non_const =
-    `?` is not allowed on `{$ty}` in {const_eval_const_context}s
-
 const_eval_range = in the range {$lo}..={$hi}
 const_eval_range_lower = greater or equal to {$lo}
 const_eval_range_singular = equal to {$lo}
@@ -379,8 +384,6 @@ const_eval_too_generic =
 const_eval_too_many_caller_args =
     calling a function with more arguments than it expected
 
-const_eval_try_block_from_output_non_const =
-    `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s
 const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s
 
 const_eval_unallowed_heap_allocations =
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index e895c44199b..015e1671682 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -708,7 +708,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
                     if trait_is_const {
                         // Trait calls are always conditionally-const.
-                        self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
+                        self.check_op(ops::ConditionallyConstCall {
+                            callee,
+                            args: fn_args,
+                            span: *fn_span,
+                            call_source,
+                        });
                         // FIXME(const_trait_impl): do a more fine-grained check whether this
                         // particular trait can be const-stably called.
                     } else {
@@ -726,7 +731,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
                 // Even if we know the callee, ensure we can use conditionally-const calls.
                 if has_const_conditions {
-                    self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
+                    self.check_op(ops::ConditionallyConstCall {
+                        callee,
+                        args: fn_args,
+                        span: *fn_span,
+                        call_source,
+                    });
                 }
 
                 // At this point, we are calling a function, `callee`, whose `DefId` is known...
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index ebd680ac28a..6707ebe7d1c 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -15,6 +15,7 @@ use rustc_middle::ty::{
     suggest_constraining_type_param,
 };
 use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind};
+use rustc_session::parse::add_feature_diagnostics;
 use rustc_span::{BytePos, Pos, Span, Symbol, sym};
 use rustc_trait_selection::traits::SelectionContext;
 use tracing::debug;
@@ -77,6 +78,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
 pub(crate) struct ConditionallyConstCall<'tcx> {
     pub callee: DefId,
     pub args: GenericArgsRef<'tcx>,
+    pub span: Span,
+    pub call_source: CallSource,
 }
 
 impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> {
@@ -91,16 +94,22 @@ impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> {
         }
     }
 
-    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
-        ccx.tcx.sess.create_feature_err(
-            errors::ConditionallyConstCall {
-                span,
-                def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args),
-                def_descr: ccx.tcx.def_descr(self.callee),
-                kind: ccx.const_kind(),
-            },
-            sym::const_trait_impl,
-        )
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
+        let mut diag = build_error_for_const_call(
+            ccx,
+            self.callee,
+            self.args,
+            self.span,
+            self.call_source,
+            "conditionally",
+            |_, _, _| {},
+        );
+
+        // Override code and mention feature.
+        diag.code(E0658);
+        add_feature_diagnostics(&mut diag, ccx.tcx.sess, sym::const_trait_impl);
+
+        diag
     }
 }
 
@@ -118,210 +127,250 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
     #[allow(rustc::diagnostic_outside_of_impl)]
     #[allow(rustc::untranslatable_diagnostic)]
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
-        let FnCallNonConst { callee, args, span, call_source } = *self;
-        let ConstCx { tcx, typing_env, .. } = *ccx;
+        let tcx = ccx.tcx;
         let caller = ccx.def_id();
 
-        let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
-            let trait_ref = TraitRef::from_method(tcx, trait_id, args);
-
-            match self_ty.kind() {
-                Param(param_ty) => {
-                    debug!(?param_ty);
-                    if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() {
-                        let constraint = with_no_trimmed_paths!(format!(
-                            "~const {}",
-                            trait_ref.print_trait_sugared(),
-                        ));
-                        suggest_constraining_type_param(
-                            tcx,
-                            generics,
-                            err,
-                            param_ty.name.as_str(),
-                            &constraint,
-                            Some(trait_ref.def_id),
-                            None,
-                        );
+        let mut err = build_error_for_const_call(
+            ccx,
+            self.callee,
+            self.args,
+            self.span,
+            self.call_source,
+            "non",
+            |err, self_ty, trait_id| {
+                // FIXME(const_trait_impl): Do we need any of this on the non-const codepath?
+
+                let trait_ref = TraitRef::from_method(tcx, trait_id, self.args);
+
+                match self_ty.kind() {
+                    Param(param_ty) => {
+                        debug!(?param_ty);
+                        if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() {
+                            let constraint = with_no_trimmed_paths!(format!(
+                                "~const {}",
+                                trait_ref.print_trait_sugared(),
+                            ));
+                            suggest_constraining_type_param(
+                                tcx,
+                                generics,
+                                err,
+                                param_ty.name.as_str(),
+                                &constraint,
+                                Some(trait_ref.def_id),
+                                None,
+                            );
+                        }
                     }
-                }
-                ty::Adt(..) => {
-                    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
-                    let obligation =
-                        Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
-                    let mut selcx = SelectionContext::new(&infcx);
-                    let implsrc = selcx.select(&obligation);
-                    if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
-                        // FIXME(const_trait_impl) revisit this
-                        if !tcx.is_const_trait_impl(data.impl_def_id) {
-                            let span = tcx.def_span(data.impl_def_id);
-                            err.subdiagnostic(errors::NonConstImplNote { span });
+                    ty::Adt(..) => {
+                        let (infcx, param_env) =
+                            tcx.infer_ctxt().build_with_typing_env(ccx.typing_env);
+                        let obligation =
+                            Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
+                        let mut selcx = SelectionContext::new(&infcx);
+                        let implsrc = selcx.select(&obligation);
+                        if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
+                            // FIXME(const_trait_impl) revisit this
+                            if !tcx.is_const_trait_impl(data.impl_def_id) {
+                                let span = tcx.def_span(data.impl_def_id);
+                                err.subdiagnostic(errors::NonConstImplNote { span });
+                            }
                         }
                     }
+                    _ => {}
                 }
-                _ => {}
+            },
+        );
+
+        if let ConstContext::Static(_) = ccx.const_kind() {
+            err.note(fluent_generated::const_eval_lazy_lock);
+        }
+
+        err
+    }
+}
+
+/// Build an error message reporting that a function call is not const (or only
+/// conditionally const). In case that this call is desugared (like an operator
+/// or sugar from something like a `for` loop), try to build a better error message
+/// that doesn't call it a method.
+fn build_error_for_const_call<'tcx>(
+    ccx: &ConstCx<'_, 'tcx>,
+    callee: DefId,
+    args: ty::GenericArgsRef<'tcx>,
+    span: Span,
+    call_source: CallSource,
+    non_or_conditionally: &'static str,
+    note_trait_if_possible: impl FnOnce(&mut Diag<'tcx>, Ty<'tcx>, DefId),
+) -> Diag<'tcx> {
+    let tcx = ccx.tcx;
+
+    let call_kind =
+        call_kind(tcx, ccx.typing_env, callee, args, span, call_source.from_hir_call(), None);
+
+    debug!(?call_kind);
+
+    let mut err = match call_kind {
+        CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
+            macro_rules! error {
+                ($err:ident) => {
+                    tcx.dcx().create_err(errors::$err {
+                        span,
+                        ty: self_ty,
+                        kind: ccx.const_kind(),
+                        non_or_conditionally,
+                    })
+                };
             }
-        };
-
-        let call_kind =
-            call_kind(tcx, ccx.typing_env, callee, args, span, call_source.from_hir_call(), None);
-
-        debug!(?call_kind);
-
-        let mut err = match call_kind {
-            CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
-                macro_rules! error {
-                    ($err:ident) => {
-                        tcx.dcx().create_err(errors::$err {
-                            span,
-                            ty: self_ty,
-                            kind: ccx.const_kind(),
-                        })
-                    };
-                }
 
-                // Don't point at the trait if this is a desugaring...
-                // FIXME(const_trait_impl): we could perhaps do this for `Iterator`.
-                match kind {
-                    CallDesugaringKind::ForLoopIntoIter | CallDesugaringKind::ForLoopNext => {
-                        error!(NonConstForLoopIntoIter)
-                    }
-                    CallDesugaringKind::QuestionBranch => {
-                        error!(NonConstQuestionBranch)
-                    }
-                    CallDesugaringKind::QuestionFromResidual => {
-                        error!(NonConstQuestionFromResidual)
-                    }
-                    CallDesugaringKind::TryBlockFromOutput => {
-                        error!(NonConstTryBlockFromOutput)
-                    }
-                    CallDesugaringKind::Await => {
-                        error!(NonConstAwait)
-                    }
+            // Don't point at the trait if this is a desugaring...
+            // FIXME(const_trait_impl): we could perhaps do this for `Iterator`.
+            match kind {
+                CallDesugaringKind::ForLoopIntoIter | CallDesugaringKind::ForLoopNext => {
+                    error!(NonConstForLoopIntoIter)
+                }
+                CallDesugaringKind::QuestionBranch => {
+                    error!(NonConstQuestionBranch)
+                }
+                CallDesugaringKind::QuestionFromResidual => {
+                    error!(NonConstQuestionFromResidual)
+                }
+                CallDesugaringKind::TryBlockFromOutput => {
+                    error!(NonConstTryBlockFromOutput)
+                }
+                CallDesugaringKind::Await => {
+                    error!(NonConstAwait)
                 }
             }
-            CallKind::FnCall { fn_trait_id, self_ty } => {
-                let note = match self_ty.kind() {
-                    FnDef(def_id, ..) => {
-                        let span = tcx.def_span(*def_id);
-                        if ccx.tcx.is_const_fn(*def_id) {
-                            span_bug!(span, "calling const FnDef errored when it shouldn't");
-                        }
-
-                        Some(errors::NonConstClosureNote::FnDef { span })
+        }
+        CallKind::FnCall { fn_trait_id, self_ty } => {
+            let note = match self_ty.kind() {
+                FnDef(def_id, ..) => {
+                    let span = tcx.def_span(*def_id);
+                    if ccx.tcx.is_const_fn(*def_id) {
+                        span_bug!(span, "calling const FnDef errored when it shouldn't");
                     }
-                    FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr),
-                    Closure(..) => Some(errors::NonConstClosureNote::Closure),
-                    _ => None,
-                };
 
-                let mut err = tcx.dcx().create_err(errors::NonConstClosure {
+                    Some(errors::NonConstClosureNote::FnDef { span })
+                }
+                FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr),
+                Closure(..) => Some(errors::NonConstClosureNote::Closure),
+                _ => None,
+            };
+
+            let mut err = tcx.dcx().create_err(errors::NonConstClosure {
+                span,
+                kind: ccx.const_kind(),
+                note,
+                non_or_conditionally,
+            });
+
+            note_trait_if_possible(&mut err, self_ty, fn_trait_id);
+            err
+        }
+        CallKind::Operator { trait_id, self_ty, .. } => {
+            let mut err = if let CallSource::MatchCmp = call_source {
+                tcx.dcx().create_err(errors::NonConstMatchEq {
                     span,
                     kind: ccx.const_kind(),
-                    note,
-                });
-
-                diag_trait(&mut err, self_ty, fn_trait_id);
-                err
-            }
-            CallKind::Operator { trait_id, self_ty, .. } => {
-                let mut err = if let CallSource::MatchCmp = call_source {
-                    tcx.dcx().create_err(errors::NonConstMatchEq {
-                        span,
-                        kind: ccx.const_kind(),
-                        ty: self_ty,
-                    })
-                } else {
-                    let mut sugg = None;
-
-                    if ccx.tcx.is_lang_item(trait_id, LangItem::PartialEq) {
-                        match (args[0].unpack(), args[1].unpack()) {
-                            (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
-                                if self_ty == rhs_ty
-                                    && self_ty.is_ref()
-                                    && self_ty.peel_refs().is_primitive() =>
-                            {
-                                let mut num_refs = 0;
-                                let mut tmp_ty = self_ty;
-                                while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
-                                    num_refs += 1;
-                                    tmp_ty = *inner_ty;
-                                }
-                                let deref = "*".repeat(num_refs);
-
-                                if let Ok(call_str) =
-                                    ccx.tcx.sess.source_map().span_to_snippet(span)
-                                {
-                                    if let Some(eq_idx) = call_str.find("==") {
-                                        if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
-                                            .find(|c: char| !c.is_whitespace())
-                                        {
-                                            let rhs_pos = span.lo()
-                                                + BytePos::from_usize(eq_idx + 2 + rhs_idx);
-                                            let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
-                                            sugg = Some(errors::ConsiderDereferencing {
-                                                deref,
-                                                span: span.shrink_to_lo(),
-                                                rhs_span,
-                                            });
-                                        }
+                    ty: self_ty,
+                    non_or_conditionally,
+                })
+            } else {
+                let mut sugg = None;
+
+                if ccx.tcx.is_lang_item(trait_id, LangItem::PartialEq) {
+                    match (args[0].unpack(), args[1].unpack()) {
+                        (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
+                            if self_ty == rhs_ty
+                                && self_ty.is_ref()
+                                && self_ty.peel_refs().is_primitive() =>
+                        {
+                            let mut num_refs = 0;
+                            let mut tmp_ty = self_ty;
+                            while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
+                                num_refs += 1;
+                                tmp_ty = *inner_ty;
+                            }
+                            let deref = "*".repeat(num_refs);
+
+                            if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
+                                if let Some(eq_idx) = call_str.find("==") {
+                                    if let Some(rhs_idx) =
+                                        call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
+                                    {
+                                        let rhs_pos =
+                                            span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
+                                        let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
+                                        sugg = Some(errors::ConsiderDereferencing {
+                                            deref,
+                                            span: span.shrink_to_lo(),
+                                            rhs_span,
+                                        });
                                     }
                                 }
                             }
-                            _ => {}
                         }
+                        _ => {}
                     }
-                    tcx.dcx().create_err(errors::NonConstOperator {
-                        span,
-                        kind: ccx.const_kind(),
-                        sugg,
-                    })
-                };
-
-                diag_trait(&mut err, self_ty, trait_id);
-                err
-            }
-            CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
-                // Check first whether the source is accessible (issue #87060)
-                let target = if tcx.sess.source_map().is_span_accessible(deref_target) {
-                    Some(deref_target)
-                } else {
-                    None
-                };
-
-                let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion {
+                }
+                tcx.dcx().create_err(errors::NonConstOperator {
                     span,
-                    ty: self_ty,
                     kind: ccx.const_kind(),
-                    target_ty: deref_target_ty,
-                    deref_target: target,
-                });
+                    sugg,
+                    non_or_conditionally,
+                })
+            };
 
-                diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span)));
-                err
-            }
-            _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => {
-                ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() })
-            }
-            _ => ccx.dcx().create_err(errors::NonConstFnCall {
+            note_trait_if_possible(&mut err, self_ty, trait_id);
+            err
+        }
+        CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
+            // Check first whether the source is accessible (issue #87060)
+            let target = if tcx.sess.source_map().is_span_accessible(deref_target) {
+                Some(deref_target)
+            } else {
+                None
+            };
+
+            let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion {
                 span,
-                def_descr: ccx.tcx.def_descr(callee),
-                def_path_str: ccx.tcx.def_path_str_with_args(callee, args),
+                ty: self_ty,
                 kind: ccx.const_kind(),
-            }),
-        };
+                target_ty: deref_target_ty,
+                deref_target: target,
+                non_or_conditionally,
+            });
+
+            note_trait_if_possible(
+                &mut err,
+                self_ty,
+                tcx.require_lang_item(LangItem::Deref, Some(span)),
+            );
+            err
+        }
+        _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => {
+            ccx.dcx().create_err(errors::NonConstFmtMacroCall {
+                span,
+                kind: ccx.const_kind(),
+                non_or_conditionally,
+            })
+        }
+        _ => ccx.dcx().create_err(errors::NonConstFnCall {
+            span,
+            def_descr: ccx.tcx.def_descr(callee),
+            def_path_str: ccx.tcx.def_path_str_with_args(callee, args),
+            kind: ccx.const_kind(),
+            non_or_conditionally,
+        }),
+    };
 
-        err.note(format!(
-            "calls in {}s are limited to constant functions, \
+    err.note(format!(
+        "calls in {}s are limited to constant functions, \
              tuple structs and tuple variants",
-            ccx.const_kind(),
-        ));
-
-        if let ConstContext::Static(_) = ccx.const_kind() {
-            err.note(fluent_generated::const_eval_lazy_lock);
-        }
+        ccx.const_kind(),
+    ));
 
-        err
-    }
+    err
 }
 
 /// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function.
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 57534540019..3fe78171cd9 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -174,16 +174,7 @@ pub(crate) struct NonConstFmtMacroCall {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
-}
-
-#[derive(Diagnostic)]
-#[diag(const_eval_conditionally_const_call)]
-pub(crate) struct ConditionallyConstCall {
-    #[primary_span]
-    pub span: Span,
-    pub def_path_str: String,
-    pub def_descr: &'static str,
-    pub kind: ConstContext,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Diagnostic)]
@@ -194,6 +185,7 @@ pub(crate) struct NonConstFnCall {
     pub def_path_str: String,
     pub def_descr: &'static str,
     pub kind: ConstContext,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Diagnostic)]
@@ -293,68 +285,75 @@ pub struct RawBytesNote {
 // FIXME(fee1-dead) do not use stringly typed `ConstContext`
 
 #[derive(Diagnostic)]
-#[diag(const_eval_match_eq_non_const, code = E0015)]
+#[diag(const_eval_non_const_match_eq, code = E0015)]
 #[note]
 pub struct NonConstMatchEq<'tcx> {
     #[primary_span]
     pub span: Span,
     pub ty: Ty<'tcx>,
     pub kind: ConstContext,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_for_loop_into_iter_non_const, code = E0015)]
+#[diag(const_eval_non_const_for_loop_into_iter, code = E0015)]
 pub struct NonConstForLoopIntoIter<'tcx> {
     #[primary_span]
     pub span: Span,
     pub ty: Ty<'tcx>,
     pub kind: ConstContext,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_question_branch_non_const, code = E0015)]
+#[diag(const_eval_non_const_question_branch, code = E0015)]
 pub struct NonConstQuestionBranch<'tcx> {
     #[primary_span]
     pub span: Span,
     pub ty: Ty<'tcx>,
     pub kind: ConstContext,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_question_from_residual_non_const, code = E0015)]
+#[diag(const_eval_non_const_question_from_residual, code = E0015)]
 pub struct NonConstQuestionFromResidual<'tcx> {
     #[primary_span]
     pub span: Span,
     pub ty: Ty<'tcx>,
     pub kind: ConstContext,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_try_block_from_output_non_const, code = E0015)]
+#[diag(const_eval_non_const_try_block_from_output, code = E0015)]
 pub struct NonConstTryBlockFromOutput<'tcx> {
     #[primary_span]
     pub span: Span,
     pub ty: Ty<'tcx>,
     pub kind: ConstContext,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_await_non_const, code = E0015)]
+#[diag(const_eval_non_const_await, code = E0015)]
 pub struct NonConstAwait<'tcx> {
     #[primary_span]
     pub span: Span,
     pub ty: Ty<'tcx>,
     pub kind: ConstContext,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_closure_non_const, code = E0015)]
+#[diag(const_eval_non_const_closure, code = E0015)]
 pub struct NonConstClosure {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
     #[subdiagnostic]
     pub note: Option<NonConstClosureNote>,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Subdiagnostic)]
@@ -381,17 +380,18 @@ pub struct ConsiderDereferencing {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_operator_non_const, code = E0015)]
+#[diag(const_eval_non_const_operator, code = E0015)]
 pub struct NonConstOperator {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
     #[subdiagnostic]
     pub sugg: Option<ConsiderDereferencing>,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_deref_coercion_non_const, code = E0015)]
+#[diag(const_eval_non_const_deref_coercion, code = E0015)]
 #[note]
 pub struct NonConstDerefCoercion<'tcx> {
     #[primary_span]
@@ -401,6 +401,7 @@ pub struct NonConstDerefCoercion<'tcx> {
     pub target_ty: Ty<'tcx>,
     #[note(const_eval_target_note)]
     pub deref_target: Option<Span>,
+    pub non_or_conditionally: &'static str,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 5421517046d..c28a4360f6f 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -572,7 +572,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // `#[coroutine]` attribute to be applied to closures to make them coroutines instead
     gated!(
         coroutine, Normal, template!(Word), ErrorFollowing,
-        EncodeCrossCrate::No, coroutines, experimental!(coroutines)
+        EncodeCrossCrate::No, coroutines, experimental!(coroutine)
     ),
 
     // RFC 3543
@@ -1019,6 +1019,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
         "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
     ),
+    rustc_attr!(
+        rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
+        "#![rustc_force_inline] forces a free function to be inlined"
+    ),
 
     // ==========================================================================
     // Internal attributes, Testing:
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index e5f98bdfb7f..83c69dc2ef4 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -31,7 +31,7 @@ struct Context {
     parent: Option<(Scope, ScopeDepth)>,
 }
 
-struct RegionResolutionVisitor<'tcx> {
+struct ScopeResolutionVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
 
     // The number of expressions and patterns visited in the current body.
@@ -71,7 +71,7 @@ struct RegionResolutionVisitor<'tcx> {
 }
 
 /// Records the lifetime of a local variable as `cx.var_parent`
-fn record_var_lifetime(visitor: &mut RegionResolutionVisitor<'_>, var_id: hir::ItemLocalId) {
+fn record_var_lifetime(visitor: &mut ScopeResolutionVisitor<'_>, var_id: hir::ItemLocalId) {
     match visitor.cx.var_parent {
         None => {
             // this can happen in extern fn declarations like
@@ -82,7 +82,7 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor<'_>, var_id: hir::I
     }
 }
 
-fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx hir::Block<'tcx>) {
+fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hir::Block<'tcx>) {
     debug!("resolve_block(blk.hir_id={:?})", blk.hir_id);
 
     let prev_cx = visitor.cx;
@@ -193,7 +193,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
     visitor.cx = prev_cx;
 }
 
-fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
+fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
     fn has_let_expr(expr: &Expr<'_>) -> bool {
         match &expr.kind {
             hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
@@ -220,7 +220,7 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir
     visitor.cx = prev_cx;
 }
 
-fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
+fn resolve_pat<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
     visitor.record_child_scope(Scope { local_id: pat.hir_id.local_id, data: ScopeData::Node });
 
     // If this is a binding then record the lifetime of that binding.
@@ -237,7 +237,7 @@ fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir
     debug!("resolve_pat - post-increment {} pat = {:?}", visitor.expr_and_pat_count, pat);
 }
 
-fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx hir::Stmt<'tcx>) {
+fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hir::Stmt<'tcx>) {
     let stmt_id = stmt.hir_id.local_id;
     debug!("resolve_stmt(stmt.id={:?})", stmt_id);
 
@@ -256,7 +256,7 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h
     visitor.cx.parent = prev_parent;
 }
 
-fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
     debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr);
 
     let prev_cx = visitor.cx;
@@ -420,10 +420,10 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
     // properly, we can't miss any types.
 
     match expr.kind {
-        // Manually recurse over closures and inline consts, because they are the only
-        // case of nested bodies that share the parent environment.
-        hir::ExprKind::Closure(&hir::Closure { body, .. })
-        | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => {
+        // Manually recurse over closures, because they are nested bodies
+        // that share the parent environment. We handle const blocks in
+        // `visit_inline_const`.
+        hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let body = visitor.tcx.hir().body(body);
             visitor.visit_body(body);
         }
@@ -554,7 +554,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
 }
 
 fn resolve_local<'tcx>(
-    visitor: &mut RegionResolutionVisitor<'tcx>,
+    visitor: &mut ScopeResolutionVisitor<'tcx>,
     pat: Option<&'tcx hir::Pat<'tcx>>,
     init: Option<&'tcx hir::Expr<'tcx>>,
 ) {
@@ -725,7 +725,7 @@ fn resolve_local<'tcx>(
     ///        | ( E& )
     /// ```
     fn record_rvalue_scope_if_borrow_expr<'tcx>(
-        visitor: &mut RegionResolutionVisitor<'tcx>,
+        visitor: &mut ScopeResolutionVisitor<'tcx>,
         expr: &hir::Expr<'_>,
         blk_id: Option<Scope>,
     ) {
@@ -782,7 +782,7 @@ fn resolve_local<'tcx>(
     }
 }
 
-impl<'tcx> RegionResolutionVisitor<'tcx> {
+impl<'tcx> ScopeResolutionVisitor<'tcx> {
     /// Records the current parent (if any) as the parent of `child_scope`.
     /// Returns the depth of `child_scope`.
     fn record_child_scope(&mut self, child_scope: Scope) -> ScopeDepth {
@@ -838,7 +838,7 @@ impl<'tcx> RegionResolutionVisitor<'tcx> {
     }
 }
 
-impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
+impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
     fn visit_block(&mut self, b: &'tcx Block<'tcx>) {
         resolve_block(self, b);
     }
@@ -906,6 +906,10 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
     fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) {
         resolve_local(self, Some(l.pat), l.init)
     }
+    fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
+        let body = self.tcx.hir().body(c.body);
+        self.visit_body(body);
+    }
 }
 
 /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
@@ -922,7 +926,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
     }
 
     let scope_tree = if let Some(body) = tcx.hir().maybe_body_owned_by(def_id.expect_local()) {
-        let mut visitor = RegionResolutionVisitor {
+        let mut visitor = ScopeResolutionVisitor {
             tcx,
             scope_tree: ScopeTree::default(),
             expr_and_pat_count: 0,
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 0c19e2e4c51..1569c0963c8 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -1036,7 +1036,7 @@ pub(super) fn const_conditions<'tcx>(
 
         icx.lowerer().lower_bounds(
             tcx.types.self_param,
-            supertraits.into_iter(),
+            supertraits,
             &mut bounds,
             ty::List::empty(),
             PredicateFilter::ConstIfConst,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 0a41dad0dd8..cb90fff782f 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -35,7 +35,7 @@ use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::middle::stability::AllowUnstable;
-use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::mir::interpret::LitToConstInput;
 use rustc_middle::ty::fold::fold_regions;
 use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
 use rustc_middle::ty::{
@@ -2262,25 +2262,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             _ => None,
         };
 
-        if let Some(lit_input) = lit_input {
-            // If an error occurred, ignore that it's a literal and leave reporting the error up to
-            // mir.
-            match tcx.at(expr.span).lit_to_const(lit_input) {
-                Ok(c) => return Some(c),
-                Err(_) if lit_input.ty.has_aliases() => {
-                    // allow the `ty` to be an alias type, though we cannot handle it here
-                    return None;
-                }
-                Err(e) => {
-                    tcx.dcx().span_delayed_bug(
-                        expr.span,
-                        format!("try_lower_anon_const_lit: couldn't lit_to_const {e:?}"),
-                    );
-                }
-            }
-        }
-
-        None
+        lit_input
+            // Allow the `ty` to be an alias type, though we cannot handle it here, we just go through
+            // the more expensive anon const code path.
+            .filter(|l| !l.ty.has_aliases())
+            .map(|l| tcx.at(expr.span).lit_to_const(l))
     }
 
     fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
@@ -2454,13 +2440,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                 hir::PatExprKind::Lit { lit, negated } => {
                                     let lit_input =
                                         LitToConstInput { lit: &lit.node, ty, neg: negated };
-                                    let ct = match tcx.lit_to_const(lit_input) {
-                                        Ok(c) => c,
-                                        Err(LitToConstError::Reported(err)) => {
-                                            ty::Const::new_error(tcx, err)
-                                        }
-                                        Err(LitToConstError::TypeError) => todo!(),
-                                    };
+                                    let ct = tcx.lit_to_const(lit_input);
                                     (ct, ty)
                                 }
 
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index bd26be11279..9ebc7a4657e 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -38,6 +38,7 @@
 use std::ops::Deref;
 
 use rustc_abi::ExternAbi;
+use rustc_attr_parsing::InlineAttr;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, struct_span_code_err};
 use rustc_hir as hir;
@@ -926,8 +927,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                         return Err(TypeError::IntrinsicCast);
                     }
 
-                    // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
+                    let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
+                    if matches!(fn_attrs.inline, InlineAttr::Force { .. }) {
+                        return Err(TypeError::ForceInlineCast);
+                    }
 
+                    // Safe `#[target_feature]` functions are not assignable to safe fn pointers
+                    // (RFC 2396).
                     if b_hdr.safety.is_safe()
                         && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
                     {
@@ -1197,6 +1203,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return Ok(prev_ty);
         }
 
+        let is_force_inline = |ty: Ty<'tcx>| {
+            if let ty::FnDef(did, _) = ty.kind() {
+                matches!(self.tcx.codegen_fn_attrs(did).inline, InlineAttr::Force { .. })
+            } else {
+                false
+            }
+        };
+        if is_force_inline(prev_ty) || is_force_inline(new_ty) {
+            return Err(TypeError::ForceInlineCast);
+        }
+
         // Special-case that coercion alone cannot handle:
         // Function items or non-capturing closures of differing IDs or GenericArgs.
         let (a_sig, b_sig) = {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 72a1e4af9bf..b3d87ef4ad2 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1096,7 +1096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     )
                 ) {
                     continue;
-                };
+                }
 
                 match self.tcx.hir().get_if_local(item_def_id) {
                     // Unmet obligation comes from a `derive` macro, point at it once to
@@ -1210,8 +1210,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
                         entry.2.push(p);
                     }
-                    Some(node) => unreachable!("encountered `{node:?}` due to `{cause:#?}`"),
-                    None => (),
+                    _ => {
+                        // It's possible to use well-formedness clauses to get obligations
+                        // which point arbitrary items like ADTs, so there's no use in ICEing
+                        // here if we find that the obligation originates from some other
+                        // node that we don't handle.
+                    }
                 }
             }
             let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 8d73c9e76de..b88137544bc 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -16,7 +16,6 @@ use rustc_abi::{AddressSpace, Align, Endian, HasDataLayout, Size};
 use rustc_ast::{LitKind, Mutability};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
-use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
@@ -84,16 +83,6 @@ pub struct LitToConstInput<'tcx> {
     pub neg: bool,
 }
 
-/// Error type for `tcx.lit_to_const`.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable)]
-pub enum LitToConstError {
-    /// The literal's inferred type did not match the expected `ty` in the input.
-    /// This is used for graceful error handling (`span_delayed_bug`) in
-    /// type checking (`Const::from_anon_const`).
-    TypeError,
-    Reported(ErrorGuaranteed),
-}
-
 #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
 pub struct AllocId(pub NonZero<u64>);
 
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 27168b2a9f2..111c3b6956a 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -132,9 +132,10 @@ impl<'tcx> MonoItem<'tcx> {
                 // creating one copy of this `#[inline]` function which may
                 // conflict with upstream crates as it could be an exported
                 // symbol.
-                match tcx.codegen_fn_attrs(instance.def_id()).inline {
-                    InlineAttr::Always => InstantiationMode::LocalCopy,
-                    _ => InstantiationMode::GloballyShared { may_conflict: true },
+                if tcx.codegen_fn_attrs(instance.def_id()).inline.always() {
+                    InstantiationMode::LocalCopy
+                } else {
+                    InstantiationMode::GloballyShared { may_conflict: true }
                 }
             }
             MonoItem::Static(..) | MonoItem::GlobalAsm(..) => {
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index b72c0e776fe..1676afb4b6e 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -141,14 +141,6 @@ impl EraseType for Result<rustc_abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::Layou
     >()];
 }
 
-impl EraseType for Result<ty::Const<'_>, mir::interpret::LitToConstError> {
-    type Result = [u8; size_of::<Result<ty::Const<'static>, mir::interpret::LitToConstError>>()];
-}
-
-impl EraseType for Result<mir::Const<'_>, mir::interpret::LitToConstError> {
-    type Result = [u8; size_of::<Result<mir::Const<'static>, mir::interpret::LitToConstError>>()];
-}
-
 impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
     type Result = [u8; size_of::<Result<mir::ConstAlloc<'static>, mir::interpret::ErrorHandled>>()];
 }
@@ -296,7 +288,6 @@ trivial! {
     rustc_middle::mir::interpret::AllocId,
     rustc_middle::mir::interpret::CtfeProvenance,
     rustc_middle::mir::interpret::ErrorHandled,
-    rustc_middle::mir::interpret::LitToConstError,
     rustc_middle::thir::ExprId,
     rustc_middle::traits::CodegenObligationError,
     rustc_middle::traits::EvaluationResult,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 95995b956cd..283675573d4 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -57,7 +57,7 @@ use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars,
 use crate::middle::stability::{self, DeprecationEntry};
 use crate::mir::interpret::{
     EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
-    EvalToValTreeResult, GlobalId, LitToConstError, LitToConstInput,
+    EvalToValTreeResult, GlobalId, LitToConstInput,
 };
 use crate::mir::mono::{CodegenUnit, CollectionMode, MonoItem};
 use crate::query::erase::{Erase, erase, restore};
@@ -1268,7 +1268,7 @@ rustc_queries! {
     // FIXME get rid of this with valtrees
     query lit_to_const(
         key: LitToConstInput<'tcx>
-    ) -> Result<ty::Const<'tcx>, LitToConstError> {
+    ) -> ty::Const<'tcx> {
         desc { "converting literal to const" }
     }
 
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 714094db053..35fbaa99569 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -109,6 +109,9 @@ impl<'tcx> TypeError<'tcx> {
             TypeError::ConstMismatch(ref values) => {
                 format!("expected `{}`, found `{}`", values.expected, values.found).into()
             }
+            TypeError::ForceInlineCast => {
+                "cannot coerce functions which must be inlined to function pointers".into()
+            }
             TypeError::IntrinsicCast => "cannot coerce intrinsics to function pointers".into(),
             TypeError::TargetFeatureCast(_) => {
                 "cannot coerce functions with `#[target_feature]` to safe function pointers".into()
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 6e6da6de749..8d4d127607d 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -770,6 +770,7 @@ where
                     size: Size::ZERO,
                     max_repr_align: None,
                     unadjusted_abi_align: tcx.data_layout.i8_align.abi,
+                    randomization_seed: 0,
                 })
             }
 
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index f611b69905c..e86e01451fe 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -165,10 +165,14 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
         arg: ty::GenericArg<'tcx>,
     ) -> ty::GenericArg<'tcx> {
         let arg = self.typing_env.as_query_input(arg);
-        self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!(
-            "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead",
-            arg.value
-        ))
+        self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| {
+            bug!(
+                "Failed to normalize {:?} in typing_env={:?}, \
+                maybe try to call `try_normalize_erasing_regions` instead",
+                arg.value,
+                self.typing_env,
+            )
+        })
     }
 }
 
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index 11904722743..1f3689926bc 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -12,6 +12,7 @@ rustc_abi = { path = "../rustc_abi" }
 rustc_apfloat = "0.2.0"
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 5d61a9d1e75..5203c33c968 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -118,6 +118,12 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
     .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
     .label = use of extern static
 
+mir_build_force_inline =
+    `{$callee}` is incompatible with `#[rustc_force_inline]`
+    .attr = annotation here
+    .callee = `{$callee}` defined here
+    .note = incompatible due to: {$reason}
+
 mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
 
 mir_build_initializing_type_with_requires_unsafe =
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
index 177c1e33a83..e4e452aff75 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
@@ -3,13 +3,12 @@
 use rustc_abi::Size;
 use rustc_ast as ast;
 use rustc_hir::LangItem;
-use rustc_middle::mir::interpret::{
-    Allocation, CTFE_ALLOC_SALT, LitToConstError, LitToConstInput, Scalar,
-};
+use rustc_middle::mir::interpret::{Allocation, CTFE_ALLOC_SALT, LitToConstInput, Scalar};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::{
-    self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, UserTypeAnnotationIndex,
+    self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt as _,
+    UserTypeAnnotationIndex,
 };
 use rustc_middle::{bug, mir, span_bug};
 use tracing::{instrument, trace};
@@ -50,16 +49,7 @@ pub(crate) fn as_constant_inner<'tcx>(
     let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
     match *kind {
         ExprKind::Literal { lit, neg } => {
-            let const_ = match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg })
-            {
-                Ok(c) => c,
-                Err(LitToConstError::Reported(guar)) => {
-                    Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar))
-                }
-                Err(LitToConstError::TypeError) => {
-                    bug!("encountered type error in `lit_to_mir_constant`")
-                }
-            };
+            let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg });
 
             ConstOperand { span, user_ty: None, const_ }
         }
@@ -108,11 +98,13 @@ pub(crate) fn as_constant_inner<'tcx>(
 }
 
 #[instrument(skip(tcx, lit_input))]
-fn lit_to_mir_constant<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    lit_input: LitToConstInput<'tcx>,
-) -> Result<Const<'tcx>, LitToConstError> {
+fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>) -> Const<'tcx> {
     let LitToConstInput { lit, ty, neg } = lit_input;
+
+    if let Err(guar) = ty.error_reported() {
+        return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar));
+    }
+
     let trunc = |n| {
         let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {
             Ok(layout) => layout.size,
@@ -123,7 +115,7 @@ fn lit_to_mir_constant<'tcx>(
         trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
         let result = width.truncate(n);
         trace!("trunc result: {}", result);
-        Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
+        ConstValue::Scalar(Scalar::from_uint(result, width))
     };
 
     let value = match (lit, ty.kind()) {
@@ -154,20 +146,18 @@ fn lit_to_mir_constant<'tcx>(
             ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
         }
         (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
-            trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })?
-        }
-        (ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty, neg)
-            .ok_or_else(|| {
-                LitToConstError::Reported(
-                    tcx.dcx()
-                        .delayed_bug(format!("couldn't parse float literal: {:?}", lit_input.lit)),
-                )
-            })?,
+            trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })
+        }
+        (ast::LitKind::Float(n, _), ty::Float(fty)) => {
+            parse_float_into_constval(*n, *fty, neg).unwrap()
+        }
         (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
         (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
-        (ast::LitKind::Err(guar), _) => return Err(LitToConstError::Reported(*guar)),
-        _ => return Err(LitToConstError::TypeError),
+        (ast::LitKind::Err(guar), _) => {
+            return Const::Ty(Ty::new_error(tcx, *guar), ty::Const::new_error(tcx, *guar));
+        }
+        _ => bug!("invalid lit/ty combination in `lit_to_mir_constant`: {lit:?}: {ty:?}"),
     };
 
-    Ok(Const::Val(value, ty))
+    Const::Val(value, ty)
 }
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index 932b6fbe026..8b01ec0d06a 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -29,6 +29,7 @@ use rustc_span::{Span, Symbol, sym};
 use super::lints;
 use crate::builder::expr::as_place::PlaceBuilder;
 use crate::builder::scope::DropKind;
+use crate::check_inline;
 
 pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -80,6 +81,7 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx
     };
 
     lints::check(tcx, &body);
+    check_inline::check_force_inline(tcx, &body);
 
     // The borrow checker will replace all the regions here with its own
     // inference variables. There's no point having non-erased regions here.
diff --git a/compiler/rustc_mir_build/src/check_inline.rs b/compiler/rustc_mir_build/src/check_inline.rs
new file mode 100644
index 00000000000..1af3b3e2c13
--- /dev/null
+++ b/compiler/rustc_mir_build/src/check_inline.rs
@@ -0,0 +1,81 @@
+use rustc_attr_parsing::InlineAttr;
+use rustc_hir::def_id::DefId;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::{Body, TerminatorKind};
+use rustc_middle::ty;
+use rustc_middle::ty::TyCtxt;
+use rustc_span::sym;
+
+/// Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its
+/// definition alone (irrespective of any specific caller).
+pub(crate) fn check_force_inline<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+    let def_id = body.source.def_id();
+    if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() {
+        return;
+    }
+    let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else {
+        return;
+    };
+
+    if let Err(reason) =
+        is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body))
+    {
+        tcx.dcx().emit_err(crate::errors::InvalidForceInline {
+            attr_span,
+            callee_span: tcx.def_span(def_id),
+            callee: tcx.def_path_str(def_id),
+            reason,
+        });
+    }
+}
+
+pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<(), &'static str> {
+    let codegen_attrs = tcx.codegen_fn_attrs(def_id);
+    if tcx.has_attr(def_id, sym::rustc_no_mir_inline) {
+        return Err("#[rustc_no_mir_inline]");
+    }
+
+    // FIXME(#127234): Coverage instrumentation currently doesn't handle inlined
+    // MIR correctly when Modified Condition/Decision Coverage is enabled.
+    if tcx.sess.instrument_coverage_mcdc() {
+        return Err("incompatible with MC/DC coverage");
+    }
+
+    let ty = tcx.type_of(def_id);
+    if match ty.instantiate_identity().kind() {
+        ty::FnDef(..) => tcx.fn_sig(def_id).instantiate_identity().c_variadic(),
+        ty::Closure(_, args) => args.as_closure().sig().c_variadic(),
+        _ => false,
+    } {
+        return Err("C variadic");
+    }
+
+    if codegen_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
+        return Err("cold");
+    }
+
+    // Intrinsic fallback bodies are automatically made cross-crate inlineable,
+    // but at this stage we don't know whether codegen knows the intrinsic,
+    // so just conservatively don't inline it. This also ensures that we do not
+    // accidentally inline the body of an intrinsic that *must* be overridden.
+    if tcx.has_attr(def_id, sym::rustc_intrinsic) {
+        return Err("callee is an intrinsic");
+    }
+
+    Ok(())
+}
+
+pub fn is_inline_valid_on_body<'tcx>(
+    _: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+) -> Result<(), &'static str> {
+    if body
+        .basic_blocks
+        .iter()
+        .any(|bb| matches!(bb.terminator().kind, TerminatorKind::TailCall { .. }))
+    {
+        return Err("can't inline functions with tail calls");
+    }
+
+    Ok(())
+}
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 790d56860d2..90c31a2caa3 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1107,3 +1107,15 @@ impl<'a> Subdiagnostic for Rust2024IncompatiblePatSugg<'a> {
         );
     }
 }
+
+#[derive(Diagnostic)]
+#[diag(mir_build_force_inline)]
+#[note]
+pub(crate) struct InvalidForceInline {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label(mir_build_callee)]
+    pub callee_span: Span,
+    pub callee: String,
+    pub reason: &'static str,
+}
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 467725841dc..76a35355de7 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -15,6 +15,7 @@
 // "Go to file" feature to silently ignore all files in the module, probably
 // because it assumes that "build" is a build-output directory. See #134365.
 mod builder;
+pub mod check_inline;
 mod check_tail_calls;
 mod check_unsafety;
 mod errors;
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index ce1c635d1b9..49db522cf0e 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -1,7 +1,7 @@
 use rustc_ast as ast;
 use rustc_hir::LangItem;
 use rustc_middle::bug;
-use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::mir::interpret::LitToConstInput;
 use rustc_middle::ty::{self, ScalarInt, TyCtxt, TypeVisitableExt as _};
 use tracing::trace;
 
@@ -10,11 +10,11 @@ use crate::builder::parse_float_into_scalar;
 pub(crate) fn lit_to_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     lit_input: LitToConstInput<'tcx>,
-) -> Result<ty::Const<'tcx>, LitToConstError> {
+) -> ty::Const<'tcx> {
     let LitToConstInput { lit, ty, neg } = lit_input;
 
     if let Err(guar) = ty.error_reported() {
-        return Ok(ty::Const::new_error(tcx, guar));
+        return ty::Const::new_error(tcx, guar);
     }
 
     let trunc = |n| {
@@ -28,8 +28,8 @@ pub(crate) fn lit_to_const<'tcx>(
         let result = width.truncate(n);
         trace!("trunc result: {}", result);
 
-        Ok(ScalarInt::try_from_uint(result, width)
-            .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
+        ScalarInt::try_from_uint(result, width)
+            .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result))
     };
 
     let valtree = match (lit, ty.kind()) {
@@ -57,20 +57,20 @@ pub(crate) fn lit_to_const<'tcx>(
         }
         (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
             let scalar_int =
-                trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })?;
+                trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() });
             ty::ValTree::from_scalar_int(scalar_int)
         }
         (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
         (ast::LitKind::Float(n, _), ty::Float(fty)) => {
-            let bits = parse_float_into_scalar(*n, *fty, neg).ok_or_else(|| {
+            let bits = parse_float_into_scalar(*n, *fty, neg).unwrap_or_else(|| {
                 tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit))
-            })?;
+            });
             ty::ValTree::from_scalar_int(bits)
         }
         (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
-        (ast::LitKind::Err(guar), _) => return Err(LitToConstError::Reported(*guar)),
-        _ => return Err(LitToConstError::TypeError),
+        (ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, *guar),
+        _ => return ty::Const::new_misc_error(tcx),
     };
 
-    Ok(ty::Const::new_value(tcx, valtree, ty))
+    ty::Const::new_value(tcx, valtree, ty)
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 242b62dfa8d..44b038bb5fa 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -13,7 +13,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd};
 use rustc_index::Idx;
 use rustc_lint as lint;
-use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::mir::interpret::LitToConstInput;
 use rustc_middle::thir::{
     Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
 };
@@ -669,11 +669,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let ct_ty = self.typeck_results.node_type(expr.hir_id);
         let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
-        match self.tcx.at(expr.span).lit_to_const(lit_input) {
-            Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind,
-            Err(LitToConstError::Reported(e)) => PatKind::Error(e),
-            Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
-        }
+        let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
+        self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
     }
 }
 
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
index d00bfc66a6a..b0c023cca82 100644
--- a/compiler/rustc_mir_transform/messages.ftl
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -19,6 +19,17 @@ mir_transform_ffi_unwind_call = call to {$foreign ->
 mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
     .suggestion = cast `{$ident}` to obtain a function pointer
 
+mir_transform_force_inline =
+    `{$callee}` could not be inlined into `{$caller}` but is required to be inlined
+    .call = ...`{$callee}` called here
+    .attr = inlining due to this annotation
+    .caller = within `{$caller}`...
+    .callee = `{$callee}` defined here
+    .note = could not be inlined due to: {$reason}
+
+mir_transform_force_inline_justification =
+    `{$callee}` is required to be inlined to: {$sym}
+
 mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
     .label = the value is held across this suspend point
     .note = {$reason}
diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs
index 4185b3f4d4d..5bd20e00eb6 100644
--- a/compiler/rustc_mir_transform/src/coverage/mappings.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs
@@ -367,9 +367,8 @@ fn calc_test_vectors_index(conditions: &mut Vec<MCDCBranch>) -> usize {
         })
         .collect::<FxIndexMap<_, _>>();
 
-    let mut queue = std::collections::VecDeque::from_iter(
-        next_conditions.swap_remove(&ConditionId::START).into_iter(),
-    );
+    let mut queue =
+        std::collections::VecDeque::from_iter(next_conditions.swap_remove(&ConditionId::START));
     num_paths_stats[ConditionId::START] = 1;
     let mut decision_end_nodes = Vec::new();
     while let Some(branch) = queue.pop_front() {
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index e1f1dd83f0d..8fce856687c 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -46,7 +46,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     // #[inline(never)] to force code generation.
     match codegen_fn_attrs.inline {
         InlineAttr::Never => return false,
-        InlineAttr::Hint | InlineAttr::Always => return true,
+        InlineAttr::Hint | InlineAttr::Always | InlineAttr::Force { .. } => return true,
         _ => {}
     }
 
@@ -69,8 +69,9 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     // Don't do any inference if codegen optimizations are disabled and also MIR inlining is not
     // enabled. This ensures that we do inference even if someone only passes -Zinline-mir,
     // which is less confusing than having to also enable -Copt-level=1.
-    if matches!(tcx.sess.opts.optimize, OptLevel::No) && !pm::should_run_pass(tcx, &inline::Inline)
-    {
+    let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline)
+        || inline::ForceInline::should_run_pass_for_callee(tcx, def_id.to_def_id());
+    if matches!(tcx.sess.opts.optimize, OptLevel::No) && !inliner_will_run {
         return false;
     }
 
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 2d9eeddea2e..015633d145f 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -4,8 +4,8 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::mir::AssertKind;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::{self, Lint};
-use rustc_span::Span;
 use rustc_span::def_id::DefId;
+use rustc_span::{Span, Symbol};
 
 use crate::fluent_generated as fluent;
 
@@ -142,3 +142,29 @@ pub(crate) struct MustNotSuspendReason {
 #[note(mir_transform_note2)]
 #[help]
 pub(crate) struct UndefinedTransmute;
+
+#[derive(Diagnostic)]
+#[diag(mir_transform_force_inline)]
+#[note]
+pub(crate) struct ForceInlineFailure {
+    #[label(mir_transform_caller)]
+    pub caller_span: Span,
+    #[label(mir_transform_callee)]
+    pub callee_span: Span,
+    #[label(mir_transform_attr)]
+    pub attr_span: Span,
+    #[primary_span]
+    #[label(mir_transform_call)]
+    pub call_span: Span,
+    pub callee: String,
+    pub caller: String,
+    pub reason: &'static str,
+    #[subdiagnostic]
+    pub justification: Option<ForceInlineJustification>,
+}
+
+#[derive(Subdiagnostic)]
+#[note(mir_transform_force_inline_justification)]
+pub(crate) struct ForceInlineJustification {
+    pub sym: Symbol,
+}
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 339acbad6b9..e4daa2b9757 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -10,13 +10,12 @@ use rustc_hir::def_id::DefId;
 use rustc_index::Idx;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::bug;
-use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
 use rustc_session::config::{DebugInfo, OptLevel};
 use rustc_span::source_map::Spanned;
-use rustc_span::sym;
 use tracing::{debug, instrument, trace, trace_span};
 
 use crate::cost_checker::CostChecker;
@@ -29,10 +28,6 @@ pub(crate) mod cycle;
 
 const TOP_DOWN_DEPTH_LIMIT: usize = 5;
 
-// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden
-// by custom rustc drivers, running all the steps by themselves. See #114628.
-pub struct Inline;
-
 #[derive(Clone, Debug)]
 struct CallSite<'tcx> {
     callee: Instance<'tcx>,
@@ -41,14 +36,12 @@ struct CallSite<'tcx> {
     source_info: SourceInfo,
 }
 
+// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden
+// by custom rustc drivers, running all the steps by themselves. See #114628.
+pub struct Inline;
+
 impl<'tcx> crate::MirPass<'tcx> for Inline {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        // FIXME(#127234): Coverage instrumentation currently doesn't handle inlined
-        // MIR correctly when Modified Condition/Decision Coverage is enabled.
-        if sess.instrument_coverage_mcdc() {
-            return false;
-        }
-
         if let Some(enabled) = sess.opts.unstable_opts.inline_mir {
             return enabled;
         }
@@ -67,7 +60,7 @@ impl<'tcx> crate::MirPass<'tcx> for Inline {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id()));
         let _guard = span.enter();
-        if inline(tcx, body) {
+        if inline::<NormalInliner<'tcx>>(tcx, body) {
             debug!("running simplify cfg on {:?}", body.source);
             simplify_cfg(body);
             deref_finder(tcx, body);
@@ -75,47 +68,83 @@ impl<'tcx> crate::MirPass<'tcx> for Inline {
     }
 }
 
-fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
-    let def_id = body.source.def_id().expect_local();
+pub struct ForceInline;
 
-    // Only do inlining into fn bodies.
-    if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() {
-        return false;
+impl ForceInline {
+    pub fn should_run_pass_for_callee<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
+        matches!(tcx.codegen_fn_attrs(def_id).inline, InlineAttr::Force { .. })
     }
-    if body.source.promoted.is_some() {
-        return false;
+}
+
+impl<'tcx> crate::MirPass<'tcx> for ForceInline {
+    fn is_enabled(&self, _: &rustc_session::Session) -> bool {
+        true
     }
-    // Avoid inlining into coroutines, since their `optimized_mir` is used for layout computation,
-    // which can create a cycle, even when no attempt is made to inline the function in the other
-    // direction.
-    if body.coroutine.is_some() {
-        return false;
+
+    fn can_be_overridden(&self) -> bool {
+        false
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let span = trace_span!("force_inline", body = %tcx.def_path_str(body.source.def_id()));
+        let _guard = span.enter();
+        if inline::<ForceInliner<'tcx>>(tcx, body) {
+            debug!("running simplify cfg on {:?}", body.source);
+            simplify_cfg(body);
+            deref_finder(tcx, body);
+        }
     }
+}
 
-    let typing_env = body.typing_env(tcx);
-    let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
+trait Inliner<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, def_id: DefId, body: &Body<'tcx>) -> Self;
 
-    let mut this = Inliner {
-        tcx,
-        typing_env,
-        codegen_fn_attrs,
-        history: Vec::new(),
-        changed: false,
-        caller_is_inline_forwarder: matches!(
-            codegen_fn_attrs.inline,
-            InlineAttr::Hint | InlineAttr::Always
-        ) && body_is_forwarder(body),
-    };
-    let blocks = START_BLOCK..body.basic_blocks.next_index();
-    this.process_blocks(body, blocks);
-    this.changed
+    fn tcx(&self) -> TyCtxt<'tcx>;
+    fn typing_env(&self) -> ty::TypingEnv<'tcx>;
+    fn history(&self) -> &[DefId];
+    fn caller_def_id(&self) -> DefId;
+
+    /// Has the caller body been changed?
+    fn changed(self) -> bool;
+
+    /// Should inlining happen for a given callee?
+    fn should_inline_for_callee(&self, def_id: DefId) -> bool;
+
+    fn check_caller_mir_body(&self, body: &Body<'tcx>) -> bool;
+
+    /// Returns inlining decision that is based on the examination of callee MIR body.
+    /// Assumes that codegen attributes have been checked for compatibility already.
+    fn check_callee_mir_body(
+        &self,
+        callsite: &CallSite<'tcx>,
+        callee_body: &Body<'tcx>,
+        callee_attrs: &CodegenFnAttrs,
+    ) -> Result<(), &'static str>;
+
+    // How many callsites in a body are we allowed to inline? We need to limit this in order
+    // to prevent super-linear growth in MIR size.
+    fn inline_limit_for_block(&self) -> Option<usize>;
+
+    /// Called when inlining succeeds.
+    fn on_inline_success(
+        &mut self,
+        callsite: &CallSite<'tcx>,
+        caller_body: &mut Body<'tcx>,
+        new_blocks: std::ops::Range<BasicBlock>,
+    );
+
+    /// Called when inlining failed or was not performed.
+    fn on_inline_failure(&self, callsite: &CallSite<'tcx>, reason: &'static str);
+
+    /// Called when the inline limit for a body is reached.
+    fn on_inline_limit_reached(&self) -> bool;
 }
 
-struct Inliner<'tcx> {
+struct ForceInliner<'tcx> {
     tcx: TyCtxt<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
-    /// Caller codegen attributes.
-    codegen_fn_attrs: &'tcx CodegenFnAttrs,
+    /// `DefId` of caller.
+    def_id: DefId,
     /// Stack of inlined instances.
     /// We only check the `DefId` and not the args because we want to
     /// avoid inlining cases of polymorphic recursion.
@@ -124,366 +153,203 @@ struct Inliner<'tcx> {
     history: Vec<DefId>,
     /// Indicates that the caller body has been modified.
     changed: bool,
-    /// Indicates that the caller is #[inline] and just calls another function,
-    /// and thus we can inline less into it as it'll be inlined itself.
-    caller_is_inline_forwarder: bool,
 }
 
-impl<'tcx> Inliner<'tcx> {
-    fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
-        // How many callsites in this body are we allowed to inline? We need to limit this in order
-        // to prevent super-linear growth in MIR size
-        let inline_limit = match self.history.len() {
-            0 => usize::MAX,
-            1..=TOP_DOWN_DEPTH_LIMIT => 1,
-            _ => return,
-        };
-        let mut inlined_count = 0;
-        for bb in blocks {
-            let bb_data = &caller_body[bb];
-            if bb_data.is_cleanup {
-                continue;
-            }
-
-            let Some(callsite) = self.resolve_callsite(caller_body, bb, bb_data) else {
-                continue;
-            };
-
-            let span = trace_span!("process_blocks", %callsite.callee, ?bb);
-            let _guard = span.enter();
-
-            match self.try_inlining(caller_body, &callsite) {
-                Err(reason) => {
-                    debug!("not-inlined {} [{}]", callsite.callee, reason);
-                }
-                Ok(new_blocks) => {
-                    debug!("inlined {}", callsite.callee);
-                    self.changed = true;
-
-                    self.history.push(callsite.callee.def_id());
-                    self.process_blocks(caller_body, new_blocks);
-                    self.history.pop();
-
-                    inlined_count += 1;
-                    if inlined_count == inline_limit {
-                        debug!("inline count reached");
-                        return;
-                    }
-                }
-            }
-        }
+impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, def_id: DefId, body: &Body<'tcx>) -> Self {
+        Self { tcx, typing_env: body.typing_env(tcx), def_id, history: Vec::new(), changed: false }
     }
 
-    /// Attempts to inline a callsite into the caller body. When successful returns basic blocks
-    /// containing the inlined body. Otherwise returns an error describing why inlining didn't take
-    /// place.
-    fn try_inlining(
-        &self,
-        caller_body: &mut Body<'tcx>,
-        callsite: &CallSite<'tcx>,
-    ) -> Result<std::ops::Range<BasicBlock>, &'static str> {
-        self.check_mir_is_available(caller_body, callsite.callee)?;
-
-        let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id());
-        let cross_crate_inlinable = self.tcx.cross_crate_inlinable(callsite.callee.def_id());
-        self.check_codegen_attributes(callsite, callee_attrs, cross_crate_inlinable)?;
-
-        // Intrinsic fallback bodies are automatically made cross-crate inlineable,
-        // but at this stage we don't know whether codegen knows the intrinsic,
-        // so just conservatively don't inline it. This also ensures that we do not
-        // accidentally inline the body of an intrinsic that *must* be overridden.
-        if self.tcx.has_attr(callsite.callee.def_id(), sym::rustc_intrinsic) {
-            return Err("Callee is an intrinsic, do not inline fallback bodies");
-        }
-
-        let terminator = caller_body[callsite.block].terminator.as_ref().unwrap();
-        let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() };
-        let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty;
-        for arg in args {
-            if !arg.node.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.typing_env)
-            {
-                // We do not allow inlining functions with unsized params. Inlining these functions
-                // could create unsized locals, which are unsound and being phased out.
-                return Err("Call has unsized argument");
-            }
-        }
-
-        let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?;
-        self.check_mir_body(callsite, callee_body, callee_attrs, cross_crate_inlinable)?;
-
-        let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions(
-            self.tcx,
-            self.typing_env,
-            ty::EarlyBinder::bind(callee_body.clone()),
-        ) else {
-            return Err("failed to normalize callee body");
-        };
-
-        // Normally, this shouldn't be required, but trait normalization failure can create a
-        // validation ICE.
-        if !validate_types(self.tcx, self.typing_env, &callee_body, &caller_body).is_empty() {
-            return Err("failed to validate callee body");
-        }
-
-        // Check call signature compatibility.
-        // Normally, this shouldn't be required, but trait normalization failure can create a
-        // validation ICE.
-        let output_type = callee_body.return_ty();
-        if !util::sub_types(self.tcx, self.typing_env, output_type, destination_ty) {
-            trace!(?output_type, ?destination_ty);
-            return Err("failed to normalize return type");
-        }
-        if callsite.fn_sig.abi() == ExternAbi::RustCall {
-            // FIXME: Don't inline user-written `extern "rust-call"` functions,
-            // since this is generally perf-negative on rustc, and we hope that
-            // LLVM will inline these functions instead.
-            if callee_body.spread_arg.is_some() {
-                return Err("do not inline user-written rust-call functions");
-            }
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
 
-            let (self_arg, arg_tuple) = match &args[..] {
-                [arg_tuple] => (None, arg_tuple),
-                [self_arg, arg_tuple] => (Some(self_arg), arg_tuple),
-                _ => bug!("Expected `rust-call` to have 1 or 2 args"),
-            };
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.typing_env
+    }
 
-            let self_arg_ty =
-                self_arg.map(|self_arg| self_arg.node.ty(&caller_body.local_decls, self.tcx));
+    fn history(&self) -> &[DefId] {
+        &self.history
+    }
 
-            let arg_tuple_ty = arg_tuple.node.ty(&caller_body.local_decls, self.tcx);
-            let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else {
-                bug!("Closure arguments are not passed as a tuple");
-            };
+    fn caller_def_id(&self) -> DefId {
+        self.def_id
+    }
 
-            for (arg_ty, input) in
-                self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
-            {
-                let input_type = callee_body.local_decls[input].ty;
-                if !util::sub_types(self.tcx, self.typing_env, input_type, arg_ty) {
-                    trace!(?arg_ty, ?input_type);
-                    return Err("failed to normalize tuple argument type");
-                }
-            }
-        } else {
-            for (arg, input) in args.iter().zip(callee_body.args_iter()) {
-                let input_type = callee_body.local_decls[input].ty;
-                let arg_ty = arg.node.ty(&caller_body.local_decls, self.tcx);
-                if !util::sub_types(self.tcx, self.typing_env, input_type, arg_ty) {
-                    trace!(?arg_ty, ?input_type);
-                    return Err("failed to normalize argument type");
-                }
-            }
-        }
+    fn changed(self) -> bool {
+        self.changed
+    }
 
-        let old_blocks = caller_body.basic_blocks.next_index();
-        self.inline_call(caller_body, callsite, callee_body);
-        let new_blocks = old_blocks..caller_body.basic_blocks.next_index();
+    fn should_inline_for_callee(&self, def_id: DefId) -> bool {
+        ForceInline::should_run_pass_for_callee(self.tcx(), def_id)
+    }
 
-        Ok(new_blocks)
+    fn check_caller_mir_body(&self, _: &Body<'tcx>) -> bool {
+        true
     }
 
-    fn check_mir_is_available(
+    #[instrument(level = "debug", skip(self, callee_body))]
+    fn check_callee_mir_body(
         &self,
-        caller_body: &Body<'tcx>,
-        callee: Instance<'tcx>,
+        _: &CallSite<'tcx>,
+        callee_body: &Body<'tcx>,
+        callee_attrs: &CodegenFnAttrs,
     ) -> Result<(), &'static str> {
-        let caller_def_id = caller_body.source.def_id();
-        let callee_def_id = callee.def_id();
-        if callee_def_id == caller_def_id {
-            return Err("self-recursion");
-        }
-
-        match callee.def {
-            InstanceKind::Item(_) => {
-                // If there is no MIR available (either because it was not in metadata or
-                // because it has no MIR because it's an extern function), then the inliner
-                // won't cause cycles on this.
-                if !self.tcx.is_mir_available(callee_def_id) {
-                    return Err("item MIR unavailable");
-                }
-            }
-            // These have no own callable MIR.
-            InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => {
-                return Err("instance without MIR (intrinsic / virtual)");
-            }
-
-            // FIXME(#127030): `ConstParamHasTy` has bad interactions with
-            // the drop shim builder, which does not evaluate predicates in
-            // the correct param-env for types being dropped. Stall resolving
-            // the MIR for this instance until all of its const params are
-            // substituted.
-            InstanceKind::DropGlue(_, Some(ty)) if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => {
-                return Err("still needs substitution");
-            }
-
-            // This cannot result in an immediate cycle since the callee MIR is a shim, which does
-            // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we
-            // do not need to catch this here, we can wait until the inliner decides to continue
-            // inlining a second time.
-            InstanceKind::VTableShim(_)
-            | InstanceKind::ReifyShim(..)
-            | InstanceKind::FnPtrShim(..)
-            | InstanceKind::ClosureOnceShim { .. }
-            | InstanceKind::ConstructCoroutineInClosureShim { .. }
-            | InstanceKind::DropGlue(..)
-            | InstanceKind::CloneShim(..)
-            | InstanceKind::ThreadLocalShim(..)
-            | InstanceKind::FnPtrAddrShim(..)
-            | InstanceKind::AsyncDropGlueCtorShim(..) => return Ok(()),
+        if callee_body.tainted_by_errors.is_some() {
+            return Err("body has errors");
         }
 
-        if self.tcx.is_constructor(callee_def_id) {
-            trace!("constructors always have MIR");
-            // Constructor functions cannot cause a query cycle.
-            return Ok(());
-        }
-
-        if callee_def_id.is_local() {
-            // If we know for sure that the function we're calling will itself try to
-            // call us, then we avoid inlining that function.
-            if self.tcx.mir_callgraph_reachable((callee, caller_def_id.expect_local())) {
-                return Err("caller might be reachable from callee (query cycle avoidance)");
-            }
-
-            Ok(())
+        let caller_attrs = self.tcx().codegen_fn_attrs(self.caller_def_id());
+        if callee_attrs.instruction_set != caller_attrs.instruction_set
+            && callee_body
+                .basic_blocks
+                .iter()
+                .any(|bb| matches!(bb.terminator().kind, TerminatorKind::InlineAsm { .. }))
+        {
+            // During the attribute checking stage we allow a callee with no
+            // instruction_set assigned to count as compatible with a function that does
+            // assign one. However, during this stage we require an exact match when any
+            // inline-asm is detected. LLVM will still possibly do an inline later on
+            // if the no-attribute function ends up with the same instruction set anyway.
+            Err("cannot move inline-asm across instruction sets")
         } else {
-            // This cannot result in an immediate cycle since the callee MIR is from another crate
-            // and is already optimized. Any subsequent inlining may cause cycles, but we do
-            // not need to catch this here, we can wait until the inliner decides to continue
-            // inlining a second time.
-            trace!("functions from other crates always have MIR");
             Ok(())
         }
     }
 
-    fn resolve_callsite(
-        &self,
-        caller_body: &Body<'tcx>,
-        bb: BasicBlock,
-        bb_data: &BasicBlockData<'tcx>,
-    ) -> Option<CallSite<'tcx>> {
-        // Only consider direct calls to functions
-        let terminator = bb_data.terminator();
-
-        // FIXME(explicit_tail_calls): figure out if we can inline tail calls
-        if let TerminatorKind::Call { ref func, fn_span, .. } = terminator.kind {
-            let func_ty = func.ty(caller_body, self.tcx);
-            if let ty::FnDef(def_id, args) = *func_ty.kind() {
-                // To resolve an instance its args have to be fully normalized.
-                let args = self.tcx.try_normalize_erasing_regions(self.typing_env, args).ok()?;
-                let callee = Instance::try_resolve(self.tcx, self.typing_env, def_id, args)
-                    .ok()
-                    .flatten()?;
-
-                if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def {
-                    return None;
-                }
-
-                if self.history.contains(&callee.def_id()) {
-                    return None;
-                }
+    fn inline_limit_for_block(&self) -> Option<usize> {
+        Some(usize::MAX)
+    }
 
-                let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args);
+    fn on_inline_success(
+        &mut self,
+        callsite: &CallSite<'tcx>,
+        caller_body: &mut Body<'tcx>,
+        new_blocks: std::ops::Range<BasicBlock>,
+    ) {
+        self.changed = true;
 
-                // Additionally, check that the body that we're inlining actually agrees
-                // with the ABI of the trait that the item comes from.
-                if let InstanceKind::Item(instance_def_id) = callee.def
-                    && self.tcx.def_kind(instance_def_id) == DefKind::AssocFn
-                    && let instance_fn_sig = self.tcx.fn_sig(instance_def_id).skip_binder()
-                    && instance_fn_sig.abi() != fn_sig.abi()
-                {
-                    return None;
-                }
+        self.history.push(callsite.callee.def_id());
+        process_blocks(self, caller_body, new_blocks);
+        self.history.pop();
+    }
 
-                let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
+    fn on_inline_failure(&self, callsite: &CallSite<'tcx>, reason: &'static str) {
+        let tcx = self.tcx();
+        let InlineAttr::Force { attr_span, reason: justification } =
+            tcx.codegen_fn_attrs(callsite.callee.def_id()).inline
+        else {
+            bug!("called on item without required inlining");
+        };
 
-                return Some(CallSite { callee, fn_sig, block: bb, source_info });
-            }
-        }
+        let call_span = callsite.source_info.span;
+        tcx.dcx().emit_err(crate::errors::ForceInlineFailure {
+            call_span,
+            attr_span,
+            caller_span: tcx.def_span(self.def_id),
+            caller: tcx.def_path_str(self.def_id),
+            callee_span: tcx.def_span(callsite.callee.def_id()),
+            callee: tcx.def_path_str(callsite.callee.def_id()),
+            reason,
+            justification: justification.map(|sym| crate::errors::ForceInlineJustification { sym }),
+        });
+    }
 
-        None
+    fn on_inline_limit_reached(&self) -> bool {
+        false
     }
+}
 
-    /// Returns an error if inlining is not possible based on codegen attributes alone. A success
-    /// indicates that inlining decision should be based on other criteria.
-    fn check_codegen_attributes(
-        &self,
-        callsite: &CallSite<'tcx>,
-        callee_attrs: &CodegenFnAttrs,
-        cross_crate_inlinable: bool,
-    ) -> Result<(), &'static str> {
-        if self.tcx.has_attr(callsite.callee.def_id(), sym::rustc_no_mir_inline) {
-            return Err("#[rustc_no_mir_inline]");
-        }
+struct NormalInliner<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
+    /// `DefId` of caller.
+    def_id: DefId,
+    /// Stack of inlined instances.
+    /// We only check the `DefId` and not the args because we want to
+    /// avoid inlining cases of polymorphic recursion.
+    /// The number of `DefId`s is finite, so checking history is enough
+    /// to ensure that we do not loop endlessly while inlining.
+    history: Vec<DefId>,
+    /// Indicates that the caller body has been modified.
+    changed: bool,
+    /// Indicates that the caller is #[inline] and just calls another function,
+    /// and thus we can inline less into it as it'll be inlined itself.
+    caller_is_inline_forwarder: bool,
+}
 
-        if let InlineAttr::Never = callee_attrs.inline {
-            return Err("never inline hint");
+impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, def_id: DefId, body: &Body<'tcx>) -> Self {
+        let typing_env = body.typing_env(tcx);
+        let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
+
+        Self {
+            tcx,
+            typing_env,
+            def_id,
+            history: Vec::new(),
+            changed: false,
+            caller_is_inline_forwarder: matches!(
+                codegen_fn_attrs.inline,
+                InlineAttr::Hint | InlineAttr::Always | InlineAttr::Force { .. }
+            ) && body_is_forwarder(body),
         }
+    }
 
-        // Reachability pass defines which functions are eligible for inlining. Generally inlining
-        // other functions is incorrect because they could reference symbols that aren't exported.
-        let is_generic = callsite.callee.args.non_erasable_generics().next().is_some();
-        if !is_generic && !cross_crate_inlinable {
-            return Err("not exported");
-        }
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
 
-        if callsite.fn_sig.c_variadic() {
-            return Err("C variadic");
-        }
+    fn caller_def_id(&self) -> DefId {
+        self.def_id
+    }
 
-        if callee_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
-            return Err("cold");
-        }
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        self.typing_env
+    }
 
-        if callee_attrs.no_sanitize != self.codegen_fn_attrs.no_sanitize {
-            return Err("incompatible sanitizer set");
-        }
+    fn history(&self) -> &[DefId] {
+        &self.history
+    }
 
-        // Two functions are compatible if the callee has no attribute (meaning
-        // that it's codegen agnostic), or sets an attribute that is identical
-        // to this function's attribute.
-        if callee_attrs.instruction_set.is_some()
-            && callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
-        {
-            return Err("incompatible instruction set");
-        }
+    fn changed(self) -> bool {
+        self.changed
+    }
+
+    fn should_inline_for_callee(&self, _: DefId) -> bool {
+        true
+    }
 
-        let callee_feature_names = callee_attrs.target_features.iter().map(|f| f.name);
-        let this_feature_names = self.codegen_fn_attrs.target_features.iter().map(|f| f.name);
-        if callee_feature_names.ne(this_feature_names) {
-            // In general it is not correct to inline a callee with target features that are a
-            // subset of the caller. This is because the callee might contain calls, and the ABI of
-            // those calls depends on the target features of the surrounding function. By moving a
-            // `Call` terminator from one MIR body to another with more target features, we might
-            // change the ABI of that call!
-            return Err("incompatible target features");
+    fn check_caller_mir_body(&self, body: &Body<'tcx>) -> bool {
+        // Avoid inlining into coroutines, since their `optimized_mir` is used for layout computation,
+        // which can create a cycle, even when no attempt is made to inline the function in the other
+        // direction.
+        if body.coroutine.is_some() {
+            return false;
         }
 
-        Ok(())
+        true
     }
 
-    /// Returns inlining decision that is based on the examination of callee MIR body.
-    /// Assumes that codegen attributes have been checked for compatibility already.
     #[instrument(level = "debug", skip(self, callee_body))]
-    fn check_mir_body(
+    fn check_callee_mir_body(
         &self,
         callsite: &CallSite<'tcx>,
         callee_body: &Body<'tcx>,
         callee_attrs: &CodegenFnAttrs,
-        cross_crate_inlinable: bool,
     ) -> Result<(), &'static str> {
-        let tcx = self.tcx;
+        let tcx = self.tcx();
 
         if let Some(_) = callee_body.tainted_by_errors {
-            return Err("Body is tainted");
+            return Err("body has errors");
         }
 
         let mut threshold = if self.caller_is_inline_forwarder {
-            self.tcx.sess.opts.unstable_opts.inline_mir_forwarder_threshold.unwrap_or(30)
-        } else if cross_crate_inlinable {
-            self.tcx.sess.opts.unstable_opts.inline_mir_hint_threshold.unwrap_or(100)
+            tcx.sess.opts.unstable_opts.inline_mir_forwarder_threshold.unwrap_or(30)
+        } else if tcx.cross_crate_inlinable(callsite.callee.def_id()) {
+            tcx.sess.opts.unstable_opts.inline_mir_hint_threshold.unwrap_or(100)
         } else {
-            self.tcx.sess.opts.unstable_opts.inline_mir_threshold.unwrap_or(50)
+            tcx.sess.opts.unstable_opts.inline_mir_threshold.unwrap_or(50)
         };
 
         // Give a bonus functions with a small number of blocks,
@@ -497,7 +363,7 @@ impl<'tcx> Inliner<'tcx> {
         // FIXME: Give a bonus to functions with only a single caller
 
         let mut checker =
-            CostChecker::new(self.tcx, self.typing_env, Some(callsite.callee), callee_body);
+            CostChecker::new(tcx, self.typing_env(), Some(callsite.callee), callee_body);
 
         checker.add_function_level_costs();
 
@@ -513,20 +379,20 @@ impl<'tcx> Inliner<'tcx> {
             checker.visit_basic_block_data(bb, blk);
 
             let term = blk.terminator();
+            let caller_attrs = tcx.codegen_fn_attrs(self.caller_def_id());
             if let TerminatorKind::Drop { ref place, target, unwind, replace: _ } = term.kind {
                 work_list.push(target);
 
                 // If the place doesn't actually need dropping, treat it like a regular goto.
-                let ty = callsite.callee.instantiate_mir(
-                    self.tcx,
-                    ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty),
-                );
-                if ty.needs_drop(tcx, self.typing_env)
+                let ty = callsite
+                    .callee
+                    .instantiate_mir(tcx, ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty));
+                if ty.needs_drop(tcx, self.typing_env())
                     && let UnwindAction::Cleanup(unwind) = unwind
                 {
                     work_list.push(unwind);
                 }
-            } else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
+            } else if callee_attrs.instruction_set != caller_attrs.instruction_set
                 && matches!(term.kind, TerminatorKind::InlineAsm { .. })
             {
                 // During the attribute checking stage we allow a callee with no
@@ -534,7 +400,7 @@ impl<'tcx> Inliner<'tcx> {
                 // assign one. However, during this stage we require an exact match when any
                 // inline-asm is detected. LLVM will still possibly do an inline later on
                 // if the no-attribute function ends up with the same instruction set anyway.
-                return Err("Cannot move inline-asm across instruction sets");
+                return Err("cannot move inline-asm across instruction sets");
             } else if let TerminatorKind::TailCall { .. } = term.kind {
                 // FIXME(explicit_tail_calls): figure out how exactly functions containing tail
                 // calls can be inlined (and if they even should)
@@ -558,321 +424,688 @@ impl<'tcx> Inliner<'tcx> {
         }
     }
 
-    fn inline_call(
-        &self,
-        caller_body: &mut Body<'tcx>,
+    fn inline_limit_for_block(&self) -> Option<usize> {
+        match self.history.len() {
+            0 => Some(usize::MAX),
+            1..=TOP_DOWN_DEPTH_LIMIT => Some(1),
+            _ => None,
+        }
+    }
+
+    fn on_inline_success(
+        &mut self,
         callsite: &CallSite<'tcx>,
-        mut callee_body: Body<'tcx>,
+        caller_body: &mut Body<'tcx>,
+        new_blocks: std::ops::Range<BasicBlock>,
     ) {
-        let terminator = caller_body[callsite.block].terminator.take().unwrap();
-        let TerminatorKind::Call { func, args, destination, unwind, target, .. } = terminator.kind
-        else {
-            bug!("unexpected terminator kind {:?}", terminator.kind);
-        };
+        self.changed = true;
 
-        let return_block = if let Some(block) = target {
-            // Prepare a new block for code that should execute when call returns. We don't use
-            // target block directly since it might have other predecessors.
-            let data = BasicBlockData::new(
-                Some(Terminator {
-                    source_info: terminator.source_info,
-                    kind: TerminatorKind::Goto { target: block },
-                }),
-                caller_body[block].is_cleanup,
-            );
-            Some(caller_body.basic_blocks_mut().push(data))
-        } else {
-            None
+        self.history.push(callsite.callee.def_id());
+        process_blocks(self, caller_body, new_blocks);
+        self.history.pop();
+    }
+
+    fn on_inline_limit_reached(&self) -> bool {
+        true
+    }
+
+    fn on_inline_failure(&self, _: &CallSite<'tcx>, _: &'static str) {}
+}
+
+fn inline<'tcx, T: Inliner<'tcx>>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
+    let def_id = body.source.def_id();
+
+    // Only do inlining into fn bodies.
+    if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() {
+        return false;
+    }
+
+    let mut inliner = T::new(tcx, def_id, body);
+    if !inliner.check_caller_mir_body(body) {
+        return false;
+    }
+
+    let blocks = START_BLOCK..body.basic_blocks.next_index();
+    process_blocks(&mut inliner, body, blocks);
+    inliner.changed()
+}
+
+fn process_blocks<'tcx, I: Inliner<'tcx>>(
+    inliner: &mut I,
+    caller_body: &mut Body<'tcx>,
+    blocks: Range<BasicBlock>,
+) {
+    let Some(inline_limit) = inliner.inline_limit_for_block() else { return };
+    let mut inlined_count = 0;
+    for bb in blocks {
+        let bb_data = &caller_body[bb];
+        if bb_data.is_cleanup {
+            continue;
+        }
+
+        let Some(callsite) = resolve_callsite(inliner, caller_body, bb, bb_data) else {
+            continue;
         };
 
-        // If the call is something like `a[*i] = f(i)`, where
-        // `i : &mut usize`, then just duplicating the `a[*i]`
-        // Place could result in two different locations if `f`
-        // writes to `i`. To prevent this we need to create a temporary
-        // borrow of the place and pass the destination as `*temp` instead.
-        fn dest_needs_borrow(place: Place<'_>) -> bool {
-            for elem in place.projection.iter() {
-                match elem {
-                    ProjectionElem::Deref | ProjectionElem::Index(_) => return true,
-                    _ => {}
+        let span = trace_span!("process_blocks", %callsite.callee, ?bb);
+        let _guard = span.enter();
+
+        match try_inlining(inliner, caller_body, &callsite) {
+            Err(reason) => {
+                debug!("not-inlined {} [{}]", callsite.callee, reason);
+                inliner.on_inline_failure(&callsite, reason);
+            }
+            Ok(new_blocks) => {
+                debug!("inlined {}", callsite.callee);
+                inliner.on_inline_success(&callsite, caller_body, new_blocks);
+
+                inlined_count += 1;
+                if inlined_count == inline_limit {
+                    if inliner.on_inline_limit_reached() {
+                        return;
+                    }
                 }
             }
+        }
+    }
+}
+
+fn resolve_callsite<'tcx, I: Inliner<'tcx>>(
+    inliner: &I,
+    caller_body: &Body<'tcx>,
+    bb: BasicBlock,
+    bb_data: &BasicBlockData<'tcx>,
+) -> Option<CallSite<'tcx>> {
+    let tcx = inliner.tcx();
+    // Only consider direct calls to functions
+    let terminator = bb_data.terminator();
+
+    // FIXME(explicit_tail_calls): figure out if we can inline tail calls
+    if let TerminatorKind::Call { ref func, fn_span, .. } = terminator.kind {
+        let func_ty = func.ty(caller_body, tcx);
+        if let ty::FnDef(def_id, args) = *func_ty.kind() {
+            if !inliner.should_inline_for_callee(def_id) {
+                debug!("not enabled");
+                return None;
+            }
+
+            // To resolve an instance its args have to be fully normalized.
+            let args = tcx.try_normalize_erasing_regions(inliner.typing_env(), args).ok()?;
+            let callee =
+                Instance::try_resolve(tcx, inliner.typing_env(), def_id, args).ok().flatten()?;
+
+            if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def {
+                return None;
+            }
+
+            if inliner.history().contains(&callee.def_id()) {
+                return None;
+            }
 
-            false
+            let fn_sig = tcx.fn_sig(def_id).instantiate(tcx, args);
+
+            // Additionally, check that the body that we're inlining actually agrees
+            // with the ABI of the trait that the item comes from.
+            if let InstanceKind::Item(instance_def_id) = callee.def
+                && tcx.def_kind(instance_def_id) == DefKind::AssocFn
+                && let instance_fn_sig = tcx.fn_sig(instance_def_id).skip_binder()
+                && instance_fn_sig.abi() != fn_sig.abi()
+            {
+                return None;
+            }
+
+            let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
+
+            return Some(CallSite { callee, fn_sig, block: bb, source_info });
         }
+    }
 
-        let dest = if dest_needs_borrow(destination) {
-            trace!("creating temp for return destination");
-            let dest = Rvalue::Ref(
-                self.tcx.lifetimes.re_erased,
-                BorrowKind::Mut { kind: MutBorrowKind::Default },
-                destination,
-            );
-            let dest_ty = dest.ty(caller_body, self.tcx);
-            let temp =
-                Place::from(self.new_call_temp(caller_body, callsite, dest_ty, return_block));
-            caller_body[callsite.block].statements.push(Statement {
-                source_info: callsite.source_info,
-                kind: StatementKind::Assign(Box::new((temp, dest))),
-            });
-            self.tcx.mk_place_deref(temp)
-        } else {
-            destination
-        };
+    None
+}
 
-        // Always create a local to hold the destination, as `RETURN_PLACE` may appear
-        // where a full `Place` is not allowed.
-        let (remap_destination, destination_local) = if let Some(d) = dest.as_local() {
-            (false, d)
-        } else {
-            (
-                true,
-                self.new_call_temp(
-                    caller_body,
-                    callsite,
-                    destination.ty(caller_body, self.tcx).ty,
-                    return_block,
-                ),
-            )
-        };
+/// Attempts to inline a callsite into the caller body. When successful returns basic blocks
+/// containing the inlined body. Otherwise returns an error describing why inlining didn't take
+/// place.
+fn try_inlining<'tcx, I: Inliner<'tcx>>(
+    inliner: &I,
+    caller_body: &mut Body<'tcx>,
+    callsite: &CallSite<'tcx>,
+) -> Result<std::ops::Range<BasicBlock>, &'static str> {
+    let tcx = inliner.tcx();
+    check_mir_is_available(inliner, caller_body, callsite.callee)?;
+
+    let callee_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id());
+    rustc_mir_build::check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?;
+    check_codegen_attributes(inliner, callsite, callee_attrs)?;
+
+    let terminator = caller_body[callsite.block].terminator.as_ref().unwrap();
+    let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() };
+    let destination_ty = destination.ty(&caller_body.local_decls, tcx).ty;
+    for arg in args {
+        if !arg.node.ty(&caller_body.local_decls, tcx).is_sized(tcx, inliner.typing_env()) {
+            // We do not allow inlining functions with unsized params. Inlining these functions
+            // could create unsized locals, which are unsound and being phased out.
+            return Err("call has unsized argument");
+        }
+    }
 
-        // Copy the arguments if needed.
-        let args = self.make_call_args(args, callsite, caller_body, &callee_body, return_block);
+    let callee_body = try_instance_mir(tcx, callsite.callee.def)?;
+    rustc_mir_build::check_inline::is_inline_valid_on_body(tcx, callee_body)?;
+    inliner.check_callee_mir_body(callsite, callee_body, callee_attrs)?;
 
-        let mut integrator = Integrator {
-            args: &args,
-            new_locals: Local::new(caller_body.local_decls.len())..,
-            new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
-            new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
-            destination: destination_local,
-            callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
-            callsite,
-            cleanup_block: unwind,
-            in_cleanup_block: false,
-            return_block,
-            tcx: self.tcx,
-            always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
+    let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions(
+        tcx,
+        inliner.typing_env(),
+        ty::EarlyBinder::bind(callee_body.clone()),
+    ) else {
+        debug!("failed to normalize callee body");
+        return Err("implementation limitation");
+    };
+
+    // Normally, this shouldn't be required, but trait normalization failure can create a
+    // validation ICE.
+    if !validate_types(tcx, inliner.typing_env(), &callee_body, &caller_body).is_empty() {
+        debug!("failed to validate callee body");
+        return Err("implementation limitation");
+    }
+
+    // Check call signature compatibility.
+    // Normally, this shouldn't be required, but trait normalization failure can create a
+    // validation ICE.
+    let output_type = callee_body.return_ty();
+    if !util::sub_types(tcx, inliner.typing_env(), output_type, destination_ty) {
+        trace!(?output_type, ?destination_ty);
+        debug!("failed to normalize return type");
+        return Err("implementation limitation");
+    }
+    if callsite.fn_sig.abi() == ExternAbi::RustCall {
+        // FIXME: Don't inline user-written `extern "rust-call"` functions,
+        // since this is generally perf-negative on rustc, and we hope that
+        // LLVM will inline these functions instead.
+        if callee_body.spread_arg.is_some() {
+            return Err("user-written rust-call functions");
+        }
+
+        let (self_arg, arg_tuple) = match &args[..] {
+            [arg_tuple] => (None, arg_tuple),
+            [self_arg, arg_tuple] => (Some(self_arg), arg_tuple),
+            _ => bug!("Expected `rust-call` to have 1 or 2 args"),
         };
 
-        // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
-        // (or existing ones, in a few special cases) in the caller.
-        integrator.visit_body(&mut callee_body);
+        let self_arg_ty = self_arg.map(|self_arg| self_arg.node.ty(&caller_body.local_decls, tcx));
 
-        // If there are any locals without storage markers, give them storage only for the
-        // duration of the call.
-        for local in callee_body.vars_and_temps_iter() {
-            if integrator.always_live_locals.contains(local) {
-                let new_local = integrator.map_local(local);
-                caller_body[callsite.block].statements.push(Statement {
-                    source_info: callsite.source_info,
-                    kind: StatementKind::StorageLive(new_local),
-                });
+        let arg_tuple_ty = arg_tuple.node.ty(&caller_body.local_decls, tcx);
+        let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else {
+            bug!("Closure arguments are not passed as a tuple");
+        };
+
+        for (arg_ty, input) in
+            self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
+        {
+            let input_type = callee_body.local_decls[input].ty;
+            if !util::sub_types(tcx, inliner.typing_env(), input_type, arg_ty) {
+                trace!(?arg_ty, ?input_type);
+                debug!("failed to normalize tuple argument type");
+                return Err("implementation limitation");
             }
         }
-        if let Some(block) = return_block {
-            // To avoid repeated O(n) insert, push any new statements to the end and rotate
-            // the slice once.
-            let mut n = 0;
-            if remap_destination {
-                caller_body[block].statements.push(Statement {
-                    source_info: callsite.source_info,
-                    kind: StatementKind::Assign(Box::new((
-                        dest,
-                        Rvalue::Use(Operand::Move(destination_local.into())),
-                    ))),
-                });
-                n += 1;
+    } else {
+        for (arg, input) in args.iter().zip(callee_body.args_iter()) {
+            let input_type = callee_body.local_decls[input].ty;
+            let arg_ty = arg.node.ty(&caller_body.local_decls, tcx);
+            if !util::sub_types(tcx, inliner.typing_env(), input_type, arg_ty) {
+                trace!(?arg_ty, ?input_type);
+                debug!("failed to normalize argument type");
+                return Err("implementation limitation");
             }
-            for local in callee_body.vars_and_temps_iter().rev() {
-                if integrator.always_live_locals.contains(local) {
-                    let new_local = integrator.map_local(local);
-                    caller_body[block].statements.push(Statement {
-                        source_info: callsite.source_info,
-                        kind: StatementKind::StorageDead(new_local),
-                    });
-                    n += 1;
-                }
+        }
+    }
+
+    let old_blocks = caller_body.basic_blocks.next_index();
+    inline_call(inliner, caller_body, callsite, callee_body);
+    let new_blocks = old_blocks..caller_body.basic_blocks.next_index();
+
+    Ok(new_blocks)
+}
+
+fn check_mir_is_available<'tcx, I: Inliner<'tcx>>(
+    inliner: &I,
+    caller_body: &Body<'tcx>,
+    callee: Instance<'tcx>,
+) -> Result<(), &'static str> {
+    let caller_def_id = caller_body.source.def_id();
+    let callee_def_id = callee.def_id();
+    if callee_def_id == caller_def_id {
+        return Err("self-recursion");
+    }
+
+    match callee.def {
+        InstanceKind::Item(_) => {
+            // If there is no MIR available (either because it was not in metadata or
+            // because it has no MIR because it's an extern function), then the inliner
+            // won't cause cycles on this.
+            if !inliner.tcx().is_mir_available(callee_def_id) {
+                debug!("item MIR unavailable");
+                return Err("implementation limitation");
             }
-            caller_body[block].statements.rotate_right(n);
+        }
+        // These have no own callable MIR.
+        InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => {
+            debug!("instance without MIR (intrinsic / virtual)");
+            return Err("implementation limitation");
         }
 
-        // Insert all of the (mapped) parts of the callee body into the caller.
-        caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
-        caller_body.source_scopes.append(&mut callee_body.source_scopes);
-        if self
-            .tcx
-            .sess
-            .opts
-            .unstable_opts
-            .inline_mir_preserve_debug
-            .unwrap_or(self.tcx.sess.opts.debuginfo != DebugInfo::None)
-        {
-            // Note that we need to preserve these in the standard library so that
-            // people working on rust can build with or without debuginfo while
-            // still getting consistent results from the mir-opt tests.
-            caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
+        // FIXME(#127030): `ConstParamHasTy` has bad interactions with
+        // the drop shim builder, which does not evaluate predicates in
+        // the correct param-env for types being dropped. Stall resolving
+        // the MIR for this instance until all of its const params are
+        // substituted.
+        InstanceKind::DropGlue(_, Some(ty)) if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => {
+            debug!("still needs substitution");
+            return Err("implementation limitation");
         }
-        caller_body.basic_blocks_mut().append(callee_body.basic_blocks_mut());
 
-        caller_body[callsite.block].terminator = Some(Terminator {
-            source_info: callsite.source_info,
-            kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
-        });
+        // This cannot result in an immediate cycle since the callee MIR is a shim, which does
+        // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we
+        // do not need to catch this here, we can wait until the inliner decides to continue
+        // inlining a second time.
+        InstanceKind::VTableShim(_)
+        | InstanceKind::ReifyShim(..)
+        | InstanceKind::FnPtrShim(..)
+        | InstanceKind::ClosureOnceShim { .. }
+        | InstanceKind::ConstructCoroutineInClosureShim { .. }
+        | InstanceKind::DropGlue(..)
+        | InstanceKind::CloneShim(..)
+        | InstanceKind::ThreadLocalShim(..)
+        | InstanceKind::FnPtrAddrShim(..)
+        | InstanceKind::AsyncDropGlueCtorShim(..) => return Ok(()),
+    }
 
-        // Copy required constants from the callee_body into the caller_body. Although we are only
-        // pushing unevaluated consts to `required_consts`, here they may have been evaluated
-        // because we are calling `instantiate_and_normalize_erasing_regions` -- so we filter again.
-        caller_body.required_consts.as_mut().unwrap().extend(
-            callee_body.required_consts().into_iter().filter(|ct| ct.const_.is_required_const()),
-        );
-        // Now that we incorporated the callee's `required_consts`, we can remove the callee from
-        // `mentioned_items` -- but we have to take their `mentioned_items` in return. This does
-        // some extra work here to save the monomorphization collector work later. It helps a lot,
-        // since monomorphization can avoid a lot of work when the "mentioned items" are similar to
-        // the actually used items. By doing this we can entirely avoid visiting the callee!
-        // We need to reconstruct the `required_item` for the callee so that we can find and
-        // remove it.
-        let callee_item = MentionedItem::Fn(func.ty(caller_body, self.tcx));
-        let caller_mentioned_items = caller_body.mentioned_items.as_mut().unwrap();
-        if let Some(idx) = caller_mentioned_items.iter().position(|item| item.node == callee_item) {
-            // We found the callee, so remove it and add its items instead.
-            caller_mentioned_items.remove(idx);
-            caller_mentioned_items.extend(callee_body.mentioned_items());
-        } else {
-            // If we can't find the callee, there's no point in adding its items. Probably it
-            // already got removed by being inlined elsewhere in the same function, so we already
-            // took its items.
+    if inliner.tcx().is_constructor(callee_def_id) {
+        trace!("constructors always have MIR");
+        // Constructor functions cannot cause a query cycle.
+        return Ok(());
+    }
+
+    if callee_def_id.is_local()
+        && !inliner
+            .tcx()
+            .is_lang_item(inliner.tcx().parent(caller_def_id), rustc_hir::LangItem::FnOnce)
+    {
+        // If we know for sure that the function we're calling will itself try to
+        // call us, then we avoid inlining that function.
+        if inliner.tcx().mir_callgraph_reachable((callee, caller_def_id.expect_local())) {
+            debug!("query cycle avoidance");
+            return Err("caller might be reachable from callee");
         }
+
+        Ok(())
+    } else {
+        // This cannot result in an immediate cycle since the callee MIR is from another crate
+        // and is already optimized. Any subsequent inlining may cause cycles, but we do
+        // not need to catch this here, we can wait until the inliner decides to continue
+        // inlining a second time.
+        trace!("functions from other crates always have MIR");
+        Ok(())
     }
+}
 
-    fn make_call_args(
-        &self,
-        args: Box<[Spanned<Operand<'tcx>>]>,
-        callsite: &CallSite<'tcx>,
-        caller_body: &mut Body<'tcx>,
-        callee_body: &Body<'tcx>,
-        return_block: Option<BasicBlock>,
-    ) -> Box<[Local]> {
-        let tcx = self.tcx;
-
-        // There is a bit of a mismatch between the *caller* of a closure and the *callee*.
-        // The caller provides the arguments wrapped up in a tuple:
-        //
-        //     tuple_tmp = (a, b, c)
-        //     Fn::call(closure_ref, tuple_tmp)
-        //
-        // meanwhile the closure body expects the arguments (here, `a`, `b`, and `c`)
-        // as distinct arguments. (This is the "rust-call" ABI hack.) Normally, codegen has
-        // the job of unpacking this tuple. But here, we are codegen. =) So we want to create
-        // a vector like
-        //
-        //     [closure_ref, tuple_tmp.0, tuple_tmp.1, tuple_tmp.2]
-        //
-        // Except for one tiny wrinkle: we don't actually want `tuple_tmp.0`. It's more convenient
-        // if we "spill" that into *another* temporary, so that we can map the argument
-        // variable in the callee MIR directly to an argument variable on our side.
-        // So we introduce temporaries like:
-        //
-        //     tmp0 = tuple_tmp.0
-        //     tmp1 = tuple_tmp.1
-        //     tmp2 = tuple_tmp.2
-        //
-        // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
-        if callsite.fn_sig.abi() == ExternAbi::RustCall && callee_body.spread_arg.is_none() {
-            // FIXME(edition_2024): switch back to a normal method call.
-            let mut args = <_>::into_iter(args);
-            let self_ = self.create_temp_if_necessary(
-                args.next().unwrap().node,
-                callsite,
-                caller_body,
-                return_block,
-            );
-            let tuple = self.create_temp_if_necessary(
-                args.next().unwrap().node,
-                callsite,
-                caller_body,
-                return_block,
-            );
-            assert!(args.next().is_none());
-
-            let tuple = Place::from(tuple);
-            let ty::Tuple(tuple_tys) = tuple.ty(caller_body, tcx).ty.kind() else {
-                bug!("Closure arguments are not passed as a tuple");
-            };
+/// Returns an error if inlining is not possible based on codegen attributes alone. A success
+/// indicates that inlining decision should be based on other criteria.
+fn check_codegen_attributes<'tcx, I: Inliner<'tcx>>(
+    inliner: &I,
+    callsite: &CallSite<'tcx>,
+    callee_attrs: &CodegenFnAttrs,
+) -> Result<(), &'static str> {
+    let tcx = inliner.tcx();
+    if let InlineAttr::Never = callee_attrs.inline {
+        return Err("never inline attribute");
+    }
 
-            // The `closure_ref` in our example above.
-            let closure_ref_arg = iter::once(self_);
+    // Reachability pass defines which functions are eligible for inlining. Generally inlining
+    // other functions is incorrect because they could reference symbols that aren't exported.
+    let is_generic = callsite.callee.args.non_erasable_generics().next().is_some();
+    if !is_generic && !tcx.cross_crate_inlinable(callsite.callee.def_id()) {
+        return Err("not exported");
+    }
 
-            // The `tmp0`, `tmp1`, and `tmp2` in our example above.
-            let tuple_tmp_args = tuple_tys.iter().enumerate().map(|(i, ty)| {
-                // This is e.g., `tuple_tmp.0` in our example above.
-                let tuple_field = Operand::Move(tcx.mk_place_field(tuple, FieldIdx::new(i), ty));
+    let codegen_fn_attrs = tcx.codegen_fn_attrs(inliner.caller_def_id());
+    if callee_attrs.no_sanitize != codegen_fn_attrs.no_sanitize {
+        return Err("incompatible sanitizer set");
+    }
 
-                // Spill to a local to make e.g., `tmp0`.
-                self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block)
-            });
+    // Two functions are compatible if the callee has no attribute (meaning
+    // that it's codegen agnostic), or sets an attribute that is identical
+    // to this function's attribute.
+    if callee_attrs.instruction_set.is_some()
+        && callee_attrs.instruction_set != codegen_fn_attrs.instruction_set
+    {
+        return Err("incompatible instruction set");
+    }
 
-            closure_ref_arg.chain(tuple_tmp_args).collect()
-        } else {
-            // FIXME(edition_2024): switch back to a normal method call.
-            <_>::into_iter(args)
-                .map(|a| self.create_temp_if_necessary(a.node, callsite, caller_body, return_block))
-                .collect()
-        }
+    let callee_feature_names = callee_attrs.target_features.iter().map(|f| f.name);
+    let this_feature_names = codegen_fn_attrs.target_features.iter().map(|f| f.name);
+    if callee_feature_names.ne(this_feature_names) {
+        // In general it is not correct to inline a callee with target features that are a
+        // subset of the caller. This is because the callee might contain calls, and the ABI of
+        // those calls depends on the target features of the surrounding function. By moving a
+        // `Call` terminator from one MIR body to another with more target features, we might
+        // change the ABI of that call!
+        return Err("incompatible target features");
     }
 
-    /// If `arg` is already a temporary, returns it. Otherwise, introduces a fresh
-    /// temporary `T` and an instruction `T = arg`, and returns `T`.
-    fn create_temp_if_necessary(
-        &self,
-        arg: Operand<'tcx>,
-        callsite: &CallSite<'tcx>,
-        caller_body: &mut Body<'tcx>,
-        return_block: Option<BasicBlock>,
-    ) -> Local {
-        // Reuse the operand if it is a moved temporary.
-        if let Operand::Move(place) = &arg
-            && let Some(local) = place.as_local()
-            && caller_body.local_kind(local) == LocalKind::Temp
-        {
-            return local;
+    Ok(())
+}
+
+fn inline_call<'tcx, I: Inliner<'tcx>>(
+    inliner: &I,
+    caller_body: &mut Body<'tcx>,
+    callsite: &CallSite<'tcx>,
+    mut callee_body: Body<'tcx>,
+) {
+    let tcx = inliner.tcx();
+    let terminator = caller_body[callsite.block].terminator.take().unwrap();
+    let TerminatorKind::Call { func, args, destination, unwind, target, .. } = terminator.kind
+    else {
+        bug!("unexpected terminator kind {:?}", terminator.kind);
+    };
+
+    let return_block = if let Some(block) = target {
+        // Prepare a new block for code that should execute when call returns. We don't use
+        // target block directly since it might have other predecessors.
+        let data = BasicBlockData::new(
+            Some(Terminator {
+                source_info: terminator.source_info,
+                kind: TerminatorKind::Goto { target: block },
+            }),
+            caller_body[block].is_cleanup,
+        );
+        Some(caller_body.basic_blocks_mut().push(data))
+    } else {
+        None
+    };
+
+    // If the call is something like `a[*i] = f(i)`, where
+    // `i : &mut usize`, then just duplicating the `a[*i]`
+    // Place could result in two different locations if `f`
+    // writes to `i`. To prevent this we need to create a temporary
+    // borrow of the place and pass the destination as `*temp` instead.
+    fn dest_needs_borrow(place: Place<'_>) -> bool {
+        for elem in place.projection.iter() {
+            match elem {
+                ProjectionElem::Deref | ProjectionElem::Index(_) => return true,
+                _ => {}
+            }
         }
 
-        // Otherwise, create a temporary for the argument.
-        trace!("creating temp for argument {:?}", arg);
-        let arg_ty = arg.ty(caller_body, self.tcx);
-        let local = self.new_call_temp(caller_body, callsite, arg_ty, return_block);
-        caller_body[callsite.block].statements.push(Statement {
-            source_info: callsite.source_info,
-            kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))),
-        });
-        local
+        false
     }
 
-    /// Introduces a new temporary into the caller body that is live for the duration of the call.
-    fn new_call_temp(
-        &self,
-        caller_body: &mut Body<'tcx>,
-        callsite: &CallSite<'tcx>,
-        ty: Ty<'tcx>,
-        return_block: Option<BasicBlock>,
-    ) -> Local {
-        let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span));
-
+    let dest = if dest_needs_borrow(destination) {
+        trace!("creating temp for return destination");
+        let dest = Rvalue::Ref(
+            tcx.lifetimes.re_erased,
+            BorrowKind::Mut { kind: MutBorrowKind::Default },
+            destination,
+        );
+        let dest_ty = dest.ty(caller_body, tcx);
+        let temp = Place::from(new_call_temp(caller_body, callsite, dest_ty, return_block));
         caller_body[callsite.block].statements.push(Statement {
             source_info: callsite.source_info,
-            kind: StatementKind::StorageLive(local),
+            kind: StatementKind::Assign(Box::new((temp, dest))),
         });
+        tcx.mk_place_deref(temp)
+    } else {
+        destination
+    };
+
+    // Always create a local to hold the destination, as `RETURN_PLACE` may appear
+    // where a full `Place` is not allowed.
+    let (remap_destination, destination_local) = if let Some(d) = dest.as_local() {
+        (false, d)
+    } else {
+        (
+            true,
+            new_call_temp(caller_body, callsite, destination.ty(caller_body, tcx).ty, return_block),
+        )
+    };
 
-        if let Some(block) = return_block {
-            caller_body[block].statements.insert(0, Statement {
+    // Copy the arguments if needed.
+    let args = make_call_args(inliner, args, callsite, caller_body, &callee_body, return_block);
+
+    let mut integrator = Integrator {
+        args: &args,
+        new_locals: Local::new(caller_body.local_decls.len())..,
+        new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
+        new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
+        destination: destination_local,
+        callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
+        callsite,
+        cleanup_block: unwind,
+        in_cleanup_block: false,
+        return_block,
+        tcx,
+        always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
+    };
+
+    // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
+    // (or existing ones, in a few special cases) in the caller.
+    integrator.visit_body(&mut callee_body);
+
+    // If there are any locals without storage markers, give them storage only for the
+    // duration of the call.
+    for local in callee_body.vars_and_temps_iter() {
+        if integrator.always_live_locals.contains(local) {
+            let new_local = integrator.map_local(local);
+            caller_body[callsite.block].statements.push(Statement {
+                source_info: callsite.source_info,
+                kind: StatementKind::StorageLive(new_local),
+            });
+        }
+    }
+    if let Some(block) = return_block {
+        // To avoid repeated O(n) insert, push any new statements to the end and rotate
+        // the slice once.
+        let mut n = 0;
+        if remap_destination {
+            caller_body[block].statements.push(Statement {
                 source_info: callsite.source_info,
-                kind: StatementKind::StorageDead(local),
+                kind: StatementKind::Assign(Box::new((
+                    dest,
+                    Rvalue::Use(Operand::Move(destination_local.into())),
+                ))),
             });
+            n += 1;
+        }
+        for local in callee_body.vars_and_temps_iter().rev() {
+            if integrator.always_live_locals.contains(local) {
+                let new_local = integrator.map_local(local);
+                caller_body[block].statements.push(Statement {
+                    source_info: callsite.source_info,
+                    kind: StatementKind::StorageDead(new_local),
+                });
+                n += 1;
+            }
         }
+        caller_body[block].statements.rotate_right(n);
+    }
 
-        local
+    // Insert all of the (mapped) parts of the callee body into the caller.
+    caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
+    caller_body.source_scopes.append(&mut callee_body.source_scopes);
+    if tcx
+        .sess
+        .opts
+        .unstable_opts
+        .inline_mir_preserve_debug
+        .unwrap_or(tcx.sess.opts.debuginfo != DebugInfo::None)
+    {
+        // Note that we need to preserve these in the standard library so that
+        // people working on rust can build with or without debuginfo while
+        // still getting consistent results from the mir-opt tests.
+        caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
     }
+    caller_body.basic_blocks_mut().append(callee_body.basic_blocks_mut());
+
+    caller_body[callsite.block].terminator = Some(Terminator {
+        source_info: callsite.source_info,
+        kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
+    });
+
+    // Copy required constants from the callee_body into the caller_body. Although we are only
+    // pushing unevaluated consts to `required_consts`, here they may have been evaluated
+    // because we are calling `instantiate_and_normalize_erasing_regions` -- so we filter again.
+    caller_body.required_consts.as_mut().unwrap().extend(
+        callee_body.required_consts().into_iter().filter(|ct| ct.const_.is_required_const()),
+    );
+    // Now that we incorporated the callee's `required_consts`, we can remove the callee from
+    // `mentioned_items` -- but we have to take their `mentioned_items` in return. This does
+    // some extra work here to save the monomorphization collector work later. It helps a lot,
+    // since monomorphization can avoid a lot of work when the "mentioned items" are similar to
+    // the actually used items. By doing this we can entirely avoid visiting the callee!
+    // We need to reconstruct the `required_item` for the callee so that we can find and
+    // remove it.
+    let callee_item = MentionedItem::Fn(func.ty(caller_body, tcx));
+    let caller_mentioned_items = caller_body.mentioned_items.as_mut().unwrap();
+    if let Some(idx) = caller_mentioned_items.iter().position(|item| item.node == callee_item) {
+        // We found the callee, so remove it and add its items instead.
+        caller_mentioned_items.remove(idx);
+        caller_mentioned_items.extend(callee_body.mentioned_items());
+    } else {
+        // If we can't find the callee, there's no point in adding its items. Probably it
+        // already got removed by being inlined elsewhere in the same function, so we already
+        // took its items.
+    }
+}
+
+fn make_call_args<'tcx, I: Inliner<'tcx>>(
+    inliner: &I,
+    args: Box<[Spanned<Operand<'tcx>>]>,
+    callsite: &CallSite<'tcx>,
+    caller_body: &mut Body<'tcx>,
+    callee_body: &Body<'tcx>,
+    return_block: Option<BasicBlock>,
+) -> Box<[Local]> {
+    let tcx = inliner.tcx();
+
+    // There is a bit of a mismatch between the *caller* of a closure and the *callee*.
+    // The caller provides the arguments wrapped up in a tuple:
+    //
+    //     tuple_tmp = (a, b, c)
+    //     Fn::call(closure_ref, tuple_tmp)
+    //
+    // meanwhile the closure body expects the arguments (here, `a`, `b`, and `c`)
+    // as distinct arguments. (This is the "rust-call" ABI hack.) Normally, codegen has
+    // the job of unpacking this tuple. But here, we are codegen. =) So we want to create
+    // a vector like
+    //
+    //     [closure_ref, tuple_tmp.0, tuple_tmp.1, tuple_tmp.2]
+    //
+    // Except for one tiny wrinkle: we don't actually want `tuple_tmp.0`. It's more convenient
+    // if we "spill" that into *another* temporary, so that we can map the argument
+    // variable in the callee MIR directly to an argument variable on our side.
+    // So we introduce temporaries like:
+    //
+    //     tmp0 = tuple_tmp.0
+    //     tmp1 = tuple_tmp.1
+    //     tmp2 = tuple_tmp.2
+    //
+    // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
+    if callsite.fn_sig.abi() == ExternAbi::RustCall && callee_body.spread_arg.is_none() {
+        // FIXME(edition_2024): switch back to a normal method call.
+        let mut args = <_>::into_iter(args);
+        let self_ = create_temp_if_necessary(
+            inliner,
+            args.next().unwrap().node,
+            callsite,
+            caller_body,
+            return_block,
+        );
+        let tuple = create_temp_if_necessary(
+            inliner,
+            args.next().unwrap().node,
+            callsite,
+            caller_body,
+            return_block,
+        );
+        assert!(args.next().is_none());
+
+        let tuple = Place::from(tuple);
+        let ty::Tuple(tuple_tys) = tuple.ty(caller_body, tcx).ty.kind() else {
+            bug!("Closure arguments are not passed as a tuple");
+        };
+
+        // The `closure_ref` in our example above.
+        let closure_ref_arg = iter::once(self_);
+
+        // The `tmp0`, `tmp1`, and `tmp2` in our example above.
+        let tuple_tmp_args = tuple_tys.iter().enumerate().map(|(i, ty)| {
+            // This is e.g., `tuple_tmp.0` in our example above.
+            let tuple_field = Operand::Move(tcx.mk_place_field(tuple, FieldIdx::new(i), ty));
+
+            // Spill to a local to make e.g., `tmp0`.
+            create_temp_if_necessary(inliner, tuple_field, callsite, caller_body, return_block)
+        });
+
+        closure_ref_arg.chain(tuple_tmp_args).collect()
+    } else {
+        // FIXME(edition_2024): switch back to a normal method call.
+        <_>::into_iter(args)
+            .map(|a| create_temp_if_necessary(inliner, a.node, callsite, caller_body, return_block))
+            .collect()
+    }
+}
+
+/// If `arg` is already a temporary, returns it. Otherwise, introduces a fresh temporary `T` and an
+/// instruction `T = arg`, and returns `T`.
+fn create_temp_if_necessary<'tcx, I: Inliner<'tcx>>(
+    inliner: &I,
+    arg: Operand<'tcx>,
+    callsite: &CallSite<'tcx>,
+    caller_body: &mut Body<'tcx>,
+    return_block: Option<BasicBlock>,
+) -> Local {
+    // Reuse the operand if it is a moved temporary.
+    if let Operand::Move(place) = &arg
+        && let Some(local) = place.as_local()
+        && caller_body.local_kind(local) == LocalKind::Temp
+    {
+        return local;
+    }
+
+    // Otherwise, create a temporary for the argument.
+    trace!("creating temp for argument {:?}", arg);
+    let arg_ty = arg.ty(caller_body, inliner.tcx());
+    let local = new_call_temp(caller_body, callsite, arg_ty, return_block);
+    caller_body[callsite.block].statements.push(Statement {
+        source_info: callsite.source_info,
+        kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))),
+    });
+    local
+}
+
+/// Introduces a new temporary into the caller body that is live for the duration of the call.
+fn new_call_temp<'tcx>(
+    caller_body: &mut Body<'tcx>,
+    callsite: &CallSite<'tcx>,
+    ty: Ty<'tcx>,
+    return_block: Option<BasicBlock>,
+) -> Local {
+    let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span));
+
+    caller_body[callsite.block].statements.push(Statement {
+        source_info: callsite.source_info,
+        kind: StatementKind::StorageLive(local),
+    });
+
+    if let Some(block) = return_block {
+        caller_body[block].statements.insert(0, Statement {
+            source_info: callsite.source_info,
+            kind: StatementKind::StorageDead(local),
+        });
+    }
+
+    local
 }
 
 /**
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index e1fba9be5bb..350929ffaa5 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -141,7 +141,7 @@ declare_passes! {
     mod gvn : GVN;
     // Made public so that `mir_drops_elaborated_and_const_checked` can be overridden
     // by custom rustc drivers, running all the steps by themselves. See #114628.
-    pub mod inline : Inline;
+    pub mod inline : Inline, ForceInline;
     mod instsimplify : InstSimplify { BeforeInline, AfterSimplifyCfg };
     mod jump_threading : JumpThreading;
     mod known_panics_lint : KnownPanicsLint;
@@ -488,7 +488,9 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
     let is_fn_like = tcx.def_kind(def).is_fn_like();
     if is_fn_like {
         // Do not compute the mir call graph without said call graph actually being used.
-        if pm::should_run_pass(tcx, &inline::Inline) {
+        if pm::should_run_pass(tcx, &inline::Inline)
+            || inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id())
+        {
             tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
         }
     }
@@ -664,6 +666,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             // Perform instsimplify before inline to eliminate some trivial calls (like clone
             // shims).
             &instsimplify::InstSimplify::BeforeInline,
+            // Perform inlining of `#[rustc_force_inline]`-annotated callees.
+            &inline::ForceInline,
             // Perform inlining, which may add a lot of code.
             &inline::Inline,
             // Code from other crates may have storage markers, so this needs to happen after
diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
index 6590702118c..50d10883d2c 100644
--- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
+++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
@@ -691,7 +691,7 @@ impl Subdiagnostic for LocalLabel<'_> {
         for dtor in self.destructors {
             dtor.add_to_diag_with(diag, f);
         }
-        let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue.into());
+        let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue);
         diag.span_label(self.span, msg);
     }
 }
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 8a45ce0762d..c3f0a989ce1 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -79,6 +79,12 @@ pub(super) trait MirPass<'tcx> {
         true
     }
 
+    /// Returns `true` if this pass can be overridden by `-Zenable-mir-passes`. This should be
+    /// true for basically every pass other than those that are necessary for correctness.
+    fn can_be_overridden(&self) -> bool {
+        true
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
 
     fn is_mir_dump_enabled(&self) -> bool {
@@ -176,6 +182,10 @@ where
 {
     let name = pass.name();
 
+    if !pass.can_be_overridden() {
+        return pass.is_enabled(tcx.sess);
+    }
+
     let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
     let overridden =
         overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| {
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 722da3c420d..4648ec33c93 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -20,7 +20,7 @@ use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument};
 
 use crate::{
-    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator,
+    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, inline,
     instsimplify, mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify,
 };
 
@@ -155,6 +155,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
             &remove_noop_landing_pads::RemoveNoopLandingPads,
             &simplify::SimplifyCfg::MakeShim,
             &instsimplify::InstSimplify::BeforeInline,
+            // Perform inlining of `#[rustc_force_inline]`-annotated callees.
+            &inline::ForceInline,
             &abort_unwinding_calls::AbortUnwindingCalls,
             &add_call_guards::CriticalCallEdges,
         ],
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index a670da94fcc..035670d4903 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -1,6 +1,7 @@
 //! Validates the MIR to ensure that invariants are upheld.
 
 use rustc_abi::{ExternAbi, FIRST_VARIANT, Size};
+use rustc_attr_parsing::InlineAttr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::LangItem;
 use rustc_index::IndexVec;
@@ -366,7 +367,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
                 self.check_edge(location, *target, EdgeKind::Normal);
                 self.check_unwind_edge(location, *unwind);
             }
-            TerminatorKind::Call { args, .. } | TerminatorKind::TailCall { args, .. } => {
+            TerminatorKind::Call { func, args, .. }
+            | TerminatorKind::TailCall { func, args, .. } => {
                 // FIXME(explicit_tail_calls): refactor this & add tail-call specific checks
                 if let TerminatorKind::Call { target, unwind, destination, .. } = terminator.kind {
                     if let Some(target) = target {
@@ -419,6 +421,13 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
                         }
                     }
                 }
+
+                if let ty::FnDef(did, ..) = func.ty(&self.body.local_decls, self.tcx).kind()
+                    && self.body.phase >= MirPhase::Runtime(RuntimePhase::Optimized)
+                    && matches!(self.tcx.codegen_fn_attrs(did).inline, InlineAttr::Force { .. })
+                {
+                    self.fail(location, "`#[rustc_force_inline]`-annotated function not inlined");
+                }
             }
             TerminatorKind::Assert { target, unwind, .. } => {
                 self.check_edge(location, *target, EdgeKind::Normal);
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 00aae03704f..416054d85fd 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -207,6 +207,7 @@
 
 use std::path::PathBuf;
 
+use rustc_attr_parsing::InlineAttr;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
@@ -224,8 +225,8 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
-    TypeVisitableExt, VtblEntry,
+    self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Interner, Ty, TyCtxt,
+    TypeFoldable, TypeVisitableExt, VtblEntry,
 };
 use rustc_middle::util::Providers;
 use rustc_middle::{bug, span_bug};
@@ -959,6 +960,14 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
         return false;
     }
 
+    if tcx.def_kind(def_id).has_codegen_attrs()
+        && matches!(tcx.codegen_fn_attrs(def_id).inline, InlineAttr::Force { .. })
+    {
+        // `#[rustc_force_inline]` items should never be codegened. This should be caught by
+        // the MIR validator.
+        tcx.delay_bug("attempt to codegen `#[rustc_force_inline]` item");
+    }
+
     if def_id.is_local() {
         // Local items cannot be referred to locally without monomorphizing them locally.
         return true;
@@ -1453,7 +1462,9 @@ impl<'v> RootCollector<'_, 'v> {
     fn is_root(&self, def_id: LocalDefId) -> bool {
         !self.tcx.generics_of(def_id).requires_monomorphization(self.tcx)
             && match self.strategy {
-                MonoItemCollectionStrategy::Eager => true,
+                MonoItemCollectionStrategy::Eager => {
+                    !matches!(self.tcx.codegen_fn_attrs(def_id).inline, InlineAttr::Force { .. })
+                }
                 MonoItemCollectionStrategy::Lazy => {
                     self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id)
                         || self.tcx.is_reachable_non_generic(def_id)
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index f39bea2a56f..9df396cbf7a 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -656,6 +656,14 @@ passes_rustc_allow_const_fn_unstable =
 passes_rustc_dirty_clean =
     attribute requires -Z query-dep-graph to be enabled
 
+passes_rustc_force_inline =
+    attribute should be applied to a function
+    .label = not a function definition
+
+passes_rustc_force_inline_coro =
+    attribute cannot be applied to a `async`, `gen` or `async gen` function
+    .label = `async`, `gen` or `async gen` function
+
 passes_rustc_layout_scalar_valid_range_arg =
     expected exactly one integer literal argument
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 7656ca86c18..1b2b8ac5dd9 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -247,7 +247,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     self.check_coroutine(attr, target);
                 }
                 [sym::linkage, ..] => self.check_linkage(attr, span, target),
-                [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent( attr.span, span, attrs),
+                [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span, span, attrs),
                 [
                     // ok
                     sym::allow
@@ -332,6 +332,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
 
         self.check_repr(attrs, span, target, item, hir_id);
         self.check_used(attrs, target, span);
+        self.check_rustc_force_inline(hir_id, attrs, span, target);
     }
 
     fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
@@ -2480,6 +2481,45 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
+    fn check_rustc_force_inline(
+        &self,
+        hir_id: HirId,
+        attrs: &[Attribute],
+        span: Span,
+        target: Target,
+    ) {
+        let force_inline_attr = attrs.iter().find(|attr| attr.has_name(sym::rustc_force_inline));
+        match (target, force_inline_attr) {
+            (Target::Closure, None) => {
+                let is_coro = matches!(
+                    self.tcx.hir().expect_expr(hir_id).kind,
+                    hir::ExprKind::Closure(hir::Closure {
+                        kind: hir::ClosureKind::Coroutine(..)
+                            | hir::ClosureKind::CoroutineClosure(..),
+                        ..
+                    })
+                );
+                let parent_did = self.tcx.hir().get_parent_item(hir_id).to_def_id();
+                let parent_span = self.tcx.def_span(parent_did);
+                let parent_force_inline_attr =
+                    self.tcx.get_attr(parent_did, sym::rustc_force_inline);
+                if let Some(attr) = parent_force_inline_attr
+                    && is_coro
+                {
+                    self.dcx().emit_err(errors::RustcForceInlineCoro {
+                        attr_span: attr.span,
+                        span: parent_span,
+                    });
+                }
+            }
+            (Target::Fn, _) => (),
+            (_, Some(attr)) => {
+                self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span, span });
+            }
+            (_, None) => (),
+        }
+    }
+
     /// Checks if `#[autodiff]` is applied to an item other than a function item.
     fn check_autodiff(&self, _hir_id: HirId, _attr: &Attribute, span: Span, target: Target) {
         debug!("check_autodiff");
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index d95fa5db0ce..13da021c614 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -689,6 +689,24 @@ pub(crate) struct RustcPubTransparent {
 }
 
 #[derive(Diagnostic)]
+#[diag(passes_rustc_force_inline)]
+pub(crate) struct RustcForceInline {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_rustc_force_inline_coro)]
+pub(crate) struct RustcForceInlineCoro {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(passes_link_ordinal)]
 pub(crate) struct LinkOrdinal {
     #[primary_span]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ef1e2c20978..a5bf5e06485 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1731,6 +1731,7 @@ symbols! {
         rustc_error,
         rustc_evaluate_where_clauses,
         rustc_expected_cgu_reuse,
+        rustc_force_inline,
         rustc_has_incoherent_inherent_impls,
         rustc_hidden_type_of_opaques,
         rustc_if_this_changed,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 333ea0214eb..58c0a05df1f 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -8,7 +8,6 @@ use rustc_middle::bug;
 use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
 use rustc_middle::ty::{
     self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt,
-    TypingEnv,
 };
 use tracing::debug;
 
@@ -387,23 +386,44 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
     ) -> Result<(), PrintError> {
         let self_ty = self.tcx.type_of(impl_def_id);
         let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
-        let (typing_env, mut self_ty, mut impl_trait_ref) =
-            if self.tcx.generics_of(impl_def_id).count() <= args.len() {
-                (
-                    TypingEnv::fully_monomorphized(),
-                    self_ty.instantiate(self.tcx, args),
-                    impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
-                )
-            } else {
-                // We are probably printing a nested item inside of an impl.
-                // Use the identity substitutions for the impl. We also need
-                // a well-formed param-env, so let's use post-analysis.
-                (
-                    TypingEnv::post_analysis(self.tcx, impl_def_id),
-                    self_ty.instantiate_identity(),
-                    impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
-                )
-            };
+        let generics = self.tcx.generics_of(impl_def_id);
+        // We have two cases to worry about here:
+        // 1. We're printing a nested item inside of an impl item, like an inner
+        // function inside of a method. Due to the way that def path printing works,
+        // we'll render this something like `<Ty as Trait>::method::inner_fn`
+        // but we have no substs for this impl since it's not really inheriting
+        // generics from the outer item. We need to use the identity substs, and
+        // to normalize we need to use the correct param-env too.
+        // 2. We're mangling an item with identity substs. This seems to only happen
+        // when generating coverage, since we try to generate coverage for unused
+        // items too, and if something isn't monomorphized then we necessarily don't
+        // have anything to substitute the instance with.
+        // NOTE: We don't support mangling partially substituted but still polymorphic
+        // instances, like `impl<A> Tr<A> for ()` where `A` is substituted w/ `(T,)`.
+        let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len()
+            || &args[..generics.count()]
+                == self
+                    .tcx
+                    .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id))
+                    .as_slice()
+        {
+            (
+                ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
+                self_ty.instantiate_identity(),
+                impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
+            )
+        } else {
+            assert!(
+                !args.has_non_region_param(),
+                "should not be mangling partially substituted \
+                polymorphic instance: {impl_def_id:?} {args:?}"
+            );
+            (
+                ty::TypingEnv::fully_monomorphized(),
+                self_ty.instantiate(self.tcx, args),
+                impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
+            )
+        };
 
         match &mut impl_trait_ref {
             Some(impl_trait_ref) => {
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index b77ad209e2b..4ddf530a00d 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -233,23 +233,44 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
 
         let self_ty = self.tcx.type_of(impl_def_id);
         let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
-        let (typing_env, mut self_ty, mut impl_trait_ref) =
-            if self.tcx.generics_of(impl_def_id).count() <= args.len() {
-                (
-                    ty::TypingEnv::fully_monomorphized(),
-                    self_ty.instantiate(self.tcx, args),
-                    impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
-                )
-            } else {
-                // We are probably printing a nested item inside of an impl.
-                // Use the identity substitutions for the impl. We also need
-                // a well-formed param-env, so let's use post-analysis.
-                (
-                    ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
-                    self_ty.instantiate_identity(),
-                    impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
-                )
-            };
+        let generics = self.tcx.generics_of(impl_def_id);
+        // We have two cases to worry about here:
+        // 1. We're printing a nested item inside of an impl item, like an inner
+        // function inside of a method. Due to the way that def path printing works,
+        // we'll render this something like `<Ty as Trait>::method::inner_fn`
+        // but we have no substs for this impl since it's not really inheriting
+        // generics from the outer item. We need to use the identity substs, and
+        // to normalize we need to use the correct param-env too.
+        // 2. We're mangling an item with identity substs. This seems to only happen
+        // when generating coverage, since we try to generate coverage for unused
+        // items too, and if something isn't monomorphized then we necessarily don't
+        // have anything to substitute the instance with.
+        // NOTE: We don't support mangling partially substituted but still polymorphic
+        // instances, like `impl<A> Tr<A> for ()` where `A` is substituted w/ `(T,)`.
+        let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len()
+            || &args[..generics.count()]
+                == self
+                    .tcx
+                    .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id))
+                    .as_slice()
+        {
+            (
+                ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
+                self_ty.instantiate_identity(),
+                impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
+            )
+        } else {
+            assert!(
+                !args.has_non_region_param(),
+                "should not be mangling partially substituted \
+                polymorphic instance: {impl_def_id:?} {args:?}"
+            );
+            (
+                ty::TypingEnv::fully_monomorphized(),
+                self_ty.instantiate(self.tcx, args),
+                impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
+            )
+        };
 
         match &mut impl_trait_ref {
             Some(impl_trait_ref) => {
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 1ab89ecde7a..b82bb27eb79 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -251,7 +251,9 @@ trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a
 
 trait_selection_nothing = {""}
 
-trait_selection_oc_cant_coerce = cannot coerce intrinsics to function pointers
+trait_selection_oc_cant_coerce_force_inline =
+    cannot coerce functions which must be inlined to function pointers
+trait_selection_oc_cant_coerce_intrinsic = cannot coerce intrinsics to function pointers
 trait_selection_oc_closure_selfref = closure/coroutine type that references itself
 trait_selection_oc_const_compat = const not compatible with trait
 trait_selection_oc_fn_lang_correct_type = {$lang_item_name ->
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index d279590d45a..53300c95fa7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -2294,7 +2294,7 @@ impl<'tcx> ObligationCause<'tcx> {
                 {
                     FailureCode::Error0644
                 }
-                TypeError::IntrinsicCast => FailureCode::Error0308,
+                TypeError::IntrinsicCast | TypeError::ForceInlineCast => FailureCode::Error0308,
                 _ => FailureCode::Error0308,
             },
         }
@@ -2360,8 +2360,11 @@ impl<'tcx> ObligationCause<'tcx> {
                 {
                     ObligationCauseFailureCode::ClosureSelfref { span }
                 }
+                TypeError::ForceInlineCast => {
+                    ObligationCauseFailureCode::CantCoerceForceInline { span, subdiags }
+                }
                 TypeError::IntrinsicCast => {
-                    ObligationCauseFailureCode::CantCoerce { span, subdiags }
+                    ObligationCauseFailureCode::CantCoerceIntrinsic { span, subdiags }
                 }
                 _ => ObligationCauseFailureCode::Generic { span, subdiags },
             },
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index a8fddff4e4a..53a4e5031c6 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1729,8 +1729,15 @@ pub enum ObligationCauseFailureCode {
         #[primary_span]
         span: Span,
     },
-    #[diag(trait_selection_oc_cant_coerce, code = E0308)]
-    CantCoerce {
+    #[diag(trait_selection_oc_cant_coerce_force_inline, code = E0308)]
+    CantCoerceForceInline {
+        #[primary_span]
+        span: Span,
+        #[subdiagnostic]
+        subdiags: Vec<TypeErrorAdditionalDiags>,
+    },
+    #[diag(trait_selection_oc_cant_coerce_intrinsic, code = E0308)]
+    CantCoerceIntrinsic {
         #[primary_span]
         span: Span,
         #[subdiagnostic]
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 637e239a570..51a7c976f60 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -4,7 +4,7 @@ use rustc_abi::{FIRST_VARIANT, VariantIdx};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
-use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::mir::interpret::LitToConstInput;
 use rustc_middle::query::Providers;
 use rustc_middle::thir::visit;
 use rustc_middle::thir::visit::Visitor;
@@ -118,13 +118,7 @@ fn recurse_build<'tcx>(
         }
         &ExprKind::Literal { lit, neg } => {
             let sp = node.span;
-            match tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) {
-                Ok(c) => c,
-                Err(LitToConstError::Reported(guar)) => ty::Const::new_error(tcx, guar),
-                Err(LitToConstError::TypeError) => {
-                    bug!("encountered type error in lit_to_const")
-                }
-            }
+            tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg })
         }
         &ExprKind::NonHirLiteral { lit, user_ty: _ } => {
             let val = ty::ValTree::from_scalar_int(lit);
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 9f138cf1275..fae787f9a40 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -347,6 +347,7 @@ fn layout_of_uncached<'tcx>(
                 size,
                 max_repr_align: None,
                 unadjusted_abi_align: element.align.abi,
+                randomization_seed: element.randomization_seed.wrapping_add(count),
             })
         }
         ty::Slice(element) => {
@@ -360,6 +361,8 @@ fn layout_of_uncached<'tcx>(
                 size: Size::ZERO,
                 max_repr_align: None,
                 unadjusted_abi_align: element.align.abi,
+                // adding a randomly chosen value to distinguish slices
+                randomization_seed: element.randomization_seed.wrapping_add(0x2dcba99c39784102),
             })
         }
         ty::Str => tcx.mk_layout(LayoutData {
@@ -371,6 +374,8 @@ fn layout_of_uncached<'tcx>(
             size: Size::ZERO,
             max_repr_align: None,
             unadjusted_abi_align: dl.i8_align.abi,
+            // another random value
+            randomization_seed: 0xc1325f37d127be22,
         }),
 
         // Odd unit types.
@@ -542,6 +547,7 @@ fn layout_of_uncached<'tcx>(
                 align,
                 max_repr_align: None,
                 unadjusted_abi_align: align.abi,
+                randomization_seed: e_ly.randomization_seed.wrapping_add(e_len),
             })
         }
 
@@ -999,6 +1005,9 @@ fn coroutine_layout<'tcx>(
         BackendRepr::Memory { sized: true }
     };
 
+    // this is similar to how ReprOptions populates its field_shuffle_seed
+    let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash().as_u64();
+
     let layout = tcx.mk_layout(LayoutData {
         variants: Variants::Multiple {
             tag,
@@ -1019,6 +1028,7 @@ fn coroutine_layout<'tcx>(
         align,
         max_repr_align: None,
         unadjusted_abi_align: align.abi,
+        randomization_seed: def_hash,
     });
     debug!("coroutine layout ({:?}): {:#?}", ty, layout);
     Ok(layout)
diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs
index 55671b84dbc..68b11489ae7 100644
--- a/compiler/rustc_type_ir/src/error.rs
+++ b/compiler/rustc_type_ir/src/error.rs
@@ -51,6 +51,9 @@ pub enum TypeError<I: Interner> {
     ConstMismatch(ExpectedFound<I::Const>),
 
     IntrinsicCast,
+    /// `#[rustc_force_inline]` functions must be inlined and must not be codegened independently,
+    /// so casting to a function pointer must be prohibited.
+    ForceInlineCast,
     /// Safe `#[target_feature]` functions are not assignable to safe function pointers.
     TargetFeatureCast(I::DefId),
 }
@@ -83,6 +86,7 @@ impl<I: Interner> TypeError<I> {
             | ProjectionMismatched(_)
             | ExistentialMismatch(_)
             | ConstMismatch(_)
+            | ForceInlineCast
             | IntrinsicCast => true,
         }
     }
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 784af940769..a4c3b7dd1b1 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -142,6 +142,7 @@
 #![feature(slice_range)]
 #![feature(std_internals)]
 #![feature(str_internals)]
+#![feature(temporary_niche_types)]
 #![feature(trusted_fused)]
 #![feature(trusted_len)]
 #![feature(trusted_random_access)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index e93ff2f9023..ad86bf4bf07 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -33,21 +33,15 @@ enum AllocInit {
     Zeroed,
 }
 
-#[repr(transparent)]
-#[cfg_attr(target_pointer_width = "16", rustc_layout_scalar_valid_range_end(0x7fff))]
-#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0x7fff_ffff))]
-#[cfg_attr(target_pointer_width = "64", rustc_layout_scalar_valid_range_end(0x7fff_ffff_ffff_ffff))]
-struct Cap(usize);
+type Cap = core::num::niche_types::UsizeNoHighBit;
 
-impl Cap {
-    const ZERO: Cap = unsafe { Cap(0) };
+const ZERO_CAP: Cap = unsafe { Cap::new_unchecked(0) };
 
-    /// `Cap(cap)`, except if `T` is a ZST then `Cap::ZERO`.
-    ///
-    /// # Safety: cap must be <= `isize::MAX`.
-    unsafe fn new<T>(cap: usize) -> Self {
-        if T::IS_ZST { Cap::ZERO } else { unsafe { Self(cap) } }
-    }
+/// `Cap(cap)`, except if `T` is a ZST then `Cap::ZERO`.
+///
+/// # Safety: cap must be <= `isize::MAX`.
+unsafe fn new_cap<T>(cap: usize) -> Cap {
+    if T::IS_ZST { ZERO_CAP } else { unsafe { Cap::new_unchecked(cap) } }
 }
 
 /// A low-level utility for more ergonomically allocating, reallocating, and deallocating
@@ -257,7 +251,7 @@ impl<T, A: Allocator> RawVec<T, A> {
         // SAFETY: Precondition passed to the caller
         unsafe {
             let ptr = ptr.cast();
-            let capacity = Cap::new::<T>(capacity);
+            let capacity = new_cap::<T>(capacity);
             Self {
                 inner: RawVecInner::from_raw_parts_in(ptr, capacity, alloc),
                 _marker: PhantomData,
@@ -275,7 +269,7 @@ impl<T, A: Allocator> RawVec<T, A> {
         // SAFETY: Precondition passed to the caller
         unsafe {
             let ptr = ptr.cast();
-            let capacity = Cap::new::<T>(capacity);
+            let capacity = new_cap::<T>(capacity);
             Self { inner: RawVecInner::from_nonnull_in(ptr, capacity, alloc), _marker: PhantomData }
         }
     }
@@ -410,7 +404,7 @@ impl<A: Allocator> RawVecInner<A> {
     const fn new_in(alloc: A, align: usize) -> Self {
         let ptr = unsafe { core::mem::transmute(align) };
         // `cap: 0` means "unallocated". zero-sized types are ignored.
-        Self { ptr, cap: Cap::ZERO, alloc }
+        Self { ptr, cap: ZERO_CAP, alloc }
     }
 
     #[cfg(not(no_global_oom_handling))]
@@ -483,7 +477,11 @@ impl<A: Allocator> RawVecInner<A> {
         // Allocators currently return a `NonNull<[u8]>` whose length
         // matches the size requested. If that ever changes, the capacity
         // here should change to `ptr.len() / mem::size_of::<T>()`.
-        Ok(Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc })
+        Ok(Self {
+            ptr: Unique::from(ptr.cast()),
+            cap: unsafe { Cap::new_unchecked(capacity) },
+            alloc,
+        })
     }
 
     #[inline]
@@ -508,7 +506,7 @@ impl<A: Allocator> RawVecInner<A> {
 
     #[inline]
     const fn capacity(&self, elem_size: usize) -> usize {
-        if elem_size == 0 { usize::MAX } else { self.cap.0 }
+        if elem_size == 0 { usize::MAX } else { self.cap.as_inner() }
     }
 
     #[inline]
@@ -518,7 +516,7 @@ impl<A: Allocator> RawVecInner<A> {
 
     #[inline]
     fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull<u8>, Layout)> {
-        if elem_layout.size() == 0 || self.cap.0 == 0 {
+        if elem_layout.size() == 0 || self.cap.as_inner() == 0 {
             None
         } else {
             // We could use Layout::array here which ensures the absence of isize and usize overflows
@@ -526,7 +524,7 @@ impl<A: Allocator> RawVecInner<A> {
             // has already been allocated so we know it can't overflow and currently Rust does not
             // support such types. So we can do better by skipping some checks and avoid an unwrap.
             unsafe {
-                let alloc_size = elem_layout.size().unchecked_mul(self.cap.0);
+                let alloc_size = elem_layout.size().unchecked_mul(self.cap.as_inner());
                 let layout = Layout::from_size_align_unchecked(alloc_size, elem_layout.align());
                 Some((self.ptr.into(), layout))
             }
@@ -562,7 +560,7 @@ impl<A: Allocator> RawVecInner<A> {
     #[inline]
     #[track_caller]
     fn grow_one(&mut self, elem_layout: Layout) {
-        if let Err(err) = self.grow_amortized(self.cap.0, 1, elem_layout) {
+        if let Err(err) = self.grow_amortized(self.cap.as_inner(), 1, elem_layout) {
             handle_error(err);
         }
     }
@@ -627,7 +625,7 @@ impl<A: Allocator> RawVecInner<A> {
         // the size requested. If that ever changes, the capacity here should
         // change to `ptr.len() / mem::size_of::<T>()`.
         self.ptr = Unique::from(ptr.cast());
-        self.cap = unsafe { Cap(cap) };
+        self.cap = unsafe { Cap::new_unchecked(cap) };
     }
 
     fn grow_amortized(
@@ -650,7 +648,7 @@ impl<A: Allocator> RawVecInner<A> {
 
         // This guarantees exponential growth. The doubling cannot overflow
         // because `cap <= isize::MAX` and the type of `cap` is `usize`.
-        let cap = cmp::max(self.cap.0 * 2, required_cap);
+        let cap = cmp::max(self.cap.as_inner() * 2, required_cap);
         let cap = cmp::max(min_non_zero_cap(elem_layout.size()), cap);
 
         let new_layout = layout_array(cap, elem_layout)?;
@@ -719,7 +717,7 @@ impl<A: Allocator> RawVecInner<A> {
             unsafe { self.alloc.deallocate(ptr, layout) };
             self.ptr =
                 unsafe { Unique::new_unchecked(ptr::without_provenance_mut(elem_layout.align())) };
-            self.cap = Cap::ZERO;
+            self.cap = ZERO_CAP;
         } else {
             let ptr = unsafe {
                 // Layout cannot overflow here because it would have
diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs
index ba57d940d8c..a3ddd6f6e23 100644
--- a/library/alloc/src/vec/is_zero.rs
+++ b/library/alloc/src/vec/is_zero.rs
@@ -40,19 +40,8 @@ impl_is_zero!(char, |x| x == '\0');
 impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
 impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
 
-unsafe impl<T> IsZero for *const T {
-    #[inline]
-    fn is_zero(&self) -> bool {
-        (*self).is_null()
-    }
-}
-
-unsafe impl<T> IsZero for *mut T {
-    #[inline]
-    fn is_zero(&self) -> bool {
-        (*self).is_null()
-    }
-}
+// `IsZero` cannot be soundly implemented for pointers because of provenance
+// (see #135338).
 
 unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
     #[inline]
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 2e654d3d1ff..b24daec2968 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -2742,3 +2742,13 @@ fn max_swap_remove() {
     let mut v = vec![0];
     v.swap_remove(usize::MAX);
 }
+
+// Regression test for #135338
+#[test]
+fn vec_null_ptr_roundtrip() {
+    let ptr = std::ptr::from_ref(&42);
+    let zero = ptr.with_addr(0);
+    let roundtripped = vec![zero; 1].pop().unwrap();
+    let new = roundtripped.with_addr(ptr.addr());
+    unsafe { new.read() };
+}
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 67d219654b9..6c1b568e231 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -51,6 +51,10 @@ mod overflow_panic;
 mod saturating;
 mod wrapping;
 
+/// 100% perma-unstable
+#[doc(hidden)]
+pub mod niche_types;
+
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg(not(no_fp_fmt_parse))]
 pub use dec2flt::ParseFloatError;
diff --git a/library/core/src/num/niche_types.rs b/library/core/src/num/niche_types.rs
new file mode 100644
index 00000000000..096713c318f
--- /dev/null
+++ b/library/core/src/num/niche_types.rs
@@ -0,0 +1,168 @@
+#![unstable(
+    feature = "temporary_niche_types",
+    issue = "none",
+    reason = "for core, alloc, and std internals until pattern types are further along"
+)]
+
+use crate::cmp::Ordering;
+use crate::fmt;
+use crate::hash::{Hash, Hasher};
+use crate::marker::StructuralPartialEq;
+
+macro_rules! define_valid_range_type {
+    ($(
+        $(#[$m:meta])*
+        $vis:vis struct $name:ident($int:ident as $uint:ident in $low:literal..=$high:literal);
+    )+) => {$(
+        #[derive(Clone, Copy, Eq)]
+        #[repr(transparent)]
+        #[rustc_layout_scalar_valid_range_start($low)]
+        #[rustc_layout_scalar_valid_range_end($high)]
+        $(#[$m])*
+        $vis struct $name($int);
+
+        const _: () = {
+            // With the `valid_range` attributes, it's always specified as unsigned
+            assert!(<$uint>::MIN == 0);
+            let ulow: $uint = $low;
+            let uhigh: $uint = $high;
+            assert!(ulow <= uhigh);
+
+            assert!(size_of::<$int>() == size_of::<$uint>());
+        };
+
+        impl $name {
+            /// Constructs an instance of this type from the underlying integer
+            /// primitive without checking whether its zero.
+            ///
+            /// # Safety
+            /// Immediate language UB if `val == 0`, as it violates the validity
+            /// invariant of this type.
+            #[inline]
+            pub const unsafe fn new_unchecked(val: $int) -> Self {
+                // SAFETY: Caller promised that `val` is non-zero.
+                unsafe { $name(val) }
+            }
+
+            #[inline]
+            pub const fn as_inner(self) -> $int {
+                // SAFETY: This is a transparent wrapper, so unwrapping it is sound
+                // (Not using `.0` due to MCP#807.)
+                unsafe { crate::mem::transmute(self) }
+            }
+        }
+
+        // This is required to allow matching a constant.  We don't get it from a derive
+        // because the derived `PartialEq` would do a field projection, which is banned
+        // by <https://github.com/rust-lang/compiler-team/issues/807>.
+        impl StructuralPartialEq for $name {}
+
+        impl PartialEq for $name {
+            #[inline]
+            fn eq(&self, other: &Self) -> bool {
+                self.as_inner() == other.as_inner()
+            }
+        }
+
+        impl Ord for $name {
+            #[inline]
+            fn cmp(&self, other: &Self) -> Ordering {
+                Ord::cmp(&self.as_inner(), &other.as_inner())
+            }
+        }
+
+        impl PartialOrd for $name {
+            #[inline]
+            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+                Some(Ord::cmp(self, other))
+            }
+        }
+
+        impl Hash for $name {
+            // Required method
+            fn hash<H: Hasher>(&self, state: &mut H) {
+                Hash::hash(&self.as_inner(), state);
+            }
+        }
+
+        impl fmt::Debug for $name {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                <$int as fmt::Debug>::fmt(&self.as_inner(), f)
+            }
+        }
+    )+};
+}
+
+define_valid_range_type! {
+    pub struct Nanoseconds(u32 as u32 in 0..=999_999_999);
+}
+
+impl Nanoseconds {
+    // SAFETY: 0 is within the valid range
+    pub const ZERO: Self = unsafe { Nanoseconds::new_unchecked(0) };
+}
+
+impl Default for Nanoseconds {
+    #[inline]
+    fn default() -> Self {
+        Self::ZERO
+    }
+}
+
+define_valid_range_type! {
+    pub struct NonZeroU8Inner(u8 as u8 in 1..=0xff);
+    pub struct NonZeroU16Inner(u16 as u16 in 1..=0xff_ff);
+    pub struct NonZeroU32Inner(u32 as u32 in 1..=0xffff_ffff);
+    pub struct NonZeroU64Inner(u64 as u64 in 1..=0xffffffff_ffffffff);
+    pub struct NonZeroU128Inner(u128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff);
+
+    pub struct NonZeroI8Inner(i8 as u8 in 1..=0xff);
+    pub struct NonZeroI16Inner(i16 as u16 in 1..=0xff_ff);
+    pub struct NonZeroI32Inner(i32 as u32 in 1..=0xffff_ffff);
+    pub struct NonZeroI64Inner(i64 as u64 in 1..=0xffffffff_ffffffff);
+    pub struct NonZeroI128Inner(i128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff);
+}
+
+#[cfg(target_pointer_width = "16")]
+define_valid_range_type! {
+    pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff);
+    pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff);
+    pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff);
+}
+#[cfg(target_pointer_width = "32")]
+define_valid_range_type! {
+    pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff);
+    pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff);
+    pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff);
+}
+#[cfg(target_pointer_width = "64")]
+define_valid_range_type! {
+    pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff_ffff_ffff);
+    pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff_ffff_ffff);
+    pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff_ffff_ffff);
+}
+
+define_valid_range_type! {
+    pub struct U32NotAllOnes(u32 as u32 in 0..=0xffff_fffe);
+    pub struct I32NotAllOnes(i32 as u32 in 0..=0xffff_fffe);
+
+    pub struct U64NotAllOnes(u64 as u64 in 0..=0xffff_ffff_ffff_fffe);
+    pub struct I64NotAllOnes(i64 as u64 in 0..=0xffff_ffff_ffff_fffe);
+}
+
+pub trait NotAllOnesHelper {
+    type Type;
+}
+pub type NotAllOnes<T> = <T as NotAllOnesHelper>::Type;
+impl NotAllOnesHelper for u32 {
+    type Type = U32NotAllOnes;
+}
+impl NotAllOnesHelper for i32 {
+    type Type = I32NotAllOnes;
+}
+impl NotAllOnesHelper for u64 {
+    type Type = U64NotAllOnes;
+}
+impl NotAllOnesHelper for i64 {
+    type Type = I64NotAllOnes;
+}
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 926723b3dba..dbce64420ac 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -37,41 +37,12 @@ pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {
 macro_rules! impl_zeroable_primitive {
     ($($NonZeroInner:ident ( $primitive:ty )),+ $(,)?) => {
         mod private {
-            use super::*;
-
             #[unstable(
                 feature = "nonzero_internals",
                 reason = "implementation detail which may disappear or be replaced at any time",
                 issue = "none"
             )]
             pub trait Sealed {}
-
-            $(
-                // This inner type is never shown directly, so intentionally does not have Debug
-                #[expect(missing_debug_implementations)]
-                // Since this struct is non-generic and derives Copy,
-                // the derived Clone is `*self` and thus doesn't field-project.
-                #[derive(Clone, Copy)]
-                #[repr(transparent)]
-                #[rustc_layout_scalar_valid_range_start(1)]
-                #[rustc_nonnull_optimization_guaranteed]
-                #[unstable(
-                    feature = "nonzero_internals",
-                    reason = "implementation detail which may disappear or be replaced at any time",
-                    issue = "none"
-                )]
-                pub struct $NonZeroInner($primitive);
-
-                // This is required to allow matching a constant.  We don't get it from a derive
-                // because the derived `PartialEq` would do a field projection, which is banned
-                // by <https://github.com/rust-lang/compiler-team/issues/807>.
-                #[unstable(
-                    feature = "nonzero_internals",
-                    reason = "implementation detail which may disappear or be replaced at any time",
-                    issue = "none"
-                )]
-                impl StructuralPartialEq for $NonZeroInner {}
-            )+
         }
 
         $(
@@ -88,7 +59,7 @@ macro_rules! impl_zeroable_primitive {
                 issue = "none"
             )]
             unsafe impl ZeroablePrimitive for $primitive {
-                type NonZeroInner = private::$NonZeroInner;
+                type NonZeroInner = super::niche_types::$NonZeroInner;
             }
         )+
     };
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 3d9ad0706eb..f58c0e12411 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -777,7 +777,7 @@ pub fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T {
 /// # type T = i32;
 /// # fn foo() -> T { 42 }
 /// // The temporary holding the return value of `foo` does *not* have its lifetime extended,
-/// // because the surrounding expression involves no function call.
+/// // because the surrounding expression involves a function call.
 /// let p = ptr::from_ref(&foo());
 /// unsafe { p.read() }; // UB! Reading from a dangling pointer ⚠️
 /// ```
@@ -828,7 +828,7 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
 /// # type T = i32;
 /// # fn foo() -> T { 42 }
 /// // The temporary holding the return value of `foo` does *not* have its lifetime extended,
-/// // because the surrounding expression involves no function call.
+/// // because the surrounding expression involves a function call.
 /// let p = ptr::from_mut(&mut foo());
 /// unsafe { p.write(T::default()) }; // UB! Writing to a dangling pointer ⚠️
 /// ```
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index d2842f69008..a687ed7129d 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -49,7 +49,7 @@ impl<'a, T> IntoIterator for &'a mut [T] {
 /// // First, we need a slice to call the `iter` method on:
 /// let slice = &[1, 2, 3];
 ///
-/// // Then we call `iter` on the slice to get the `Iter` struct,
+/// // Then we call `iter` on the slice to get the `Iter` iterator,
 /// // and iterate over it:
 /// for element in slice.iter() {
 ///     println!("{element}");
@@ -107,24 +107,20 @@ impl<'a, T> Iter<'a, T> {
 
     /// Views the underlying data as a subslice of the original data.
     ///
-    /// This has the same lifetime as the original slice, and so the
-    /// iterator can continue to be used while this exists.
-    ///
     /// # Examples
     ///
     /// Basic usage:
     ///
     /// ```
     /// // First, we need a slice to call the `iter` method on:
-    /// // struct (`&[usize]` here):
     /// let slice = &[1, 2, 3];
     ///
-    /// // Then we call `iter` on the slice to get the `Iter` struct:
+    /// // Then we call `iter` on the slice to get the `Iter` iterator:
     /// let mut iter = slice.iter();
     /// // Here `as_slice` still returns the whole slice, so this prints "[1, 2, 3]":
     /// println!("{:?}", iter.as_slice());
     ///
-    /// // Now, we call the `next` method to remove the first element of the iterator:
+    /// // Now, we call the `next` method to remove the first element from the iterator:
     /// iter.next();
     /// // Here the iterator does not contain the first element of the slice any more,
     /// // so `as_slice` only returns the last two elements of the slice,
@@ -181,7 +177,7 @@ impl<T> AsRef<[T]> for Iter<'_, T> {
 /// // First, we need a slice to call the `iter_mut` method on:
 /// let slice = &mut [1, 2, 3];
 ///
-/// // Then we call `iter_mut` on the slice to get the `IterMut` struct,
+/// // Then we call `iter_mut` on the slice to get the `IterMut` iterator,
 /// // iterate over it and increment each element value:
 /// for element in slice.iter_mut() {
 ///     *element += 1;
@@ -286,25 +282,30 @@ impl<'a, T> IterMut<'a, T> {
 
     /// Views the underlying data as a subslice of the original data.
     ///
-    /// To avoid creating `&mut [T]` references that alias, the returned slice
-    /// borrows its lifetime from the iterator the method is applied on.
-    ///
     /// # Examples
     ///
     /// Basic usage:
     ///
     /// ```
-    /// let mut slice: &mut [usize] = &mut [1, 2, 3];
+    /// // First, we need a slice to call the `iter_mut` method on:
+    /// let slice = &mut [1, 2, 3];
     ///
-    /// // First, we get the iterator:
+    /// // Then we call `iter_mut` on the slice to get the `IterMut` iterator:
     /// let mut iter = slice.iter_mut();
-    /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]":
-    /// assert_eq!(iter.as_slice(), &[1, 2, 3]);
+    /// // Here `as_slice` still returns the whole slice, so this prints "[1, 2, 3]":
+    /// println!("{:?}", iter.as_slice());
     ///
-    /// // Next, we move to the second element of the slice:
-    /// iter.next();
-    /// // Now `as_slice` returns "[2, 3]":
-    /// assert_eq!(iter.as_slice(), &[2, 3]);
+    /// // Now, we call the `next` method to remove the first element from the iterator
+    /// // and increment its value:
+    /// *iter.next().unwrap() += 1;
+    /// // Here the iterator does not contain the first element of the slice any more,
+    /// // so `as_slice` only returns the last two elements of the slice,
+    /// // and so this prints "[2, 3]":
+    /// println!("{:?}", iter.as_slice());
+    ///
+    /// // The underlying slice still contains three elements, but its first element
+    /// // was increased by 1, so this prints "[2, 2, 3]":
+    /// println!("{:?}", slice);
     /// ```
     #[must_use]
     #[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")]
@@ -315,9 +316,6 @@ impl<'a, T> IterMut<'a, T> {
 
     /// Views the underlying data as a mutable subslice of the original data.
     ///
-    /// To avoid creating `&mut [T]` references that alias, the returned slice
-    /// borrows its lifetime from the iterator the method is applied on.
-    ///
     /// # Examples
     ///
     /// Basic usage:
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 2d93148bac0..22bd46c567e 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -21,6 +21,7 @@
 
 use crate::fmt;
 use crate::iter::Sum;
+use crate::num::niche_types::Nanoseconds;
 use crate::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
 
 const NANOS_PER_SEC: u32 = 1_000_000_000;
@@ -37,24 +38,6 @@ const HOURS_PER_DAY: u64 = 24;
 #[unstable(feature = "duration_units", issue = "120301")]
 const DAYS_PER_WEEK: u64 = 7;
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[repr(transparent)]
-#[rustc_layout_scalar_valid_range_start(0)]
-#[rustc_layout_scalar_valid_range_end(999_999_999)]
-struct Nanoseconds(u32);
-
-impl Nanoseconds {
-    // SAFETY: 0 is within the valid range
-    const ZERO: Self = unsafe { Nanoseconds(0) };
-}
-
-impl Default for Nanoseconds {
-    #[inline]
-    fn default() -> Self {
-        Self::ZERO
-    }
-}
-
 /// A `Duration` type to represent a span of time, typically used for system
 /// timeouts.
 ///
@@ -211,14 +194,14 @@ impl Duration {
     pub const fn new(secs: u64, nanos: u32) -> Duration {
         if nanos < NANOS_PER_SEC {
             // SAFETY: nanos < NANOS_PER_SEC, therefore nanos is within the valid range
-            Duration { secs, nanos: unsafe { Nanoseconds(nanos) } }
+            Duration { secs, nanos: unsafe { Nanoseconds::new_unchecked(nanos) } }
         } else {
             let secs = secs
                 .checked_add((nanos / NANOS_PER_SEC) as u64)
                 .expect("overflow in Duration::new");
             let nanos = nanos % NANOS_PER_SEC;
             // SAFETY: nanos % NANOS_PER_SEC < NANOS_PER_SEC, therefore nanos is within the valid range
-            Duration { secs, nanos: unsafe { Nanoseconds(nanos) } }
+            Duration { secs, nanos: unsafe { Nanoseconds::new_unchecked(nanos) } }
         }
     }
 
@@ -263,7 +246,7 @@ impl Duration {
         let subsec_millis = (millis % MILLIS_PER_SEC) as u32;
         // SAFETY: (x % 1_000) * 1_000_000 < 1_000_000_000
         //         => x % 1_000 < 1_000
-        let subsec_nanos = unsafe { Nanoseconds(subsec_millis * NANOS_PER_MILLI) };
+        let subsec_nanos = unsafe { Nanoseconds::new_unchecked(subsec_millis * NANOS_PER_MILLI) };
 
         Duration { secs, nanos: subsec_nanos }
     }
@@ -289,7 +272,7 @@ impl Duration {
         let subsec_micros = (micros % MICROS_PER_SEC) as u32;
         // SAFETY: (x % 1_000_000) * 1_000 < 1_000_000_000
         //         => x % 1_000_000 < 1_000_000
-        let subsec_nanos = unsafe { Nanoseconds(subsec_micros * NANOS_PER_MICRO) };
+        let subsec_nanos = unsafe { Nanoseconds::new_unchecked(subsec_micros * NANOS_PER_MICRO) };
 
         Duration { secs, nanos: subsec_nanos }
     }
@@ -320,7 +303,7 @@ impl Duration {
         let secs = nanos / NANOS_PER_SEC;
         let subsec_nanos = (nanos % NANOS_PER_SEC) as u32;
         // SAFETY: x % 1_000_000_000 < 1_000_000_000
-        let subsec_nanos = unsafe { Nanoseconds(subsec_nanos) };
+        let subsec_nanos = unsafe { Nanoseconds::new_unchecked(subsec_nanos) };
 
         Duration { secs, nanos: subsec_nanos }
     }
@@ -458,7 +441,7 @@ impl Duration {
     #[rustc_const_stable(feature = "duration_zero", since = "1.53.0")]
     #[inline]
     pub const fn is_zero(&self) -> bool {
-        self.secs == 0 && self.nanos.0 == 0
+        self.secs == 0 && self.nanos.as_inner() == 0
     }
 
     /// Returns the number of _whole_ seconds contained by this `Duration`.
@@ -509,7 +492,7 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn subsec_millis(&self) -> u32 {
-        self.nanos.0 / NANOS_PER_MILLI
+        self.nanos.as_inner() / NANOS_PER_MILLI
     }
 
     /// Returns the fractional part of this `Duration`, in whole microseconds.
@@ -532,7 +515,7 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn subsec_micros(&self) -> u32 {
-        self.nanos.0 / NANOS_PER_MICRO
+        self.nanos.as_inner() / NANOS_PER_MICRO
     }
 
     /// Returns the fractional part of this `Duration`, in nanoseconds.
@@ -555,7 +538,7 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn subsec_nanos(&self) -> u32 {
-        self.nanos.0
+        self.nanos.as_inner()
     }
 
     /// Returns the total number of whole milliseconds contained by this `Duration`.
@@ -573,7 +556,8 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn as_millis(&self) -> u128 {
-        self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos.0 / NANOS_PER_MILLI) as u128
+        self.secs as u128 * MILLIS_PER_SEC as u128
+            + (self.nanos.as_inner() / NANOS_PER_MILLI) as u128
     }
 
     /// Returns the total number of whole microseconds contained by this `Duration`.
@@ -591,7 +575,8 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn as_micros(&self) -> u128 {
-        self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos.0 / NANOS_PER_MICRO) as u128
+        self.secs as u128 * MICROS_PER_SEC as u128
+            + (self.nanos.as_inner() / NANOS_PER_MICRO) as u128
     }
 
     /// Returns the total number of nanoseconds contained by this `Duration`.
@@ -609,7 +594,7 @@ impl Duration {
     #[must_use]
     #[inline]
     pub const fn as_nanos(&self) -> u128 {
-        self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos.0 as u128
+        self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos.as_inner() as u128
     }
 
     /// Computes the absolute difference between `self` and `other`.
@@ -649,7 +634,7 @@ impl Duration {
     #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
     pub const fn checked_add(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
-            let mut nanos = self.nanos.0 + rhs.nanos.0;
+            let mut nanos = self.nanos.as_inner() + rhs.nanos.as_inner();
             if nanos >= NANOS_PER_SEC {
                 nanos -= NANOS_PER_SEC;
                 if let Some(new_secs) = secs.checked_add(1) {
@@ -707,11 +692,11 @@ impl Duration {
     #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
     pub const fn checked_sub(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
-            let nanos = if self.nanos.0 >= rhs.nanos.0 {
-                self.nanos.0 - rhs.nanos.0
+            let nanos = if self.nanos.as_inner() >= rhs.nanos.as_inner() {
+                self.nanos.as_inner() - rhs.nanos.as_inner()
             } else if let Some(sub_secs) = secs.checked_sub(1) {
                 secs = sub_secs;
-                self.nanos.0 + NANOS_PER_SEC - rhs.nanos.0
+                self.nanos.as_inner() + NANOS_PER_SEC - rhs.nanos.as_inner()
             } else {
                 return None;
             };
@@ -763,7 +748,7 @@ impl Duration {
     #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
     pub const fn checked_mul(self, rhs: u32) -> Option<Duration> {
         // Multiply nanoseconds as u64, because it cannot overflow that way.
-        let total_nanos = self.nanos.0 as u64 * rhs as u64;
+        let total_nanos = self.nanos.as_inner() as u64 * rhs as u64;
         let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
         let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
         // FIXME(const-hack): use `and_then` once that is possible.
@@ -820,7 +805,8 @@ impl Duration {
     pub const fn checked_div(self, rhs: u32) -> Option<Duration> {
         if rhs != 0 {
             let (secs, extra_secs) = (self.secs / (rhs as u64), self.secs % (rhs as u64));
-            let (mut nanos, extra_nanos) = (self.nanos.0 / rhs, self.nanos.0 % rhs);
+            let (mut nanos, extra_nanos) =
+                (self.nanos.as_inner() / rhs, self.nanos.as_inner() % rhs);
             nanos +=
                 ((extra_secs * (NANOS_PER_SEC as u64) + extra_nanos as u64) / (rhs as u64)) as u32;
             debug_assert!(nanos < NANOS_PER_SEC);
@@ -846,7 +832,7 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts_float", since = "1.83.0")]
     pub const fn as_secs_f64(&self) -> f64 {
-        (self.secs as f64) + (self.nanos.0 as f64) / (NANOS_PER_SEC as f64)
+        (self.secs as f64) + (self.nanos.as_inner() as f64) / (NANOS_PER_SEC as f64)
     }
 
     /// Returns the number of seconds contained by this `Duration` as `f32`.
@@ -865,7 +851,7 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts_float", since = "1.83.0")]
     pub const fn as_secs_f32(&self) -> f32 {
-        (self.secs as f32) + (self.nanos.0 as f32) / (NANOS_PER_SEC as f32)
+        (self.secs as f32) + (self.nanos.as_inner() as f32) / (NANOS_PER_SEC as f32)
     }
 
     /// Returns the number of milliseconds contained by this `Duration` as `f64`.
@@ -885,7 +871,7 @@ impl Duration {
     #[inline]
     pub const fn as_millis_f64(&self) -> f64 {
         (self.secs as f64) * (MILLIS_PER_SEC as f64)
-            + (self.nanos.0 as f64) / (NANOS_PER_MILLI as f64)
+            + (self.nanos.as_inner() as f64) / (NANOS_PER_MILLI as f64)
     }
 
     /// Returns the number of milliseconds contained by this `Duration` as `f32`.
@@ -905,7 +891,7 @@ impl Duration {
     #[inline]
     pub const fn as_millis_f32(&self) -> f32 {
         (self.secs as f32) * (MILLIS_PER_SEC as f32)
-            + (self.nanos.0 as f32) / (NANOS_PER_MILLI as f32)
+            + (self.nanos.as_inner() as f32) / (NANOS_PER_MILLI as f32)
     }
 
     /// Creates a new `Duration` from the specified number of seconds represented
@@ -1084,8 +1070,9 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts_float", since = "1.83.0")]
     pub const fn div_duration_f64(self, rhs: Duration) -> f64 {
-        let self_nanos = (self.secs as f64) * (NANOS_PER_SEC as f64) + (self.nanos.0 as f64);
-        let rhs_nanos = (rhs.secs as f64) * (NANOS_PER_SEC as f64) + (rhs.nanos.0 as f64);
+        let self_nanos =
+            (self.secs as f64) * (NANOS_PER_SEC as f64) + (self.nanos.as_inner() as f64);
+        let rhs_nanos = (rhs.secs as f64) * (NANOS_PER_SEC as f64) + (rhs.nanos.as_inner() as f64);
         self_nanos / rhs_nanos
     }
 
@@ -1105,8 +1092,9 @@ impl Duration {
     #[inline]
     #[rustc_const_stable(feature = "duration_consts_float", since = "1.83.0")]
     pub const fn div_duration_f32(self, rhs: Duration) -> f32 {
-        let self_nanos = (self.secs as f32) * (NANOS_PER_SEC as f32) + (self.nanos.0 as f32);
-        let rhs_nanos = (rhs.secs as f32) * (NANOS_PER_SEC as f32) + (rhs.nanos.0 as f32);
+        let self_nanos =
+            (self.secs as f32) * (NANOS_PER_SEC as f32) + (self.nanos.as_inner() as f32);
+        let rhs_nanos = (rhs.secs as f32) * (NANOS_PER_SEC as f32) + (rhs.nanos.as_inner() as f32);
         self_nanos / rhs_nanos
     }
 }
@@ -1201,13 +1189,13 @@ macro_rules! sum_durations {
         for entry in $iter {
             total_secs =
                 total_secs.checked_add(entry.secs).expect("overflow in iter::sum over durations");
-            total_nanos = match total_nanos.checked_add(entry.nanos.0 as u64) {
+            total_nanos = match total_nanos.checked_add(entry.nanos.as_inner() as u64) {
                 Some(n) => n,
                 None => {
                     total_secs = total_secs
                         .checked_add(total_nanos / NANOS_PER_SEC as u64)
                         .expect("overflow in iter::sum over durations");
-                    (total_nanos % NANOS_PER_SEC as u64) + entry.nanos.0 as u64
+                    (total_nanos % NANOS_PER_SEC as u64) + entry.nanos.as_inner() as u64
                 }
             };
         }
@@ -1399,27 +1387,27 @@ impl fmt::Debug for Duration {
         let prefix = if f.sign_plus() { "+" } else { "" };
 
         if self.secs > 0 {
-            fmt_decimal(f, self.secs, self.nanos.0, NANOS_PER_SEC / 10, prefix, "s")
-        } else if self.nanos.0 >= NANOS_PER_MILLI {
+            fmt_decimal(f, self.secs, self.nanos.as_inner(), NANOS_PER_SEC / 10, prefix, "s")
+        } else if self.nanos.as_inner() >= NANOS_PER_MILLI {
             fmt_decimal(
                 f,
-                (self.nanos.0 / NANOS_PER_MILLI) as u64,
-                self.nanos.0 % NANOS_PER_MILLI,
+                (self.nanos.as_inner() / NANOS_PER_MILLI) as u64,
+                self.nanos.as_inner() % NANOS_PER_MILLI,
                 NANOS_PER_MILLI / 10,
                 prefix,
                 "ms",
             )
-        } else if self.nanos.0 >= NANOS_PER_MICRO {
+        } else if self.nanos.as_inner() >= NANOS_PER_MICRO {
             fmt_decimal(
                 f,
-                (self.nanos.0 / NANOS_PER_MICRO) as u64,
-                self.nanos.0 % NANOS_PER_MICRO,
+                (self.nanos.as_inner() / NANOS_PER_MICRO) as u64,
+                self.nanos.as_inner() % NANOS_PER_MICRO,
                 NANOS_PER_MICRO / 10,
                 prefix,
                 "µs",
             )
         } else {
-            fmt_decimal(f, self.nanos.0 as u64, 0, 1, prefix, "ns")
+            fmt_decimal(f, self.nanos.as_inner() as u64, 0, 1, prefix, "ns")
         }
     }
 }
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 26a09f0daca..b19c9cee75a 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -419,7 +419,7 @@ pub mod token_stream {
 /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
 /// To quote `$` itself, use `$$`.
 #[unstable(feature = "proc_macro_quote", issue = "54722")]
-#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals)]
+#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals, proc_macro_totokens)]
 #[rustc_builtin_macro]
 pub macro quote($($t:tt)*) {
     /* compiler built-in */
diff --git a/library/proc_macro/src/quote.rs b/library/proc_macro/src/quote.rs
index 04fa696d5e6..bcb15912bb6 100644
--- a/library/proc_macro/src/quote.rs
+++ b/library/proc_macro/src/quote.rs
@@ -4,12 +4,14 @@
 //! This quasiquoter uses macros 2.0 hygiene to reliably access
 //! items from `proc_macro`, to build a `proc_macro::TokenStream`.
 
-use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
+use crate::{
+    Delimiter, Group, Ident, Literal, Punct, Spacing, Span, ToTokens, TokenStream, TokenTree,
+};
 
-macro_rules! quote_tt {
-    (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) };
-    ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) };
-    ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) };
+macro_rules! minimal_quote_tt {
+    (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, minimal_quote!($($t)*)) };
+    ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, minimal_quote!($($t)*)) };
+    ({$($t:tt)*}) => { Group::new(Delimiter::Brace, minimal_quote!($($t)*)) };
     (,) => { Punct::new(',', Spacing::Alone) };
     (.) => { Punct::new('.', Spacing::Alone) };
     (;) => { Punct::new(';', Spacing::Alone) };
@@ -21,21 +23,20 @@ macro_rules! quote_tt {
     ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) };
 }
 
-macro_rules! quote_ts {
+macro_rules! minimal_quote_ts {
     ((@ $($t:tt)*)) => { $($t)* };
     (::) => {
-        [
-            TokenTree::from(Punct::new(':', Spacing::Joint)),
-            TokenTree::from(Punct::new(':', Spacing::Alone)),
-        ].iter()
-            .cloned()
-            .map(|mut x| {
-                x.set_span(Span::def_site());
-                x
-            })
-            .collect::<TokenStream>()
+        {
+            let mut c = (
+                TokenTree::from(Punct::new(':', Spacing::Joint)),
+                TokenTree::from(Punct::new(':', Spacing::Alone))
+            );
+            c.0.set_span(Span::def_site());
+            c.1.set_span(Span::def_site());
+            [c.0, c.1].into_iter().collect::<TokenStream>()
+        }
     };
-    ($t:tt) => { TokenTree::from(quote_tt!($t)) };
+    ($t:tt) => { TokenTree::from(minimal_quote_tt!($t)) };
 }
 
 /// Simpler version of the real `quote!` macro, implemented solely
@@ -46,12 +47,14 @@ macro_rules! quote_ts {
 ///
 /// Note: supported tokens are a subset of the real `quote!`, but
 /// unquoting is different: instead of `$x`, this uses `(@ expr)`.
-macro_rules! quote {
-    () => { TokenStream::new() };
+macro_rules! minimal_quote {
     ($($t:tt)*) => {
-        [
-            $(TokenStream::from(quote_ts!($t)),)*
-        ].iter().cloned().collect::<TokenStream>()
+        {
+            #[allow(unused_mut)] // In case the expansion is empty
+            let mut ts = TokenStream::new();
+            $(ToTokens::to_tokens(&minimal_quote_ts!($t), &mut ts);)*
+            ts
+        }
     };
 }
 
@@ -62,52 +65,66 @@ macro_rules! quote {
 #[unstable(feature = "proc_macro_quote", issue = "54722")]
 pub fn quote(stream: TokenStream) -> TokenStream {
     if stream.is_empty() {
-        return quote!(crate::TokenStream::new());
+        return minimal_quote!(crate::TokenStream::new());
     }
-    let proc_macro_crate = quote!(crate);
+    let proc_macro_crate = minimal_quote!(crate);
     let mut after_dollar = false;
-    let tokens = stream
-        .into_iter()
-        .filter_map(|tree| {
-            if after_dollar {
-                after_dollar = false;
-                match tree {
-                    TokenTree::Ident(_) => {
-                        return Some(quote!(Into::<crate::TokenStream>::into(
-                        Clone::clone(&(@ tree))),));
-                    }
-                    TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
-                    _ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
-                }
-            } else if let TokenTree::Punct(ref tt) = tree {
-                if tt.as_char() == '$' {
-                    after_dollar = true;
-                    return None;
+
+    let mut tokens = crate::TokenStream::new();
+    for tree in stream {
+        if after_dollar {
+            after_dollar = false;
+            match tree {
+                TokenTree::Ident(_) => {
+                    minimal_quote!(crate::ToTokens::to_tokens(&(@ tree), &mut ts);)
+                        .to_tokens(&mut tokens);
+                    continue;
                 }
+                TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
+                _ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
             }
+        } else if let TokenTree::Punct(ref tt) = tree {
+            if tt.as_char() == '$' {
+                after_dollar = true;
+                continue;
+            }
+        }
 
-            Some(quote!(crate::TokenStream::from((@ match tree {
-                TokenTree::Punct(tt) => quote!(crate::TokenTree::Punct(crate::Punct::new(
+        match tree {
+            TokenTree::Punct(tt) => {
+                minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(
                     (@ TokenTree::from(Literal::character(tt.as_char()))),
                     (@ match tt.spacing() {
-                        Spacing::Alone => quote!(crate::Spacing::Alone),
-                        Spacing::Joint => quote!(crate::Spacing::Joint),
+                        Spacing::Alone => minimal_quote!(crate::Spacing::Alone),
+                        Spacing::Joint => minimal_quote!(crate::Spacing::Joint),
                     }),
-                ))),
-                TokenTree::Group(tt) => quote!(crate::TokenTree::Group(crate::Group::new(
+                )), &mut ts);)
+            }
+            TokenTree::Group(tt) => {
+                minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Group(crate::Group::new(
                     (@ match tt.delimiter() {
-                        Delimiter::Parenthesis => quote!(crate::Delimiter::Parenthesis),
-                        Delimiter::Brace => quote!(crate::Delimiter::Brace),
-                        Delimiter::Bracket => quote!(crate::Delimiter::Bracket),
-                        Delimiter::None => quote!(crate::Delimiter::None),
+                        Delimiter::Parenthesis => minimal_quote!(crate::Delimiter::Parenthesis),
+                        Delimiter::Brace => minimal_quote!(crate::Delimiter::Brace),
+                        Delimiter::Bracket => minimal_quote!(crate::Delimiter::Bracket),
+                        Delimiter::None => minimal_quote!(crate::Delimiter::None),
                     }),
                     (@ quote(tt.stream())),
-                ))),
-                TokenTree::Ident(tt) => quote!(crate::TokenTree::Ident(crate::Ident::new(
-                    (@ TokenTree::from(Literal::string(&tt.to_string()))),
+                )), &mut ts);)
+            }
+            TokenTree::Ident(tt) => {
+                let literal = tt.to_string();
+                let (literal, ctor) = if let Some(stripped) = literal.strip_prefix("r#") {
+                    (stripped, minimal_quote!(crate::Ident::new_raw))
+                } else {
+                    (literal.as_str(), minimal_quote!(crate::Ident::new))
+                };
+                minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Ident((@ ctor)(
+                    (@ TokenTree::from(Literal::string(literal))),
                     (@ quote_span(proc_macro_crate.clone(), tt.span())),
-                ))),
-                TokenTree::Literal(tt) => quote!(crate::TokenTree::Literal({
+                )), &mut ts);)
+            }
+            TokenTree::Literal(tt) => {
+                minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Literal({
                     let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string())))
                         .parse::<crate::TokenStream>()
                         .unwrap()
@@ -120,16 +137,22 @@ pub fn quote(stream: TokenStream) -> TokenStream {
                     } else {
                         unreachable!()
                     }
-                }))
-            })),))
-        })
-        .collect::<TokenStream>();
-
+                }), &mut ts);)
+            }
+        }
+        .to_tokens(&mut tokens);
+    }
     if after_dollar {
         panic!("unexpected trailing `$` in `quote!`");
     }
 
-    quote!([(@ tokens)].iter().cloned().collect::<crate::TokenStream>())
+    minimal_quote! {
+        {
+            let mut ts = crate::TokenStream::new();
+            (@ tokens)
+            ts
+        }
+    }
 }
 
 /// Quote a `Span` into a `TokenStream`.
@@ -137,5 +160,5 @@ pub fn quote(stream: TokenStream) -> TokenStream {
 #[unstable(feature = "proc_macro_quote", issue = "54722")]
 pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream {
     let id = span.save_span();
-    quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id)))))
+    minimal_quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id)))))
 }
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 2f8f5c5c581..022bbab1012 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -357,6 +357,7 @@
 #![feature(str_internals)]
 #![feature(strict_provenance_atomic_ptr)]
 #![feature(sync_unsafe_cell)]
+#![feature(temporary_niche_types)]
 #![feature(ub_checks)]
 #![feature(used_with_arg)]
 // tidy-alphabetical-end
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index abb13b75f50..1e814eca3c1 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -11,6 +11,8 @@ use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::{fmt, fs, io};
 
+type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
+
 /// A borrowed file descriptor.
 ///
 /// This has a lifetime parameter to tie it to the lifetime of something that owns the file
@@ -32,15 +34,10 @@ use crate::{fmt, fs, io};
 /// instead, but this is not supported on all platforms.
 #[derive(Copy, Clone)]
 #[repr(transparent)]
-#[rustc_layout_scalar_valid_range_start(0)]
-// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
-// 32-bit c_int. Below is -2, in two's complement, but that only works out
-// because c_int is 32 bits.
-#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
 #[rustc_nonnull_optimization_guaranteed]
 #[stable(feature = "io_safety", since = "1.63.0")]
 pub struct BorrowedFd<'fd> {
-    fd: RawFd,
+    fd: ValidRawFd,
     _phantom: PhantomData<&'fd OwnedFd>,
 }
 
@@ -56,15 +53,10 @@ pub struct BorrowedFd<'fd> {
 ///
 /// You can use [`AsFd::as_fd`] to obtain a [`BorrowedFd`].
 #[repr(transparent)]
-#[rustc_layout_scalar_valid_range_start(0)]
-// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
-// 32-bit c_int. Below is -2, in two's complement, but that only works out
-// because c_int is 32 bits.
-#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
 #[rustc_nonnull_optimization_guaranteed]
 #[stable(feature = "io_safety", since = "1.63.0")]
 pub struct OwnedFd {
-    fd: RawFd,
+    fd: ValidRawFd,
 }
 
 impl BorrowedFd<'_> {
@@ -80,7 +72,8 @@ impl BorrowedFd<'_> {
     pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
         assert!(fd != u32::MAX as RawFd);
         // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
-        unsafe { Self { fd, _phantom: PhantomData } }
+        let fd = unsafe { ValidRawFd::new_unchecked(fd) };
+        Self { fd, _phantom: PhantomData }
     }
 }
 
@@ -130,7 +123,7 @@ impl BorrowedFd<'_> {
 impl AsRawFd for BorrowedFd<'_> {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        self.fd
+        self.fd.as_inner()
     }
 }
 
@@ -138,7 +131,7 @@ impl AsRawFd for BorrowedFd<'_> {
 impl AsRawFd for OwnedFd {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        self.fd
+        self.fd.as_inner()
     }
 }
 
@@ -146,7 +139,7 @@ impl AsRawFd for OwnedFd {
 impl IntoRawFd for OwnedFd {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        ManuallyDrop::new(self).fd
+        ManuallyDrop::new(self).fd.as_inner()
     }
 }
 
@@ -164,7 +157,8 @@ impl FromRawFd for OwnedFd {
     unsafe fn from_raw_fd(fd: RawFd) -> Self {
         assert_ne!(fd, u32::MAX as RawFd);
         // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
-        unsafe { Self { fd } }
+        let fd = unsafe { ValidRawFd::new_unchecked(fd) };
+        Self { fd }
     }
 }
 
@@ -187,12 +181,12 @@ impl Drop for OwnedFd {
             #[cfg(not(target_os = "hermit"))]
             {
                 #[cfg(unix)]
-                crate::sys::fs::debug_assert_fd_is_open(self.fd);
+                crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner());
 
-                let _ = libc::close(self.fd);
+                let _ = libc::close(self.fd.as_inner());
             }
             #[cfg(target_os = "hermit")]
-            let _ = hermit_abi::close(self.fd);
+            let _ = hermit_abi::close(self.fd.as_inner());
         }
     }
 }
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index 2d18f339615..b8601b533fe 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -54,6 +54,9 @@ use crate::{fmt, net, sys};
 /// Raw file descriptors.
 pub type RawFd = i32;
 
+// The max of this is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`.
+type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
+
 /// A borrowed SOLID Sockets file descriptor.
 ///
 /// This has a lifetime parameter to tie it to the lifetime of something that
@@ -69,12 +72,9 @@ pub type RawFd = i32;
 /// socket, which is then borrowed under the same lifetime.
 #[derive(Copy, Clone)]
 #[repr(transparent)]
-#[rustc_layout_scalar_valid_range_start(0)]
-// This is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`.
-#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
 #[rustc_nonnull_optimization_guaranteed]
 pub struct BorrowedFd<'socket> {
-    fd: RawFd,
+    fd: ValidRawFd,
     _phantom: PhantomData<&'socket OwnedFd>,
 }
 
@@ -87,12 +87,9 @@ pub struct BorrowedFd<'socket> {
 /// an argument, it is not captured or consumed, and it never has the value
 /// `SOLID_NET_INVALID_FD`.
 #[repr(transparent)]
-#[rustc_layout_scalar_valid_range_start(0)]
-// This is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`.
-#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
 #[rustc_nonnull_optimization_guaranteed]
 pub struct OwnedFd {
-    fd: RawFd,
+    fd: ValidRawFd,
 }
 
 impl BorrowedFd<'_> {
@@ -108,7 +105,8 @@ impl BorrowedFd<'_> {
         assert!(fd != -1 as RawFd);
         // SAFETY: we just asserted that the value is in the valid range and
         // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
-        unsafe { Self { fd, _phantom: PhantomData } }
+        let fd = unsafe { ValidRawFd::new_unchecked(fd) };
+        Self { fd, _phantom: PhantomData }
     }
 }
 
@@ -132,21 +130,21 @@ impl BorrowedFd<'_> {
 impl AsRawFd for BorrowedFd<'_> {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        self.fd
+        self.fd.as_inner()
     }
 }
 
 impl AsRawFd for OwnedFd {
     #[inline]
     fn as_raw_fd(&self) -> RawFd {
-        self.fd
+        self.fd.as_inner()
     }
 }
 
 impl IntoRawFd for OwnedFd {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        ManuallyDrop::new(self).fd
+        ManuallyDrop::new(self).fd.as_inner()
     }
 }
 
@@ -162,14 +160,15 @@ impl FromRawFd for OwnedFd {
         assert_ne!(fd, -1 as RawFd);
         // SAFETY: we just asserted that the value is in the valid range and
         // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
-        unsafe { Self { fd } }
+        let fd = unsafe { ValidRawFd::new_unchecked(fd) };
+        Self { fd }
     }
 }
 
 impl Drop for OwnedFd {
     #[inline]
     fn drop(&mut self) {
-        unsafe { sys::net::netc::close(self.fd) };
+        unsafe { sys::net::netc::close(self.fd.as_inner()) };
     }
 }
 
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index c6d7bad9440..6e13a8b502a 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -9,6 +9,9 @@ use crate::mem::{self, ManuallyDrop};
 use crate::sys::cvt;
 use crate::{fmt, io, sys};
 
+// The max here is -2, in two's complement. -1 is `INVALID_SOCKET`.
+type ValidRawSocket = core::num::niche_types::NotAllOnes<RawSocket>;
+
 /// A borrowed socket.
 ///
 /// This has a lifetime parameter to tie it to the lifetime of something that
@@ -24,17 +27,10 @@ use crate::{fmt, io, sys};
 /// socket, which is then borrowed under the same lifetime.
 #[derive(Copy, Clone)]
 #[repr(transparent)]
-#[rustc_layout_scalar_valid_range_start(0)]
-// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
-#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
-#[cfg_attr(
-    target_pointer_width = "64",
-    rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
-)]
 #[rustc_nonnull_optimization_guaranteed]
 #[stable(feature = "io_safety", since = "1.63.0")]
 pub struct BorrowedSocket<'socket> {
-    socket: RawSocket,
+    socket: ValidRawSocket,
     _phantom: PhantomData<&'socket OwnedSocket>,
 }
 
@@ -47,17 +43,10 @@ pub struct BorrowedSocket<'socket> {
 /// argument or returned as an owned value, and it never has the value
 /// `INVALID_SOCKET`.
 #[repr(transparent)]
-#[rustc_layout_scalar_valid_range_start(0)]
-// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
-#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))]
-#[cfg_attr(
-    target_pointer_width = "64",
-    rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
-)]
 #[rustc_nonnull_optimization_guaranteed]
 #[stable(feature = "io_safety", since = "1.63.0")]
 pub struct OwnedSocket {
-    socket: RawSocket,
+    socket: ValidRawSocket,
 }
 
 impl BorrowedSocket<'_> {
@@ -73,7 +62,8 @@ impl BorrowedSocket<'_> {
     #[stable(feature = "io_safety", since = "1.63.0")]
     pub const unsafe fn borrow_raw(socket: RawSocket) -> Self {
         assert!(socket != sys::c::INVALID_SOCKET as RawSocket);
-        unsafe { Self { socket, _phantom: PhantomData } }
+        let socket = unsafe { ValidRawSocket::new_unchecked(socket) };
+        Self { socket, _phantom: PhantomData }
     }
 }
 
@@ -172,7 +162,7 @@ fn last_error() -> io::Error {
 impl AsRawSocket for BorrowedSocket<'_> {
     #[inline]
     fn as_raw_socket(&self) -> RawSocket {
-        self.socket
+        self.socket.as_inner()
     }
 }
 
@@ -180,7 +170,7 @@ impl AsRawSocket for BorrowedSocket<'_> {
 impl AsRawSocket for OwnedSocket {
     #[inline]
     fn as_raw_socket(&self) -> RawSocket {
-        self.socket
+        self.socket.as_inner()
     }
 }
 
@@ -188,7 +178,7 @@ impl AsRawSocket for OwnedSocket {
 impl IntoRawSocket for OwnedSocket {
     #[inline]
     fn into_raw_socket(self) -> RawSocket {
-        ManuallyDrop::new(self).socket
+        ManuallyDrop::new(self).socket.as_inner()
     }
 }
 
@@ -196,10 +186,9 @@ impl IntoRawSocket for OwnedSocket {
 impl FromRawSocket for OwnedSocket {
     #[inline]
     unsafe fn from_raw_socket(socket: RawSocket) -> Self {
-        unsafe {
-            debug_assert_ne!(socket, sys::c::INVALID_SOCKET as RawSocket);
-            Self { socket }
-        }
+        debug_assert_ne!(socket, sys::c::INVALID_SOCKET as RawSocket);
+        let socket = unsafe { ValidRawSocket::new_unchecked(socket) };
+        Self { socket }
     }
 }
 
@@ -208,7 +197,7 @@ impl Drop for OwnedSocket {
     #[inline]
     fn drop(&mut self) {
         unsafe {
-            let _ = sys::c::closesocket(self.socket as sys::c::SOCKET);
+            let _ = sys::c::closesocket(self.socket.as_inner() as sys::c::SOCKET);
         }
     }
 }
diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs
index 04dd10ad806..fa2e470d6b6 100644
--- a/library/std/src/sys/pal/solid/fs.rs
+++ b/library/std/src/sys/pal/solid/fs.rs
@@ -12,15 +12,12 @@ use crate::sys::unsupported;
 pub use crate::sys_common::fs::exists;
 use crate::sys_common::ignore_notfound;
 
+type CIntNotMinusOne = core::num::niche_types::NotAllOnes<c_int>;
+
 /// A file descriptor.
 #[derive(Clone, Copy)]
-#[rustc_layout_scalar_valid_range_start(0)]
-// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
-// 32-bit c_int. Below is -2, in two's complement, but that only works out
-// because c_int is 32 bits.
-#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
 struct FileDesc {
-    fd: c_int,
+    fd: CIntNotMinusOne,
 }
 
 impl FileDesc {
@@ -29,12 +26,13 @@ impl FileDesc {
         assert_ne!(fd, -1i32);
         // Safety: we just asserted that the value is in the valid range and
         // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
-        unsafe { FileDesc { fd } }
+        let fd = unsafe { CIntNotMinusOne::new_unchecked(fd) };
+        FileDesc { fd }
     }
 
     #[inline]
     fn raw(&self) -> c_int {
-        self.fd
+        self.fd.as_inner()
     }
 }
 
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index e360ba0f6d7..f657f82e6e3 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -130,25 +130,27 @@ impl Thread {
         }
     }
 
-    #[cfg(target_os = "linux")]
+    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"))]
     pub fn set_name(name: &CStr) {
-        const TASK_COMM_LEN: usize = 16;
-
         unsafe {
-            // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20.
-            let name = truncate_cstr::<{ TASK_COMM_LEN }>(name);
+            cfg_if::cfg_if! {
+                if #[cfg(target_os = "linux")] {
+                    // Linux limits the allowed length of the name.
+                    const TASK_COMM_LEN: usize = 16;
+                    let name = truncate_cstr::<{ TASK_COMM_LEN }>(name);
+                } else {
+                    // FreeBSD and DragonFly BSD do not enforce length limits.
+                }
+            };
+            // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux,
+            // FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0.
             let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
             // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
             debug_assert_eq!(res, 0);
         }
     }
 
-    #[cfg(any(
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        target_os = "openbsd",
-        target_os = "nuttx"
-    ))]
+    #[cfg(any(target_os = "openbsd", target_os = "nuttx"))]
     pub fn set_name(name: &CStr) {
         unsafe {
             libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs
index 343864d0b3f..e224980e95f 100644
--- a/library/std/src/sys/pal/unix/time.rs
+++ b/library/std/src/sys/pal/unix/time.rs
@@ -1,3 +1,5 @@
+use core::num::niche_types::Nanoseconds;
+
 use crate::time::Duration;
 use crate::{fmt, io};
 
@@ -16,12 +18,6 @@ pub(in crate::sys) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec {
 };
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[repr(transparent)]
-#[rustc_layout_scalar_valid_range_start(0)]
-#[rustc_layout_scalar_valid_range_end(999_999_999)]
-struct Nanoseconds(u32);
-
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct SystemTime {
     pub(crate) t: Timespec,
 }
@@ -59,14 +55,14 @@ impl fmt::Debug for SystemTime {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("SystemTime")
             .field("tv_sec", &self.t.tv_sec)
-            .field("tv_nsec", &self.t.tv_nsec.0)
+            .field("tv_nsec", &self.t.tv_nsec)
             .finish()
     }
 }
 
 impl Timespec {
     const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec {
-        Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }
+        Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } }
     }
 
     pub const fn zero() -> Timespec {
@@ -147,12 +143,15 @@ impl Timespec {
             //
             // Ideally this code could be rearranged such that it more
             // directly expresses the lower-cost behavior we want from it.
-            let (secs, nsec) = if self.tv_nsec.0 >= other.tv_nsec.0 {
-                ((self.tv_sec - other.tv_sec) as u64, self.tv_nsec.0 - other.tv_nsec.0)
+            let (secs, nsec) = if self.tv_nsec.as_inner() >= other.tv_nsec.as_inner() {
+                (
+                    (self.tv_sec - other.tv_sec) as u64,
+                    self.tv_nsec.as_inner() - other.tv_nsec.as_inner(),
+                )
             } else {
                 (
                     (self.tv_sec - other.tv_sec - 1) as u64,
-                    self.tv_nsec.0 + (NSEC_PER_SEC as u32) - other.tv_nsec.0,
+                    self.tv_nsec.as_inner() + (NSEC_PER_SEC as u32) - other.tv_nsec.as_inner(),
                 )
             };
 
@@ -170,7 +169,7 @@ impl Timespec {
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
-        let mut nsec = other.subsec_nanos() + self.tv_nsec.0;
+        let mut nsec = other.subsec_nanos() + self.tv_nsec.as_inner();
         if nsec >= NSEC_PER_SEC as u32 {
             nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
@@ -182,7 +181,7 @@ impl Timespec {
         let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
-        let mut nsec = self.tv_nsec.0 as i32 - other.subsec_nanos() as i32;
+        let mut nsec = self.tv_nsec.as_inner() as i32 - other.subsec_nanos() as i32;
         if nsec < 0 {
             nsec += NSEC_PER_SEC as i32;
             secs = secs.checked_sub(1)?;
@@ -194,7 +193,7 @@ impl Timespec {
     pub fn to_timespec(&self) -> Option<libc::timespec> {
         Some(libc::timespec {
             tv_sec: self.tv_sec.try_into().ok()?,
-            tv_nsec: self.tv_nsec.0.try_into().ok()?,
+            tv_nsec: self.tv_nsec.as_inner().try_into().ok()?,
         })
     }
 
@@ -203,7 +202,7 @@ impl Timespec {
     #[cfg(target_os = "nto")]
     pub(in crate::sys) fn to_timespec_capped(&self) -> Option<libc::timespec> {
         // Check if timeout in nanoseconds would fit into an u64
-        if (self.tv_nsec.0 as u64)
+        if (self.tv_nsec.as_inner() as u64)
             .checked_add((self.tv_sec as u64).checked_mul(NSEC_PER_SEC)?)
             .is_none()
         {
@@ -219,7 +218,7 @@ impl Timespec {
         not(target_arch = "riscv32")
     ))]
     pub fn to_timespec64(&self) -> __timespec64 {
-        __timespec64::new(self.tv_sec, self.tv_nsec.0 as _)
+        __timespec64::new(self.tv_sec, self.tv_nsec.as_inner() as _)
     }
 }
 
@@ -293,7 +292,7 @@ impl fmt::Debug for Instant {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Instant")
             .field("tv_sec", &self.t.tv_sec)
-            .field("tv_nsec", &self.t.tv_nsec.0)
+            .field("tv_nsec", &self.t.tv_nsec)
             .finish()
     }
 }
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 3657d9b3112..50fea43aee0 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -181,10 +181,7 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<
 /// copy and remove the file otherwise
 pub fn move_file<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
     match fs::rename(&from, &to) {
-        // FIXME: Once `ErrorKind::CrossesDevices` is stabilized use
-        // if e.kind() == io::ErrorKind::CrossesDevices {
-        #[cfg(unix)]
-        Err(e) if e.raw_os_error() == Some(libc::EXDEV) => {
+        Err(e) if e.kind() == io::ErrorKind::CrossesDevices => {
             std::fs::copy(&from, &to)?;
             std::fs::remove_file(&from)
         }
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index 508b7b40c01..2f52ff5a99a 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -1,29 +1,30 @@
 # Docker images for CI
 
 This folder contains a bunch of docker images used by the continuous integration
-(CI) of Rust. An script is accompanied (`run.sh`) with these images to actually
-execute them. To test out an image execute:
+(CI) of Rust. A script is accompanied (`run.sh`) with these images to actually
+execute them.
 
-```
-./src/ci/docker/run.sh $image_name
-```
+Note that a single Docker image can be used by multiple CI jobs, so the job name
+is the important thing that you should know. You can examine the existing CI jobs in
+the [`jobs.yml`](../github-actions/jobs.yml) file.
 
-for example:
+To run a specific CI job locally, you can use the following script:
 
 ```
-./src/ci/docker/run.sh x86_64-gnu
+python3 ./src/ci/github-actions/ci.py run-local <job-name>
 ```
 
-Images will output artifacts in an `obj/$image_name` dir at the root of a repository. Note
-that the script will overwrite the contents of this directory.
-
-To match conditions in rusts CI, also set the environment variable `DEPLOY=1`, e.g.:
+For example, to run the `x86_64-gnu-llvm-18-1` job:
 ```
-DEPLOY=1 ./src/ci/docker/run.sh x86_64-gnu
+python3 ./src/ci/github-actions/ci.py run-local x86_64-gnu-llvm-18-1
 ```
 
+The job will output artifacts in an `obj/<image-name>` dir at the root of a repository. Note
+that the script will overwrite the contents of this directory. `<image-name>` is set based on the
+Docker image executed in the given CI job.
+
 **NOTE**: In CI, the script outputs the artifacts to the `obj` directory,
-while locally, to the `obj/$image_name` directory. This is primarily to prevent
+while locally, to the `obj/<image-name>` directory. This is primarily to prevent
 strange linker errors when using multiple Docker images.
 
 For some Linux workflows (for example `x86_64-gnu-llvm-18-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-18-3` workflow, you can run the following script:
diff --git a/src/ci/github-actions/calculate-job-matrix.py b/src/ci/github-actions/ci.py
index 1f994f0ffd2..b7dac412dbe 100755
--- a/src/ci/github-actions/calculate-job-matrix.py
+++ b/src/ci/github-actions/ci.py
@@ -1,18 +1,20 @@
 #!/usr/bin/env python3
 
 """
-This script serves for generating a matrix of jobs that should
-be executed on CI.
+This script contains CI functionality.
+It can be used to generate a matrix of jobs that should
+be executed on CI, or run a specific CI job locally.
 
-It reads job definitions from `src/ci/github-actions/jobs.yml`
-and filters them based on the event that happened on CI.
+It reads job definitions from `src/ci/github-actions/jobs.yml`.
 """
 
+import argparse
 import dataclasses
 import json
 import logging
 import os
 import re
+import subprocess
 import typing
 from pathlib import Path
 from typing import List, Dict, Any, Optional
@@ -25,13 +27,19 @@ JOBS_YAML_PATH = Path(__file__).absolute().parent / "jobs.yml"
 Job = Dict[str, Any]
 
 
-def name_jobs(jobs: List[Dict], prefix: str) -> List[Job]:
+def add_job_properties(jobs: List[Dict], prefix: str) -> List[Job]:
     """
-    Add a `name` attribute to each job, based on its image and the given `prefix`.
+    Modify the `name` attribute of each job, based on its base name and the given `prefix`.
+    Add an `image` attribute to each job, based on its image.
     """
+    modified_jobs = []
     for job in jobs:
-        job["name"] = f"{prefix} - {job['image']}"
-    return jobs
+        # Create a copy of the `job` dictionary to avoid modifying `jobs`
+        new_job = dict(job)
+        new_job["image"] = get_job_image(new_job)
+        new_job["full_name"] = f"{prefix} - {new_job['name']}"
+        modified_jobs.append(new_job)
+    return modified_jobs
 
 
 def add_base_env(jobs: List[Job], environment: Dict[str, str]) -> List[Job]:
@@ -39,11 +47,15 @@ def add_base_env(jobs: List[Job], environment: Dict[str, str]) -> List[Job]:
     Prepends `environment` to the `env` attribute of each job.
     The `env` of each job has higher precedence than `environment`.
     """
+    modified_jobs = []
     for job in jobs:
         env = environment.copy()
         env.update(job.get("env", {}))
-        job["env"] = env
-    return jobs
+
+        new_job = dict(job)
+        new_job["env"] = env
+        modified_jobs.append(new_job)
+    return modified_jobs
 
 
 @dataclasses.dataclass
@@ -116,7 +128,9 @@ def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]:
 
 def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[Job]:
     if isinstance(run_type, PRRunType):
-        return add_base_env(name_jobs(job_data["pr"], "PR"), job_data["envs"]["pr"])
+        return add_base_env(
+            add_job_properties(job_data["pr"], "PR"), job_data["envs"]["pr"]
+        )
     elif isinstance(run_type, TryRunType):
         jobs = job_data["try"]
         custom_jobs = run_type.custom_jobs
@@ -130,7 +144,7 @@ def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[
             jobs = []
             unknown_jobs = []
             for custom_job in custom_jobs:
-                job = [j for j in job_data["auto"] if j["image"] == custom_job]
+                job = [j for j in job_data["auto"] if j["name"] == custom_job]
                 if not job:
                     unknown_jobs.append(custom_job)
                     continue
@@ -140,10 +154,10 @@ def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[
                     f"Custom job(s) `{unknown_jobs}` not found in auto jobs"
                 )
 
-        return add_base_env(name_jobs(jobs, "try"), job_data["envs"]["try"])
+        return add_base_env(add_job_properties(jobs, "try"), job_data["envs"]["try"])
     elif isinstance(run_type, AutoRunType):
         return add_base_env(
-            name_jobs(job_data["auto"], "auto"), job_data["envs"]["auto"]
+            add_job_properties(job_data["auto"], "auto"), job_data["envs"]["auto"]
         )
 
     return []
@@ -181,12 +195,64 @@ def format_run_type(run_type: WorkflowRunType) -> str:
         raise AssertionError()
 
 
-if __name__ == "__main__":
-    logging.basicConfig(level=logging.INFO)
+def get_job_image(job: Job) -> str:
+    """
+    By default, the Docker image of a job is based on its name.
+    However, it can be overridden by its IMAGE environment variable.
+    """
+    env = job.get("env", {})
+    # Return the IMAGE environment variable if it exists, otherwise return the job name
+    return env.get("IMAGE", job["name"])
 
-    with open(JOBS_YAML_PATH) as f:
-        data = yaml.safe_load(f)
 
+def is_linux_job(job: Job) -> bool:
+    return "ubuntu" in job["os"]
+
+
+def find_linux_job(job_data: Dict[str, Any], job_name: str, pr_jobs: bool) -> Job:
+    candidates = job_data["pr"] if pr_jobs else job_data["auto"]
+    jobs = [job for job in candidates if job.get("name") == job_name]
+    if len(jobs) == 0:
+        available_jobs = "\n".join(
+            sorted(job["name"] for job in candidates if is_linux_job(job))
+        )
+        raise Exception(f"""Job `{job_name}` not found in {'pr' if pr_jobs else 'auto'} jobs.
+The following jobs are available:
+{available_jobs}""")
+    assert len(jobs) == 1
+
+    job = jobs[0]
+    if not is_linux_job(job):
+        raise Exception("Only Linux jobs can be executed locally")
+    return job
+
+
+def run_workflow_locally(job_data: Dict[str, Any], job_name: str, pr_jobs: bool):
+    DOCKER_DIR = Path(__file__).absolute().parent.parent / "docker"
+
+    job = find_linux_job(job_data, job_name=job_name, pr_jobs=pr_jobs)
+
+    custom_env = {}
+    # Replicate src/ci/scripts/setup-environment.sh
+    # Adds custom environment variables to the job
+    if job_name.startswith("dist-"):
+        if job_name.endswith("-alt"):
+            custom_env["DEPLOY_ALT"] = "1"
+        else:
+            custom_env["DEPLOY"] = "1"
+    custom_env.update({k: str(v) for (k, v) in job.get("env", {}).items()})
+
+    args = [str(DOCKER_DIR / "run.sh"), get_job_image(job)]
+    env_formatted = [f"{k}={v}" for (k, v) in sorted(custom_env.items())]
+    print(f"Executing `{' '.join(env_formatted)} {' '.join(args)}`")
+
+    env = os.environ.copy()
+    env.update(custom_env)
+
+    subprocess.run(args, env=env)
+
+
+def calculate_job_matrix(job_data: Dict[str, Any]):
     github_ctx = get_github_ctx()
 
     run_type = find_run_type(github_ctx)
@@ -197,7 +263,7 @@ if __name__ == "__main__":
 
     jobs = []
     if run_type is not None:
-        jobs = calculate_jobs(run_type, data)
+        jobs = calculate_jobs(run_type, job_data)
     jobs = skip_jobs(jobs, channel)
 
     if not jobs:
@@ -208,3 +274,45 @@ if __name__ == "__main__":
     logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}")
     print(f"jobs={json.dumps(jobs)}")
     print(f"run_type={run_type}")
+
+
+def create_cli_parser():
+    parser = argparse.ArgumentParser(
+        prog="ci.py", description="Generate or run CI workflows"
+    )
+    subparsers = parser.add_subparsers(
+        help="Command to execute", dest="command", required=True
+    )
+    subparsers.add_parser(
+        "calculate-job-matrix",
+        help="Generate a matrix of jobs that should be executed in CI",
+    )
+    run_parser = subparsers.add_parser(
+        "run-local", help="Run a CI jobs locally (on Linux)"
+    )
+    run_parser.add_argument(
+        "job_name",
+        help="CI job that should be executed. By default, a merge (auto) "
+        "job with the given name will be executed",
+    )
+    run_parser.add_argument(
+        "--pr", action="store_true", help="Run a PR job instead of an auto job"
+    )
+    return parser
+
+
+if __name__ == "__main__":
+    logging.basicConfig(level=logging.INFO)
+
+    with open(JOBS_YAML_PATH) as f:
+        data = yaml.safe_load(f)
+
+    parser = create_cli_parser()
+    args = parser.parse_args()
+
+    if args.command == "calculate-job-matrix":
+        calculate_job_matrix(data)
+    elif args.command == "run-local":
+        run_workflow_locally(data, args.job_name, args.pr)
+    else:
+        raise Exception(f"Unknown command {args.command}")
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 876a7793592..d88be6543a3 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -91,26 +91,26 @@ envs:
 # These jobs automatically inherit envs.pr, to avoid repeating
 # it in each job definition.
 pr:
-  - image: mingw-check
+  - name: mingw-check
     <<: *job-linux-4c
-  - image: mingw-check-tidy
+  - name: mingw-check-tidy
     continue_on_error: true
     <<: *job-linux-4c
-  - image: x86_64-gnu-llvm-18
+  - name: x86_64-gnu-llvm-18
     env:
       ENABLE_GCC_CODEGEN: "1"
       # We are adding (temporarily) a dummy commit on the compiler
       READ_ONLY_SRC: "0"
       DOCKER_SCRIPT: x86_64-gnu-llvm.sh
     <<: *job-linux-16c
-  - image: x86_64-gnu-tools
+  - name: x86_64-gnu-tools
     <<: *job-linux-16c
 
 # Jobs that run when you perform a try build (@bors try)
 # These jobs automatically inherit envs.try, to avoid repeating
 # it in each job definition.
 try:
-  - image: dist-x86_64-linux
+  - name: dist-x86_64-linux
     env:
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-linux-16c
@@ -123,106 +123,106 @@ auto:
   #   Linux/Docker builders   #
   #############################
 
-  - image: aarch64-gnu
+  - name: aarch64-gnu
     <<: *job-aarch64-linux
 
-  - image: aarch64-gnu-debug
+  - name: aarch64-gnu-debug
     <<: *job-aarch64-linux
 
-  - image: arm-android
+  - name: arm-android
     <<: *job-linux-4c
 
-  - image: armhf-gnu
+  - name: armhf-gnu
     <<: *job-linux-4c
 
-  - image: dist-aarch64-linux
+  - name: dist-aarch64-linux
     env:
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-linux-4c
 
-  - image: dist-android
+  - name: dist-android
     <<: *job-linux-4c
 
-  - image: dist-arm-linux
+  - name: dist-arm-linux
     <<: *job-linux-8c
 
-  - image: dist-armhf-linux
+  - name: dist-armhf-linux
     <<: *job-linux-4c
 
-  - image: dist-armv7-linux
+  - name: dist-armv7-linux
     <<: *job-linux-4c
 
-  - image: dist-i586-gnu-i586-i686-musl
+  - name: dist-i586-gnu-i586-i686-musl
     <<: *job-linux-4c
 
-  - image: dist-i686-linux
+  - name: dist-i686-linux
     <<: *job-linux-4c
 
-  - image: dist-loongarch64-linux
+  - name: dist-loongarch64-linux
     <<: *job-linux-4c
 
-  - image: dist-loongarch64-musl
+  - name: dist-loongarch64-musl
     <<: *job-linux-4c
 
-  - image: dist-ohos
+  - name: dist-ohos
     <<: *job-linux-4c
 
-  - image: dist-powerpc-linux
+  - name: dist-powerpc-linux
     <<: *job-linux-4c
 
-  - image: dist-powerpc64-linux
+  - name: dist-powerpc64-linux
     <<: *job-linux-4c
 
-  - image: dist-powerpc64le-linux
+  - name: dist-powerpc64le-linux
     <<: *job-linux-4c-largedisk
 
-  - image: dist-riscv64-linux
+  - name: dist-riscv64-linux
     <<: *job-linux-4c
 
-  - image: dist-s390x-linux
+  - name: dist-s390x-linux
     <<: *job-linux-4c
 
-  - image: dist-various-1
+  - name: dist-various-1
     <<: *job-linux-4c
 
-  - image: dist-various-2
+  - name: dist-various-2
     <<: *job-linux-4c
 
-  - image: dist-x86_64-freebsd
+  - name: dist-x86_64-freebsd
     <<: *job-linux-4c
 
-  - image: dist-x86_64-illumos
+  - name: dist-x86_64-illumos
     <<: *job-linux-4c
 
-  - image: dist-x86_64-linux
+  - name: dist-x86_64-linux
     env:
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-linux-16c
 
-  - image: dist-x86_64-linux-alt
+  - name: dist-x86_64-linux-alt
     env:
       IMAGE: dist-x86_64-linux
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-linux-16c
 
-  - image: dist-x86_64-musl
+  - name: dist-x86_64-musl
     env:
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-linux-4c
 
-  - image: dist-x86_64-netbsd
+  - name: dist-x86_64-netbsd
     <<: *job-linux-4c
 
   # The i686-gnu job is split into multiple jobs to run tests in parallel.
   # i686-gnu-1 skips tests that run in i686-gnu-2.
-  - image: i686-gnu-1
+  - name: i686-gnu-1
     env:
       IMAGE: i686-gnu
       DOCKER_SCRIPT: stage_2_test_set1.sh
     <<: *job-linux-4c
 
   # Skip tests that run in i686-gnu-1
-  - image: i686-gnu-2
+  - name: i686-gnu-2
     env:
       IMAGE: i686-gnu
       DOCKER_SCRIPT: stage_2_test_set2.sh
@@ -230,14 +230,14 @@ auto:
 
   # The i686-gnu-nopt job is split into multiple jobs to run tests in parallel.
   # i686-gnu-nopt-1 skips tests that run in i686-gnu-nopt-2
-  - image: i686-gnu-nopt-1
+  - name: i686-gnu-nopt-1
     env:
       IMAGE: i686-gnu-nopt
       DOCKER_SCRIPT: /scripts/stage_2_test_set1.sh
     <<: *job-linux-4c
 
   # Skip tests that run in i686-gnu-nopt-1
-  - image: i686-gnu-nopt-2
+  - name: i686-gnu-nopt-2
     env:
       IMAGE: i686-gnu-nopt
       DOCKER_SCRIPT: >-
@@ -245,13 +245,13 @@ auto:
         /scripts/stage_2_test_set2.sh
     <<: *job-linux-4c
 
-  - image: mingw-check
+  - name: mingw-check
     <<: *job-linux-4c
 
-  - image: test-various
+  - name: test-various
     <<: *job-linux-4c
 
-  - image: x86_64-fuchsia
+  - name: x86_64-fuchsia
     # Only run this job on the nightly channel. Fuchsia requires
     # nightly features to compile, and this job would fail if
     # executed on beta and stable.
@@ -260,10 +260,10 @@ auto:
 
   # Tests integration with Rust for Linux.
   # Builds stage 1 compiler and tries to compile a few RfL examples with it.
-  - image: x86_64-rust-for-linux
+  - name: x86_64-rust-for-linux
     <<: *job-linux-4c
 
-  - image: x86_64-gnu
+  - name: x86_64-gnu
     <<: *job-linux-4c
 
   # This job ensures commits landing on nightly still pass the full
@@ -271,7 +271,7 @@ auto:
   # depend on the channel being built (for example if they include the
   # channel name on the output), and this builder prevents landing
   # changes that would result in broken builds after a promotion.
-  - image: x86_64-gnu-stable
+  - name: x86_64-gnu-stable
     # Only run this job on the nightly channel. Running this on beta
     # could cause failures when `dev: 1` in `stage0.txt`, and running
     # this on stable is useless.
@@ -281,20 +281,20 @@ auto:
       RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable
     <<: *job-linux-4c
 
-  - image: x86_64-gnu-aux
+  - name: x86_64-gnu-aux
     <<: *job-linux-4c
 
-  - image: x86_64-gnu-debug
+  - name: x86_64-gnu-debug
     # This seems to be needed because a full stage 2 build + run-make tests
     # overwhelms the storage capacity of the standard 4c runner.
     <<: *job-linux-4c-largedisk
 
-  - image: x86_64-gnu-distcheck
+  - name: x86_64-gnu-distcheck
     <<: *job-linux-8c
 
   # The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel.
   # x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}.
-  - image: x86_64-gnu-llvm-19-1
+  - name: x86_64-gnu-llvm-19-1
     env:
       RUST_BACKTRACE: 1
       IMAGE: x86_64-gnu-llvm-19
@@ -302,7 +302,7 @@ auto:
     <<: *job-linux-4c
 
   # Skip tests that run in x86_64-gnu-llvm-19-{1,3}
-  - image: x86_64-gnu-llvm-19-2
+  - name: x86_64-gnu-llvm-19-2
     env:
       RUST_BACKTRACE: 1
       IMAGE: x86_64-gnu-llvm-19
@@ -310,7 +310,7 @@ auto:
     <<: *job-linux-4c
 
   # Skip tests that run in x86_64-gnu-llvm-19-{1,2}
-  - image: x86_64-gnu-llvm-19-3
+  - name: x86_64-gnu-llvm-19-3
     env:
       RUST_BACKTRACE: 1
       IMAGE: x86_64-gnu-llvm-19
@@ -319,7 +319,7 @@ auto:
 
   # The x86_64-gnu-llvm-18 job is split into multiple jobs to run tests in parallel.
   # x86_64-gnu-llvm-18-1 skips tests that run in x86_64-gnu-llvm-18-{2,3}.
-  - image: x86_64-gnu-llvm-18-1
+  - name: x86_64-gnu-llvm-18-1
     env:
       RUST_BACKTRACE: 1
       READ_ONLY_SRC: "0"
@@ -328,7 +328,7 @@ auto:
     <<: *job-linux-4c
 
   # Skip tests that run in x86_64-gnu-llvm-18-{1,3}
-  - image: x86_64-gnu-llvm-18-2
+  - name: x86_64-gnu-llvm-18-2
     env:
       RUST_BACKTRACE: 1
       READ_ONLY_SRC: "0"
@@ -337,7 +337,7 @@ auto:
     <<: *job-linux-4c
 
   # Skip tests that run in x86_64-gnu-llvm-18-{1,2}
-  - image: x86_64-gnu-llvm-18-3
+  - name: x86_64-gnu-llvm-18-3
     env:
       RUST_BACKTRACE: 1
       READ_ONLY_SRC: "0"
@@ -345,10 +345,10 @@ auto:
       DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
     <<: *job-linux-4c
 
-  - image: x86_64-gnu-nopt
+  - name: x86_64-gnu-nopt
     <<: *job-linux-4c
 
-  - image: x86_64-gnu-tools
+  - name: x86_64-gnu-tools
     env:
       DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
     <<: *job-linux-4c
@@ -357,7 +357,7 @@ auto:
   #  macOS Builders  #
   ####################
 
-  - image: dist-x86_64-apple
+  - name: dist-x86_64-apple
     env:
       SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin
       RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin --set rust.codegen-units=1
@@ -371,7 +371,7 @@ auto:
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-macos-xl
 
-  - image: dist-apple-various
+  - name: dist-apple-various
     env:
       SCRIPT: ./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim,aarch64-apple-ios-macabi,x86_64-apple-ios-macabi
       # Mac Catalyst cannot currently compile the sanitizer:
@@ -385,19 +385,19 @@ auto:
       NO_OVERFLOW_CHECKS: 1
     <<: *job-macos-xl
 
-  - image: x86_64-apple-1
+  - name: x86_64-apple-1
     env:
       <<: *env-x86_64-apple-tests
     <<: *job-macos-xl
 
-  - image: x86_64-apple-2
+  - name: x86_64-apple-2
     env:
       SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc
       <<: *env-x86_64-apple-tests
     <<: *job-macos-xl
 
   # This target only needs to support 11.0 and up as nothing else supports the hardware
-  - image: dist-aarch64-apple
+  - name: dist-aarch64-apple
     env:
       SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin
       RUST_CONFIGURE_ARGS: >-
@@ -421,7 +421,7 @@ auto:
     <<: *job-macos-m1
 
   # This target only needs to support 11.0 and up as nothing else supports the hardware
-  - image: aarch64-apple
+  - name: aarch64-apple
     env:
       SCRIPT: ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin
       RUST_CONFIGURE_ARGS: >-
@@ -442,20 +442,20 @@ auto:
   #  Windows Builders  #
   ######################
 
-  - image: x86_64-msvc
+  - name: x86_64-msvc
     env:
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
       SCRIPT: make ci-msvc
     <<: *job-windows-8c
 
-  - image: i686-msvc
+  - name: i686-msvc
     env:
       RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
       SCRIPT: make ci-msvc
     <<: *job-windows-8c
 
   # x86_64-msvc-ext is split into multiple jobs to run tests in parallel.
-  - image: x86_64-msvc-ext1
+  - name: x86_64-msvc-ext1
     env:
       SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld
@@ -464,7 +464,7 @@ auto:
   # Temporary builder to workaround CI issues
   # See <https://github.com/rust-lang/rust/issues/127883>
   #FIXME: Remove this, and re-enable the same tests in `checktools.sh`, once CI issues are fixed.
-  - image: x86_64-msvc-ext2
+  - name: x86_64-msvc-ext2
     env:
       SCRIPT: >
         python x.py test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass &&
@@ -476,7 +476,7 @@ auto:
     <<: *job-windows
 
   # Run `checktools.sh` and upload the toolstate file.
-  - image: x86_64-msvc-ext3
+  - name: x86_64-msvc-ext3
     env:
       SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows
       HOST_TARGET: x86_64-pc-windows-msvc
@@ -500,7 +500,7 @@ auto:
   # came from the mingw-w64 SourceForge download site. Unfortunately
   # SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
 
-  - image: i686-mingw
+  - name: i686-mingw
     env:
       RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
       SCRIPT: make ci-mingw
@@ -510,7 +510,7 @@ auto:
     <<: *job-windows-8c
 
   # x86_64-mingw is split into two jobs to run tests in parallel.
-  - image: x86_64-mingw-1
+  - name: x86_64-mingw-1
     env:
       SCRIPT: make ci-mingw-x
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
@@ -519,7 +519,7 @@ auto:
       NO_DOWNLOAD_CI_LLVM: 1
     <<: *job-windows
 
-  - image: x86_64-mingw-2
+  - name: x86_64-mingw-2
     env:
       SCRIPT: make ci-mingw-bootstrap
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
@@ -528,7 +528,7 @@ auto:
       NO_DOWNLOAD_CI_LLVM: 1
     <<: *job-windows
 
-  - image: dist-x86_64-msvc
+  - name: dist-x86_64-msvc
     env:
       RUST_CONFIGURE_ARGS: >-
         --build=x86_64-pc-windows-msvc
@@ -542,7 +542,7 @@ auto:
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-windows-8c
 
-  - image: dist-i686-msvc
+  - name: dist-i686-msvc
     env:
       RUST_CONFIGURE_ARGS: >-
         --build=i686-pc-windows-msvc
@@ -555,7 +555,7 @@ auto:
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-windows
 
-  - image: dist-aarch64-msvc
+  - name: dist-aarch64-msvc
     env:
       RUST_CONFIGURE_ARGS: >-
         --build=x86_64-pc-windows-msvc
@@ -567,7 +567,7 @@ auto:
       DIST_REQUIRE_ALL_TOOLS: 1
     <<: *job-windows
 
-  - image: dist-i686-mingw
+  - name: dist-i686-mingw
     env:
       RUST_CONFIGURE_ARGS: >-
         --build=i686-pc-windows-gnu
@@ -580,7 +580,7 @@ auto:
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-windows
 
-  - image: dist-x86_64-mingw
+  - name: dist-x86_64-mingw
     env:
       SCRIPT: python x.py dist bootstrap --include-default-paths
       RUST_CONFIGURE_ARGS: >-
@@ -593,7 +593,7 @@ auto:
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-windows
 
-  - image: dist-x86_64-msvc-alt
+  - name: dist-x86_64-msvc-alt
     env:
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
       SCRIPT: python x.py dist bootstrap --include-default-paths
diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md
index 3080dc6bf5d..8feda59829b 100644
--- a/src/doc/rustc-dev-guide/src/building/optimized-build.md
+++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md
@@ -126,4 +126,4 @@ Here is an example of how can `opt-dist` be used locally (outside of CI):
 [`Environment`]: https://github.com/rust-lang/rust/blob/ee451f8faccf3050c76cdcd82543c917b40c7962/src/tools/opt-dist/src/environment.rs#L5
 
 > Note: if you want to run the actual CI pipeline, instead of running `opt-dist` locally,
-> you can execute `DEPLOY=1 src/ci/docker/run.sh dist-x86_64-linux`.
+> you can execute `python3 src/ci/github-actions/ci.py run-local dist-x86_64-linux`.
diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md
index 5e27a2fd770..0ad1d2a28ed 100644
--- a/src/doc/rustc-dev-guide/src/tests/ci.md
+++ b/src/doc/rustc-dev-guide/src/tests/ci.md
@@ -28,7 +28,7 @@ Our CI is primarily executed on [GitHub Actions], with a single workflow defined
 in [`.github/workflows/ci.yml`], which contains a bunch of steps that are
 unified for all CI jobs that we execute. When a commit is pushed to a
 corresponding branch or a PR, the workflow executes the
-[`calculate-job-matrix.py`] script, which dynamically generates the specific CI
+[`ci.py`] script, which dynamically generates the specific CI
 jobs that should be executed. This script uses the [`jobs.yml`] file as an
 input, which contains a declarative configuration of all our CI jobs.
 
@@ -299,8 +299,7 @@ platform’s custom [Docker container]. This has a lot of advantages for us:
 - We can avoid reinstalling tools (like QEMU or the Android emulator) every time
   thanks to Docker image caching.
 - Users can run the same tests in the same environment locally by just running
-  `src/ci/docker/run.sh image-name`, which is awesome to debug failures. Note
-  that there are only linux docker images available locally due to licensing and
+  `python3 src/ci/github-actions/ci.py run-local <job-name>`, which is awesome to debug failures. Note that there are only linux docker images available locally due to licensing and
   other restrictions.
 
 The docker images prefixed with `dist-` are used for building artifacts while
@@ -413,7 +412,7 @@ To learn more about the dashboard, see the [Datadog CI docs].
 [GitHub Actions]: https://github.com/rust-lang/rust/actions
 [`jobs.yml`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/jobs.yml
 [`.github/workflows/ci.yml`]: https://github.com/rust-lang/rust/blob/master/.github/workflows/ci.yml
-[`calculate-job-matrix.py`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/calculate-job-matrix.py
+[`ci.py`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/ci.py
 [rust-lang-ci]: https://github.com/rust-lang-ci/rust/actions
 [bors]: https://github.com/bors
 [homu]: https://github.com/rust-lang/homu
diff --git a/src/doc/rustc-dev-guide/src/tests/docker.md b/src/doc/rustc-dev-guide/src/tests/docker.md
index 31e3825f567..a0aa8bd3e77 100644
--- a/src/doc/rustc-dev-guide/src/tests/docker.md
+++ b/src/doc/rustc-dev-guide/src/tests/docker.md
@@ -45,6 +45,15 @@ Some additional notes about using the Docker images:
   containers. With the container name, run `docker exec -it <CONTAINER>
   /bin/bash` where `<CONTAINER>` is the container name like `4ba195e95cef`.
 
+The approach described above is a relatively low-level interface for running the Docker images
+directly. If you want to run a full CI Linux job locally with Docker, in a way that is as close to CI as possible, you can use the following command:
+
+```bash
+python3 src/ci/github-actions/ci.py run-local <job-name>
+# For example:
+python3 src/ci/github-actions/ci.py run-local dist-x86_64-linux-alt
+```
+
 [Docker]: https://www.docker.com/
 [`src/ci/docker`]: https://github.com/rust-lang/rust/tree/master/src/ci/docker
 [`src/ci/docker/run.sh`]: https://github.com/rust-lang/rust/blob/master/src/ci/docker/run.sh
diff --git a/src/doc/unstable-book/src/language-features/default-field-values.md b/src/doc/unstable-book/src/language-features/default-field-values.md
new file mode 100644
index 00000000000..3143b2d7cae
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/default-field-values.md
@@ -0,0 +1,93 @@
+# `default_field_values`
+
+The tracking issue for this feature is: [#132162]
+
+[#132162]: https://github.com/rust-lang/rust/issues/132162
+
+The RFC for this feature is: [#3681]
+
+[#3681]: https://github.com/rust-lang/rfcs/blob/master/text/3681-default-field-values.md
+
+------------------------
+
+The `default_field_values` feature allows users to specify a const value for
+individual fields in struct definitions, allowing those to be omitted from
+initializers.
+
+## Examples
+
+```rust
+#![feature(default_field_values)]
+
+#[derive(Default)]
+struct Pet {
+    name: Option<String>, // impl Default for Pet will use Default::default() for name
+    age: i128 = 42, // impl Default for Pet will use the literal 42 for age
+}
+
+fn main() {
+    let a = Pet { name: Some(String::new()), .. }; // Pet { name: Some(""), age: 42 }
+    let b = Pet::default(); // Pet { name: None, age: 42 }
+    assert_eq!(a.age, b.age);
+    // The following would be a compilation error: `name` needs to be specified
+    // let _ = Pet { .. };
+}
+```
+
+## `#[derive(Default)]`
+
+When deriving Default, the provided values are then used. On enum variants,
+the variant must still be marked with `#[default]` and have all its fields
+with default values.
+
+```rust
+#![feature(default_field_values)]
+
+#[derive(Default)]
+enum A {
+    #[default]
+    B {
+        x: i32 = 0,
+        y: i32 = 0,
+    },
+    C,
+}
+```
+
+## Enum variants
+
+This feature also supports enum variants for both specifying default values
+and `#[derive(Default)]`.
+
+## Interaction with `#[non_exhaustive]`
+
+A struct or enum variant marked with `#[non_exhaustive]` is not allowed to
+have default field values.
+
+## Lints
+
+When manually implementing the `Default` trait for a type that has default
+field values, if any of these are overriden in the impl the
+`default_overrides_default_fields` lint will trigger. This lint is in place
+to avoid surprising diverging behavior between `S { .. }` and
+`S::default()`, where using the same type in both ways could result in
+different values. The appropriate way to write a manual `Default`
+implementation is to use the functional update syntax:
+
+```rust
+#![feature(default_field_values)]
+
+struct Pet {
+    name: String,
+    age: i128 = 42, // impl Default for Pet will use the literal 42 for age
+}
+
+impl Default for Pet {
+    fn default() -> Pet {
+        Pet {
+            name: "no-name".to_string(),
+            ..
+        }
+    }
+}
+```
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject fd784878cfa843e3e29a6654ecf564c62fae673
+Subproject 088d496082726091024f1689c124a0c3dccbd77
diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml
index bcb3193ad67..d6534fbaff9 100644
--- a/src/tools/clippy/.github/workflows/clippy_dev.yml
+++ b/src/tools/clippy/.github/workflows/clippy_dev.yml
@@ -17,6 +17,9 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # Run
     - name: Build
diff --git a/src/tools/clippy/.github/workflows/clippy_mq.yml b/src/tools/clippy/.github/workflows/clippy_mq.yml
index 49622048050..dee7d028655 100644
--- a/src/tools/clippy/.github/workflows/clippy_mq.yml
+++ b/src/tools/clippy/.github/workflows/clippy_mq.yml
@@ -23,6 +23,8 @@ jobs:
       uses: actions/checkout@v4
       with:
         ref: ${{ github.ref }}
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # Run
     - name: Check Changelog
@@ -63,6 +65,8 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install i686 dependencies
       if: matrix.host == 'i686-unknown-linux-gnu'
@@ -74,7 +78,8 @@ jobs:
     - name: Install toolchain
       run: |
         rustup set default-host ${{ matrix.host }}
-        rustup show active-toolchain
+        # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
+        rustup show active-toolchain || rustup toolchain install
 
     # Run
     - name: Build
@@ -121,9 +126,13 @@ jobs:
      # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install toolchain
-      run: rustup show active-toolchain
+      run: |
+        # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
+        rustup show active-toolchain || rustup toolchain install
 
     - name: Test metadata collection
       run: cargo collect-metadata
@@ -136,9 +145,13 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install toolchain
-      run: rustup show active-toolchain
+      run: |
+        # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
+        rustup show active-toolchain || rustup toolchain install
 
     # Run
     - name: Build Integration Test
@@ -188,9 +201,13 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install toolchain
-      run: rustup show active-toolchain
+      run: |
+        # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
+        rustup show active-toolchain || rustup toolchain install
 
     # Download
     - name: Download target dir
@@ -205,7 +222,7 @@ jobs:
     # Run
     - name: Test ${{ matrix.integration }}
       run: |
-          TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ')
+          TOOLCHAIN=$(rustup show active-toolchain | head -n 1 | cut -f1 -d' ')
           rustup run $TOOLCHAIN $CARGO_TARGET_DIR/debug/integration --show-output
       env:
         INTEGRATION: ${{ matrix.integration }}
diff --git a/src/tools/clippy/.github/workflows/clippy_pr.yml b/src/tools/clippy/.github/workflows/clippy_pr.yml
index 2e5b5bd41df..80523d91f4f 100644
--- a/src/tools/clippy/.github/workflows/clippy_pr.yml
+++ b/src/tools/clippy/.github/workflows/clippy_pr.yml
@@ -25,9 +25,14 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Install toolchain
-      run: rustup show active-toolchain
+      run: |
+        # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
+        rustup show active-toolchain || rustup toolchain install
 
     # Run
     - name: Build
diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml
index 32dc251c836..b42f3e7712f 100644
--- a/src/tools/clippy/.github/workflows/deploy.yml
+++ b/src/tools/clippy/.github/workflows/deploy.yml
@@ -22,19 +22,27 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Checkout
       uses: actions/checkout@v4
       with:
         ref: ${{ env.TARGET_BRANCH }}
         path: 'out'
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # Run
     - name: Set tag name
       if: startswith(github.ref, 'refs/tags/')
       run: |
-        TAG=$(basename ${{ github.ref }})
+        TAG=$(basename "${TAGNAME}")
         echo "TAG_NAME=$TAG" >> $GITHUB_ENV
+      env:
+        # Make sure that the reference gets expanded before injecting it
+        TAGNAME: ${{ github.ref }}
     - name: Set beta to true
       if: github.ref == 'refs/heads/beta'
       run: echo "BETA=true" >> $GITHUB_ENV
diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml
index 3cbda0b3824..64966f1d189 100644
--- a/src/tools/clippy/.github/workflows/lintcheck.yml
+++ b/src/tools/clippy/.github/workflows/lintcheck.yml
@@ -21,6 +21,8 @@ jobs:
       uses: actions/checkout@v4
       with:
         fetch-depth: 2
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # HEAD is the generated merge commit `refs/pull/N/merge` between the PR and `master`, `HEAD^`
     # being the commit from `master` that is the base of the merge
@@ -73,6 +75,9 @@ jobs:
     steps:
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Cache lintcheck bin
       id: cache-lintcheck-bin
@@ -103,6 +108,9 @@ jobs:
     steps:
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Restore lintcheck bin
       uses: actions/cache/restore@v4
diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml
index 0d402fe7064..69d00dc027e 100644
--- a/src/tools/clippy/.github/workflows/remark.yml
+++ b/src/tools/clippy/.github/workflows/remark.yml
@@ -12,6 +12,9 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Setup Node.js
       uses: actions/setup-node@v4
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index b6033de9350..1770e8095a0 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,52 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[aa0d5513...master](https://github.com/rust-lang/rust-clippy/compare/aa0d5513...master)
+[786fbd6d...master](https://github.com/rust-lang/rust-clippy/compare/786fbd6d...master)
+
+## Rust 1.84
+
+Current stable, released 2025-01-09
+
+[View all 84 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-10-03T21%3A23%3A58Z..2024-11-14T17%3A41%3A37Z+base%3Amaster)
+
+### New Lints
+
+* Added [`unnecessary_map_or`] to `style`
+  [#11796](https://github.com/rust-lang/rust-clippy/pull/11796)
+* Added [`arbitrary_source_item_ordering`] to `restriction`
+  [#13376](https://github.com/rust-lang/rust-clippy/pull/13376)
+* Added [`map_with_unused_argument_over_ranges`] to `restriction`
+  [#13034](https://github.com/rust-lang/rust-clippy/pull/13034)
+* Added [`map_all_any_identity`] to `complexity`
+  [#13499](https://github.com/rust-lang/rust-clippy/pull/13499)
+* Added [`needless_as_bytes`] to `complexity`
+  [#13437](https://github.com/rust-lang/rust-clippy/pull/13437)
+* Added [`unnecessary_literal_bound`] to `pedantic`
+  [#13395](https://github.com/rust-lang/rust-clippy/pull/13395)
+* Added [`manual_ignore_case_cmp`] to `perf`
+  [#13334](https://github.com/rust-lang/rust-clippy/pull/13334)
+* Added [`regex_creation_in_loops`] to `perf`
+  [#13412](https://github.com/rust-lang/rust-clippy/pull/13412)
+
+### Moves and Deprecations
+
+* Moved [`manual_is_power_of_two`] to `pedantic` (From `complexity`, now allow-by-default)
+  [#13553](https://github.com/rust-lang/rust-clippy/pull/13553)
+* Move [`module_name_repetitions`] to `restriction` (from `pedantic`)
+  [#13541](https://github.com/rust-lang/rust-clippy/pull/13541)
+
+### Enhancements
+
+* [`doc_markdown`]: Added the following identifiers to [`doc-valid-idents`]:
+  CoAP, MHz, GHz, and THz
+  [#13633](https://github.com/rust-lang/rust-clippy/pull/13633)
+  [#13460](https://github.com/rust-lang/rust-clippy/pull/13460)
+* [`large_const_arrays`]: Changed the default of [`array-size-threshold`] to `16kb` (from `512kb`)
+  [#13485](https://github.com/rust-lang/rust-clippy/pull/13485)
 
 ## Rust 1.83
 
-Current stable, released 2024-11-28
+Released 2024-11-28
 
 [View all 64 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-08-25T09%3A59%3A01Z..2024-10-03T13%3A42%3A56Z+base%3Amaster)
 
@@ -5493,6 +5534,7 @@ Released 2018-09-13
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
+[`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last
 [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
 [`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
 [`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
@@ -6252,6 +6294,7 @@ Released 2018-09-13
 [`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold
 [`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability
 [`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold
+[`lint-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-inconsistent-struct-field-initializers
 [`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold
 [`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else
 [`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 77cb0006ff8..efa59fecc0e 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy"
 # begin autogenerated version
-version = "0.1.85"
+version = "0.1.86"
 # end autogenerated version
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
diff --git a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
index df9b1bbe18f..2b2c096b049 100644
--- a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
+++ b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
@@ -83,7 +83,12 @@ As section headers, we use:
 
 ```
 ### New Lints
+* Added [`LINT`] to `GROUP`
+
 ### Moves and Deprecations
+* Moved [`LINT`] to `GROUP` (From `GROUP`, now LEVEL-by-default)
+* Renamed `LINT` to [`LINT`]
+
 ### Enhancements
 ### False Positive Fixes
 ### Suggestion Fixes/Improvements
diff --git a/src/tools/clippy/book/src/development/method_checking.md b/src/tools/clippy/book/src/development/method_checking.md
index 9c5d4b516db..b3126024b99 100644
--- a/src/tools/clippy/book/src/development/method_checking.md
+++ b/src/tools/clippy/book/src/development/method_checking.md
@@ -21,7 +21,7 @@ use clippy_utils::is_trait_method;
 impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         // Check our expr is calling a method with pattern matching
-        if let hir::ExprKind::MethodCall(path, _, [self_arg, ..]) = &expr.kind
+        if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind
             // Check if the name of this method is `our_fancy_method`
             && path.ident.name.as_str() == "our_fancy_method"
             // We can check the type of the self argument whenever necessary.
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index ea1d7d11389..181e794e6e4 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -582,6 +582,33 @@ The maximum size of the `Err`-variant in a `Result` returned from a function
 * [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err)
 
 
+## `lint-inconsistent-struct-field-initializers`
+Whether to suggest reordering constructor fields when initializers are present.
+
+Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
+suggested code would compile, it can change semantics if the initializer expressions have side effects. The
+following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
+
+```rust
+struct MyStruct {
+    vector: Vec<u32>,
+    length: usize
+}
+fn main() {
+    let vector = vec![1,2,3];
+    MyStruct { length: vector.len(), vector};
+}
+```
+
+[from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
+
+**Default Value:** `false`
+
+---
+**Affected lints:**
+* [`inconsistent_struct_constructor`](https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor)
+
+
 ## `literal-representation-threshold`
 The lower bound for linting decimal literals
 
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
index a7b0cc56ea1..f4789c9d030 100644
--- a/src/tools/clippy/clippy.toml
+++ b/src/tools/clippy/clippy.toml
@@ -1,5 +1,7 @@
 avoid-breaking-exported-api = false
 
+lint-inconsistent-struct-field-initializers = true
+
 [[disallowed-methods]]
 path = "rustc_lint::context::LintContext::lint"
 reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 3f18a0bc7d2..c761e207c6b 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_config"
 # begin autogenerated version
-version = "0.1.85"
+version = "0.1.86"
 # end autogenerated version
 edition = "2021"
 publish = false
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index bffa04f6f09..c616589c56e 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -532,6 +532,26 @@ define_Conf! {
     /// The maximum size of the `Err`-variant in a `Result` returned from a function
     #[lints(result_large_err)]
     large_error_threshold: u64 = 128,
+    /// Whether to suggest reordering constructor fields when initializers are present.
+    ///
+    /// Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
+    /// suggested code would compile, it can change semantics if the initializer expressions have side effects. The
+    /// following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
+    ///
+    /// ```rust
+    /// struct MyStruct {
+    ///     vector: Vec<u32>,
+    ///     length: usize
+    /// }
+    /// fn main() {
+    ///     let vector = vec![1,2,3];
+    ///     MyStruct { length: vector.len(), vector};
+    /// }
+    /// ```
+    ///
+    /// [from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
+    #[lints(inconsistent_struct_constructor)]
+    lint_inconsistent_struct_field_initializers: bool = false,
     /// The lower bound for linting decimal literals
     #[lints(decimal_literal_representation)]
     literal_representation_threshold: u64 = 16384,
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index c6673859282..790dafa811f 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -179,8 +179,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
                 #[expect(clippy::drain_collect)]
                 fields.push(ClippyConf {
                     name,
-                    lints: lints.drain(..).collect(),
                     attrs: &conf[attrs_start..attrs_end],
+                    lints: lints.drain(..).collect(),
                     field: conf[field_start..i].trim_end(),
                 });
                 attrs_start = i;
@@ -191,8 +191,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
                 #[expect(clippy::drain_collect)]
                 fields.push(ClippyConf {
                     name,
-                    lints: lints.drain(..).collect(),
                     attrs: &conf[attrs_start..attrs_end],
+                    lints: lints.drain(..).collect(),
                     field: conf[field_start..i].trim_end(),
                 });
                 attrs_start = i;
@@ -220,8 +220,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
     }
     fields.push(ClippyConf {
         name,
-        lints,
         attrs: &conf[attrs_start..attrs_end],
+        lints,
         field: conf[field_start..].trim_end(),
     });
 
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index c1f8e82f698..b575ac1bf4c 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_lints"
 # begin autogenerated version
-version = "0.1.85"
+version = "0.1.86"
 # end autogenerated version
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index 74153990266..380b094d017 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -428,8 +428,8 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
 
             // Makes a note of the current item for comparison with the next.
             cur_t = Some(CurItem {
-                order: module_level_order,
                 item,
+                order: module_level_order,
                 name: get_item_name(item),
             });
         }
@@ -464,7 +464,7 @@ fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleIte
         ItemKind::Use(..) => Use,
         ItemKind::Static(..) => Static,
         ItemKind::Const(..) => Const,
-        ItemKind::Fn{ .. } => Fn,
+        ItemKind::Fn { .. } => Fn,
         ItemKind::Macro(..) => Macro,
         ItemKind::Mod(..) => Mod,
         ItemKind::ForeignMod { .. } => ForeignMod,
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
index 32c28c09c36..8c91c65eaf7 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
@@ -66,7 +66,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute])
 
 fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
     let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion());
-    let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) {
+    let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.next_back()) {
         first.span.with_hi(last.span.hi())
     } else {
         return;
diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
index 67aa33ca06c..6057144bc6a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
@@ -1,11 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::Msrv;
-use clippy_utils::source::snippet_with_context;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::{is_lint_allowed, msrvs, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::Adjust;
+use rustc_span::BytePos;
 
 use super::BORROW_AS_PTR;
 
@@ -32,12 +34,21 @@ pub(super) fn check<'tcx>(
             return false;
         }
 
-        let suggestion = if msrv.meets(msrvs::RAW_REF_OP) {
+        let (suggestion, span) = if msrv.meets(msrvs::RAW_REF_OP) {
             let operator_kind = match mutability {
                 Mutability::Not => "const",
                 Mutability::Mut => "mut",
             };
-            format!("&raw {operator_kind} {snip}")
+            // Make sure that the span to be replaced doesn't include parentheses, that could break the
+            // suggestion.
+            let span = if has_enclosing_paren(snippet_with_applicability(cx, expr.span, "", &mut app)) {
+                expr.span
+                    .with_lo(expr.span.lo() + BytePos(1))
+                    .with_hi(expr.span.hi() - BytePos(1))
+            } else {
+                expr.span
+            };
+            (format!("&raw {operator_kind} {snip}"), span)
         } else {
             let Some(std_or_core) = std_or_core(cx) else {
                 return false;
@@ -46,18 +57,10 @@ pub(super) fn check<'tcx>(
                 Mutability::Not => "addr_of",
                 Mutability::Mut => "addr_of_mut",
             };
-            format!("{std_or_core}::ptr::{macro_name}!({snip})")
+            (format!("{std_or_core}::ptr::{macro_name}!({snip})"), expr.span)
         };
 
-        span_lint_and_sugg(
-            cx,
-            BORROW_AS_PTR,
-            expr.span,
-            "borrow as raw pointer",
-            "try",
-            suggestion,
-            Applicability::MachineApplicable,
-        );
+        span_lint_and_sugg(cx, BORROW_AS_PTR, span, "borrow as raw pointer", "try", suggestion, app);
         return true;
     }
     false
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index c64c0e15144..d90cf124fe4 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -836,11 +836,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             as_underscore::check(cx, expr, cast_to_hir);
             as_pointer_underscore::check(cx, cast_to, cast_to_hir);
 
-            let was_borrow_as_ptr_emitted = if self.msrv.meets(msrvs::BORROW_AS_PTR) {
-                borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, &self.msrv)
-            } else {
-                false
-            };
+            let was_borrow_as_ptr_emitted = self.msrv.meets(msrvs::BORROW_AS_PTR)
+                && borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, &self.msrv);
             if self.msrv.meets(msrvs::PTR_FROM_REF) && !was_borrow_as_ptr_emitted {
                 ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
             }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 7451fb909ef..3ff10d850f8 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -372,6 +372,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::CLONE_ON_REF_PTR_INFO,
     crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
     crate::methods::CONST_IS_EMPTY_INFO,
+    crate::methods::DOUBLE_ENDED_ITERATOR_LAST_INFO,
     crate::methods::DRAIN_COLLECT_INFO,
     crate::methods::ERR_EXPECT_INFO,
     crate::methods::EXPECT_FUN_CALL_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index 40377dd841e..3e2b7055de4 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -1,6 +1,6 @@
 use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::ty::{implements_trait_with_env, is_type_diagnostic_item};
 use clippy_utils::{is_doc_hidden, return_ty};
 use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
 use rustc_lint::LateContext;
@@ -70,7 +70,14 @@ pub fn check(
             && let typeck = cx.tcx.typeck_body(body_id)
             && let body = cx.tcx.hir().body(body_id)
             && let ret_ty = typeck.expr_ty(body.value)
-            && implements_trait(cx, ret_ty, future, &[])
+            && implements_trait_with_env(
+                cx.tcx,
+                ty::TypingEnv::non_body_analysis(cx.tcx, owner_id.def_id),
+                ret_ty,
+                future,
+                Some(owner_id.def_id.to_def_id()),
+                &[],
+            )
             && let ty::Coroutine(_, subs) = ret_ty.kind()
             && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result)
         {
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index c835b81679b..7561a6cf2a7 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -797,8 +797,8 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
         parser.into_offset_iter(),
         &doc,
         Fragments {
-            fragments: &fragments,
             doc: &doc,
+            fragments: &fragments,
         },
     ))
 }
diff --git a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
index 2327da0ccff..1f89cab9148 100644
--- a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
@@ -25,7 +25,7 @@ pub(super) fn check(
             // page. So associated items or impl blocks are not part of this list.
             ItemKind::Static(..)
                 | ItemKind::Const(..)
-                | ItemKind::Fn{ .. }
+                | ItemKind::Fn { .. }
                 | ItemKind::Macro(..)
                 | ItemKind::Mod(..)
                 | ItemKind::TyAlias(..)
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 70524e458c7..2bec4f2f99e 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -678,12 +678,12 @@ fn find_insert_calls<'tcx>(
         map: contains_expr.map,
         key: contains_expr.key,
         ctxt: expr.span.ctxt(),
-        edits: Vec::new(),
-        is_map_used: false,
         allow_insert_closure: true,
         can_use_entry: true,
         in_tail_pos: true,
         is_single_insert: true,
+        is_map_used: false,
+        edits: Vec::new(),
         loops: Vec::new(),
         locals: HirIdSet::default(),
     };
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 2cd48ef98e5..c0b4743fd71 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -182,7 +182,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc
                 // will succeed iff `T: 'static`. But the region of `T` is always erased by `typeck.expr_ty()` when
                 // T is a generic type. For example, return type of `Option<String>::as_deref()` is a generic.
                 // So we have a hack like this.
-                && generic_args.len() > 0
+                && !generic_args.is_empty()
             {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 4427edb752e..ef272c305d3 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -243,11 +243,11 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
                 && !predicates.is_empty()
             {
                 Some(ImplTraitBound {
+                    span: bound.span(),
                     predicates,
+                    trait_def_id,
                     args: path.args.map_or([].as_slice(), |p| p.args),
                     constraints: path.args.map_or([].as_slice(), |p| p.constraints),
-                    trait_def_id,
-                    span: bound.span(),
                 })
             } else {
                 None
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 4fcd2abb769..39ff3c13bcc 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -1,19 +1,21 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_config::Conf;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::fulfill_or_allowed;
 use clippy_utils::source::snippet;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
-use rustc_hir::{self as hir, ExprKind, StructTailExpr};
+use rustc_hir::{self as hir, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::impl_lint_pass;
+use rustc_span::Span;
 use rustc_span::symbol::Symbol;
-use std::fmt::{self, Write as _};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for struct constructors where all fields are shorthand and
-    /// the order of the field init shorthand in the constructor is inconsistent
-    /// with the order in the struct definition.
+    /// Checks for struct constructors where the order of the field
+    /// init in the constructor is inconsistent with the order in the
+    /// struct definition.
     ///
     /// ### Why is this bad?
     /// Since the order of fields in a constructor doesn't affect the
@@ -59,16 +61,37 @@ declare_clippy_lint! {
     #[clippy::version = "1.52.0"]
     pub INCONSISTENT_STRUCT_CONSTRUCTOR,
     pedantic,
-    "the order of the field init shorthand is inconsistent with the order in the struct definition"
+    "the order of the field init is inconsistent with the order in the struct definition"
 }
 
-declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]);
+pub struct InconsistentStructConstructor {
+    lint_inconsistent_struct_field_initializers: bool,
+}
+
+impl InconsistentStructConstructor {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            lint_inconsistent_struct_field_initializers: conf.lint_inconsistent_struct_field_initializers,
+        }
+    }
+}
+
+impl_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]);
 
 impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if let ExprKind::Struct(qpath, fields, base) = expr.kind
-            && fields.iter().all(|f| f.is_shorthand)
-            && !expr.span.from_expansion()
+        let ExprKind::Struct(_, fields, _) = expr.kind else {
+            return;
+        };
+        let all_fields_are_shorthand = fields.iter().all(|f| f.is_shorthand);
+        let applicability = if all_fields_are_shorthand {
+            Applicability::MachineApplicable
+        } else if self.lint_inconsistent_struct_field_initializers {
+            Applicability::MaybeIncorrect
+        } else {
+            return;
+        };
+        if !expr.span.from_expansion()
             && let ty = cx.typeck_results().expr_ty(expr)
             && let Some(adt_def) = ty.ty_adt_def()
             && adt_def.is_struct()
@@ -85,36 +108,24 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
                 return;
             }
 
-            let mut ordered_fields: Vec<_> = fields.iter().map(|f| f.ident.name).collect();
-            ordered_fields.sort_unstable_by_key(|id| def_order_map[id]);
-
-            let mut fields_snippet = String::new();
-            let (last_ident, idents) = ordered_fields.split_last().unwrap();
-            for ident in idents {
-                let _: fmt::Result = write!(fields_snippet, "{ident}, ");
-            }
-            fields_snippet.push_str(&last_ident.to_string());
-
-            let base_snippet = if let StructTailExpr::Base(base) = base {
-                format!(", ..{}", snippet(cx, base.span, ".."))
-            } else {
-                String::new()
-            };
-
-            let sugg = format!(
-                "{} {{ {fields_snippet}{base_snippet} }}",
-                snippet(cx, qpath.span(), ".."),
-            );
+            let span = field_with_attrs_span(cx.tcx, fields.first().unwrap())
+                .with_hi(field_with_attrs_span(cx.tcx, fields.last().unwrap()).hi());
 
             if !fulfill_or_allowed(cx, INCONSISTENT_STRUCT_CONSTRUCTOR, Some(ty_hir_id)) {
-                span_lint_and_sugg(
+                span_lint_and_then(
                     cx,
                     INCONSISTENT_STRUCT_CONSTRUCTOR,
-                    expr.span,
+                    span,
                     "struct constructor field order is inconsistent with struct definition field order",
-                    "try",
-                    sugg,
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        let msg = if all_fields_are_shorthand {
+                            "try"
+                        } else {
+                            "if the field evaluation order doesn't matter, try"
+                        };
+                        let sugg = suggestion(cx, fields, &def_order_map);
+                        diag.span_suggestion(span, msg, sugg, applicability);
+                    },
                 );
             }
         }
@@ -135,3 +146,45 @@ fn is_consistent_order<'tcx>(fields: &'tcx [hir::ExprField<'tcx>], def_order_map
 
     true
 }
+
+fn suggestion<'tcx>(
+    cx: &LateContext<'_>,
+    fields: &'tcx [hir::ExprField<'tcx>],
+    def_order_map: &FxHashMap<Symbol, usize>,
+) -> String {
+    let ws = fields
+        .windows(2)
+        .map(|w| {
+            let w0_span = field_with_attrs_span(cx.tcx, &w[0]);
+            let w1_span = field_with_attrs_span(cx.tcx, &w[1]);
+            let span = w0_span.between(w1_span);
+            snippet(cx, span, " ")
+        })
+        .collect::<Vec<_>>();
+
+    let mut fields = fields.to_vec();
+    fields.sort_unstable_by_key(|field| def_order_map[&field.ident.name]);
+    let field_snippets = fields
+        .iter()
+        .map(|field| snippet(cx, field_with_attrs_span(cx.tcx, field), ".."))
+        .collect::<Vec<_>>();
+
+    assert_eq!(field_snippets.len(), ws.len() + 1);
+
+    let mut sugg = String::new();
+    for i in 0..field_snippets.len() {
+        sugg += &field_snippets[i];
+        if i < ws.len() {
+            sugg += &ws[i];
+        }
+    }
+    sugg
+}
+
+fn field_with_attrs_span(tcx: TyCtxt<'_>, field: &hir::ExprField<'_>) -> Span {
+    if let Some(attr) = tcx.hir().attrs(field.hir_id).first() {
+        field.span.with_lo(attr.span.lo())
+    } else {
+        field.span
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 1c63ca9d974..5418acc105e 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{SpanRangeExt, snippet_with_context};
 use clippy_utils::sugg::{Sugg, has_enclosing_paren};
+use clippy_utils::ty::implements_trait;
 use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, is_trait_method, peel_ref_operators};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -626,18 +627,30 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         })
     }
 
-    let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
-    match ty.kind() {
-        ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| {
-            let is_empty = sym!(is_empty);
-            cx.tcx
-                .associated_items(principal.def_id())
-                .filter_by_name_unhygienic(is_empty)
-                .any(|item| is_is_empty(cx, item))
-        }),
-        ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id),
-        ty::Adt(id, _) => has_is_empty_impl(cx, id.did()),
-        ty::Array(..) | ty::Slice(..) | ty::Str => true,
-        _ => false,
+    fn ty_has_is_empty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, depth: usize) -> bool {
+        match ty.kind() {
+            ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| {
+                let is_empty = sym!(is_empty);
+                cx.tcx
+                    .associated_items(principal.def_id())
+                    .filter_by_name_unhygienic(is_empty)
+                    .any(|item| is_is_empty(cx, item))
+            }),
+            ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id),
+            ty::Adt(id, _) => {
+                has_is_empty_impl(cx, id.did())
+                    || (cx.tcx.recursion_limit().value_within_limit(depth)
+                        && cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| {
+                            implements_trait(cx, ty, deref_id, &[])
+                                && cx
+                                    .get_associated_type(ty, deref_id, "Target")
+                                    .is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1))
+                        }))
+            },
+            ty::Array(..) | ty::Slice(..) | ty::Str => true,
+            _ => false,
+        }
     }
+
+    ty_has_is_empty(cx, cx.typeck_results().expr_ty(expr).peel_refs(), 0)
 }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index d33013ba663..fad6f9d0880 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -649,7 +649,11 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn));
     store.register_late_pass(move |_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub::new(conf)));
     store.register_late_pass(|_| Box::new(default_numeric_fallback::DefaultNumericFallback));
-    store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
+    store.register_late_pass(move |_| {
+        Box::new(inconsistent_struct_constructor::InconsistentStructConstructor::new(
+            conf,
+        ))
+    });
     store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
     store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
     store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(conf)));
diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
index f88605fbea0..6be30f3c957 100644
--- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
@@ -38,8 +38,8 @@ pub(super) fn check<'tcx>(
         cx,
         label,
         inner_labels: label.into_iter().collect(),
-        is_finite: false,
         loop_depth: 0,
+        is_finite: false,
     };
     loop_visitor.visit_block(loop_block);
 
diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
index 312bcb55a95..006addb987f 100644
--- a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
@@ -220,11 +220,11 @@ impl<'tcx> LateLintPass<'tcx> for ExprMetavarsInUnsafe {
         // `check_stmt_post` on `(Late)LintPass`, which we'd need to detect when we're leaving a macro span
 
         let mut vis = BodyVisitor {
+            macro_unsafe_blocks: Vec::new(),
             #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
             expn_depth: if body.value.span.from_expansion() { 1 } else { 0 },
-            macro_unsafe_blocks: Vec::new(),
-            lint: self,
-            cx
+            cx,
+            lint: self
         };
         vis.visit_body(body);
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
index bbb89bee835..aa59b047b16 100644
--- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
@@ -2,14 +2,15 @@ use clippy_utils::SpanlessEq;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::sugg::Sugg;
-use rustc_ast::{BinOpKind, LitKind};
+use clippy_utils::sugg::{Sugg, has_enclosing_paren};
+use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self};
 use rustc_session::impl_lint_pass;
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Symbol;
 
 use clippy_config::Conf;
@@ -138,9 +139,40 @@ fn build_suggestion(
     applicability: &mut Applicability,
 ) {
     let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_par();
+    let type_suffix = if cx.typeck_results().expr_ty(lhs).is_numeric()
+        && matches!(
+            lhs.kind,
+            ExprKind::Lit(Spanned {
+                node: LitKind::Int(_, LitIntType::Unsuffixed),
+                ..
+            }) | ExprKind::Unary(UnOp::Neg, Expr {
+                kind: ExprKind::Lit(Spanned {
+                    node: LitKind::Int(_, LitIntType::Unsuffixed),
+                    ..
+                }),
+                ..
+            })
+        ) {
+        format!("_{}", cx.typeck_results().expr_ty(rhs))
+    } else {
+        String::new()
+    };
+    let dividend_sugg_str = dividend_sugg.into_string();
+    // If `dividend_sugg` has enclosing paren like `(-2048)` and we need to add type suffix in the
+    // suggestion message, we want to make a suggestion string before `div_ceil` like
+    // `(-2048_{type_suffix})`.
+    let suggestion_before_div_ceil = if has_enclosing_paren(&dividend_sugg_str) {
+        format!(
+            "{}{})",
+            &dividend_sugg_str[..dividend_sugg_str.len() - 1].to_string(),
+            type_suffix
+        )
+    } else {
+        format!("{dividend_sugg_str}{type_suffix}")
+    };
     let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability);
 
-    let sugg = format!("{dividend_sugg}.div_ceil({divisor_snippet})");
+    let sugg = format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})");
 
     span_lint_and_sugg(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
index dabfac3f613..506f4f6d9de 100644
--- a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
@@ -32,7 +32,7 @@ declare_clippy_lint! {
     ///    a.eq_ignore_ascii_case(b) || a.eq_ignore_ascii_case("abc")
     /// }
     /// ```
-    #[clippy::version = "1.82.0"]
+    #[clippy::version = "1.84.0"]
     pub MANUAL_IGNORE_CASE_CMP,
     perf,
     "manual case-insensitive ASCII comparison"
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index 5b9eedd9b8b..9860deba843 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -9,7 +9,7 @@ use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd, PatExpr, PatExprKind, Lit};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, sym};
 
@@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
             && !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_))
         {
             let arg = peel_ref_operators(cx, arg);
-            let ty_sugg = get_ty_sugg(cx, arg, start);
+            let ty_sugg = get_ty_sugg(cx, arg);
             let range = check_expr_range(start, end);
             check_is_ascii(cx, expr.span, arg, &range, ty_sugg);
         }
@@ -123,19 +123,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
     extract_msrv_attr!(LateContext);
 }
 
-fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>, bound_expr: &Expr<'_>) -> Option<(Span, &'static str)> {
-    if let ExprKind::Lit(lit) = bound_expr.kind
-        && let local_hid = path_to_local(arg)?
-        && let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid)
+fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> {
+    let local_hid = path_to_local(arg)?;
+    if let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid)
         // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given
         && ty_span == span
     {
-        let ty_str = match lit.node {
-            Char(_) => "char",
-            Byte(_) => "u8",
-            _ => return None,
-        };
-        return Some((*ty_span, ty_str));
+        let arg_type = cx.typeck_results().expr_ty(arg);
+        return Some((*ty_span, arg_type));
     }
     None
 }
@@ -145,7 +140,7 @@ fn check_is_ascii(
     span: Span,
     recv: &Expr<'_>,
     range: &CharRange,
-    ty_sugg: Option<(Span, &'_ str)>,
+    ty_sugg: Option<(Span, Ty<'_>)>,
 ) {
     let sugg = match range {
         CharRange::UpperChar => "is_ascii_uppercase",
@@ -159,8 +154,8 @@ fn check_is_ascii(
     let mut app = Applicability::MachineApplicable;
     let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par();
     let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))];
-    if let Some((ty_span, ty_str)) = ty_sugg {
-        suggestion.push((ty_span, format!("{recv}: {ty_str}")));
+    if let Some((ty_span, ty)) = ty_sugg {
+        suggestion.push((ty_span, format!("{recv}: {ty}")));
     }
 
     span_lint_and_then(
@@ -206,7 +201,6 @@ fn check_expr_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
     }
 }
 
-
 fn check_range(start: &PatExpr<'_>, end: &PatExpr<'_>) -> CharRange {
     if let PatExprKind::Lit{ lit: start_lit, negated: false } = &start.kind
         && let PatExprKind::Lit{ lit: end_lit, negated: false  } = &end.kind
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 1fd2ebcb54a..ac1eae07eff 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -583,11 +583,6 @@ declare_clippy_lint! {
     /// are the same on purpose, you can factor them
     /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
     ///
-    /// ### Known problems
-    /// False positive possible with order dependent `match`
-    /// (see issue
-    /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
-    ///
     /// ### Example
     /// ```rust,ignore
     /// match foo {
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 7e74b36b441..edac97344a0 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -1,6 +1,6 @@
 use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet, walk_span_to_context};
+use clippy_utils::source::walk_span_to_context;
 use clippy_utils::sugg::{Sugg, make_unop};
 use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
 use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures};
@@ -274,7 +274,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
                 ExprKind::AddrOf(_, _, borrowed) => borrowed,
                 _ => op,
             };
-            let mut sugg = format!("{}.{good_method}", snippet(cx, result_expr.span, "_"));
+            let mut app = Applicability::MachineApplicable;
+            let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_par();
+            let mut sugg = format!("{receiver_sugg}.{good_method}");
 
             if let Some(guard) = maybe_guard {
                 // wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying!
@@ -307,7 +309,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
                 format!("redundant pattern matching, consider using `{good_method}`"),
                 "try",
                 sugg,
-                Applicability::MachineApplicable,
+                app,
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index b1d0686ffc4..38f876fed80 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -345,7 +345,7 @@ impl<'a> PatState<'a> {
 
             PatKind::Guard(..) => {
                 matches!(self, Self::Wild)
-            }
+            },
 
             // Patterns for things which can only contain a single sub-pattern.
             PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) | PatKind::Box(pat) | PatKind::Deref(pat) => {
diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
new file mode 100644
index 00000000000..208172980c9
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
@@ -0,0 +1,41 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_trait_method;
+use clippy_utils::ty::implements_trait;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Instance;
+use rustc_span::{Span, sym};
+
+use super::DOUBLE_ENDED_ITERATOR_LAST;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Expr<'_>, call_span: Span) {
+    let typeck = cx.typeck_results();
+
+    // if the "last" method is that of Iterator
+    if is_trait_method(cx, expr, sym::Iterator)
+        // if self implements DoubleEndedIterator
+        && let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator)
+        && let self_type = cx.typeck_results().expr_ty(self_expr)
+        && implements_trait(cx, self_type.peel_refs(), deiter_id, &[])
+        // resolve the method definition
+        && let id = typeck.type_dependent_def_id(expr.hir_id).unwrap()
+        && let args = typeck.node_args(expr.hir_id)
+        && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
+        // find the provided definition of Iterator::last
+        && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
+        && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last")
+        // if the resolved method is the same as the provided definition
+        && fn_def.def_id() == last_def.def_id
+    {
+        span_lint_and_sugg(
+            cx,
+            DOUBLE_ENDED_ITERATOR_LAST,
+            call_span,
+            "called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator",
+            "try",
+            "next_back()".to_string(),
+            Applicability::MachineApplicable,
+        );
+    }
+}
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 07a7a12b162..f7bb8c1d696 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_trait_method, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -17,10 +17,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_
         let mut applicability = Applicability::MachineApplicable;
 
         let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability);
+        let span = expr.span.with_lo(map_span.lo());
+        // If the methods are separated with comments, we don't apply suggestion automatically.
+        if span_contains_comment(cx.tcx.sess.source_map(), span) {
+            applicability = Applicability::Unspecified;
+        }
         span_lint_and_sugg(
             cx,
             MAP_FLATTEN,
-            expr.span.with_lo(map_span.lo()),
+            span,
             format!("called `map(..).flatten()` on `{caller_ty_name}`"),
             format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"),
             format!("{method_to_use}({closure_snippet})"),
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
index 1f204de01da..05360144657 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method, path_to_local};
+use rustc_ast::BindingMode;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{self as hir, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::{Span, sym};
 
@@ -24,6 +25,16 @@ pub(super) fn check(
         && is_expr_untyped_identity_function(cx, map_arg)
         && let Some(sugg_span) = expr.span.trim_start(caller.span)
     {
+        // If the result of `.map(identity)` is used as a mutable reference,
+        // the caller must not be an immutable binding.
+        if cx.typeck_results().expr_ty_adjusted(expr).is_mutable_ptr()
+            && let Some(hir_id) = path_to_local(caller)
+            && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
+            && !matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
+        {
+            return;
+        }
+
         span_lint_and_sugg(
             cx,
             MAP_IDENTITY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 810287fa541..51351f6b7cd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -14,6 +14,7 @@ mod clone_on_copy;
 mod clone_on_ref_ptr;
 mod cloned_instead_of_copied;
 mod collapsible_str_replace;
+mod double_ended_iterator_last;
 mod drain_collect;
 mod err_expect;
 mod expect_fun_call;
@@ -4284,6 +4285,32 @@ declare_clippy_lint! {
     "map of a trivial closure (not dependent on parameter) over a range"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for `Iterator::last` being called on a  `DoubleEndedIterator`, which can be replaced
+    /// with `DoubleEndedIterator::next_back`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// `Iterator::last` is implemented by consuming the iterator, which is unnecessary if
+    /// the iterator is a `DoubleEndedIterator`. Since Rust traits do not allow specialization,
+    /// `Iterator::last` cannot be optimized for `DoubleEndedIterator`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let last_arg = "echo hello world".split(' ').last();
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let last_arg = "echo hello world".split(' ').next_back();
+    /// ```
+    #[clippy::version = "1.85.0"]
+    pub DOUBLE_ENDED_ITERATOR_LAST,
+    perf,
+    "using `Iterator::last` on a `DoubleEndedIterator`"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -4449,6 +4476,7 @@ impl_lint_pass!(Methods => [
     MAP_ALL_ANY_IDENTITY,
     MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
     UNNECESSARY_MAP_OR,
+    DOUBLE_ENDED_ITERATOR_LAST,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4931,6 +4959,7 @@ impl Methods {
                             false,
                         );
                     }
+                    double_ended_iterator_last::check(cx, expr, recv, call_span);
                 },
                 ("len", []) => {
                     if let Some(("as_bytes", prev_recv, [], _, _)) = method_call(recv) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
index 348f740e7dd..6993150fb57 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
@@ -7,6 +7,7 @@ use rustc_span::Span;
 use super::NEEDLESS_CHARACTER_ITERATION;
 use super::utils::get_last_chain_binding_hir_id;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::paths::CHAR_IS_ASCII;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::{match_def_path, path_to_local_id, peel_blocks};
 
@@ -77,7 +78,7 @@ fn handle_expr(
             if revert != is_all
                 && let ExprKind::Path(path) = fn_path.kind
                 && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id()
-                && match_def_path(cx, fn_def_id, &["core", "char", "methods", "<impl char>", "is_ascii"])
+                && match_def_path(cx, fn_def_id, &CHAR_IS_ASCII)
                 && path_to_local_id(peels_expr_ref(arg), first_param)
                 && let Some(snippet) = before_chars.get_source_text(cx)
             {
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index ea4984f83ad..2780c3f8af5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -470,14 +470,14 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>(
     captured_ids: HirIdSet,
 ) -> Option<Vec<IterFunction>> {
     let mut visitor = IterFunctionVisitor {
-        uses: Vec::new(),
-        target: id,
-        seen_other: false,
-        cx,
-        current_mutably_captured_ids: HirIdSet::default(),
         illegal_mutable_capture_ids: captured_ids,
+        current_mutably_captured_ids: HirIdSet::default(),
+        cx,
+        uses: Vec::new(),
         hir_id_uses_map: FxHashMap::default(),
         current_statement_hir_id: None,
+        seen_other: false,
+        target: id,
     };
     visitor.visit_block(block);
     if visitor.seen_other {
diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
index db2b9d4d92f..82e66a0500a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
@@ -1,6 +1,7 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths::STDIN;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_local_use_after_expr;
@@ -33,7 +34,7 @@ fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool {
 
 pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
     if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
-        && match_def_path(cx, recv_adt.did(), &["std", "io", "stdio", "Stdin"])
+        && match_def_path(cx, recv_adt.did(), &STDIN)
         && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind
         && let Res::Local(local_id) = path.res
     {
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 c6d4ef5911e..8a99974394c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -297,8 +297,8 @@ fn parse_iter_usage<'tcx>(
                     {
                         Some(IterUsage {
                             kind: IterUsageKind::NextTuple,
-                            span: e.span,
                             unwrap_kind: None,
+                            span: e.span,
                         })
                     } else {
                         None
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index b5d8972d7aa..c27d1fb4903 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -124,30 +124,30 @@ pub(super) fn check(
         match lit.node {
             ast::LitKind::Bool(false) => {
                 check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, Replacement {
+                    method_name: "any",
                     has_args: true,
                     has_generic_return: false,
-                    method_name: "any",
                 });
             },
             ast::LitKind::Bool(true) => {
                 check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, Replacement {
+                    method_name: "all",
                     has_args: true,
                     has_generic_return: false,
-                    method_name: "all",
                 });
             },
             ast::LitKind::Int(Pu128(0), _) => {
                 check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, Replacement {
+                    method_name: "sum",
                     has_args: false,
                     has_generic_return: needs_turbofish(cx, expr),
-                    method_name: "sum",
                 });
             },
             ast::LitKind::Int(Pu128(1), _) => {
                 check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, Replacement {
+                    method_name: "product",
                     has_args: false,
                     has_generic_return: needs_turbofish(cx, expr),
-                    method_name: "product",
                 });
             },
             _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
index 1199d289761..b7dbebe60a4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
@@ -7,7 +7,7 @@ use clippy_utils::source::snippet_opt;
 use clippy_utils::sugg::{Sugg, make_binop};
 use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{is_from_proc_macro, path_to_local_id};
+use clippy_utils::{get_parent_expr, is_from_proc_macro, path_to_local_id};
 use rustc_ast::LitKind::Bool;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
@@ -96,11 +96,25 @@ pub(super) fn check<'a>(
             Sugg::hir(cx, non_binding_location, "")
         )));
 
-        let binop = make_binop(op.node, &Sugg::hir(cx, recv, ".."), &inner_non_binding)
-            .maybe_par()
-            .into_string();
+        let mut app = Applicability::MachineApplicable;
+        let binop = make_binop(
+            op.node,
+            &Sugg::hir_with_applicability(cx, recv, "..", &mut app),
+            &inner_non_binding,
+        );
 
-        (binop, "a standard comparison", Applicability::MaybeIncorrect)
+        let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) {
+            match parent_expr.kind {
+                ExprKind::Binary(..) | ExprKind::Unary(..) | ExprKind::Cast(..) => binop.maybe_par(),
+                ExprKind::MethodCall(_, receiver, _, _) if receiver.hir_id == expr.hir_id => binop.maybe_par(),
+                _ => binop,
+            }
+        } else {
+            binop
+        }
+        .into_string();
+
+        (sugg, "a standard comparison", app)
     } else if !def_bool
         && msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND)
         && let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite())
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 42107581ab4..964f1603f0e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -494,7 +494,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
     for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
         match node {
             Node::Stmt(_) => return true,
-            Node::Block(..) => continue,
+            Node::Block(..) => {},
             Node::Item(item) => {
                 if let ItemKind::Fn { body: body_id, .. } = &item.kind
                     && let output_ty = return_ty(cx, item.owner_id)
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 121c4326d64..2572e186ce6 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
@@ -2,7 +2,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::qualify_min_const_fn::is_min_const_fn;
-use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
+use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, is_in_test, trait_ref_of_method};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
@@ -97,6 +97,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
         span: Span,
         def_id: LocalDefId,
     ) {
+        let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
+        if is_in_test(cx.tcx, hir_id) {
+            return;
+        }
+
         if !self.msrv.meets(msrvs::CONST_IF_MATCH) {
             return;
         }
@@ -136,8 +141,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             return;
         }
 
-        let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
-
         // Const fns are not allowed as methods in a trait.
         {
             let parent = cx.tcx.hir().get_parent_item(hir_id).def_id;
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 1141728640d..29dcbaa9e62 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -192,7 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
         match it.kind {
-            hir::ItemKind::Fn{ .. } => {
+            hir::ItemKind::Fn { .. } => {
                 // ignore main()
                 if it.ident.name == sym::main {
                     let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index b18f18d89e5..05aa425de9e 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
             return;
         }
         match it.kind {
-            hir::ItemKind::Fn{ .. } => {
+            hir::ItemKind::Fn { .. } => {
                 let desc = "a function";
                 let attrs = cx.tcx.hir().attrs(it.hir_id());
                 check_missing_inline_attrs(cx, attrs, it.span, desc);
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 3c47d0edfdc..5f7fde30f03 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
 use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -80,7 +81,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
                     applicability = Applicability::HasPlaceholders;
                     "&'_ mut self".to_string()
                 } else {
-                    format!("&{} mut self", &lifetime.ident.name)
+                    let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability);
+                    format!("&{lt_name} mut self")
                 }
             },
             (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
@@ -89,7 +91,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
                     applicability = Applicability::HasPlaceholders;
                     "&'_ self".to_string()
                 } else {
-                    format!("&{} self", &lifetime.ident.name)
+                    let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability);
+                    format!("&{lt_name} self")
                 }
             },
             (Mode::Value, Mutability::Mut) => "mut self".to_string(),
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index c48232f9905..05b31fc84b9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::{indent_of, snippet, snippet_block};
-use rustc_ast::ast;
+use rustc_ast::{Block, Label, ast};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
@@ -11,6 +11,7 @@ declare_clippy_lint! {
     /// that contain a `continue` statement in either their main blocks or their
     /// `else`-blocks, when omitting the `else`-block possibly with some
     /// rearrangement of code can make the code easier to understand.
+    /// The lint also checks if the last statement in the loop is a `continue`
     ///
     /// ### Why is this bad?
     /// Having explicit `else` blocks for `if` statements
@@ -75,6 +76,49 @@ declare_clippy_lint! {
     ///     # break;
     /// }
     /// ```
+    ///
+    /// ```rust
+    /// # use std::io::ErrorKind;
+    ///
+    /// fn foo() -> ErrorKind { ErrorKind::NotFound }
+    /// for _ in 0..10 {
+    ///     match foo() {
+    ///         ErrorKind::NotFound => {
+    ///             eprintln!("not found");
+    ///             continue
+    ///         }
+    ///         ErrorKind::TimedOut => {
+    ///             eprintln!("timeout");
+    ///             continue
+    ///         }
+    ///         _ => {
+    ///             eprintln!("other error");
+    ///             continue
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    /// Could be rewritten as
+    ///
+    ///
+    /// ```rust
+    /// # use std::io::ErrorKind;
+    ///
+    /// fn foo() -> ErrorKind { ErrorKind::NotFound }
+    /// for _ in 0..10 {
+    ///     match foo() {
+    ///         ErrorKind::NotFound => {
+    ///             eprintln!("not found");
+    ///         }
+    ///         ErrorKind::TimedOut => {
+    ///             eprintln!("timeout");
+    ///         }
+    ///         _ => {
+    ///             eprintln!("other error");
+    ///         }
+    ///     }
+    /// }
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub NEEDLESS_CONTINUE,
     pedantic,
@@ -144,7 +188,7 @@ impl EarlyLintPass for NeedlessContinue {
 ///
 /// - The expression is a `continue` node.
 /// - The expression node is a block with the first statement being a `continue`.
-fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) -> bool {
+fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&Label>) -> bool {
     match else_expr.kind {
         ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label),
         ast::ExprKind::Continue(l) => compare_labels(label, l.as_ref()),
@@ -152,7 +196,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>)
     }
 }
 
-fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
+fn is_first_block_stmt_continue(block: &Block, label: Option<&Label>) -> bool {
     block.stmts.first().is_some_and(|stmt| match stmt.kind {
         ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
             if let ast::ExprKind::Continue(ref l) = e.kind {
@@ -166,7 +210,7 @@ fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>)
 }
 
 /// If the `continue` has a label, check it matches the label of the loop.
-fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast::Label>) -> bool {
+fn compare_labels(loop_label: Option<&Label>, continue_label: Option<&Label>) -> bool {
     match (loop_label, continue_label) {
         // `loop { continue; }` or `'a loop { continue; }`
         (_, None) => true,
@@ -181,7 +225,7 @@ fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast::
 /// the AST object representing the loop block of `expr`.
 fn with_loop_block<F>(expr: &ast::Expr, mut func: F)
 where
-    F: FnMut(&ast::Block, Option<&ast::Label>),
+    F: FnMut(&Block, Option<&Label>),
 {
     if let ast::ExprKind::While(_, loop_block, label)
     | ast::ExprKind::ForLoop {
@@ -205,7 +249,7 @@ where
 /// - The `else` expression.
 fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F)
 where
-    F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr),
+    F: FnMut(&ast::Expr, &ast::Expr, &Block, &ast::Expr),
 {
     match stmt.kind {
         ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
@@ -231,14 +275,14 @@ struct LintData<'a> {
     /// The condition expression for the above `if`.
     if_cond: &'a ast::Expr,
     /// The `then` block of the `if` statement.
-    if_block: &'a ast::Block,
+    if_block: &'a Block,
     /// The `else` block of the `if` statement.
     /// Note that we only work with `if` exprs that have an `else` branch.
     else_expr: &'a ast::Expr,
     /// The 0-based index of the `if` statement in the containing loop block.
     stmt_idx: usize,
     /// The statements of the loop block.
-    loop_block: &'a ast::Block,
+    loop_block: &'a Block,
 }
 
 const MSG_REDUNDANT_CONTINUE_EXPRESSION: &str = "this `continue` expression is redundant";
@@ -329,33 +373,74 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
     )
 }
 
-fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
-    if let ast::ExprKind::Loop(loop_block, loop_label, ..) = &expr.kind
-        && let Some(last_stmt) = loop_block.stmts.last()
+fn check_last_stmt_in_expr<F>(inner_expr: &ast::Expr, func: &F)
+where
+    F: Fn(Option<&Label>, Span),
+{
+    match &inner_expr.kind {
+        ast::ExprKind::Continue(continue_label) => {
+            func(continue_label.as_ref(), inner_expr.span);
+        },
+        ast::ExprKind::If(_, then_block, else_block) => {
+            check_last_stmt_in_block(then_block, func);
+            if let Some(else_block) = else_block {
+                check_last_stmt_in_expr(else_block, func);
+            }
+        },
+        ast::ExprKind::Match(_, arms, _) => {
+            for arm in arms {
+                if let Some(expr) = &arm.body {
+                    check_last_stmt_in_expr(expr, func);
+                }
+            }
+        },
+        ast::ExprKind::Block(b, _) => {
+            check_last_stmt_in_block(b, func);
+        },
+        _ => {},
+    }
+}
+
+fn check_last_stmt_in_block<F>(b: &Block, func: &F)
+where
+    F: Fn(Option<&Label>, Span),
+{
+    if let Some(last_stmt) = b.stmts.last()
         && let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind
-        && let ast::ExprKind::Continue(continue_label) = inner_expr.kind
-        && compare_labels(loop_label.as_ref(), continue_label.as_ref())
     {
-        span_lint_and_help(
-            cx,
-            NEEDLESS_CONTINUE,
-            last_stmt.span,
-            MSG_REDUNDANT_CONTINUE_EXPRESSION,
-            None,
-            DROP_CONTINUE_EXPRESSION_MSG,
-        );
+        check_last_stmt_in_expr(inner_expr, func);
     }
+}
+
+fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
     with_loop_block(expr, |loop_block, label| {
-        for (i, stmt) in loop_block.stmts.iter().enumerate() {
+        let p = |continue_label: Option<&Label>, span: Span| {
+            if compare_labels(label, continue_label) {
+                span_lint_and_help(
+                    cx,
+                    NEEDLESS_CONTINUE,
+                    span,
+                    MSG_REDUNDANT_CONTINUE_EXPRESSION,
+                    None,
+                    DROP_CONTINUE_EXPRESSION_MSG,
+                );
+            }
+        };
+
+        let stmts = &loop_block.stmts;
+        for (i, stmt) in stmts.iter().enumerate() {
+            let mut maybe_emitted_in_if = false;
             with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
                 let data = &LintData {
-                    stmt_idx: i,
                     if_expr,
                     if_cond: cond,
                     if_block: then_block,
                     else_expr,
+                    stmt_idx: i,
                     loop_block,
                 };
+
+                maybe_emitted_in_if = true;
                 if needless_continue_in_else(else_expr, label) {
                     emit_warning(
                         cx,
@@ -365,8 +450,14 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
                     );
                 } else if is_first_block_stmt_continue(then_block, label) {
                     emit_warning(cx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
+                } else {
+                    maybe_emitted_in_if = false;
                 }
             });
+
+            if i == stmts.len() - 1 && !maybe_emitted_in_if {
+                check_last_stmt_in_block(loop_block, &p);
+            }
         }
     });
 }
@@ -400,7 +491,7 @@ fn erode_from_back(s: &str) -> String {
     if ret.is_empty() { s.to_string() } else { ret }
 }
 
-fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> {
+fn span_of_first_expr_in_block(block: &Block) -> Option<Span> {
     block.stmts.first().map(|stmt| stmt.span)
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 92644456f63..ccd50758044 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -144,7 +144,7 @@ impl NoEffect {
                     |diag| {
                         for parent in cx.tcx.hir().parent_iter(stmt.hir_id) {
                             if let Node::Item(item) = parent.1
-                                && let ItemKind::Fn{ .. } = item.kind
+                                && let ItemKind::Fn { .. } = item.kind
                                 && let Node::Block(block) = cx.tcx.parent_hir_node(stmt.hir_id)
                                 && let [.., final_stmt] = block.stmts
                                 && final_stmt.hir_id == stmt.hir_id
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 ebd301d5156..8409d179b0f 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -189,6 +189,8 @@ impl<'tcx> NonCopyConst<'tcx> {
     }
 
     fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
+        // No branch that we check (yet) should continue if val isn't a ValTree::Branch
+        let ty::ValTree::Branch(val) = val else { return false };
         match *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.
@@ -197,12 +199,13 @@ impl<'tcx> NonCopyConst<'tcx> {
             // contained value.
             ty::Adt(def, ..) if def.is_union() => false,
             ty::Array(ty, _) => val
-                .unwrap_branch()
                 .iter()
                 .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
             ty::Adt(def, args) if def.is_enum() => {
-                let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
-                let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().to_u32());
+                let Some((&ty::ValTree::Leaf(variant_index), fields)) = val.split_first() else {
+                    return false;
+                };
+                let variant_index = VariantIdx::from_u32(variant_index.to_u32());
                 fields
                     .iter()
                     .copied()
@@ -215,12 +218,10 @@ impl<'tcx> NonCopyConst<'tcx> {
                     .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty))
             },
             ty::Adt(def, args) => val
-                .unwrap_branch()
                 .iter()
                 .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
                 .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
             ty::Tuple(tys) => val
-                .unwrap_branch()
                 .iter()
                 .zip(tys)
                 .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 2fee1c72a91..56c4157d6fe 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -270,10 +270,10 @@ impl SimilarNamesNameVisitor<'_, '_, '_> {
             return;
         }
         self.0.names.push(ExistingName {
-            exemptions: get_exemptions(interned_name).unwrap_or(&[]),
             interned: ident.name,
             span: ident.span,
             len: count,
+            exemptions: get_exemptions(interned_name).unwrap_or(&[]),
         });
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 65ef56fd211..0eca788c787 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -47,6 +47,7 @@ impl ArithmeticSideEffects {
         Self {
             allowed_binary,
             allowed_unary,
+            const_span: None,
             disallowed_int_methods: [
                 sym::saturating_div,
                 sym::wrapping_div,
@@ -55,7 +56,6 @@ impl ArithmeticSideEffects {
             ]
             .into_iter()
             .collect(),
-            const_span: None,
             expr_span: None,
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
index d2529d4d9f8..668f09bbfd5 100644
--- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
@@ -143,11 +143,11 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> {
             self.searcher = Some(PathbufPushSearcher {
                 local_id: id,
                 lhs_is_let: true,
-                name: name.name,
                 let_ty_span: local.ty.map(|ty| ty.span),
-                err_span: local.span,
                 init_val: *init_expr,
                 arg: None,
+                name: name.name,
+                err_span: local.span,
             });
         }
     }
@@ -165,10 +165,10 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> {
                 local_id: id,
                 lhs_is_let: false,
                 let_ty_span: None,
-                name: name.ident.name,
-                err_span: expr.span,
                 init_val: *right,
                 arg: None,
+                name: name.ident.name,
+                err_span: expr.span,
             });
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs
index 6a1d40334e7..a27f9b63114 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_else.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs
@@ -69,7 +69,6 @@ impl EarlyLintPass for RedundantElse {
                 ExprKind::If(_, next_then, Some(next_els)) => {
                     then = next_then;
                     els = next_els;
-                    continue;
                 },
                 // else if without else
                 ExprKind::If(..) => return,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 4f46ca3c715..658d93e634c 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -17,9 +17,9 @@ declare_clippy_lint! {
     /// Checks for redundant redefinitions of local bindings.
     ///
     /// ### Why is this bad?
-    /// Redundant redefinitions of local bindings do not change behavior and are likely to be unintended.
+    /// Redundant redefinitions of local bindings do not change behavior other than variable's lifetimes and are likely to be unintended.
     ///
-    /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation.
+    /// These rebindings can be intentional to shorten the lifetimes of variables because they affect when the `Drop` implementation is called. Other than that, they do not affect your code's meaning but they _may_ affect `rustc`'s stack allocation.
     ///
     /// ### Example
     /// ```no_run
@@ -41,7 +41,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.73.0"]
     pub REDUNDANT_LOCALS,
-    correctness,
+    suspicious,
     "redundant redefinition of a local binding"
 }
 declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 6a5bf1b8045..9443dca154e 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -24,6 +24,11 @@ declare_clippy_lint! {
     /// ```ignore
     /// Regex::new("(")
     /// ```
+    ///
+    /// Use instead:
+    /// ```ignore
+    /// Regex::new("\(")
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub INVALID_REGEX,
     correctness,
@@ -49,6 +54,11 @@ declare_clippy_lint! {
     /// ```ignore
     /// Regex::new("^foobar")
     /// ```
+    ///
+    /// Use instead:
+    /// ```ignore
+    /// str::starts_with("foobar")
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub TRIVIAL_REGEX,
     nursery,
@@ -87,7 +97,7 @@ declare_clippy_lint! {
     ///     }
     /// }
     /// ```
-    #[clippy::version = "1.83.0"]
+    #[clippy::version = "1.84.0"]
     pub REGEX_CREATION_IN_LOOPS,
     perf,
     "regular expression compilation performed in a loop"
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index c690696aefc..597bfddecbc 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -282,9 +282,9 @@ impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> {
                 }
             {
                 let mut apa = AuxParamsAttr {
-                    first_bind_ident: ident,
                     first_block_hir_id: self.ap.curr_block_hir_id,
                     first_block_span: self.ap.curr_block_span,
+                    first_bind_ident: ident,
                     first_method_span: {
                         let expr_or_init = expr_or_init(self.cx, expr);
                         if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind {
@@ -395,8 +395,8 @@ impl Default for AuxParamsAttr {
             counter: 0,
             has_expensive_expr_after_last_attr: false,
             first_block_hir_id: HirId::INVALID,
-            first_bind_ident: Ident::empty(),
             first_block_span: DUMMY_SP,
+            first_bind_ident: Ident::empty(),
             first_method_span: DUMMY_SP,
             first_stmt_span: DUMMY_SP,
             last_bind_ident: Ident::empty(),
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 8c8f11569c8..d2d693eaa1f 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
@@ -203,14 +203,18 @@ impl SlowVectorInit {
             "len",
         );
 
-        span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
-            diag.span_suggestion(
-                vec_alloc.allocation_expr.span.source_callsite(),
-                "consider replacing this with",
-                format!("vec![0; {len_expr}]"),
-                Applicability::Unspecified,
-            );
-        });
+        let span_to_replace = slow_fill
+            .span
+            .with_lo(vec_alloc.allocation_expr.span.source_callsite().lo());
+        span_lint_and_sugg(
+            cx,
+            SLOW_VECTOR_INITIALIZATION,
+            span_to_replace,
+            msg,
+            "consider replacing this with",
+            format!("vec![0; {len_expr}]"),
+            Applicability::Unspecified,
+        );
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 78f0b7d121c..ff116800512 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -384,9 +384,9 @@ impl<'tcx> IndexBinding<'_, 'tcx> {
 
     fn is_used_after_swap(&mut self, idx_ident: Ident) -> bool {
         let mut v = IndexBindingVisitor {
-            found_used: false,
-            suggest_span: self.suggest_span,
             idx: idx_ident,
+            suggest_span: self.suggest_span,
+            found_used: false,
         };
 
         for stmt in self.block.stmts {
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index a1d92c3ac71..82cc5155380 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::has_repr_attr;
+use clippy_utils::{has_repr_attr, is_in_test};
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
@@ -37,7 +37,10 @@ declare_lint_pass!(TrailingEmptyArray => [TRAILING_EMPTY_ARRAY]);
 
 impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) {
+        if is_struct_with_trailing_zero_sized_array(cx, item)
+            && !has_repr_attr(cx, item.hir_id())
+            && !is_in_test(cx.tcx, item.hir_id())
+        {
             span_lint_and_help(
                 cx,
                 TRAILING_EMPTY_ARRAY,
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 48d65eb15d9..26323af3122 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
@@ -30,17 +30,14 @@ pub(super) fn check<'tcx>(
             | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
             (ReducedTy::OrderedFields(Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
             (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) if reduced_tys.from_fat_ptr => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
 
             // ptr <-> ptr
@@ -50,7 +47,6 @@ pub(super) fn check<'tcx>(
             {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
 
             // fat ptr <-> (*size, *size)
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 363aea8be72..43cce625c64 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -388,8 +388,8 @@ impl<'tcx> LateLintPass<'tcx> for Types {
 
         self.check_fn_decl(cx, decl, CheckTyContext {
             is_in_trait_impl,
-            is_exported,
             in_body: matches!(fn_kind, FnKind::Closure),
+            is_exported,
             ..CheckTyContext::default()
         });
     }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs b/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs
index 8165a45bc5b..9f107fbeec0 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs
@@ -47,7 +47,7 @@ declare_clippy_lint! {
     ///     }
     /// }
     /// ```
-    #[clippy::version = "1.83.0"]
+    #[clippy::version = "1.84.0"]
     pub UNNECESSARY_LITERAL_BOUND,
     pedantic,
     "detects &str that could be &'static str in function return types"
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index c899b1868a6..d00bd7f2b3d 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -120,8 +120,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
             let mut visitor = AsyncFnVisitor {
                 cx,
                 found_await: false,
-                async_depth: 0,
                 await_in_async_block: None,
+                async_depth: 0,
             };
             walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
             if !visitor.found_await {
@@ -129,9 +129,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
                 // The actual linting happens in `check_crate_post`, once we've found all
                 // uses of local async functions that do require asyncness to pass typeck
                 self.unused_async_fns.push(UnusedAsyncFn {
-                    await_in_async_block: visitor.await_in_async_block,
-                    fn_span: span,
                     def_id,
+                    fn_span: span,
+                    await_in_async_block: visitor.await_in_async_block,
                 });
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 89bb429e265..eaa119b045f 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -245,9 +245,9 @@ impl<'tcx> UnwrappableVariablesVisitor<'_, 'tcx> {
         let prev_len = self.unwrappables.len();
         for unwrap_info in collect_unwrap_info(self.cx, if_expr, cond, branch, else_branch, true) {
             let mut delegate = MutationVisitor {
-                tcx: self.cx.tcx,
                 is_mutated: false,
                 local_id: unwrap_info.local_id,
+                tcx: self.cx.tcx,
             };
 
             let vis = ExprUseVisitor::for_clippy(self.cx, cond.hir_id.owner.def_id, &mut delegate);
@@ -397,8 +397,8 @@ impl<'tcx> LateLintPass<'tcx> for Unwrap {
         }
 
         let mut v = UnwrappableVariablesVisitor {
-            cx,
             unwrappables: Vec::new(),
+            cx,
         };
 
         walk_fn(&mut v, kind, decl, body.id(), fn_id);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index a5fad68eea1..08c178ed229 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -73,6 +73,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
         SimplifiedType::Slice,
         SimplifiedType::Str,
         SimplifiedType::Bool,
+        SimplifiedType::Char,
     ]
     .iter()
     .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter())
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index ef1c46154d2..0730b561bc2 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -8,7 +8,7 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::is_copy;
 use clippy_utils::visitors::for_each_local_use_after_expr;
-use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method};
+use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -132,9 +132,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
     fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
         for (span, lint_opt) in &self.span_to_lint_map {
             if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt {
-                let help_msg = format!("you can use {} directly", suggest_slice.desc(),);
+                let help_msg = format!("you can use {} directly", suggest_slice.desc());
                 span_lint_hir_and_then(cx, USELESS_VEC, *hir_id, *span, "useless use of `vec!`", |diag| {
-                    diag.span_suggestion(*span, help_msg, snippet, *applicability);
+                    // If the `vec!` macro contains comment, better not make the suggestion machine
+                    // applicable as it would remove them.
+                    let applicability = if *applicability != Applicability::Unspecified
+                        && let source_map = cx.tcx.sess.source_map()
+                        && span_contains_comment(source_map, *span)
+                    {
+                        Applicability::Unspecified
+                    } else {
+                        *applicability
+                    };
+                    diag.span_suggestion(*span, help_msg, snippet, applicability);
                 });
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index cbc6885ae5d..d87d554eb07 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -166,8 +166,8 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
                 local_id: id,
                 init,
                 lhs_is_let: true,
-                name: name.name,
                 let_ty_span: local.ty.map(|ty| ty.span),
+                name: name.name,
                 err_span: local.span,
                 found: 0,
                 last_push_expr: init_expr.hir_id,
@@ -206,8 +206,8 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
                 && name.ident.as_str() == "push"
             {
                 self.searcher = Some(VecPushSearcher {
-                    found: searcher.found + 1,
                     err_span: searcher.err_span.to(stmt.span),
+                    found: searcher.found + 1,
                     last_push_expr: expr.hir_id,
                     ..searcher
                 });
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index a42ddcdae35..31ae002e47d 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -248,8 +248,8 @@ impl Write {
     pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
         Self {
             format_args,
-            allow_print_in_tests: conf.allow_print_in_tests,
             in_debug_impl: false,
+            allow_print_in_tests: conf.allow_print_in_tests,
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
index a702e0785a9..4df34891a2b 100644
--- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs
+++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -300,8 +300,8 @@ fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, cause: Caus
     };
 
     let mut vis = ExitPointFinder {
-        cx,
         state: ExitPointState::WalkUpTo(spawn_expr.hir_id),
+        cx,
     };
     if let Break(ExitCallFound) = vis.visit_block(block) {
         // Visitor found an unconditional `exit()` call, so don't lint.
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 945827c98c1..7fa070cd226 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_utils"
 # begin autogenerated version
-version = "0.1.85"
+version = "0.1.86"
 # end autogenerated version
 edition = "2021"
 description = "Helpful tools for writing lints, provided as they are used in Clippy"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index 73fefbcd570..c267b804124 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2024-12-26
+nightly-2025-01-09
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 4e12577b6df..60be7e4a4d3 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -196,8 +196,8 @@ impl<'hir> IfOrIfLet<'hir> {
             if let ExprKind::DropTemps(new_cond) = cond.kind {
                 return Some(Self {
                     cond: new_cond,
-                    r#else,
                     then,
+                    r#else,
                 });
             }
             if let ExprKind::Let(..) = cond.kind {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index d1d0abd4690..a1c48d5c36c 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -806,8 +806,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         Self {
             cx,
             maybe_typeck_results: cx.maybe_typeck_results(),
-            path_check: PathCheck::default(),
             s: FxHasher::default(),
+            path_check: PathCheck::default(),
         }
     }
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index d42e40acbc0..eecfc3fb13f 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1243,9 +1243,9 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
 
     let mut v = V {
         cx,
-        allow_closure: true,
         loops: Vec::new(),
         locals: HirIdSet::default(),
+        allow_closure: true,
         captures: HirIdMap::default(),
     };
     v.visit_expr(expr);
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 17e6558a41c..cf73bae2583 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -32,8 +32,8 @@ impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
     ) -> Self {
         Self {
             possible_borrower: TransitiveRelation::default(),
-            cx,
             body,
+            cx,
             possible_origin,
         }
     }
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 98bcedecccc..2169a5fdd63 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -130,7 +130,7 @@ impl Msrv {
         let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv]));
 
         if let Some(msrv_attr) = msrv_attrs.next() {
-            if let Some(duplicate) = msrv_attrs.last() {
+            if let Some(duplicate) = msrv_attrs.next_back() {
                 sess.dcx()
                     .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times")
                     .with_span_note(msrv_attr.span(), "first definition found here")
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 8cb8cd59014..f15fffc09e8 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -33,6 +33,8 @@ pub const CHILD: [&str; 3] = ["std", "process", "Child"];
 pub const CHILD_ID: [&str; 4] = ["std", "process", "Child", "id"];
 pub const CHILD_KILL: [&str; 4] = ["std", "process", "Child", "kill"];
 pub const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"];
+pub const CHAR_IS_ASCII: [&str; 5] = ["core", "char", "methods", "<impl char>", "is_ascii"];
+pub const STDIN: [&str; 4] = ["std", "io", "stdio", "Stdin"];
 
 // Paths in clippy itself
 pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
diff --git a/src/tools/clippy/lintcheck/src/output.rs b/src/tools/clippy/lintcheck/src/output.rs
index e38036315c2..dcc1ec339ef 100644
--- a/src/tools/clippy/lintcheck/src/output.rs
+++ b/src/tools/clippy/lintcheck/src/output.rs
@@ -94,8 +94,8 @@ impl ClippyWarning {
         Some(Self {
             name,
             diag,
-            url,
             krate: krate.to_string(),
+            url,
         })
     }
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 1000d90f52a..b1f0a82b1f4 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2024-12-26"
+channel = "nightly-2025-01-09"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index b8e0413e97b..e2e4d92df79 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -574,12 +574,12 @@ impl LintMetadata {
             id_location: None,
             group: "deprecated",
             level: "none",
-            version,
             docs: format!(
                 "### What it does\n\n\
                 Nothing. This lint has been deprecated\n\n\
                 ### Deprecation reason\n\n{reason}.\n",
             ),
+            version,
             applicability: Applicability::Unspecified,
         }
     }
diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs
index a8225d037e8..64eba5e0888 100644
--- a/src/tools/clippy/tests/missing-test-files.rs
+++ b/src/tools/clippy/tests/missing-test-files.rs
@@ -59,7 +59,7 @@ fn explore_directory(dir: &Path) -> Vec<String> {
                             missing_files.push(path.to_str().unwrap().to_string());
                         }
                     },
-                    _ => continue,
+                    _ => {},
                 };
             }
         }
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index b99e8c0e76f..ff178924bd1 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -1,3 +1,4 @@
+
 thread '<unnamed>' panicked at clippy_lints/src/utils/internal_lints/produce_ice.rs:
 Would you like some help with that?
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml
new file mode 100644
index 00000000000..f43c9d97e82
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml
@@ -0,0 +1 @@
+lint-inconsistent-struct-field-initializers = true
diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed
new file mode 100644
index 00000000000..8092e40ff9f
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed
@@ -0,0 +1,79 @@
+#![warn(clippy::inconsistent_struct_constructor)]
+#![allow(clippy::redundant_field_names)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::no_effect)]
+
+#[derive(Default)]
+struct Foo {
+    x: i32,
+    y: i32,
+    z: i32,
+}
+
+fn main() {
+    let x = 1;
+    let y = 1;
+    let z = 1;
+
+    Foo { x, y, z: z };
+
+    Foo {
+        x,
+        z: z,
+        ..Default::default()
+    };
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1859261645
+mod field_attributes {
+    struct HirId;
+    struct BodyVisitor {
+        macro_unsafe_blocks: Vec<HirId>,
+        expn_depth: u32,
+    }
+    fn check_body(condition: bool) {
+        BodyVisitor {
+            macro_unsafe_blocks: Vec::new(),
+            #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
+            expn_depth: if condition { 1 } else { 0 },
+        };
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874539800
+mod cfgs_between_fields {
+    #[allow(clippy::non_minimal_cfg)]
+    fn cfg_all() {
+        struct S {
+            a: i32,
+            b: i32,
+            #[cfg(all())]
+            c: i32,
+            d: i32,
+        }
+        let s = S {
+            a: 3,
+            b: 2,
+            #[cfg(all())]
+            c: 1,
+            d: 0,
+        };
+    }
+
+    fn cfg_any() {
+        struct S {
+            a: i32,
+            b: i32,
+            #[cfg(any())]
+            c: i32,
+            d: i32,
+        }
+        let s = S {
+            a: 3,
+            #[cfg(any())]
+            c: 1,
+            b: 2,
+            d: 0,
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs
new file mode 100644
index 00000000000..cd1aff96652
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs
@@ -0,0 +1,79 @@
+#![warn(clippy::inconsistent_struct_constructor)]
+#![allow(clippy::redundant_field_names)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::no_effect)]
+
+#[derive(Default)]
+struct Foo {
+    x: i32,
+    y: i32,
+    z: i32,
+}
+
+fn main() {
+    let x = 1;
+    let y = 1;
+    let z = 1;
+
+    Foo { y, x, z: z };
+
+    Foo {
+        z: z,
+        x,
+        ..Default::default()
+    };
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1859261645
+mod field_attributes {
+    struct HirId;
+    struct BodyVisitor {
+        macro_unsafe_blocks: Vec<HirId>,
+        expn_depth: u32,
+    }
+    fn check_body(condition: bool) {
+        BodyVisitor {
+            #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
+            expn_depth: if condition { 1 } else { 0 },
+            macro_unsafe_blocks: Vec::new(),
+        };
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874539800
+mod cfgs_between_fields {
+    #[allow(clippy::non_minimal_cfg)]
+    fn cfg_all() {
+        struct S {
+            a: i32,
+            b: i32,
+            #[cfg(all())]
+            c: i32,
+            d: i32,
+        }
+        let s = S {
+            d: 0,
+            #[cfg(all())]
+            c: 1,
+            b: 2,
+            a: 3,
+        };
+    }
+
+    fn cfg_any() {
+        struct S {
+            a: i32,
+            b: i32,
+            #[cfg(any())]
+            c: i32,
+            d: i32,
+        }
+        let s = S {
+            d: 0,
+            #[cfg(any())]
+            c: 1,
+            b: 2,
+            a: 3,
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr
new file mode 100644
index 00000000000..d2533960b84
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr
@@ -0,0 +1,77 @@
+error: struct constructor field order is inconsistent with struct definition field order
+  --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:18:11
+   |
+LL |     Foo { y, x, z: z };
+   |           ^^^^^^^^^^ help: if the field evaluation order doesn't matter, try: `x, y, z: z`
+   |
+   = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]`
+
+error: struct constructor field order is inconsistent with struct definition field order
+  --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:21:9
+   |
+LL | /         z: z,
+LL | |         x,
+   | |_________^
+   |
+help: if the field evaluation order doesn't matter, try
+   |
+LL ~         x,
+LL ~         z: z,
+   |
+
+error: struct constructor field order is inconsistent with struct definition field order
+  --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:36:13
+   |
+LL | /             #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
+LL | |             expn_depth: if condition { 1 } else { 0 },
+LL | |             macro_unsafe_blocks: Vec::new(),
+   | |___________________________________________^
+   |
+help: if the field evaluation order doesn't matter, try
+   |
+LL ~             macro_unsafe_blocks: Vec::new(),
+LL +             #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
+LL ~             expn_depth: if condition { 1 } else { 0 },
+   |
+
+error: struct constructor field order is inconsistent with struct definition field order
+  --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:55:13
+   |
+LL | /             d: 0,
+LL | |             #[cfg(all())]
+LL | |             c: 1,
+LL | |             b: 2,
+LL | |             a: 3,
+   | |________________^
+   |
+help: if the field evaluation order doesn't matter, try
+   |
+LL ~             a: 3,
+LL +             b: 2,
+LL +             #[cfg(all())]
+LL +             c: 1,
+LL ~             d: 0,
+   |
+
+error: struct constructor field order is inconsistent with struct definition field order
+  --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:72:13
+   |
+LL | /             d: 0,
+LL | |             #[cfg(any())]
+LL | |             c: 1,
+LL | |             b: 2,
+LL | |             a: 3,
+   | |________________^
+   |
+help: if the field evaluation order doesn't matter, try
+   |
+LL ~             a: 3,
+LL +             #[cfg(any())]
+LL +             c: 1,
+LL +             b: 2,
+LL ~             d: 0,
+   |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 200129da25f..01e9f5c26a3 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -46,6 +46,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            future-size-threshold
            ignore-interior-mutability
            large-error-threshold
+           lint-inconsistent-struct-field-initializers
            literal-representation-threshold
            matches-for-let-else
            max-fn-params-bools
@@ -134,6 +135,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            future-size-threshold
            ignore-interior-mutability
            large-error-threshold
+           lint-inconsistent-struct-field-initializers
            literal-representation-threshold
            matches-for-let-else
            max-fn-params-bools
@@ -222,6 +224,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            future-size-threshold
            ignore-interior-mutability
            large-error-threshold
+           lint-inconsistent-struct-field-initializers
            literal-representation-threshold
            matches-for-let-else
            max-fn-params-bools
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
index 289a5ef38b8..5365f3dd443 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
@@ -16,4 +16,12 @@ fn main() {
 
     let mut val_mut = 1;
     let _p_mut = std::ptr::addr_of_mut!(val_mut);
+
+    let mut x: [i32; 2] = [42, 43];
+    let _raw = std::ptr::addr_of_mut!(x[1]).wrapping_offset(-1);
+}
+
+fn issue_13882() {
+    let mut x: [i32; 2] = [42, 43];
+    let _raw = (&raw mut x[1]).wrapping_offset(-1);
 }
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
index b5328cb22dc..261894f1341 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
@@ -16,4 +16,12 @@ fn main() {
 
     let mut val_mut = 1;
     let _p_mut = &mut val_mut as *mut i32;
+
+    let mut x: [i32; 2] = [42, 43];
+    let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
+}
+
+fn issue_13882() {
+    let mut x: [i32; 2] = [42, 43];
+    let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
 }
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
index ea618b06e2c..4595fa4f248 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
@@ -13,5 +13,17 @@ error: borrow as raw pointer
 LL |     let _p_mut = &mut val_mut as *mut i32;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)`
 
-error: aborting due to 2 previous errors
+error: borrow as raw pointer
+  --> tests/ui/borrow_as_ptr.rs:21:16
+   |
+LL |     let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(x[1])`
+
+error: borrow as raw pointer
+  --> tests/ui/borrow_as_ptr.rs:26:17
+   |
+LL |     let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
+   |                 ^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut x[1]`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
index de220505c3e..a49d53fbbd3 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
@@ -47,6 +47,17 @@ impl<T> std::ops::Deref for StaticRef<T> {
     }
 }
 
+// ICE regression test
+mod issue12979 {
+    use std::cell::UnsafeCell;
+
+    const ATOMIC_TUPLE: (Vec<UnsafeCell<u8>>, ()) = (Vec::new(), ());
+
+    fn main() {
+        let _x = &ATOMIC_TUPLE.0;
+    }
+}
+
 // use a tuple to make sure referencing a field behind a pointer isn't linted.
 const CELL_REF: StaticRef<(UnsafeCell<u32>,)> = unsafe { StaticRef::new(std::ptr::null()) };
 
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
index 9a9028c8649..4cefcc28008 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
@@ -1,5 +1,5 @@
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:54:5
+  --> tests/ui/borrow_interior_mutable_const/others.rs:65:5
    |
 LL |     ATOMIC.store(1, Ordering::SeqCst);
    |     ^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(clippy::borrow_interior_mutable_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:55:16
+  --> tests/ui/borrow_interior_mutable_const/others.rs:66:16
    |
 LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
    |                ^^^^^^
@@ -20,7 +20,7 @@ LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:58:22
+  --> tests/ui/borrow_interior_mutable_const/others.rs:69:22
    |
 LL |     let _once_ref = &ONCE_INIT;
    |                      ^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     let _once_ref = &ONCE_INIT;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:59:25
+  --> tests/ui/borrow_interior_mutable_const/others.rs:70:25
    |
 LL |     let _once_ref_2 = &&ONCE_INIT;
    |                         ^^^^^^^^^
@@ -36,7 +36,7 @@ LL |     let _once_ref_2 = &&ONCE_INIT;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:60:27
+  --> tests/ui/borrow_interior_mutable_const/others.rs:71:27
    |
 LL |     let _once_ref_4 = &&&&ONCE_INIT;
    |                           ^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     let _once_ref_4 = &&&&ONCE_INIT;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:61:26
+  --> tests/ui/borrow_interior_mutable_const/others.rs:72:26
    |
 LL |     let _once_mut = &mut ONCE_INIT;
    |                          ^^^^^^^^^
@@ -52,7 +52,7 @@ LL |     let _once_mut = &mut ONCE_INIT;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:72:14
+  --> tests/ui/borrow_interior_mutable_const/others.rs:83:14
    |
 LL |     let _ = &ATOMIC_TUPLE;
    |              ^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     let _ = &ATOMIC_TUPLE;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:73:14
+  --> tests/ui/borrow_interior_mutable_const/others.rs:84:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0;
    |              ^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL |     let _ = &ATOMIC_TUPLE.0;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:74:19
+  --> tests/ui/borrow_interior_mutable_const/others.rs:85:19
    |
 LL |     let _ = &(&&&&ATOMIC_TUPLE).0;
    |                   ^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     let _ = &(&&&&ATOMIC_TUPLE).0;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:75:14
+  --> tests/ui/borrow_interior_mutable_const/others.rs:86:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0[0];
    |              ^^^^^^^^^^^^
@@ -84,7 +84,7 @@ LL |     let _ = &ATOMIC_TUPLE.0[0];
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:76:13
+  --> tests/ui/borrow_interior_mutable_const/others.rs:87:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
    |             ^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:81:13
+  --> tests/ui/borrow_interior_mutable_const/others.rs:92:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0];
    |             ^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0];
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:86:5
+  --> tests/ui/borrow_interior_mutable_const/others.rs:97:5
    |
 LL |     CELL.set(2);
    |     ^^^^
@@ -108,7 +108,7 @@ LL |     CELL.set(2);
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:87:16
+  --> tests/ui/borrow_interior_mutable_const/others.rs:98:16
    |
 LL |     assert_eq!(CELL.get(), 6);
    |                ^^^^
diff --git a/src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs b/src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs
new file mode 100644
index 00000000000..f3ab9cebb7c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs
@@ -0,0 +1,9 @@
+// ICE: #10972
+// asked to assemble constituent types of unexpected type: Binder(Foo, [])
+#![feature(type_alias_impl_trait)]
+
+use std::fmt::Debug;
+type Foo = impl Debug;
+const FOO2: Foo = 22_u32;
+
+pub fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-13862.rs b/src/tools/clippy/tests/ui/crashes/ice-13862.rs
new file mode 100644
index 00000000000..a5f010054b2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-13862.rs
@@ -0,0 +1,19 @@
+#![crate_type = "lib"]
+#![no_std]
+
+use core::future::Future;
+use core::pin::Pin;
+use core::task::{Context, Poll};
+
+pub struct S<const N: u8>;
+
+impl<const N: u8> Future for S<N> {
+    type Output = ();
+    fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
+        todo!()
+    }
+}
+
+pub fn f<const N: u8>() -> S<N> {
+    S
+}
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
new file mode 100644
index 00000000000..06c48e33753
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
@@ -0,0 +1,53 @@
+#![warn(clippy::double_ended_iterator_last)]
+
+// Typical case
+pub fn last_arg(s: &str) -> Option<&str> {
+    s.split(' ').next_back()
+}
+
+fn main() {
+    // General case
+    struct DeIterator;
+    impl Iterator for DeIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for DeIterator {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = DeIterator.next_back();
+    // Should not apply to other methods of Iterator
+    let _ = DeIterator.count();
+
+    // Should not apply to simple iterators
+    struct SimpleIterator;
+    impl Iterator for SimpleIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = SimpleIterator.last();
+
+    // Should not apply to custom implementations of last()
+    struct CustomLast;
+    impl Iterator for CustomLast {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+        fn last(self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for CustomLast {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = CustomLast.last();
+}
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
new file mode 100644
index 00000000000..9c13b496d11
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
@@ -0,0 +1,53 @@
+#![warn(clippy::double_ended_iterator_last)]
+
+// Typical case
+pub fn last_arg(s: &str) -> Option<&str> {
+    s.split(' ').last()
+}
+
+fn main() {
+    // General case
+    struct DeIterator;
+    impl Iterator for DeIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for DeIterator {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = DeIterator.last();
+    // Should not apply to other methods of Iterator
+    let _ = DeIterator.count();
+
+    // Should not apply to simple iterators
+    struct SimpleIterator;
+    impl Iterator for SimpleIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = SimpleIterator.last();
+
+    // Should not apply to custom implementations of last()
+    struct CustomLast;
+    impl Iterator for CustomLast {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+        fn last(self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for CustomLast {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = CustomLast.last();
+}
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
new file mode 100644
index 00000000000..b795c18a736
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
@@ -0,0 +1,17 @@
+error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
+  --> tests/ui/double_ended_iterator_last.rs:5:18
+   |
+LL |     s.split(' ').last()
+   |                  ^^^^^^ help: try: `next_back()`
+   |
+   = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]`
+
+error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
+  --> tests/ui/double_ended_iterator_last.rs:22:24
+   |
+LL |     let _ = DeIterator.last();
+   |                        ^^^^^^ help: try: `next_back()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed
index 4c324587c96..67bd3e4d279 100644
--- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed
+++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed
@@ -60,7 +60,11 @@ mod with_base {
         let z = 1;
 
         // Should lint.
-        Foo { x, z, ..Default::default() };
+        Foo {
+            x,
+            z,
+            ..Default::default()
+        };
 
         // Should NOT lint because the order is consistent with the definition.
         Foo {
diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr
index 97bb7c789a7..c145eb2a239 100644
--- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr
+++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr
@@ -1,21 +1,24 @@
 error: struct constructor field order is inconsistent with struct definition field order
-  --> tests/ui/inconsistent_struct_constructor.rs:36:9
+  --> tests/ui/inconsistent_struct_constructor.rs:36:15
    |
 LL |         Foo { y, x, z };
-   |         ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }`
+   |               ^^^^^^^ help: try: `x, y, z`
    |
    = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]`
 
 error: struct constructor field order is inconsistent with struct definition field order
-  --> tests/ui/inconsistent_struct_constructor.rs:63:9
+  --> tests/ui/inconsistent_struct_constructor.rs:64:13
    |
-LL | /         Foo {
-LL | |             z,
+LL | /             z,
 LL | |             x,
-LL | |             ..Default::default()
-LL | |         };
-   | |_________^ help: try: `Foo { x, z, ..Default::default() }`
+   | |_____________^
+   |
+help: try
+   |
+LL ~             x,
+LL ~             z,
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/infinite_iter.rs b/src/tools/clippy/tests/ui/infinite_iter.rs
index da95ba04b82..178e300ff5b 100644
--- a/src/tools/clippy/tests/ui/infinite_iter.rs
+++ b/src/tools/clippy/tests/ui/infinite_iter.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, clippy::double_ended_iterator_last)]
 
 use std::iter::repeat;
 fn square_is_lower_64(x: &u32) -> bool {
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
index 7d8a584b022..d7d3d299349 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
@@ -1,5 +1,10 @@
 #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
-#![allow(dead_code, clippy::let_unit_value, clippy::useless_vec)]
+#![allow(
+    dead_code,
+    clippy::let_unit_value,
+    clippy::useless_vec,
+    clippy::double_ended_iterator_last
+)]
 
 fn main() {
     let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
index 58c374ab8cd..45e1349febd 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
@@ -1,5 +1,10 @@
 #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
-#![allow(dead_code, clippy::let_unit_value, clippy::useless_vec)]
+#![allow(
+    dead_code,
+    clippy::let_unit_value,
+    clippy::useless_vec,
+    clippy::double_ended_iterator_last
+)]
 
 fn main() {
     let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
index 7a822a79494..e6680266f10 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
@@ -1,5 +1,5 @@
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:7:29
+  --> tests/ui/iter_overeager_cloned.rs:12:29
    |
 LL |     let _: Option<String> = vec.iter().cloned().last();
    |                             ^^^^^^^^^^----------------
@@ -10,7 +10,7 @@ LL |     let _: Option<String> = vec.iter().cloned().last();
    = help: to override `-D warnings` add `#[allow(clippy::iter_overeager_cloned)]`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:9:29
+  --> tests/ui/iter_overeager_cloned.rs:14:29
    |
 LL |     let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------
@@ -18,7 +18,7 @@ LL |     let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
    |                                                         help: try: `.next().cloned()`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:11:20
+  --> tests/ui/iter_overeager_cloned.rs:16:20
    |
 LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------
@@ -29,7 +29,7 @@ LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
    = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:13:21
+  --> tests/ui/iter_overeager_cloned.rs:18:21
    |
 LL |     let _: Vec<_> = vec.iter().cloned().take(2).collect();
    |                     ^^^^^^^^^^-----------------
@@ -37,7 +37,7 @@ LL |     let _: Vec<_> = vec.iter().cloned().take(2).collect();
    |                               help: try: `.take(2).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:15:21
+  --> tests/ui/iter_overeager_cloned.rs:20:21
    |
 LL |     let _: Vec<_> = vec.iter().cloned().skip(2).collect();
    |                     ^^^^^^^^^^-----------------
@@ -45,7 +45,7 @@ LL |     let _: Vec<_> = vec.iter().cloned().skip(2).collect();
    |                               help: try: `.skip(2).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:17:13
+  --> tests/ui/iter_overeager_cloned.rs:22:13
    |
 LL |     let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------
@@ -53,7 +53,7 @@ LL |     let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
    |                                             help: try: `.nth(2).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:19:13
+  --> tests/ui/iter_overeager_cloned.rs:24:13
    |
 LL |       let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
    |  _____________^
@@ -69,7 +69,7 @@ LL ~         .flatten().cloned();
    |
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:24:13
+  --> tests/ui/iter_overeager_cloned.rs:29:13
    |
 LL |     let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
    |             ^^^^^^^^^^----------------------------------------
@@ -77,7 +77,7 @@ LL |     let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
    |                       help: try: `.filter(|&x| x.starts_with('2')).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:26:13
+  --> tests/ui/iter_overeager_cloned.rs:31:13
    |
 LL |     let _ = vec.iter().cloned().find(|x| x == "2");
    |             ^^^^^^^^^^----------------------------
@@ -85,7 +85,7 @@ LL |     let _ = vec.iter().cloned().find(|x| x == "2");
    |                       help: try: `.find(|&x| x == "2").cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:30:17
+  --> tests/ui/iter_overeager_cloned.rs:35:17
    |
 LL |         let _ = vec.iter().cloned().filter(f);
    |                 ^^^^^^^^^^-------------------
@@ -93,7 +93,7 @@ LL |         let _ = vec.iter().cloned().filter(f);
    |                           help: try: `.filter(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:31:17
+  --> tests/ui/iter_overeager_cloned.rs:36:17
    |
 LL |         let _ = vec.iter().cloned().find(f);
    |                 ^^^^^^^^^^-----------------
@@ -101,7 +101,7 @@ LL |         let _ = vec.iter().cloned().find(f);
    |                           help: try: `.find(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:37:17
+  --> tests/ui/iter_overeager_cloned.rs:42:17
    |
 LL |         let _ = vec.iter().cloned().filter(f);
    |                 ^^^^^^^^^^-------------------
@@ -109,7 +109,7 @@ LL |         let _ = vec.iter().cloned().filter(f);
    |                           help: try: `.filter(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:38:17
+  --> tests/ui/iter_overeager_cloned.rs:43:17
    |
 LL |         let _ = vec.iter().cloned().find(f);
    |                 ^^^^^^^^^^-----------------
@@ -117,7 +117,7 @@ LL |         let _ = vec.iter().cloned().find(f);
    |                           help: try: `.find(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:45:9
+  --> tests/ui/iter_overeager_cloned.rs:50:9
    |
 LL |         iter.cloned().filter(move |(&a, b)| a == 1 && b == &target)
    |         ^^^^-------------------------------------------------------
@@ -125,7 +125,7 @@ LL |         iter.cloned().filter(move |(&a, b)| a == 1 && b == &target)
    |             help: try: `.filter(move |&(&a, b)| a == 1 && b == &target).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:56:13
+  --> tests/ui/iter_overeager_cloned.rs:61:13
    |
 LL |             iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target)
    |             ^^^^------------------------------------------------------------
@@ -133,7 +133,7 @@ LL |             iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target
    |                 help: try: `.filter(move |&S { a, b }| **a == 1 && b == &target).cloned()`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:60:13
+  --> tests/ui/iter_overeager_cloned.rs:65:13
    |
 LL |     let _ = vec.iter().cloned().map(|x| x.len());
    |             ^^^^^^^^^^--------------------------
@@ -141,7 +141,7 @@ LL |     let _ = vec.iter().cloned().map(|x| x.len());
    |                       help: try: `.map(|x| x.len())`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:65:13
+  --> tests/ui/iter_overeager_cloned.rs:70:13
    |
 LL |     let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
    |             ^^^^^^^^^^----------------------------------------------
@@ -149,7 +149,7 @@ LL |     let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
    |                       help: try: `.for_each(|x| assert!(!x.is_empty()))`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:67:13
+  --> tests/ui/iter_overeager_cloned.rs:72:13
    |
 LL |     let _ = vec.iter().cloned().all(|x| x.len() == 1);
    |             ^^^^^^^^^^-------------------------------
@@ -157,7 +157,7 @@ LL |     let _ = vec.iter().cloned().all(|x| x.len() == 1);
    |                       help: try: `.all(|x| x.len() == 1)`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:69:13
+  --> tests/ui/iter_overeager_cloned.rs:74:13
    |
 LL |     let _ = vec.iter().cloned().any(|x| x.len() == 1);
    |             ^^^^^^^^^^-------------------------------
diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed
index 27319d9c20e..c9c476ba421 100644
--- a/src/tools/clippy/tests/ui/len_zero.fixed
+++ b/src/tools/clippy/tests/ui/len_zero.fixed
@@ -108,6 +108,8 @@ fn main() {
     let d2s = DerefToDerefToString {};
     println!("{}", (**d2s).is_empty());
 
+    println!("{}", std::borrow::Cow::Borrowed("").is_empty());
+
     let y = One;
     if y.len() == 0 {
         // No error; `One` does not have `.is_empty()`.
@@ -226,3 +228,23 @@ fn binop_with_macros() {
 
     (!has_is_empty.is_empty()).then(|| println!("This can happen."));
 }
+
+fn no_infinite_recursion() -> bool {
+    struct S;
+
+    impl Deref for S {
+        type Target = Self;
+        fn deref(&self) -> &Self::Target {
+            self
+        }
+    }
+
+    impl PartialEq<&'static str> for S {
+        fn eq(&self, _other: &&'static str) -> bool {
+            false
+        }
+    }
+
+    // Do not crash while checking if S implements `.is_empty()`
+    S == ""
+}
diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs
index 03c05bc6ed7..610a5448d10 100644
--- a/src/tools/clippy/tests/ui/len_zero.rs
+++ b/src/tools/clippy/tests/ui/len_zero.rs
@@ -108,6 +108,8 @@ fn main() {
     let d2s = DerefToDerefToString {};
     println!("{}", &**d2s == "");
 
+    println!("{}", std::borrow::Cow::Borrowed("") == "");
+
     let y = One;
     if y.len() == 0 {
         // No error; `One` does not have `.is_empty()`.
@@ -226,3 +228,23 @@ fn binop_with_macros() {
 
     (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen."));
 }
+
+fn no_infinite_recursion() -> bool {
+    struct S;
+
+    impl Deref for S {
+        type Target = Self;
+        fn deref(&self) -> &Self::Target {
+            self
+        }
+    }
+
+    impl PartialEq<&'static str> for S {
+        fn eq(&self, _other: &&'static str) -> bool {
+            false
+        }
+    }
+
+    // Do not crash while checking if S implements `.is_empty()`
+    S == ""
+}
diff --git a/src/tools/clippy/tests/ui/len_zero.stderr b/src/tools/clippy/tests/ui/len_zero.stderr
index 5c849a2aca6..8d6b57e4b6d 100644
--- a/src/tools/clippy/tests/ui/len_zero.stderr
+++ b/src/tools/clippy/tests/ui/len_zero.stderr
@@ -58,107 +58,113 @@ error: comparison to empty slice
 LL |     println!("{}", &**d2s == "");
    |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
 
+error: comparison to empty slice
+  --> tests/ui/len_zero.rs:111:20
+   |
+LL |     println!("{}", std::borrow::Cow::Borrowed("") == "");
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `std::borrow::Cow::Borrowed("").is_empty()`
+
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:124:8
+  --> tests/ui/len_zero.rs:126:8
    |
 LL |     if has_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:127:8
+  --> tests/ui/len_zero.rs:129:8
    |
 LL |     if has_is_empty.len() != 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:130:8
+  --> tests/ui/len_zero.rs:132:8
    |
 LL |     if has_is_empty.len() > 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:133:8
+  --> tests/ui/len_zero.rs:135:8
    |
 LL |     if has_is_empty.len() < 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:136:8
+  --> tests/ui/len_zero.rs:138:8
    |
 LL |     if has_is_empty.len() >= 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:147:8
+  --> tests/ui/len_zero.rs:149:8
    |
 LL |     if 0 == has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:150:8
+  --> tests/ui/len_zero.rs:152:8
    |
 LL |     if 0 != has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:153:8
+  --> tests/ui/len_zero.rs:155:8
    |
 LL |     if 0 < has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:156:8
+  --> tests/ui/len_zero.rs:158:8
    |
 LL |     if 1 <= has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:159:8
+  --> tests/ui/len_zero.rs:161:8
    |
 LL |     if 1 > has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:173:8
+  --> tests/ui/len_zero.rs:175:8
    |
 LL |     if with_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:185:6
+  --> tests/ui/len_zero.rs:187:6
    |
 LL |     (has_is_empty.len() > 0).then(|| println!("This can happen."));
    |      ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:186:6
+  --> tests/ui/len_zero.rs:188:6
    |
 LL |     (has_is_empty.len() == 0).then(|| println!("Or this!"));
    |      ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:190:8
+  --> tests/ui/len_zero.rs:192:8
    |
 LL |     if b.len() != 0 {}
    |        ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:224:8
+  --> tests/ui/len_zero.rs:226:8
    |
 LL |     if has_is_empty.len() == compare_to!(0) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:225:8
+  --> tests/ui/len_zero.rs:227:8
    |
 LL |     if has_is_empty.len() == zero!() {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:227:6
+  --> tests/ui/len_zero.rs:229:6
    |
 LL |     (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen."));
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
-error: aborting due to 26 previous errors
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.fixed b/src/tools/clippy/tests/ui/manual_div_ceil.fixed
index e7801f7376a..1fb1df5b442 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.fixed
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.fixed
@@ -28,3 +28,25 @@ fn main() {
     let _ = (7_u32 as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (4 - 1)) / 4;
 }
+
+fn issue_13843() {
+    let x = 3usize;
+    let _ = 2048_usize.div_ceil(x);
+
+    let x = 5usize;
+    let _ = 2048usize.div_ceil(x);
+
+    let x = 5usize;
+    let _ = 2048_usize.div_ceil(x);
+
+    let x = 2048usize;
+    let _ = x.div_ceil(4);
+
+    let _: u32 = 2048_u32.div_ceil(6);
+    let _: usize = 2048_usize.div_ceil(6);
+    let _: u32 = 0x2048_u32.div_ceil(0x6);
+
+    let _ = 2048_u32.div_ceil(6u32);
+
+    let _ = 1_000_000_u32.div_ceil(6u32);
+}
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.rs b/src/tools/clippy/tests/ui/manual_div_ceil.rs
index 2de74c7eaa8..4f6d38f0d14 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.rs
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.rs
@@ -28,3 +28,25 @@ fn main() {
     let _ = (7_u32 as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (4 - 1)) / 4;
 }
+
+fn issue_13843() {
+    let x = 3usize;
+    let _ = (2048 + x - 1) / x;
+
+    let x = 5usize;
+    let _ = (2048usize + x - 1) / x;
+
+    let x = 5usize;
+    let _ = (2048_usize + x - 1) / x;
+
+    let x = 2048usize;
+    let _ = (x + 4 - 1) / 4;
+
+    let _: u32 = (2048 + 6 - 1) / 6;
+    let _: usize = (2048 + 6 - 1) / 6;
+    let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
+
+    let _ = (2048 + 6u32 - 1) / 6u32;
+
+    let _ = (1_000_000 + 6u32 - 1) / 6u32;
+}
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.stderr b/src/tools/clippy/tests/ui/manual_div_ceil.stderr
index dc652dff405..3d87fe8e040 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.stderr
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.stderr
@@ -31,5 +31,59 @@ error: manually reimplementing `div_ceil`
 LL |     let _ = (7_i32 as u32 + (4 - 1)) / 4;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)`
 
-error: aborting due to 5 previous errors
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:34:13
+   |
+LL |     let _ = (2048 + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:37:13
+   |
+LL |     let _ = (2048usize + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:40:13
+   |
+LL |     let _ = (2048_usize + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:43:13
+   |
+LL |     let _ = (x + 4 - 1) / 4;
+   |             ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:45:18
+   |
+LL |     let _: u32 = (2048 + 6 - 1) / 6;
+   |                  ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:46:20
+   |
+LL |     let _: usize = (2048 + 6 - 1) / 6;
+   |                    ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:47:18
+   |
+LL |     let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:49:13
+   |
+LL |     let _ = (2048 + 6u32 - 1) / 6u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:51:13
+   |
+LL |     let _ = (1_000_000 + 6u32 - 1) / 6u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed
index a1d678c6689..f32b78aa14d 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed
+++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed
@@ -23,3 +23,30 @@ fn main() {
 
     let _ = (x + (y - 1)) / z;
 }
+
+fn issue_13843() {
+    let x = 3usize;
+    let _ = 2048_usize.div_ceil(x);
+
+    let x = 5usize;
+    let _ = 2048usize.div_ceil(x);
+
+    let x = 5usize;
+    let _ = 2048_usize.div_ceil(x);
+
+    let x = 2048usize;
+    let _ = x.div_ceil(4);
+
+    let _ = 2048_i32.div_ceil(4);
+
+    let _: u32 = 2048_u32.div_ceil(6);
+    let _: usize = 2048_usize.div_ceil(6);
+    let _: u32 = 0x2048_u32.div_ceil(0x6);
+
+    let _ = 2048_u32.div_ceil(6u32);
+
+    let x = -2;
+    let _ = (-2048_i32).div_ceil(x);
+
+    let _ = 1_000_000_u32.div_ceil(6u32);
+}
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs
index 58cb1dbe34d..54d89fcbd46 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs
+++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs
@@ -23,3 +23,30 @@ fn main() {
 
     let _ = (x + (y - 1)) / z;
 }
+
+fn issue_13843() {
+    let x = 3usize;
+    let _ = (2048 + x - 1) / x;
+
+    let x = 5usize;
+    let _ = (2048usize + x - 1) / x;
+
+    let x = 5usize;
+    let _ = (2048_usize + x - 1) / x;
+
+    let x = 2048usize;
+    let _ = (x + 4 - 1) / 4;
+
+    let _ = (2048 + 4 - 1) / 4;
+
+    let _: u32 = (2048 + 6 - 1) / 6;
+    let _: usize = (2048 + 6 - 1) / 6;
+    let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
+
+    let _ = (2048 + 6u32 - 1) / 6u32;
+
+    let x = -2;
+    let _ = (-2048 + x - 1) / x;
+
+    let _ = (1_000_000 + 6u32 - 1) / 6u32;
+}
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr
index 361ef9bd9f4..c5e8c1a687c 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr
+++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr
@@ -43,5 +43,71 @@ error: manually reimplementing `div_ceil`
 LL |     let _ = (z_u + (4 - 1)) / 4;
    |             ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `z_u.div_ceil(4)`
 
-error: aborting due to 7 previous errors
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:29:13
+   |
+LL |     let _ = (2048 + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:32:13
+   |
+LL |     let _ = (2048usize + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:35:13
+   |
+LL |     let _ = (2048_usize + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:38:13
+   |
+LL |     let _ = (x + 4 - 1) / 4;
+   |             ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:40:13
+   |
+LL |     let _ = (2048 + 4 - 1) / 4;
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_i32.div_ceil(4)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:42:18
+   |
+LL |     let _: u32 = (2048 + 6 - 1) / 6;
+   |                  ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:43:20
+   |
+LL |     let _: usize = (2048 + 6 - 1) / 6;
+   |                    ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:44:18
+   |
+LL |     let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:46:13
+   |
+LL |     let _ = (2048 + 6u32 - 1) / 6u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:49:13
+   |
+LL |     let _ = (-2048 + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(-2048_i32).div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:51:13
+   |
+LL |     let _ = (1_000_000 + 6u32 - 1) / 6u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)`
+
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
index a72caa3a37e..179149f697d 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
@@ -82,3 +82,8 @@ fn generics() {
     take_while(|c: u8| c.is_ascii_uppercase());
     take_while(|c: char| c.is_ascii_uppercase());
 }
+
+fn adds_type_reference() {
+    let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c: &&char| c.is_ascii_digit()).collect();
+    let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect();
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
index bb6e2a317da..74f35ce94e8 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
@@ -82,3 +82,8 @@ fn generics() {
     take_while(|c| (b'A'..=b'Z').contains(&c));
     take_while(|c: char| ('A'..='Z').contains(&c));
 }
+
+fn adds_type_reference() {
+    let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c| ('0'..='9').contains(c)).collect();
+    let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect();
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
index a93ccace28a..92d93208006 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
@@ -173,5 +173,27 @@ error: manual check for common ascii range
 LL |     take_while(|c: char| ('A'..='Z').contains(&c));
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_uppercase()`
 
-error: aborting due to 27 previous errors
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:87:63
+   |
+LL |     let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c| ('0'..='9').contains(c)).collect();
+   |                                                               ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c: &&char| c.is_ascii_digit()).collect();
+   |                                                            ~~~~~~~~~  ~~~~~~~~~~~~~~~~~~
+
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:88:71
+   |
+LL |     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect();
+   |                                                                       ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect();
+   |                                                                    ~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs
index 76916d46591..eafc8b6e81c 100644
--- a/src/tools/clippy/tests/ui/map_flatten.rs
+++ b/src/tools/clippy/tests/ui/map_flatten.rs
@@ -55,6 +55,18 @@ fn long_span() {
         .collect();
 }
 
+#[allow(clippy::useless_vec)]
+fn no_suggestion_if_comments_present() {
+    let vec = vec![vec![1, 2, 3]];
+    let _ = vec
+        .iter()
+        // a lovely comment explaining the code in very detail
+        .map(|x| x.iter())
+        //~^ ERROR: called `map(..).flatten()` on `Iterator`
+        // the answer to life, the universe and everything could be here
+        .flatten();
+}
+
 fn main() {
     long_span();
 }
diff --git a/src/tools/clippy/tests/ui/map_flatten.stderr b/src/tools/clippy/tests/ui/map_flatten.stderr
index a5837b97617..34bd174d7dd 100644
--- a/src/tools/clippy/tests/ui/map_flatten.stderr
+++ b/src/tools/clippy/tests/ui/map_flatten.stderr
@@ -102,5 +102,14 @@ LL +             }
 LL +         })
    |
 
-error: aborting due to 4 previous errors
+error: called `map(..).flatten()` on `Iterator`
+  --> tests/ui/map_flatten.rs:64:10
+   |
+LL |           .map(|x| x.iter())
+   |  __________^
+...  |
+LL | |         .flatten();
+   | |__________________^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| x.iter())`
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed
index 53ebfb40ba0..3257ddc6f72 100644
--- a/src/tools/clippy/tests/ui/map_identity.fixed
+++ b/src/tools/clippy/tests/ui/map_identity.fixed
@@ -61,3 +61,18 @@ fn issue11764() {
     // no match ergonomics for `(i32, i32)`
     let _ = x.iter().copied();
 }
+
+fn issue13904() {
+    // don't lint: `it.next()` would not be legal as `it` is immutable
+    let it = [1, 2, 3].into_iter();
+    let _ = it.map(|x| x).next();
+
+    // lint
+    #[allow(unused_mut)]
+    let mut it = [1, 2, 3].into_iter();
+    let _ = it.next();
+
+    // lint
+    let it = [1, 2, 3].into_iter();
+    let _ = { it }.next();
+}
diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs
index c646c056859..be3bb9a4f10 100644
--- a/src/tools/clippy/tests/ui/map_identity.rs
+++ b/src/tools/clippy/tests/ui/map_identity.rs
@@ -65,3 +65,18 @@ fn issue11764() {
     // no match ergonomics for `(i32, i32)`
     let _ = x.iter().copied().map(|(x, y)| (x, y));
 }
+
+fn issue13904() {
+    // don't lint: `it.next()` would not be legal as `it` is immutable
+    let it = [1, 2, 3].into_iter();
+    let _ = it.map(|x| x).next();
+
+    // lint
+    #[allow(unused_mut)]
+    let mut it = [1, 2, 3].into_iter();
+    let _ = it.map(|x| x).next();
+
+    // lint
+    let it = [1, 2, 3].into_iter();
+    let _ = { it }.map(|x| x).next();
+}
diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr
index 0a0dc9c8f07..aa3fc4ae0b5 100644
--- a/src/tools/clippy/tests/ui/map_identity.stderr
+++ b/src/tools/clippy/tests/ui/map_identity.stderr
@@ -73,5 +73,17 @@ error: unnecessary map of the identity function
 LL |     let _ = x.iter().copied().map(|(x, y)| (x, y));
    |                              ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
-error: aborting due to 11 previous errors
+error: unnecessary map of the identity function
+  --> tests/ui/map_identity.rs:77:15
+   |
+LL |     let _ = it.map(|x| x).next();
+   |               ^^^^^^^^^^^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+  --> tests/ui/map_identity.rs:81:19
+   |
+LL |     let _ = { it }.map(|x| x).next();
+   |                   ^^^^^^^^^^^ help: remove the call to `map`
+
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
index ca323dcf173..d2f9e34a5ce 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -47,7 +47,34 @@ fn get_y() -> u32 {
     Y
 }
 
-// Don't lint entrypoint functions
+#[cfg(test)]
+mod with_test_fn {
+    #[derive(Clone, Copy)]
+    pub struct Foo {
+        pub n: u32,
+    }
+
+    impl Foo {
+        #[must_use]
+        pub const fn new(n: u32) -> Foo {
+            Foo { n }
+        }
+    }
+
+    #[test]
+    fn foo_is_copy() {
+        let foo = Foo::new(42);
+        let one = foo;
+        let two = foo;
+        _ = one;
+        _ = two;
+    }
+}
+
+// Allowing on this function, because it would lint, which we don't want in this case.
+// if we have `#[start]` and `#[test]` check `is_entrypoint_fn(cx, def_id.to_def_id())` is stopped
+// working
+#[allow(clippy::missing_const_for_fn)]
 #[start]
 fn init(num: isize, something: *const *const u8) -> isize {
     1
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed
index 9da60c687d4..530eb77d83d 100644
--- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed
@@ -64,4 +64,9 @@ impl ValType {
     }
 }
 
+trait Foo<'r#struct> {
+    fn f1(&'r#struct self) {}
+    fn f2(&'r#struct mut self) {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs
index fc4ec5cb0b3..5a1ff96a11c 100644
--- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs
@@ -64,4 +64,9 @@ impl ValType {
     }
 }
 
+trait Foo<'r#struct> {
+    fn f1(self: &'r#struct Self) {}
+    fn f2(self: &'r#struct mut Self) {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr
index c653267f752..7ebbbaa122f 100644
--- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr
@@ -37,5 +37,17 @@ error: the type of the `self` parameter does not need to be arbitrary
 LL |     pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) {
    |                                          ^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'a mut self`
 
-error: aborting due to 6 previous errors
+error: the type of the `self` parameter does not need to be arbitrary
+  --> tests/ui/needless_arbitrary_self_type.rs:68:11
+   |
+LL |     fn f1(self: &'r#struct Self) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'r#struct self`
+
+error: the type of the `self` parameter does not need to be arbitrary
+  --> tests/ui/needless_arbitrary_self_type.rs:69:11
+   |
+LL |     fn f2(self: &'r#struct mut Self) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'r#struct mut self`
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_continue.rs b/src/tools/clippy/tests/ui/needless_continue.rs
index b6d8a8f61ae..334a2b32775 100644
--- a/src/tools/clippy/tests/ui/needless_continue.rs
+++ b/src/tools/clippy/tests/ui/needless_continue.rs
@@ -87,6 +87,14 @@ fn simple_loop4() {
     }
 }
 
+fn simple_loop5() {
+    loop {
+        println!("bleh");
+        { continue }
+        //~^ ERROR: this `continue` expression is redundant
+    }
+}
+
 mod issue_2329 {
     fn condition() -> bool {
         unimplemented!()
@@ -168,3 +176,60 @@ fn issue_13641() {
         }
     }
 }
+
+mod issue_4077 {
+    fn main() {
+        'outer: loop {
+            'inner: loop {
+                do_something();
+                if some_expr() {
+                    println!("bar-7");
+                    continue 'outer;
+                } else if !some_expr() {
+                    println!("bar-8");
+                    continue 'inner;
+                } else {
+                    println!("bar-9");
+                    continue 'inner;
+                }
+            }
+        }
+
+        for _ in 0..10 {
+            match "foo".parse::<i32>() {
+                Ok(_) => do_something(),
+                Err(_) => {
+                    println!("bar-10");
+                    continue;
+                },
+            }
+        }
+
+        loop {
+            if true {
+            } else {
+                // redundant `else`
+                continue; // redundant `continue`
+            }
+        }
+
+        loop {
+            if some_expr() {
+                continue;
+            } else {
+                do_something();
+            }
+        }
+    }
+
+    // The contents of these functions are irrelevant, the purpose of this file is
+    // shown in main.
+
+    fn do_something() {
+        std::process::exit(0);
+    }
+
+    fn some_expr() -> bool {
+        true
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_continue.stderr b/src/tools/clippy/tests/ui/needless_continue.stderr
index 0741ba69248..ec39d623419 100644
--- a/src/tools/clippy/tests/ui/needless_continue.stderr
+++ b/src/tools/clippy/tests/ui/needless_continue.stderr
@@ -63,7 +63,7 @@ error: this `continue` expression is redundant
   --> tests/ui/needless_continue.rs:60:9
    |
 LL |         continue;
-   |         ^^^^^^^^^
+   |         ^^^^^^^^
    |
    = help: consider dropping the `continue` expression
 
@@ -71,7 +71,7 @@ error: this `continue` expression is redundant
   --> tests/ui/needless_continue.rs:68:9
    |
 LL |         continue;
-   |         ^^^^^^^^^
+   |         ^^^^^^^^
    |
    = help: consider dropping the `continue` expression
 
@@ -91,8 +91,16 @@ LL |         continue
    |
    = help: consider dropping the `continue` expression
 
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:93:11
+   |
+LL |         { continue }
+   |           ^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
 error: this `else` block is redundant
-  --> tests/ui/needless_continue.rs:136:24
+  --> tests/ui/needless_continue.rs:144:24
    |
 LL |                   } else {
    |  ________________________^
@@ -117,7 +125,7 @@ LL | |                 }
                            }
 
 error: there is no need for an explicit `else` block for this `if` expression
-  --> tests/ui/needless_continue.rs:143:17
+  --> tests/ui/needless_continue.rs:151:17
    |
 LL | /                 if condition() {
 LL | |
@@ -137,12 +145,70 @@ LL | |                 }
                            }
 
 error: this `continue` expression is redundant
-  --> tests/ui/needless_continue.rs:166:13
+  --> tests/ui/needless_continue.rs:174:13
    |
 LL |             continue 'b;
-   |             ^^^^^^^^^^^^
+   |             ^^^^^^^^^^^
    |
    = help: consider dropping the `continue` expression
 
-error: aborting due to 9 previous errors
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:190:21
+   |
+LL |                     continue 'inner;
+   |                     ^^^^^^^^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:193:21
+   |
+LL |                     continue 'inner;
+   |                     ^^^^^^^^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:203:21
+   |
+LL |                     continue;
+   |                     ^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
+error: this `else` block is redundant
+  --> tests/ui/needless_continue.rs:210:20
+   |
+LL |               } else {
+   |  ____________________^
+LL | |                 // redundant `else`
+LL | |                 continue; // redundant `continue`
+LL | |             }
+   | |_____________^
+   |
+   = help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block
+                       if true {
+           // merged code follows:
+           
+                       }
+
+error: there is no need for an explicit `else` block for this `if` expression
+  --> tests/ui/needless_continue.rs:217:13
+   |
+LL | /             if some_expr() {
+LL | |                 continue;
+LL | |             } else {
+LL | |                 do_something();
+LL | |             }
+   | |_____________^
+   |
+   = help: consider dropping the `else` clause
+                       if some_expr() {
+                           continue;
+                       }
+                       {
+                           do_something();
+                       }
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index c9b76262d70..c7e0cd2610f 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -137,3 +137,11 @@ fn issue10803() {
     // Don't lint
     let _ = matches!(x, Some(16));
 }
+
+fn issue13902() {
+    let x = Some(0);
+    let p = &raw const x;
+    unsafe {
+        let _ = (*p).is_none();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index a5f9caf659c..6d9a9f7f942 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -164,3 +164,11 @@ fn issue10803() {
     // Don't lint
     let _ = matches!(x, Some(16));
 }
+
+fn issue13902() {
+    let x = Some(0);
+    let p = &raw const x;
+    unsafe {
+        let _ = matches!(*p, None);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index 575f199be42..34d80f5ca78 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -209,5 +209,11 @@ error: redundant pattern matching, consider using `is_none()`
 LL |     let _ = matches!(x, None);
    |             ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()`
 
-error: aborting due to 30 previous errors
+error: redundant pattern matching, consider using `is_none()`
+  --> tests/ui/redundant_pattern_matching_option.rs:172:17
+   |
+LL |         let _ = matches!(*p, None);
+   |                 ^^^^^^^^^^^^^^^^^^ help: try: `(*p).is_none()`
+
+error: aborting due to 31 previous errors
 
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
index 16f81019574..2ba87f41250 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
@@ -11,22 +11,22 @@ fn extend_vector() {
     // Extend with constant expression
     let len = 300;
     let mut vec1 = Vec::with_capacity(len);
-    vec1.extend(repeat(0).take(len));
     //~^ ERROR: slow zero-filling initialization
     //~| NOTE: `-D clippy::slow-vector-initialization` implied by `-D warnings`
+    vec1.extend(repeat(0).take(len));
 
     // Extend with len expression
     let mut vec2 = Vec::with_capacity(len - 10);
-    vec2.extend(repeat(0).take(len - 10));
     //~^ ERROR: slow zero-filling initialization
+    vec2.extend(repeat(0).take(len - 10));
 
     // Extend with mismatching expression should not be warned
     let mut vec3 = Vec::with_capacity(24322);
     vec3.extend(repeat(0).take(2));
 
     let mut vec4 = Vec::with_capacity(len);
-    vec4.extend(repeat(0).take(vec4.capacity()));
     //~^ ERROR: slow zero-filling initialization
+    vec4.extend(repeat(0).take(vec4.capacity()));
 }
 
 fn mixed_extend_resize_vector() {
@@ -36,20 +36,20 @@ fn mixed_extend_resize_vector() {
 
     // Slow initialization
     let mut resized_vec = Vec::with_capacity(30);
-    resized_vec.resize(30, 0);
     //~^ ERROR: slow zero-filling initialization
+    resized_vec.resize(30, 0);
 
     let mut extend_vec = Vec::with_capacity(30);
-    extend_vec.extend(repeat(0).take(30));
     //~^ ERROR: slow zero-filling initialization
+    extend_vec.extend(repeat(0).take(30));
 }
 
 fn resize_vector() {
     // Resize with constant expression
     let len = 300;
     let mut vec1 = Vec::with_capacity(len);
-    vec1.resize(len, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(len, 0);
 
     // Resize mismatch len
     let mut vec2 = Vec::with_capacity(200);
@@ -57,39 +57,39 @@ fn resize_vector() {
 
     // Resize with len expression
     let mut vec3 = Vec::with_capacity(len - 10);
-    vec3.resize(len - 10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec3.resize(len - 10, 0);
 
     let mut vec4 = Vec::with_capacity(len);
-    vec4.resize(vec4.capacity(), 0);
     //~^ ERROR: slow zero-filling initialization
+    vec4.resize(vec4.capacity(), 0);
 
     // Reinitialization should be warned
     vec1 = Vec::with_capacity(10);
-    vec1.resize(10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(10, 0);
 }
 
 fn from_empty_vec() {
     // Resize with constant expression
     let len = 300;
     let mut vec1 = Vec::new();
-    vec1.resize(len, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(len, 0);
 
     // Resize with len expression
     let mut vec3 = Vec::new();
-    vec3.resize(len - 10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec3.resize(len - 10, 0);
 
     // Reinitialization should be warned
     vec1 = Vec::new();
-    vec1.resize(10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(10, 0);
 
     vec1 = vec![];
-    vec1.resize(10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(10, 0);
 
     macro_rules! x {
         () => {
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
index 353c677097b..7f4b9f7b67a 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
@@ -1,109 +1,122 @@
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:14:5
+  --> tests/ui/slow_vector_initialization.rs:13:20
    |
-LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec1.extend(repeat(0).take(len));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec1 = Vec::with_capacity(len);
+   |  ____________________^
+...  |
+LL | |     vec1.extend(repeat(0).take(len));
+   | |____________________________________^ help: consider replacing this with: `vec![0; len]`
    |
    = note: `-D clippy::slow-vector-initialization` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::slow_vector_initialization)]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:20:5
+  --> tests/ui/slow_vector_initialization.rs:19:20
    |
-LL |     let mut vec2 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
-LL |     vec2.extend(repeat(0).take(len - 10));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec2 = Vec::with_capacity(len - 10);
+   |  ____________________^
+LL | |
+LL | |     vec2.extend(repeat(0).take(len - 10));
+   | |_________________________________________^ help: consider replacing this with: `vec![0; len - 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:28:5
+  --> tests/ui/slow_vector_initialization.rs:27:20
    |
-LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec4.extend(repeat(0).take(vec4.capacity()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec4 = Vec::with_capacity(len);
+   |  ____________________^
+LL | |
+LL | |     vec4.extend(repeat(0).take(vec4.capacity()));
+   | |________________________________________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:39:5
+  --> tests/ui/slow_vector_initialization.rs:38:27
    |
-LL |     let mut resized_vec = Vec::with_capacity(30);
-   |                           ---------------------- help: consider replacing this with: `vec![0; 30]`
-LL |     resized_vec.resize(30, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut resized_vec = Vec::with_capacity(30);
+   |  ___________________________^
+LL | |
+LL | |     resized_vec.resize(30, 0);
+   | |_____________________________^ help: consider replacing this with: `vec![0; 30]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:43:5
+  --> tests/ui/slow_vector_initialization.rs:42:26
    |
-LL |     let mut extend_vec = Vec::with_capacity(30);
-   |                          ---------------------- help: consider replacing this with: `vec![0; 30]`
-LL |     extend_vec.extend(repeat(0).take(30));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut extend_vec = Vec::with_capacity(30);
+   |  __________________________^
+LL | |
+LL | |     extend_vec.extend(repeat(0).take(30));
+   | |_________________________________________^ help: consider replacing this with: `vec![0; 30]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:51:5
+  --> tests/ui/slow_vector_initialization.rs:50:20
    |
-LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec1.resize(len, 0);
-   |     ^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec1 = Vec::with_capacity(len);
+   |  ____________________^
+LL | |
+LL | |     vec1.resize(len, 0);
+   | |_______________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:60:5
+  --> tests/ui/slow_vector_initialization.rs:59:20
    |
-LL |     let mut vec3 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
-LL |     vec3.resize(len - 10, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec3 = Vec::with_capacity(len - 10);
+   |  ____________________^
+LL | |
+LL | |     vec3.resize(len - 10, 0);
+   | |____________________________^ help: consider replacing this with: `vec![0; len - 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:64:5
+  --> tests/ui/slow_vector_initialization.rs:63:20
    |
-LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec4.resize(vec4.capacity(), 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec4 = Vec::with_capacity(len);
+   |  ____________________^
+LL | |
+LL | |     vec4.resize(vec4.capacity(), 0);
+   | |___________________________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:69:5
+  --> tests/ui/slow_vector_initialization.rs:68:12
    |
-LL |     vec1 = Vec::with_capacity(10);
-   |            ---------------------- help: consider replacing this with: `vec![0; 10]`
-LL |     vec1.resize(10, 0);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |       vec1 = Vec::with_capacity(10);
+   |  ____________^
+LL | |
+LL | |     vec1.resize(10, 0);
+   | |______________________^ help: consider replacing this with: `vec![0; 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:77:5
+  --> tests/ui/slow_vector_initialization.rs:76:20
    |
-LL |     let mut vec1 = Vec::new();
-   |                    ---------- help: consider replacing this with: `vec![0; len]`
-LL |     vec1.resize(len, 0);
-   |     ^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec1 = Vec::new();
+   |  ____________________^
+LL | |
+LL | |     vec1.resize(len, 0);
+   | |_______________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:82:5
+  --> tests/ui/slow_vector_initialization.rs:81:20
    |
-LL |     let mut vec3 = Vec::new();
-   |                    ---------- help: consider replacing this with: `vec![0; len - 10]`
-LL |     vec3.resize(len - 10, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec3 = Vec::new();
+   |  ____________________^
+LL | |
+LL | |     vec3.resize(len - 10, 0);
+   | |____________________________^ help: consider replacing this with: `vec![0; len - 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:87:5
+  --> tests/ui/slow_vector_initialization.rs:86:12
    |
-LL |     vec1 = Vec::new();
-   |            ---------- help: consider replacing this with: `vec![0; 10]`
-LL |     vec1.resize(10, 0);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |       vec1 = Vec::new();
+   |  ____________^
+LL | |
+LL | |     vec1.resize(10, 0);
+   | |______________________^ help: consider replacing this with: `vec![0; 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:91:5
+  --> tests/ui/slow_vector_initialization.rs:90:12
    |
-LL |     vec1 = vec![];
-   |            ------ help: consider replacing this with: `vec![0; 10]`
-LL |     vec1.resize(10, 0);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |       vec1 = vec![];
+   |  ____________^
+LL | |
+LL | |     vec1.resize(10, 0);
+   | |______________________^ help: consider replacing this with: `vec![0; 10]`
 
 error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/starts_ends_with.fixed b/src/tools/clippy/tests/ui/starts_ends_with.fixed
index 4a66ca7ec91..252b6e5a98c 100644
--- a/src/tools/clippy/tests/ui/starts_ends_with.fixed
+++ b/src/tools/clippy/tests/ui/starts_ends_with.fixed
@@ -1,4 +1,4 @@
-#![allow(clippy::needless_if, dead_code, unused_must_use)]
+#![allow(clippy::needless_if, dead_code, unused_must_use, clippy::double_ended_iterator_last)]
 
 fn main() {}
 
diff --git a/src/tools/clippy/tests/ui/starts_ends_with.rs b/src/tools/clippy/tests/ui/starts_ends_with.rs
index 16a68e02d66..6c5655f3178 100644
--- a/src/tools/clippy/tests/ui/starts_ends_with.rs
+++ b/src/tools/clippy/tests/ui/starts_ends_with.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::needless_if, dead_code, unused_must_use)]
+#![allow(clippy::needless_if, dead_code, unused_must_use, clippy::double_ended_iterator_last)]
 
 fn main() {}
 
diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.rs b/src/tools/clippy/tests/ui/trailing_empty_array.rs
index 309a5920dfd..ea3b8ff01af 100644
--- a/src/tools/clippy/tests/ui/trailing_empty_array.rs
+++ b/src/tools/clippy/tests/ui/trailing_empty_array.rs
@@ -193,3 +193,17 @@ type C = ConstParamNoDefault<0>;
 type D = ConstParamNonZeroDefault<0>;
 
 fn main() {}
+
+#[cfg(test)]
+mod tests {
+    pub struct Friend {
+        age: u8,
+    }
+
+    #[test]
+    fn oldest_empty_is_none() {
+        struct Michael {
+            friends: [Friend; 0],
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed
index 70b78ceca50..efea28e7045 100644
--- a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed
@@ -3,15 +3,16 @@
 #![allow(clippy::no_effect)]
 #![allow(clippy::eq_op)]
 #![allow(clippy::unnecessary_lazy_evaluations)]
+#![allow(clippy::nonminimal_bool)]
 #[clippy::msrv = "1.70.0"]
 #[macro_use]
 extern crate proc_macros;
 
 fn main() {
     // should trigger
-    let _ = (Some(5) == Some(5));
-    let _ = (Some(5) != Some(5));
-    let _ = (Some(5) == Some(5));
+    let _ = Some(5) == Some(5);
+    let _ = Some(5) != Some(5);
+    let _ = Some(5) == Some(5);
     let _ = Some(5).is_some_and(|n| {
         let _ = n;
         6 >= 5
@@ -21,10 +22,13 @@ fn main() {
     let _ = Some(5).is_some_and(|n| n == n);
     let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 });
     let _ = Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5]);
-    let _ = (Ok::<i32, i32>(5) == Ok(5));
+    let _ = Ok::<i32, i32>(5) == Ok(5);
     let _ = (Some(5) == Some(5)).then(|| 1);
     let _ = Some(5).is_none_or(|n| n == 5);
     let _ = Some(5).is_none_or(|n| 5 == n);
+    let _ = !(Some(5) == Some(5));
+    let _ = (Some(5) == Some(5)) || false;
+    let _ = (Some(5) == Some(5)) as usize;
 
     macro_rules! x {
         () => {
@@ -60,7 +64,7 @@ fn main() {
     #[derive(PartialEq)]
     struct S2;
     let r: Result<i32, S2> = Ok(4);
-    let _ = (r == Ok(8));
+    let _ = r == Ok(8);
 
     // do not lint `Result::map_or(true, …)`
     let r: Result<i32, S2> = Ok(4);
diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.rs b/src/tools/clippy/tests/ui/unnecessary_map_or.rs
index 50757715977..05a0ca816ef 100644
--- a/src/tools/clippy/tests/ui/unnecessary_map_or.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_map_or.rs
@@ -3,6 +3,7 @@
 #![allow(clippy::no_effect)]
 #![allow(clippy::eq_op)]
 #![allow(clippy::unnecessary_lazy_evaluations)]
+#![allow(clippy::nonminimal_bool)]
 #[clippy::msrv = "1.70.0"]
 #[macro_use]
 extern crate proc_macros;
@@ -28,6 +29,9 @@ fn main() {
     let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
     let _ = Some(5).map_or(true, |n| n == 5);
     let _ = Some(5).map_or(true, |n| 5 == n);
+    let _ = !Some(5).map_or(false, |n| n == 5);
+    let _ = Some(5).map_or(false, |n| n == 5) || false;
+    let _ = Some(5).map_or(false, |n| n == 5) as usize;
 
     macro_rules! x {
         () => {
diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr
index 890abb01228..2b78996d5f3 100644
--- a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr
@@ -1,30 +1,30 @@
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:12:13
+  --> tests/ui/unnecessary_map_or.rs:13:13
    |
 LL |     let _ = Some(5).map_or(false, |n| n == 5);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Some(5) == Some(5)`
    |
    = note: `-D clippy::unnecessary-map-or` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_map_or)]`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:13:13
+  --> tests/ui/unnecessary_map_or.rs:14:13
    |
 LL |     let _ = Some(5).map_or(true, |n| n != 5);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) != Some(5))`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Some(5) != Some(5)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:14:13
+  --> tests/ui/unnecessary_map_or.rs:15:13
    |
 LL |       let _ = Some(5).map_or(false, |n| {
    |  _____________^
 LL | |         let _ = 1;
 LL | |         n == 5
 LL | |     });
-   | |______^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+   | |______^ help: use a standard comparison instead: `Some(5) == Some(5)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:18:13
+  --> tests/ui/unnecessary_map_or.rs:19:13
    |
 LL |       let _ = Some(5).map_or(false, |n| {
    |  _____________^
@@ -42,88 +42,106 @@ LL ~     });
    |
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:22:13
+  --> tests/ui/unnecessary_map_or.rs:23:13
    |
 LL |     let _ = Some(vec![5]).map_or(false, |n| n == [5]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![5]).is_some_and(|n| n == [5])`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:23:13
+  --> tests/ui/unnecessary_map_or.rs:24:13
    |
 LL |     let _ = Some(vec![1]).map_or(false, |n| vec![2] == n);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![1]).is_some_and(|n| vec![2] == n)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:24:13
+  --> tests/ui/unnecessary_map_or.rs:25:13
    |
 LL |     let _ = Some(5).map_or(false, |n| n == n);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == n)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:25:13
+  --> tests/ui/unnecessary_map_or.rs:26:13
    |
 LL |     let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 })`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:26:13
+  --> tests/ui/unnecessary_map_or.rs:27:13
    |
 LL |     let _ = Ok::<Vec<i32>, i32>(vec![5]).map_or(false, |n| n == [5]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5])`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:27:13
+  --> tests/ui/unnecessary_map_or.rs:28:13
    |
 LL |     let _ = Ok::<i32, i32>(5).map_or(false, |n| n == 5);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Ok::<i32, i32>(5) == Ok(5))`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Ok::<i32, i32>(5) == Ok(5)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:28:13
+  --> tests/ui/unnecessary_map_or.rs:29:13
    |
 LL |     let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:29:13
+  --> tests/ui/unnecessary_map_or.rs:30:13
    |
 LL |     let _ = Some(5).map_or(true, |n| n == 5);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| n == 5)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:30:13
+  --> tests/ui/unnecessary_map_or.rs:31:13
    |
 LL |     let _ = Some(5).map_or(true, |n| 5 == n);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| 5 == n)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:54:13
+  --> tests/ui/unnecessary_map_or.rs:32:14
+   |
+LL |     let _ = !Some(5).map_or(false, |n| n == 5);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+
+error: this `map_or` can be simplified
+  --> tests/ui/unnecessary_map_or.rs:33:13
+   |
+LL |     let _ = Some(5).map_or(false, |n| n == 5) || false;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+
+error: this `map_or` can be simplified
+  --> tests/ui/unnecessary_map_or.rs:34:13
+   |
+LL |     let _ = Some(5).map_or(false, |n| n == 5) as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+
+error: this `map_or` can be simplified
+  --> tests/ui/unnecessary_map_or.rs:58:13
    |
 LL |     let _ = r.map_or(false, |x| x == 7);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:59:13
+  --> tests/ui/unnecessary_map_or.rs:63:13
    |
 LL |     let _ = r.map_or(false, func);
    |             ^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(func)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:60:13
+  --> tests/ui/unnecessary_map_or.rs:64:13
    |
 LL |     let _ = Some(5).map_or(false, func);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(func)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:61:13
+  --> tests/ui/unnecessary_map_or.rs:65:13
    |
 LL |     let _ = Some(5).map_or(true, func);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(func)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:66:13
+  --> tests/ui/unnecessary_map_or.rs:70:13
    |
 LL |     let _ = r.map_or(false, |x| x == 8);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(r == Ok(8))`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `r == Ok(8)`
 
-error: aborting due to 18 previous errors
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui/useless_vec.rs b/src/tools/clippy/tests/ui/useless_vec.rs
new file mode 100644
index 00000000000..880809f81d7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_vec.rs
@@ -0,0 +1,15 @@
+//@no-rustfix: no suggestions
+
+#![warn(clippy::useless_vec)]
+
+// Regression test for <https://github.com/rust-lang/rust-clippy/issues/13692>.
+fn foo() {
+    // There should be no suggestion in this case.
+    let _some_variable = vec![
+        //~^ useless_vec
+        1, 2, // i'm here to stay
+        3, 4, // but this one going away ;-;
+    ]; // that is life anyways
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/useless_vec.stderr b/src/tools/clippy/tests/ui/useless_vec.stderr
new file mode 100644
index 00000000000..e47364fb06d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_vec.stderr
@@ -0,0 +1,21 @@
+error: useless use of `vec!`
+  --> tests/ui/useless_vec.rs:8:26
+   |
+LL |       let _some_variable = vec![
+   |  __________________________^
+LL | |
+LL | |         1, 2, // i'm here to stay
+LL | |         3, 4, // but this one going away ;-;
+LL | |     ]; // that is life anyways
+   | |_____^
+   |
+   = note: `-D clippy::useless-vec` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]`
+help: you can use an array directly
+   |
+LL ~     let _some_variable = [1, 2, // i'm here to stay
+LL ~         3, 4]; // that is life anyways
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index 0c1f63880cd..108171586ea 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -197,6 +197,7 @@ fn layout_of_simd_ty(
         align,
         max_repr_align: None,
         unadjusted_abi_align: align.abi,
+        randomization_seed: 0,
     }))
 }
 
@@ -313,6 +314,7 @@ pub fn layout_of_ty_query(
                 size,
                 max_repr_align: None,
                 unadjusted_abi_align: element.align.abi,
+                randomization_seed: 0,
             }
         }
         TyKind::Slice(element) => {
@@ -326,6 +328,7 @@ pub fn layout_of_ty_query(
                 size: Size::ZERO,
                 max_repr_align: None,
                 unadjusted_abi_align: element.align.abi,
+                randomization_seed: 0,
             }
         }
         TyKind::Str => Layout {
@@ -337,6 +340,7 @@ pub fn layout_of_ty_query(
             size: Size::ZERO,
             max_repr_align: None,
             unadjusted_abi_align: dl.i8_align.abi,
+            randomization_seed: 0,
         },
         // Potentially-wide pointers.
         TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index b55469f332a..1d88726d945 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -31,18 +31,31 @@ use crate::utils::{format_mutability, mk_sp, mk_sp_lo_plus_one, rewrite_ident};
 ///     - `[small, ntp]`
 ///     - unary tuple constructor `([small, ntp])`
 ///     - `&[small]`
-pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool {
+pub(crate) fn is_short_pattern(
+    context: &RewriteContext<'_>,
+    pat: &ast::Pat,
+    pat_str: &str,
+) -> bool {
     // We also require that the pattern is reasonably 'small' with its literal width.
-    pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(pat)
+    pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(context, pat)
 }
 
-fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
-    match pat.kind {
-        ast::PatKind::Rest
-        | ast::PatKind::Never
-        | ast::PatKind::Wild
-        | ast::PatKind::Err(_)
-        | ast::PatKind::Expr(_) => true,
+fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool {
+    match &pat.kind {
+        ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => {
+            true
+        }
+        ast::PatKind::Expr(expr) => match &expr.kind {
+            ast::ExprKind::Lit(_) => true,
+            ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind {
+                ast::ExprKind::Lit(_) => true,
+                _ => unreachable!(),
+            },
+            ast::ExprKind::ConstBlock(_) | ast::ExprKind::Path(..) => {
+                context.config.style_edition() <= StyleEdition::Edition2024
+            }
+            _ => unreachable!(),
+        },
         ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
         ast::PatKind::Struct(..)
         | ast::PatKind::MacCall(..)
@@ -57,8 +70,8 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
         ast::PatKind::Box(ref p)
         | PatKind::Deref(ref p)
         | ast::PatKind::Ref(ref p, _)
-        | ast::PatKind::Paren(ref p) => is_short_pattern_inner(&*p),
-        PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(p)),
+        | ast::PatKind::Paren(ref p) => is_short_pattern_inner(context, &*p),
+        PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(context, p)),
     }
 }
 
@@ -96,7 +109,7 @@ impl Rewrite for Pat {
                 let use_mixed_layout = pats
                     .iter()
                     .zip(pat_strs.iter())
-                    .all(|(pat, pat_str)| is_short_pattern(pat, pat_str));
+                    .all(|(pat, pat_str)| is_short_pattern(context, pat, pat_str));
                 let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect();
                 let tactic = if use_mixed_layout {
                     DefinitiveListTactic::Mixed
diff --git a/src/tools/rustfmt/tests/source/pattern.rs b/src/tools/rustfmt/tests/source/pattern.rs
index f06d03cadf2..ed6ad690fa9 100644
--- a/src/tools/rustfmt/tests/source/pattern.rs
+++ b/src/tools/rustfmt/tests/source/pattern.rs
@@ -88,3 +88,13 @@ fn issue3728() {
         | c;
     foo((1,));
 }
+
+fn literals() {
+    match 42 {
+        const { 1 + 2 } | 4
+        | 6 => {}
+        10 | 11 | 12
+        | 13 | 14 => {}
+        _ => {}
+    }
+}
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/target/pattern.rs b/src/tools/rustfmt/tests/target/pattern.rs
index 576018ac623..e867f65929d 100644
--- a/src/tools/rustfmt/tests/target/pattern.rs
+++ b/src/tools/rustfmt/tests/target/pattern.rs
@@ -96,3 +96,11 @@ fn issue3728() {
     let foo = |(c,)| c;
     foo((1,));
 }
+
+fn literals() {
+    match 42 {
+        const { 1 + 2 } | 4 | 6 => {}
+        10 | 11 | 12 | 13 | 14 => {}
+        _ => {}
+    }
+}
diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs
index 8126bf84618..1c2dd3e8875 100644
--- a/tests/codegen/slice-init.rs
+++ b/tests/codegen/slice-init.rs
@@ -63,6 +63,32 @@ pub fn nonzero_integer_array() {
     opaque(&x);
 }
 
+const N: usize = 100;
+
+// CHECK-LABEL: @u16_init_one_bytes
+#[no_mangle]
+pub fn u16_init_one_bytes() -> [u16; N] {
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: call void @llvm.memset.p0
+    [const { u16::from_be_bytes([1, 1]) }; N]
+}
+
+// FIXME: undef bytes can just be initialized with the same value as the
+// defined bytes, if the defines bytes are all the same.
+// CHECK-LABEL: @option_none_init
+#[no_mangle]
+pub fn option_none_init() -> [Option<u8>; N] {
+    // CHECK-NOT: select
+    // CHECK: br label %repeat_loop_header{{.*}}
+    // CHECK-NOT: switch
+    // CHECK: icmp
+    // CHECK-NOT: call void @llvm.memset.p0
+    [None; N]
+}
+
 // Use an opaque function to prevent rustc from removing useless drops.
 #[inline(never)]
 pub fn opaque(_: impl Sized) {}
diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs
index 33de0913f77..e835a7ef69b 100644
--- a/tests/codegen/vec-in-place.rs
+++ b/tests/codegen/vec-in-place.rs
@@ -37,8 +37,11 @@ pub struct Baz {
 #[no_mangle]
 pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
     vec.into_iter().map(|e| e as u8).collect()
@@ -48,8 +51,11 @@ pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
 #[no_mangle]
 pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
     vec.into_iter().map(|e| Wrapper(e)).collect()
@@ -76,8 +82,11 @@ pub fn vec_iterator_cast_signed_nested(vec: Vec<Vec<i32>>) -> Vec<Vec<u32>> {
 #[no_mangle]
 pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
     vec.into_iter().map(|e| e.0).collect()
@@ -87,8 +96,11 @@ pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
 #[no_mangle]
 pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
     vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
@@ -98,8 +110,11 @@ pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
 #[no_mangle]
 pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
 
@@ -114,8 +129,11 @@ pub fn vec_iterator_cast_deaggregate_tra(vec: Vec<Bar>) -> Vec<[u64; 4]> {
 #[no_mangle]
 pub fn vec_iterator_cast_deaggregate_fold(vec: Vec<Baz>) -> Vec<[u64; 4]> {
     // CHECK-NOT: loop
-    // CHECK: call
-    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    // CHECK: call{{.+}}void @llvm.assume(i1 %{{.+}})
     // CHECK-NOT: loop
     // CHECK-NOT: call
 
@@ -138,6 +156,12 @@ pub fn vec_iterator_cast_unwrap_drop(vec: Vec<Wrapper<String>>) -> Vec<String> {
     // CHECK-NOT: call
     // CHECK-NOT: %{{.*}} = mul
     // CHECK-NOT: %{{.*}} = udiv
+    // CHECK: call
+    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: call
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
 
     vec.into_iter().map(|Wrapper(e)| e).collect()
 }
@@ -154,6 +178,12 @@ pub fn vec_iterator_cast_wrap_drop(vec: Vec<String>) -> Vec<Wrapper<String>> {
     // CHECK-NOT: call
     // CHECK-NOT: %{{.*}} = mul
     // CHECK-NOT: %{{.*}} = udiv
+    // CHECK: call
+    // CHECK-SAME: void @llvm.assume(i1 %{{.+}})
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: call
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
     // CHECK: ret void
 
     vec.into_iter().map(Wrapper).collect()
diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs
index a8ad5b6f1a3..4821e840884 100644
--- a/tests/codegen/vec_pop_push_noop.rs
+++ b/tests/codegen/vec_pop_push_noop.rs
@@ -12,9 +12,6 @@ pub fn noop(v: &mut Vec<u8>) {
     // CHECK-NOT: call
     // CHECK: tail call void @llvm.assume
     // CHECK-NOT: grow_one
-    // llvm-pre-19: call
-    // llvm-pre-19-same: void @llvm.assume
-    // llvm-pre-19-NOT: grow_one
     // CHECK-NOT: call
     // CHECK: {{ret|[}]}}
     if let Some(x) = v.pop() {
diff --git a/tests/coverage/generic-unused-impl.cov-map b/tests/coverage/generic-unused-impl.cov-map
new file mode 100644
index 00000000000..5878de231ba
--- /dev/null
+++ b/tests/coverage/generic-unused-impl.cov-map
@@ -0,0 +1,18 @@
+Function name: <generic_unused_impl::W<_> as core::convert::From<[<_ as generic_unused_impl::Foo>::Assoc; 1]>>::from (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 0b, 05, 03, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 11, 5) to (start + 3, 6)
+Highest counter ID seen: (none)
+
+Function name: generic_unused_impl::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 0d]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 13)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/generic-unused-impl.coverage b/tests/coverage/generic-unused-impl.coverage
new file mode 100644
index 00000000000..c3a3c724290
--- /dev/null
+++ b/tests/coverage/generic-unused-impl.coverage
@@ -0,0 +1,18 @@
+   LL|       |// Regression test for #135235.
+   LL|       |trait Foo {
+   LL|       |    type Assoc;
+   LL|       |
+   LL|       |    fn from(s: Self::Assoc) -> Self;
+   LL|       |}
+   LL|       |
+   LL|       |struct W<T>(T);
+   LL|       |
+   LL|       |impl<T: Foo> From<[T::Assoc; 1]> for W<T> {
+   LL|      0|    fn from(from: [T::Assoc; 1]) -> Self {
+   LL|      0|        let [item] = from;
+   LL|      0|        W(Foo::from(item))
+   LL|      0|    }
+   LL|       |}
+   LL|       |
+   LL|      1|fn main() {}
+
diff --git a/tests/coverage/generic-unused-impl.rs b/tests/coverage/generic-unused-impl.rs
new file mode 100644
index 00000000000..86231389450
--- /dev/null
+++ b/tests/coverage/generic-unused-impl.rs
@@ -0,0 +1,17 @@
+// Regression test for #135235.
+trait Foo {
+    type Assoc;
+
+    fn from(s: Self::Assoc) -> Self;
+}
+
+struct W<T>(T);
+
+impl<T: Foo> From<[T::Assoc; 1]> for W<T> {
+    fn from(from: [T::Assoc; 1]) -> Self {
+        let [item] = from;
+        W(Foo::from(item))
+    }
+}
+
+fn main() {}
diff --git a/tests/crashes/114317.rs b/tests/crashes/114317.rs
deleted file mode 100644
index 09fd2beeba8..00000000000
--- a/tests/crashes/114317.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ known-bug: #114317
-#![feature(generic_const_exprs)]
-
-struct A<const B: str = 1, C>;
-
-fn main() {}
diff --git a/tests/crashes/126182.rs b/tests/crashes/126182.rs
deleted file mode 100644
index 2219a6cb5fa..00000000000
--- a/tests/crashes/126182.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ known-bug: rust-lang/rust#126182
-
-#![feature(generic_const_exprs)]
-#![allow(incomplete_features)]
-
-struct Cond<const B: bool>;
-
-struct Thing<T = Cond<0>>(T);
-
-impl Thing {}
diff --git a/tests/debuginfo/strings-and-strs.rs b/tests/debuginfo/strings-and-strs.rs
index 3d6589db34b..543e74e1744 100644
--- a/tests/debuginfo/strings-and-strs.rs
+++ b/tests/debuginfo/strings-and-strs.rs
@@ -7,7 +7,7 @@
 // gdb-command:run
 
 // gdb-command:print plain_string
-// gdb-check:$1 = alloc::string::String {vec: alloc::vec::Vec<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {inner: alloc::raw_vec::RawVecInner<alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x[...]}, _marker: core::marker::PhantomData<u8>}, cap: alloc::raw_vec::Cap (5), alloc: alloc::alloc::Global}, _marker: core::marker::PhantomData<u8>}, len: 5}}
+// gdb-check:$1 = alloc::string::String {vec: alloc::vec::Vec<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {inner: alloc::raw_vec::RawVecInner<alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x[...]}, _marker: core::marker::PhantomData<u8>}, cap: core::num::niche_types::UsizeNoHighBit (5), alloc: alloc::alloc::Global}, _marker: core::marker::PhantomData<u8>}, len: 5}}
 
 // gdb-command:print plain_str
 // gdb-check:$2 = "Hello"
diff --git a/tests/mir-opt/inline/forced.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced.caller.ForceInline.panic-abort.diff
new file mode 100644
index 00000000000..f894f06e5a0
--- /dev/null
+++ b/tests/mir-opt/inline/forced.caller.ForceInline.panic-abort.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
++     scope 1 (inlined callee_forced) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = callee_forced() -> [return: bb1, unwind unreachable];
+-     }
+- 
+-     bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced.caller.ForceInline.panic-unwind.diff
new file mode 100644
index 00000000000..7b70fd66566
--- /dev/null
+++ b/tests/mir-opt/inline/forced.caller.ForceInline.panic-unwind.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
++     scope 1 (inlined callee_forced) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = callee_forced() -> [return: bb1, unwind continue];
+-     }
+- 
+-     bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced.rs b/tests/mir-opt/inline/forced.rs
new file mode 100644
index 00000000000..0447ef2e4d7
--- /dev/null
+++ b/tests/mir-opt/inline/forced.rs
@@ -0,0 +1,13 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ compile-flags: -Copt-level=0 --crate-type=lib
+#![feature(rustc_attrs)]
+
+#[rustc_force_inline]
+pub fn callee_forced() {}
+
+// EMIT_MIR forced.caller.ForceInline.diff
+pub fn caller() {
+    callee_forced();
+    // CHECK-LABEL: fn caller(
+    // CHECK: (inlined callee_forced)
+}
diff --git a/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-abort.diff
new file mode 100644
index 00000000000..42048bceef8
--- /dev/null
+++ b/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-abort.diff
@@ -0,0 +1,12 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> {async fn body of caller()} {
+      let mut _0: {async fn body of caller()};
+  
+      bb0: {
+          _0 = {coroutine@$DIR/forced_async.rs:10:19: 14:2 (#0)};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-unwind.diff
new file mode 100644
index 00000000000..42048bceef8
--- /dev/null
+++ b/tests/mir-opt/inline/forced_async.caller.ForceInline.panic-unwind.diff
@@ -0,0 +1,12 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> {async fn body of caller()} {
+      let mut _0: {async fn body of caller()};
+  
+      bb0: {
+          _0 = {coroutine@$DIR/forced_async.rs:10:19: 14:2 (#0)};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_async.rs b/tests/mir-opt/inline/forced_async.rs
new file mode 100644
index 00000000000..456f8fdc5ce
--- /dev/null
+++ b/tests/mir-opt/inline/forced_async.rs
@@ -0,0 +1,14 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ compile-flags: -Copt-level=0 --crate-type=lib
+//@ edition: 2021
+#![feature(rustc_attrs)]
+
+#[rustc_force_inline]
+pub fn callee_forced() {}
+
+// EMIT_MIR forced_async.caller.ForceInline.diff
+async fn caller() {
+    callee_forced();
+    // CHECK-LABEL: fn caller(
+    // CHECK: (inlined callee_forced)
+}
diff --git a/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-abort.diff
new file mode 100644
index 00000000000..def2375efd0
--- /dev/null
+++ b/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-abort.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller::{closure#0}` before ForceInline
++ // MIR for `caller::{closure#0}` after ForceInline
+  
+  fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure.rs:10:6: 10:8}) -> () {
+      let mut _0: ();
+      let _2: ();
++     scope 1 (inlined callee_forced) {
++     }
+  
+      bb0: {
+          StorageLive(_2);
+-         _2 = callee_forced() -> [return: bb1, unwind unreachable];
+-     }
+- 
+-     bb1: {
+          StorageDead(_2);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-unwind.diff
new file mode 100644
index 00000000000..8f50c20587d
--- /dev/null
+++ b/tests/mir-opt/inline/forced_closure.caller-{closure#0}.ForceInline.panic-unwind.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller::{closure#0}` before ForceInline
++ // MIR for `caller::{closure#0}` after ForceInline
+  
+  fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure.rs:10:6: 10:8}) -> () {
+      let mut _0: ();
+      let _2: ();
++     scope 1 (inlined callee_forced) {
++     }
+  
+      bb0: {
+          StorageLive(_2);
+-         _2 = callee_forced() -> [return: bb1, unwind continue];
+-     }
+- 
+-     bb1: {
+          StorageDead(_2);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_closure.rs b/tests/mir-opt/inline/forced_closure.rs
new file mode 100644
index 00000000000..a5590d6c7f0
--- /dev/null
+++ b/tests/mir-opt/inline/forced_closure.rs
@@ -0,0 +1,15 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ compile-flags: -Copt-level=0 --crate-type=lib
+#![feature(rustc_attrs)]
+
+#[rustc_force_inline]
+pub fn callee_forced() {}
+
+// EMIT_MIR forced_closure.caller-{closure#0}.ForceInline.diff
+pub fn caller() {
+    (|| {
+        callee_forced();
+        // CHECK-LABEL: fn caller::{closure#0}(
+        // CHECK: (inlined callee_forced)
+    })();
+}
diff --git a/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-abort.diff
new file mode 100644
index 00000000000..f894f06e5a0
--- /dev/null
+++ b/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-abort.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
++     scope 1 (inlined callee_forced) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = callee_forced() -> [return: bb1, unwind unreachable];
+-     }
+- 
+-     bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-unwind.diff
new file mode 100644
index 00000000000..7b70fd66566
--- /dev/null
+++ b/tests/mir-opt/inline/forced_dead_code.caller.ForceInline.panic-unwind.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
++     scope 1 (inlined callee_forced) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = callee_forced() -> [return: bb1, unwind continue];
+-     }
+- 
+-     bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_dead_code.rs b/tests/mir-opt/inline/forced_dead_code.rs
new file mode 100644
index 00000000000..832272cde7f
--- /dev/null
+++ b/tests/mir-opt/inline/forced_dead_code.rs
@@ -0,0 +1,17 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ compile-flags: -Copt-level=0 -Clink-dead-code
+#![feature(rustc_attrs)]
+
+#[rustc_force_inline]
+pub fn callee_forced() {}
+
+// EMIT_MIR forced_dead_code.caller.ForceInline.diff
+pub fn caller() {
+    callee_forced();
+    // CHECK-LABEL: fn caller(
+    // CHECK: (inlined callee_forced)
+}
+
+fn main() {
+    caller();
+}
diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr
index 7d384bc875f..d9742612bcf 100644
--- a/tests/ui/abi/c-zst.aarch64-darwin.stderr
+++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: 0,
                        },
                    },
                    mode: Ignore,
@@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: 0,
                    },
                },
                mode: Ignore,
diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr
index 7980710bab6..0e98b5f806b 100644
--- a/tests/ui/abi/c-zst.powerpc-linux.stderr
+++ b/tests/ui/abi/c-zst.powerpc-linux.stderr
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: 0,
                        },
                    },
                    mode: Indirect {
@@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: 0,
                    },
                },
                mode: Ignore,
diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr
index 7980710bab6..0e98b5f806b 100644
--- a/tests/ui/abi/c-zst.s390x-linux.stderr
+++ b/tests/ui/abi/c-zst.s390x-linux.stderr
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: 0,
                        },
                    },
                    mode: Indirect {
@@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: 0,
                    },
                },
                mode: Ignore,
diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr
index 7980710bab6..0e98b5f806b 100644
--- a/tests/ui/abi/c-zst.sparc64-linux.stderr
+++ b/tests/ui/abi/c-zst.sparc64-linux.stderr
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: 0,
                        },
                    },
                    mode: Indirect {
@@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: 0,
                    },
                },
                mode: Ignore,
diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr
index 7d384bc875f..d9742612bcf 100644
--- a/tests/ui/abi/c-zst.x86_64-linux.stderr
+++ b/tests/ui/abi/c-zst.x86_64-linux.stderr
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: 0,
                        },
                    },
                    mode: Ignore,
@@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: 0,
                    },
                },
                mode: Ignore,
diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
index 7980710bab6..0e98b5f806b 100644
--- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
+++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: 0,
                        },
                    },
                    mode: Indirect {
@@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: 0,
                    },
                },
                mode: Ignore,
diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs
index 565743bf978..6dbc3161464 100644
--- a/tests/ui/abi/debug.rs
+++ b/tests/ui/abi/debug.rs
@@ -1,4 +1,5 @@
 //@ normalize-stderr: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN"
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 //@ normalize-stderr: "(size): Size\([48] bytes\)" -> "$1: $$SOME_SIZE"
 //@ normalize-stderr: "(can_unwind): (true|false)" -> "$1: $$SOME_BOOL"
 //@ normalize-stderr: "(valid_range): 0\.\.=(4294967295|18446744073709551615)" -> "$1: $$FULL"
diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr
index aa51c42c58d..e550e5bfcf3 100644
--- a/tests/ui/abi/debug.stderr
+++ b/tests/ui/abi/debug.stderr
@@ -25,6 +25,7 @@ error: fn_abi_of(test) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Direct(
@@ -71,6 +72,7 @@ error: fn_abi_of(test) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Direct(
@@ -87,7 +89,7 @@ error: fn_abi_of(test) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:15:1
+  --> $DIR/debug.rs:16:1
    |
 LL | fn test(_x: u8) -> bool { true }
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,6 +130,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Direct(
@@ -165,6 +168,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Direct(
@@ -181,7 +185,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:18:1
+  --> $DIR/debug.rs:19:1
    |
 LL | type TestFnPtr = fn(bool) -> u8;
    | ^^^^^^^^^^^^^^
@@ -214,6 +218,7 @@ error: fn_abi_of(test_generic) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Direct(
@@ -248,6 +253,7 @@ error: fn_abi_of(test_generic) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Ignore,
@@ -257,13 +263,13 @@ error: fn_abi_of(test_generic) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:21:1
+  --> $DIR/debug.rs:22:1
    |
 LL | fn test_generic<T>(_x: *const T) { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
-  --> $DIR/debug.rs:24:1
+  --> $DIR/debug.rs:25:1
    |
 LL | const C: () = ();
    | ^^^^^^^^^^^
@@ -296,6 +302,7 @@ error: ABIs are not compatible
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Direct(
@@ -330,6 +337,7 @@ error: ABIs are not compatible
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Ignore,
@@ -366,6 +374,7 @@ error: ABIs are not compatible
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Direct(
@@ -400,6 +409,7 @@ error: ABIs are not compatible
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Ignore,
@@ -409,7 +419,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:40:1
+  --> $DIR/debug.rs:41:1
    |
 LL | type TestAbiNe = (fn(u8), fn(u32));
    | ^^^^^^^^^^^^^^
@@ -439,6 +449,7 @@ error: ABIs are not compatible
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Indirect {
@@ -477,6 +488,7 @@ error: ABIs are not compatible
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Ignore,
@@ -510,6 +522,7 @@ error: ABIs are not compatible
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Indirect {
@@ -548,6 +561,7 @@ error: ABIs are not compatible
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Ignore,
@@ -557,7 +571,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:43:1
+  --> $DIR/debug.rs:44:1
    |
 LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32]));
    | ^^^^^^^^^^^^^^^^^^^^
@@ -589,6 +603,7 @@ error: ABIs are not compatible
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Direct(
@@ -623,6 +638,7 @@ error: ABIs are not compatible
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Ignore,
@@ -659,6 +675,7 @@ error: ABIs are not compatible
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Direct(
@@ -693,6 +710,7 @@ error: ABIs are not compatible
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Ignore,
@@ -702,7 +720,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:46:1
+  --> $DIR/debug.rs:47:1
    |
 LL | type TestAbiNeFloat = (fn(f32), fn(u32));
    | ^^^^^^^^^^^^^^^^^^^
@@ -735,6 +753,7 @@ error: ABIs are not compatible
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Direct(
@@ -769,6 +788,7 @@ error: ABIs are not compatible
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Ignore,
@@ -805,6 +825,7 @@ error: ABIs are not compatible
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Direct(
@@ -839,6 +860,7 @@ error: ABIs are not compatible
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Ignore,
@@ -848,13 +870,13 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:50:1
+  --> $DIR/debug.rs:51:1
    |
 LL | type TestAbiNeSign = (fn(i32), fn(u32));
    | ^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/debug.rs:53:46
+  --> $DIR/debug.rs:54:46
    |
 LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str)));
    |                                              ^^^^^^^^^^ doesn't have a size known at compile-time
@@ -863,7 +885,7 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str)));
    = note: only the last element of a tuple may have a dynamically sized type
 
 error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
-  --> $DIR/debug.rs:28:5
+  --> $DIR/debug.rs:29:5
    |
 LL |     const C: () = ();
    |     ^^^^^^^^^^^
@@ -906,6 +928,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: $SEED,
                        },
                    },
                    mode: Direct(
@@ -942,6 +965,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: $SEED,
                    },
                },
                mode: Ignore,
@@ -951,7 +975,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:33:5
+  --> $DIR/debug.rs:34:5
    |
 LL |     fn assoc_test(&self) { }
    |     ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr
index 8e1791e27d2..781e9b2f4c9 100644
--- a/tests/ui/abi/sysv64-zst.stderr
+++ b/tests/ui/abi/sysv64-zst.stderr
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: 0,
                        },
                    },
                    mode: Ignore,
@@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: 0,
                    },
                },
                mode: Ignore,
diff --git a/tests/ui/abi/win64-zst.x86_64-linux.stderr b/tests/ui/abi/win64-zst.x86_64-linux.stderr
index 76d90670eb1..a28a59fdd8d 100644
--- a/tests/ui/abi/win64-zst.x86_64-linux.stderr
+++ b/tests/ui/abi/win64-zst.x86_64-linux.stderr
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: 0,
                        },
                    },
                    mode: Ignore,
@@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: 0,
                    },
                },
                mode: Ignore,
diff --git a/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr b/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr
index 7ee90e24744..cf0cc00c5ed 100644
--- a/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr
+++ b/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: 0,
                        },
                    },
                    mode: Indirect {
@@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: 0,
                    },
                },
                mode: Ignore,
diff --git a/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr b/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr
index 76d90670eb1..a28a59fdd8d 100644
--- a/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr
+++ b/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                            },
                            max_repr_align: None,
                            unadjusted_abi_align: $SOME_ALIGN,
+                           randomization_seed: 0,
                        },
                    },
                    mode: Ignore,
@@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: $SOME_ALIGN,
+                       randomization_seed: 0,
                    },
                },
                mode: Ignore,
diff --git a/tests/ui/coherence/auxiliary/pr_review_132289_2_lib.rs b/tests/ui/coherence/auxiliary/pr_review_132289_2_lib.rs
new file mode 100644
index 00000000000..4b79147dce1
--- /dev/null
+++ b/tests/ui/coherence/auxiliary/pr_review_132289_2_lib.rs
@@ -0,0 +1,37 @@
+pub type A = &'static [usize; 1];
+pub type B = &'static [usize; 100];
+
+pub trait Trait<P> {
+    type Assoc;
+}
+
+pub type Dyn<P> = dyn Trait<P, Assoc = A>;
+
+pub trait LocallyUnimplemented<P> {}
+
+impl<P, T: ?Sized> Trait<P> for T
+where
+    T: LocallyUnimplemented<P>,
+{
+    type Assoc = B;
+}
+
+trait MakeArray<Arr> {
+    fn make() -> &'static Arr;
+}
+impl<const N: usize> MakeArray<[usize; N]> for () {
+    fn make() -> &'static [usize; N] {
+        &[1337; N]
+    }
+}
+
+// it would be sound for this return type to be interpreted as being
+// either of A or B, if that's what a soundness fix for overlap of
+// dyn Trait's impls would entail
+
+// In this test, we check at the call-site that the interpretation
+// is consistent across crates in this specific scenario.
+pub fn function<P>() -> (<Dyn<P> as Trait<P>>::Assoc, usize) {
+    let val = <() as MakeArray<_>>::make();
+    (val, val.len())
+}
diff --git a/tests/ui/coherence/auxiliary/pr_review_132289_3_lib.rs b/tests/ui/coherence/auxiliary/pr_review_132289_3_lib.rs
new file mode 100644
index 00000000000..f90be3b2487
--- /dev/null
+++ b/tests/ui/coherence/auxiliary/pr_review_132289_3_lib.rs
@@ -0,0 +1,12 @@
+use std::ops::Index;
+
+pub trait Trait {
+    fn f(&self)
+    where
+        dyn Index<(), Output = ()>: Index<()>;
+    //  rustc (correctly) determines ^^^^^^^^ this bound to be true
+}
+
+pub fn call(x: &dyn Trait) {
+    x.f(); // so we can call `f`
+}
diff --git a/tests/ui/coherence/pr-review-132289-1.rs b/tests/ui/coherence/pr-review-132289-1.rs
new file mode 100644
index 00000000000..ab3ed9655e0
--- /dev/null
+++ b/tests/ui/coherence/pr-review-132289-1.rs
@@ -0,0 +1,52 @@
+// This is a regression test for issues that came up during review of the (closed)
+// PR #132289; this single-crate test case is
+// the first example from @steffahn during review.
+// https://github.com/rust-lang/rust/pull/132289#issuecomment-2564492153
+
+//@ check-pass
+
+type A = &'static [usize; 1];
+type B = &'static [usize; 100];
+
+type DynSomething = dyn Something<Assoc = A>;
+
+trait Super {
+    type Assoc;
+}
+impl Super for Foo {
+    type Assoc = A;
+}
+
+trait IsDynSomething {}
+impl IsDynSomething for DynSomething {}
+
+impl<T: ?Sized> Super for T
+where
+    T: IsDynSomething,
+{
+    type Assoc = B;
+}
+
+trait Something: Super {
+    fn method(&self) -> Self::Assoc;
+}
+
+struct Foo;
+impl Something for Foo {
+    fn method(&self) -> Self::Assoc {
+        &[1337]
+    }
+}
+
+fn main() {
+    let x = &Foo;
+    let y: &DynSomething = x;
+
+    // no surprises here
+    let _arr1: A = x.method();
+
+    // this (`_arr2`) can't ever become B either, soundly
+    let _arr2: A = y.method();
+    // there aren't any other arrays being defined anywhere in this
+    // test case, besides the length-1 one containing [1337]
+}
diff --git a/tests/ui/coherence/pr-review-132289-2.rs b/tests/ui/coherence/pr-review-132289-2.rs
new file mode 100644
index 00000000000..95ad86c61ff
--- /dev/null
+++ b/tests/ui/coherence/pr-review-132289-2.rs
@@ -0,0 +1,26 @@
+// This is a regression test for issues that came up during review of the (closed)
+// PR #132289; this 2-crate test case is adapted from
+// the second example from @steffahn during review.
+// https://github.com/rust-lang/rust/pull/132289#issuecomment-2564587796
+
+//@ run-pass
+//@ aux-build: pr_review_132289_2_lib.rs
+
+extern crate pr_review_132289_2_lib;
+
+use pr_review_132289_2_lib::{function, Dyn, LocallyUnimplemented};
+
+struct Param;
+
+impl LocallyUnimplemented<Param> for Dyn<Param> {}
+
+// it would be sound for `function::<Param>`'s return type to be
+// either of A or B, if that's what a soundness fix for overlap of
+// dyn Trait's impls would entail
+
+// In this test, we check at this call-site that the interpretation
+// is consistent with the function definition's body.
+fn main() {
+    let (arr, len) = function::<Param>();
+    assert_eq!(arr.len(), len);
+}
diff --git a/tests/ui/coherence/pr-review-132289-3.rs b/tests/ui/coherence/pr-review-132289-3.rs
new file mode 100644
index 00000000000..7e597baa6ec
--- /dev/null
+++ b/tests/ui/coherence/pr-review-132289-3.rs
@@ -0,0 +1,50 @@
+// This is a regression test for issues that came up during review of the (closed)
+// PR #132289; this 3-ish-crate (including std) test case is adapted from
+// the third example from @steffahn during review.
+// https://github.com/rust-lang/rust/pull/132289#issuecomment-2564599221
+
+//@ run-pass
+//@ check-run-results
+//@ aux-build: pr_review_132289_3_lib.rs
+
+extern crate pr_review_132289_3_lib;
+
+use std::ops::Index;
+
+use pr_review_132289_3_lib::{call, Trait};
+
+trait SubIndex<I>: Index<I> {}
+
+struct Param;
+
+trait Project {
+    type Ty: ?Sized;
+}
+impl Project for () {
+    type Ty = dyn SubIndex<Param, Output = ()>;
+}
+
+impl Index<Param> for <() as Project>::Ty {
+    type Output = ();
+
+    fn index(&self, _: Param) -> &() {
+        &()
+    }
+}
+
+struct Struct;
+
+impl Trait for Struct {
+    fn f(&self)
+    where
+        // higher-ranked to allow potentially-false bounds
+        for<'a> dyn Index<(), Output = ()>: Index<()>,
+        // after #132289 rustc used to believe this bound false
+    {
+        println!("hello!");
+    }
+}
+
+fn main() {
+    call(&Struct); // <- would segfault if the method `f` wasn't part of the vtable
+}
diff --git a/tests/ui/coherence/pr-review-132289-3.run.stdout b/tests/ui/coherence/pr-review-132289-3.run.stdout
new file mode 100644
index 00000000000..4effa19f4f7
--- /dev/null
+++ b/tests/ui/coherence/pr-review-132289-3.run.stdout
@@ -0,0 +1 @@
+hello!
diff --git a/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs b/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs
new file mode 100644
index 00000000000..1ed0965e1bd
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs
@@ -0,0 +1,22 @@
+//! ICE regression test for #114317 and #126182
+//! Type mismatches of literals cause errors int typeck,
+//! but those errors cannot be propagated to the various
+//! `lit_to_const` call sites. Now `lit_to_const` just delays
+//! a bug and produces an error constant on its own.
+
+#![feature(adt_const_params)]
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct A<const B: () = 1, C>(C);
+//~^ ERROR: generic parameters with a default must be trailing
+//~| ERROR: mismatched types
+
+struct Cond<const B: bool>;
+
+struct Thing<T = Cond<0>>(T);
+//~^ ERROR: mismatched types
+
+impl Thing {}
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr
new file mode 100644
index 00000000000..e4613e498b2
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.stderr
@@ -0,0 +1,21 @@
+error: generic parameters with a default must be trailing
+  --> $DIR/lit_type_mismatch.rs:11:16
+   |
+LL | struct A<const B: () = 1, C>(C);
+   |                ^
+
+error[E0308]: mismatched types
+  --> $DIR/lit_type_mismatch.rs:11:24
+   |
+LL | struct A<const B: () = 1, C>(C);
+   |                        ^ expected `()`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/lit_type_mismatch.rs:17:23
+   |
+LL | struct Thing<T = Cond<0>>(T);
+   |                       ^ expected `bool`, found integer
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr
index be92429e3ab..11a824ba73b 100644
--- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr
+++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr
@@ -1,27 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:29:21
-   |
-LL |   get_flag::<false, 0xFF>();
-   |                     ^^^^ expected `char`, found `u8`
-
-error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:31:14
-   |
-LL |   get_flag::<7, 'c'>();
-   |              ^ expected `bool`, found integer
-
-error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:33:14
-   |
-LL |   get_flag::<42, 0x5ad>();
-   |              ^^ expected `bool`, found integer
-
-error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:33:18
-   |
-LL |   get_flag::<42, 0x5ad>();
-   |                  ^^^^^ expected `char`, found `u8`
-
 error[E0080]: evaluation of constant value failed
   --> $DIR/invalid-patterns.rs:38:32
    |
@@ -56,6 +32,30 @@ error[E0080]: evaluation of constant value failed
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
    |                                                          ^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
+error[E0308]: mismatched types
+  --> $DIR/invalid-patterns.rs:29:21
+   |
+LL |   get_flag::<false, 0xFF>();
+   |                     ^^^^ expected `char`, found `u8`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-patterns.rs:31:14
+   |
+LL |   get_flag::<7, 'c'>();
+   |              ^ expected `bool`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-patterns.rs:33:14
+   |
+LL |   get_flag::<42, 0x5ad>();
+   |              ^^ expected `bool`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-patterns.rs:33:18
+   |
+LL |   get_flag::<42, 0x5ad>();
+   |                  ^^^^^ expected `char`, found `u8`
+
 error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0080, E0308.
diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr
index be92429e3ab..11a824ba73b 100644
--- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr
+++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr
@@ -1,27 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:29:21
-   |
-LL |   get_flag::<false, 0xFF>();
-   |                     ^^^^ expected `char`, found `u8`
-
-error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:31:14
-   |
-LL |   get_flag::<7, 'c'>();
-   |              ^ expected `bool`, found integer
-
-error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:33:14
-   |
-LL |   get_flag::<42, 0x5ad>();
-   |              ^^ expected `bool`, found integer
-
-error[E0308]: mismatched types
-  --> $DIR/invalid-patterns.rs:33:18
-   |
-LL |   get_flag::<42, 0x5ad>();
-   |                  ^^^^^ expected `char`, found `u8`
-
 error[E0080]: evaluation of constant value failed
   --> $DIR/invalid-patterns.rs:38:32
    |
@@ -56,6 +32,30 @@ error[E0080]: evaluation of constant value failed
 LL |   get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
    |                                                          ^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
+error[E0308]: mismatched types
+  --> $DIR/invalid-patterns.rs:29:21
+   |
+LL |   get_flag::<false, 0xFF>();
+   |                     ^^^^ expected `char`, found `u8`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-patterns.rs:31:14
+   |
+LL |   get_flag::<7, 'c'>();
+   |              ^ expected `bool`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-patterns.rs:33:14
+   |
+LL |   get_flag::<42, 0x5ad>();
+   |              ^^ expected `bool`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-patterns.rs:33:18
+   |
+LL |   get_flag::<42, 0x5ad>();
+   |                  ^^^^^ expected `char`, found `u8`
+
 error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0080, E0308.
diff --git a/tests/ui/coroutine/gen_block.e2024.stderr b/tests/ui/coroutine/gen_block.e2024.stderr
index 322259cf2f8..0491bdbc2e1 100644
--- a/tests/ui/coroutine/gen_block.e2024.stderr
+++ b/tests/ui/coroutine/gen_block.e2024.stderr
@@ -1,4 +1,4 @@
-error[E0658]: the `#[coroutines]` attribute is an experimental feature
+error[E0658]: the `#[coroutine]` attribute is an experimental feature
   --> $DIR/gen_block.rs:20:13
    |
 LL |     let _ = #[coroutine] || yield true;
@@ -8,7 +8,7 @@ LL |     let _ = #[coroutine] || yield true;
    = help: add `#![feature(coroutines)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: the `#[coroutines]` attribute is an experimental feature
+error[E0658]: the `#[coroutine]` attribute is an experimental feature
   --> $DIR/gen_block.rs:24:13
    |
 LL |     let _ = #[coroutine] || {};
diff --git a/tests/ui/coroutine/gen_block.none.stderr b/tests/ui/coroutine/gen_block.none.stderr
index 15123a49e48..43437793005 100644
--- a/tests/ui/coroutine/gen_block.none.stderr
+++ b/tests/ui/coroutine/gen_block.none.stderr
@@ -44,7 +44,7 @@ LL |     let _ = #[coroutine] || yield true;
    = help: add `#![feature(coroutines)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: the `#[coroutines]` attribute is an experimental feature
+error[E0658]: the `#[coroutine]` attribute is an experimental feature
   --> $DIR/gen_block.rs:20:13
    |
 LL |     let _ = #[coroutine] || yield true;
@@ -54,7 +54,7 @@ LL |     let _ = #[coroutine] || yield true;
    = help: add `#![feature(coroutines)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: the `#[coroutines]` attribute is an experimental feature
+error[E0658]: the `#[coroutine]` attribute is an experimental feature
   --> $DIR/gen_block.rs:24:13
    |
 LL |     let _ = #[coroutine] || {};
diff --git a/tests/ui/coroutine/gen_block.rs b/tests/ui/coroutine/gen_block.rs
index 6734de3b667..4494d654eeb 100644
--- a/tests/ui/coroutine/gen_block.rs
+++ b/tests/ui/coroutine/gen_block.rs
@@ -18,9 +18,9 @@ fn main() {
     //~^^ ERROR `yield` can only be used in
 
     let _ = #[coroutine] || yield true; //[none]~ ERROR yield syntax is experimental
-    //~^ ERROR `#[coroutines]` attribute is an experimental feature
+    //~^ ERROR `#[coroutine]` attribute is an experimental feature
     //~^^ ERROR yield syntax is experimental
 
     let _ = #[coroutine] || {};
-    //~^ ERROR `#[coroutines]` attribute is an experimental feature
+    //~^ ERROR `#[coroutine]` attribute is an experimental feature
 }
diff --git a/tests/ui/force-inlining/asm.rs b/tests/ui/force-inlining/asm.rs
new file mode 100644
index 00000000000..85014ffa515
--- /dev/null
+++ b/tests/ui/force-inlining/asm.rs
@@ -0,0 +1,68 @@
+//@ build-fail
+//@ compile-flags: --crate-type=lib --target thumbv4t-none-eabi
+//@ needs-llvm-components: arm
+
+// Checks that forced inlining won't mix asm with incompatible instruction sets.
+
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+#[lang = "freeze"]
+pub unsafe trait Freeze {}
+
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
+    0
+}
+
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! asm {
+    ("assembly template",
+        $(operands,)*
+        $(options($(option),*))?
+    ) => {
+        /* compiler built-in */
+    };
+}
+
+#[instruction_set(arm::a32)]
+#[rustc_force_inline]
+fn instruction_set_a32() {}
+
+#[instruction_set(arm::t32)]
+#[rustc_force_inline]
+fn instruction_set_t32() {}
+
+#[rustc_force_inline]
+fn instruction_set_default() {}
+
+#[rustc_force_inline]
+fn inline_always_and_using_inline_asm() {
+    unsafe { asm!("/* do nothing */") };
+}
+
+#[instruction_set(arm::t32)]
+pub fn t32() {
+    instruction_set_a32();
+//~^ ERROR `instruction_set_a32` could not be inlined into `t32` but is required to be inlined
+    instruction_set_t32();
+    instruction_set_default();
+    inline_always_and_using_inline_asm();
+//~^ ERROR `inline_always_and_using_inline_asm` could not be inlined into `t32` but is required to be inlined
+}
+
+pub fn default() {
+    instruction_set_a32();
+//~^ ERROR `instruction_set_a32` could not be inlined into `default` but is required to be inlined
+    instruction_set_t32();
+//~^ ERROR `instruction_set_t32` could not be inlined into `default` but is required to be inlined
+    instruction_set_default();
+    inline_always_and_using_inline_asm();
+}
diff --git a/tests/ui/force-inlining/asm.stderr b/tests/ui/force-inlining/asm.stderr
new file mode 100644
index 00000000000..ef04688965b
--- /dev/null
+++ b/tests/ui/force-inlining/asm.stderr
@@ -0,0 +1,34 @@
+error: `instruction_set_a32` could not be inlined into `t32` but is required to be inlined
+  --> $DIR/asm.rs:53:5
+   |
+LL |     instruction_set_a32();
+   |     ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_a32` called here
+   |
+   = note: could not be inlined due to: incompatible instruction set
+
+error: `inline_always_and_using_inline_asm` could not be inlined into `t32` but is required to be inlined
+  --> $DIR/asm.rs:57:5
+   |
+LL |     inline_always_and_using_inline_asm();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...`inline_always_and_using_inline_asm` called here
+   |
+   = note: could not be inlined due to: cannot move inline-asm across instruction sets
+
+error: `instruction_set_a32` could not be inlined into `default` but is required to be inlined
+  --> $DIR/asm.rs:62:5
+   |
+LL |     instruction_set_a32();
+   |     ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_a32` called here
+   |
+   = note: could not be inlined due to: incompatible instruction set
+
+error: `instruction_set_t32` could not be inlined into `default` but is required to be inlined
+  --> $DIR/asm.rs:64:5
+   |
+LL |     instruction_set_t32();
+   |     ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_t32` called here
+   |
+   = note: could not be inlined due to: incompatible instruction set
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/force-inlining/auxiliary/callees.rs b/tests/ui/force-inlining/auxiliary/callees.rs
new file mode 100644
index 00000000000..7468b8f1098
--- /dev/null
+++ b/tests/ui/force-inlining/auxiliary/callees.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: --crate-type=lib
+#![feature(rustc_attrs)]
+
+#[rustc_force_inline = "the test requires it"]
+pub fn forced_with_reason() {
+}
+
+#[rustc_force_inline]
+pub fn forced() {
+}
diff --git a/tests/ui/force-inlining/cast.rs b/tests/ui/force-inlining/cast.rs
new file mode 100644
index 00000000000..8f51ec83977
--- /dev/null
+++ b/tests/ui/force-inlining/cast.rs
@@ -0,0 +1,25 @@
+//@ check-fail
+//@ compile-flags: --crate-type=lib
+#![allow(internal_features)]
+#![feature(rustc_attrs)]
+
+#[rustc_force_inline]
+pub fn callee(x: isize) -> usize { unimplemented!() }
+
+fn a() {
+    let _: fn(isize) -> usize = callee;
+//~^ ERROR cannot coerce functions which must be inlined to function pointers
+}
+
+fn b() {
+    let _ = callee as fn(isize) -> usize;
+//~^ ERROR non-primitive cast
+}
+
+fn c() {
+    let _: [fn(isize) -> usize; 2] = [
+        callee,
+//~^ ERROR cannot coerce functions which must be inlined to function pointers
+        callee,
+    ];
+}
diff --git a/tests/ui/force-inlining/cast.stderr b/tests/ui/force-inlining/cast.stderr
new file mode 100644
index 00000000000..116919e5fe7
--- /dev/null
+++ b/tests/ui/force-inlining/cast.stderr
@@ -0,0 +1,40 @@
+error[E0308]: cannot coerce functions which must be inlined to function pointers
+  --> $DIR/cast.rs:10:33
+   |
+LL |     let _: fn(isize) -> usize = callee;
+   |            ------------------   ^^^^^^ cannot coerce functions which must be inlined to function pointers
+   |            |
+   |            expected due to this
+   |
+   = note: expected fn pointer `fn(_) -> _`
+                 found fn item `fn(_) -> _ {callee}`
+   = note: fn items are distinct from fn pointers
+help: consider casting to a fn pointer
+   |
+LL |     let _: fn(isize) -> usize = callee as fn(isize) -> usize;
+   |                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0605]: non-primitive cast: `fn(isize) -> usize {callee}` as `fn(isize) -> usize`
+  --> $DIR/cast.rs:15:13
+   |
+LL |     let _ = callee as fn(isize) -> usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
+
+error[E0308]: cannot coerce functions which must be inlined to function pointers
+  --> $DIR/cast.rs:21:9
+   |
+LL |         callee,
+   |         ^^^^^^ cannot coerce functions which must be inlined to function pointers
+   |
+   = note: expected fn pointer `fn(_) -> _`
+                 found fn item `fn(_) -> _ {callee}`
+   = note: fn items are distinct from fn pointers
+help: consider casting to a fn pointer
+   |
+LL |         callee as fn(isize) -> usize,
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0605.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/force-inlining/cross-crate.rs b/tests/ui/force-inlining/cross-crate.rs
new file mode 100644
index 00000000000..a3f0c2c873e
--- /dev/null
+++ b/tests/ui/force-inlining/cross-crate.rs
@@ -0,0 +1,13 @@
+//@ aux-build:callees.rs
+//@ build-pass
+//@ compile-flags: --crate-type=lib
+
+extern crate callees;
+
+// Test that forced inlining across crates works as expected.
+
+pub fn caller() {
+    callees::forced();
+
+    callees::forced_with_reason();
+}
diff --git a/tests/ui/force-inlining/deny-async.rs b/tests/ui/force-inlining/deny-async.rs
new file mode 100644
index 00000000000..bdf6271bd2a
--- /dev/null
+++ b/tests/ui/force-inlining/deny-async.rs
@@ -0,0 +1,24 @@
+//@ check-fail
+//@ compile-flags: --crate-type=lib
+//@ edition: 2021
+#![allow(internal_features)]
+#![feature(rustc_attrs)]
+
+// Test that forced inlining into async functions w/ errors works as expected.
+
+#[rustc_no_mir_inline]
+#[rustc_force_inline]
+//~^ ERROR `callee` is incompatible with `#[rustc_force_inline]`
+pub fn callee() {
+}
+
+#[rustc_no_mir_inline]
+#[rustc_force_inline = "the test requires it"]
+//~^ ERROR `callee_justified` is incompatible with `#[rustc_force_inline]`
+pub fn callee_justified() {
+}
+
+async fn async_caller() {
+    callee();
+    callee_justified();
+}
diff --git a/tests/ui/force-inlining/deny-async.stderr b/tests/ui/force-inlining/deny-async.stderr
new file mode 100644
index 00000000000..302ca419071
--- /dev/null
+++ b/tests/ui/force-inlining/deny-async.stderr
@@ -0,0 +1,24 @@
+error: `callee` is incompatible with `#[rustc_force_inline]`
+  --> $DIR/deny-async.rs:10:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | pub fn callee() {
+   | --------------- `callee` defined here
+   |
+   = note: incompatible due to: #[rustc_no_mir_inline]
+
+error: `callee_justified` is incompatible with `#[rustc_force_inline]`
+  --> $DIR/deny-async.rs:16:1
+   |
+LL | #[rustc_force_inline = "the test requires it"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | pub fn callee_justified() {
+   | ------------------------- `callee_justified` defined here
+   |
+   = note: incompatible due to: #[rustc_no_mir_inline]
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/force-inlining/deny-closure.rs b/tests/ui/force-inlining/deny-closure.rs
new file mode 100644
index 00000000000..31314c450fc
--- /dev/null
+++ b/tests/ui/force-inlining/deny-closure.rs
@@ -0,0 +1,25 @@
+//@ check-fail
+//@ compile-flags: --crate-type=lib
+#![allow(internal_features)]
+#![feature(rustc_attrs)]
+
+// Test that forced inlining into closures w/ errors works as expected.
+
+#[rustc_no_mir_inline]
+#[rustc_force_inline]
+//~^ ERROR `callee` is incompatible with `#[rustc_force_inline]`
+pub fn callee() {
+}
+
+#[rustc_no_mir_inline]
+#[rustc_force_inline = "the test requires it"]
+//~^ ERROR `callee_justified` is incompatible with `#[rustc_force_inline]`
+pub fn callee_justified() {
+}
+
+pub fn caller() {
+    (|| {
+        callee();
+        callee_justified();
+    })();
+}
diff --git a/tests/ui/force-inlining/deny-closure.stderr b/tests/ui/force-inlining/deny-closure.stderr
new file mode 100644
index 00000000000..e657a295420
--- /dev/null
+++ b/tests/ui/force-inlining/deny-closure.stderr
@@ -0,0 +1,24 @@
+error: `callee` is incompatible with `#[rustc_force_inline]`
+  --> $DIR/deny-closure.rs:9:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | pub fn callee() {
+   | --------------- `callee` defined here
+   |
+   = note: incompatible due to: #[rustc_no_mir_inline]
+
+error: `callee_justified` is incompatible with `#[rustc_force_inline]`
+  --> $DIR/deny-closure.rs:15:1
+   |
+LL | #[rustc_force_inline = "the test requires it"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | pub fn callee_justified() {
+   | ------------------------- `callee_justified` defined here
+   |
+   = note: incompatible due to: #[rustc_no_mir_inline]
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/force-inlining/deny.rs b/tests/ui/force-inlining/deny.rs
new file mode 100644
index 00000000000..7712f5f50f3
--- /dev/null
+++ b/tests/ui/force-inlining/deny.rs
@@ -0,0 +1,23 @@
+//@ check-fail
+//@ compile-flags: --crate-type=lib
+#![allow(internal_features)]
+#![feature(rustc_attrs)]
+
+// Test that forced inlining w/ errors works as expected.
+
+#[rustc_no_mir_inline]
+#[rustc_force_inline]
+//~^ ERROR `callee` is incompatible with `#[rustc_force_inline]`
+pub fn callee() {
+}
+
+#[rustc_no_mir_inline]
+#[rustc_force_inline = "the test requires it"]
+//~^ ERROR `callee_justified` is incompatible with `#[rustc_force_inline]`
+pub fn callee_justified() {
+}
+
+pub fn caller() {
+    callee();
+    callee_justified();
+}
diff --git a/tests/ui/force-inlining/deny.stderr b/tests/ui/force-inlining/deny.stderr
new file mode 100644
index 00000000000..c276fa28ba8
--- /dev/null
+++ b/tests/ui/force-inlining/deny.stderr
@@ -0,0 +1,24 @@
+error: `callee` is incompatible with `#[rustc_force_inline]`
+  --> $DIR/deny.rs:9:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | pub fn callee() {
+   | --------------- `callee` defined here
+   |
+   = note: incompatible due to: #[rustc_no_mir_inline]
+
+error: `callee_justified` is incompatible with `#[rustc_force_inline]`
+  --> $DIR/deny.rs:15:1
+   |
+LL | #[rustc_force_inline = "the test requires it"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | pub fn callee_justified() {
+   | ------------------------- `callee_justified` defined here
+   |
+   = note: incompatible due to: #[rustc_no_mir_inline]
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/force-inlining/early-deny.rs b/tests/ui/force-inlining/early-deny.rs
new file mode 100644
index 00000000000..99b03a4e0e2
--- /dev/null
+++ b/tests/ui/force-inlining/early-deny.rs
@@ -0,0 +1,21 @@
+//@ check-fail
+//@ compile-flags: --crate-type=lib
+#![feature(c_variadic)]
+#![feature(rustc_attrs)]
+
+#[rustc_no_mir_inline]
+#[rustc_force_inline]
+//~^ ERROR `rustc_attr` is incompatible with `#[rustc_force_inline]`
+pub fn rustc_attr() {
+}
+
+#[cold]
+#[rustc_force_inline]
+//~^ ERROR `cold` is incompatible with `#[rustc_force_inline]`
+pub fn cold() {
+}
+
+#[rustc_force_inline]
+//~^ ERROR `variadic` is incompatible with `#[rustc_force_inline]`
+pub unsafe extern "C" fn variadic(args: ...) {
+}
diff --git a/tests/ui/force-inlining/early-deny.stderr b/tests/ui/force-inlining/early-deny.stderr
new file mode 100644
index 00000000000..abee66fd293
--- /dev/null
+++ b/tests/ui/force-inlining/early-deny.stderr
@@ -0,0 +1,35 @@
+error: `rustc_attr` is incompatible with `#[rustc_force_inline]`
+  --> $DIR/early-deny.rs:7:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | pub fn rustc_attr() {
+   | ------------------- `rustc_attr` defined here
+   |
+   = note: incompatible due to: #[rustc_no_mir_inline]
+
+error: `cold` is incompatible with `#[rustc_force_inline]`
+  --> $DIR/early-deny.rs:13:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | pub fn cold() {
+   | ------------- `cold` defined here
+   |
+   = note: incompatible due to: cold
+
+error: `variadic` is incompatible with `#[rustc_force_inline]`
+  --> $DIR/early-deny.rs:18:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | pub unsafe extern "C" fn variadic(args: ...) {
+   | -------------------------------------------- `variadic` defined here
+   |
+   = note: incompatible due to: C variadic
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/force-inlining/gate.rs b/tests/ui/force-inlining/gate.rs
new file mode 100644
index 00000000000..d6a01a74a44
--- /dev/null
+++ b/tests/ui/force-inlining/gate.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: --crate-type=lib
+#![allow(internal_features)]
+
+#[rustc_force_inline]
+//~^ ERROR #![rustc_force_inline] forces a free function to be inlined
+pub fn bare() {
+}
+
+#[rustc_force_inline = "the test requires it"]
+//~^ ERROR #![rustc_force_inline] forces a free function to be inlined
+pub fn justified() {
+}
diff --git a/tests/ui/force-inlining/gate.stderr b/tests/ui/force-inlining/gate.stderr
new file mode 100644
index 00000000000..e3973a08c23
--- /dev/null
+++ b/tests/ui/force-inlining/gate.stderr
@@ -0,0 +1,21 @@
+error[E0658]: #![rustc_force_inline] forces a free function to be inlined
+  --> $DIR/gate.rs:4:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: #![rustc_force_inline] forces a free function to be inlined
+  --> $DIR/gate.rs:9:1
+   |
+LL | #[rustc_force_inline = "the test requires it"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/force-inlining/invalid.rs b/tests/ui/force-inlining/invalid.rs
new file mode 100644
index 00000000000..7574078b245
--- /dev/null
+++ b/tests/ui/force-inlining/invalid.rs
@@ -0,0 +1,164 @@
+//@ edition: 2024
+#![allow(internal_features, unused_imports, unused_macros)]
+#![feature(extern_types)]
+#![feature(gen_blocks)]
+#![feature(rustc_attrs)]
+#![feature(stmt_expr_attributes)]
+#![feature(trait_alias)]
+
+// Test that invalid force inlining attributes error as expected.
+
+#[rustc_force_inline("foo")]
+//~^ ERROR malformed `rustc_force_inline` attribute input
+pub fn forced1() {
+}
+
+#[rustc_force_inline(bar, baz)]
+//~^ ERROR malformed `rustc_force_inline` attribute input
+pub fn forced2() {
+}
+
+#[rustc_force_inline(2)]
+//~^ ERROR malformed `rustc_force_inline` attribute input
+pub fn forced3() {
+}
+
+#[rustc_force_inline = 2]
+//~^ ERROR malformed `rustc_force_inline` attribute input
+pub fn forced4() {
+}
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+extern crate std as other_std;
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+use std::collections::HashMap;
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+static _FOO: &'static str = "FOO";
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+const _BAR: u32 = 3;
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+mod foo { }
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+unsafe extern "C" {
+    #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+    static X: &'static u32;
+
+    #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+    type Y;
+
+    #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+    fn foo();
+}
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+type Foo = u32;
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+enum Bar<#[rustc_force_inline] T> {
+//~^ ERROR attribute should be applied to a function
+    #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+    Baz(std::marker::PhantomData<T>),
+}
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+struct Qux {
+    #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+    field: u32,
+}
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+union FooBar {
+    x: u32,
+    y: u32,
+}
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+trait FooBaz {
+    #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+    type Foo;
+    #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+    const Bar: i32;
+
+    #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+    fn foo() {}
+}
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+trait FooQux = FooBaz;
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+impl<T> Bar<T> {
+    #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+    fn foo() {}
+}
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+impl<T> FooBaz for Bar<T> {
+    type Foo = u32;
+    const Bar: i32 = 3;
+}
+
+#[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+macro_rules! barqux { ($foo:tt) => { $foo }; }
+
+fn barqux(#[rustc_force_inline] _x: u32) {}
+//~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
+//~^^ ERROR attribute should be applied to a function
+
+#[rustc_force_inline]
+//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function
+async fn async_foo() {}
+
+#[rustc_force_inline]
+//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function
+gen fn gen_foo() {}
+
+#[rustc_force_inline]
+//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function
+async gen fn async_gen_foo() {}
+
+fn main() {
+    let _x = #[rustc_force_inline] || { };
+//~^ ERROR attribute should be applied to a function
+    let _y = #[rustc_force_inline] 3 + 4;
+//~^ ERROR attribute should be applied to a function
+    #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+    let _z = 3;
+
+    match _z {
+        #[rustc_force_inline]
+//~^ ERROR attribute should be applied to a function
+        1 => (),
+        _ => (),
+    }
+}
diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr
new file mode 100644
index 00000000000..5d280124129
--- /dev/null
+++ b/tests/ui/force-inlining/invalid.stderr
@@ -0,0 +1,377 @@
+error: malformed `rustc_force_inline` attribute input
+  --> $DIR/invalid.rs:11:1
+   |
+LL | #[rustc_force_inline("foo")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: the following are the possible correct uses
+   |
+LL | #[rustc_force_inline = "reason"]
+   |
+LL | #[rustc_force_inline]
+   |
+
+error: malformed `rustc_force_inline` attribute input
+  --> $DIR/invalid.rs:16:1
+   |
+LL | #[rustc_force_inline(bar, baz)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: the following are the possible correct uses
+   |
+LL | #[rustc_force_inline = "reason"]
+   |
+LL | #[rustc_force_inline]
+   |
+
+error: malformed `rustc_force_inline` attribute input
+  --> $DIR/invalid.rs:21:1
+   |
+LL | #[rustc_force_inline(2)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: the following are the possible correct uses
+   |
+LL | #[rustc_force_inline = "reason"]
+   |
+LL | #[rustc_force_inline]
+   |
+
+error: malformed `rustc_force_inline` attribute input
+  --> $DIR/invalid.rs:26:1
+   |
+LL | #[rustc_force_inline = 2]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: the following are the possible correct uses
+   |
+LL | #[rustc_force_inline = "reason"]
+   |
+LL | #[rustc_force_inline]
+   |
+
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
+  --> $DIR/invalid.rs:133:11
+   |
+LL | fn barqux(#[rustc_force_inline] _x: u32) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:31:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | extern crate std as other_std;
+   | ------------------------------ not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:35:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | use std::collections::HashMap;
+   | ------------------------------ not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:39:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | static _FOO: &'static str = "FOO";
+   | ---------------------------------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:43:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | const _BAR: u32 = 3;
+   | -------------------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:47:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | mod foo { }
+   | ----------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:51:1
+   |
+LL |   #[rustc_force_inline]
+   |   ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | / unsafe extern "C" {
+LL | |     #[rustc_force_inline]
+LL | |
+LL | |     static X: &'static u32;
+...  |
+LL | |     fn foo();
+LL | | }
+   | |_- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:67:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | type Foo = u32;
+   | --------------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:71:1
+   |
+LL |   #[rustc_force_inline]
+   |   ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | / enum Bar<#[rustc_force_inline] T> {
+LL | |
+LL | |     #[rustc_force_inline]
+...  |
+LL | | }
+   | |_- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:73:10
+   |
+LL | enum Bar<#[rustc_force_inline] T> {
+   |          ^^^^^^^^^^^^^^^^^^^^^ - not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:75:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     Baz(std::marker::PhantomData<T>),
+   |     -------------------------------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:80:1
+   |
+LL |   #[rustc_force_inline]
+   |   ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | / struct Qux {
+LL | |     #[rustc_force_inline]
+LL | |
+LL | |     field: u32,
+LL | | }
+   | |_- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:83:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     field: u32,
+   |     ---------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:88:1
+   |
+LL |   #[rustc_force_inline]
+   |   ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | / union FooBar {
+LL | |     x: u32,
+LL | |     y: u32,
+LL | | }
+   | |_- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:95:1
+   |
+LL |   #[rustc_force_inline]
+   |   ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | / trait FooBaz {
+LL | |     #[rustc_force_inline]
+LL | |
+LL | |     type Foo;
+...  |
+LL | |     fn foo() {}
+LL | | }
+   | |_- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:110:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | trait FooQux = FooBaz;
+   | ---------------------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:114:1
+   |
+LL |   #[rustc_force_inline]
+   |   ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | / impl<T> Bar<T> {
+LL | |     #[rustc_force_inline]
+LL | |
+LL | |     fn foo() {}
+LL | | }
+   | |_- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:122:1
+   |
+LL |   #[rustc_force_inline]
+   |   ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | / impl<T> FooBaz for Bar<T> {
+LL | |     type Foo = u32;
+LL | |     const Bar: i32 = 3;
+LL | | }
+   | |_- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:129:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | macro_rules! barqux { ($foo:tt) => { $foo }; }
+   | ---------------------------------------------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:133:11
+   |
+LL | fn barqux(#[rustc_force_inline] _x: u32) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^--------
+   |           |
+   |           not a function definition
+
+error: attribute cannot be applied to a `async`, `gen` or `async gen` function
+  --> $DIR/invalid.rs:137:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | async fn async_foo() {}
+   | -------------------- `async`, `gen` or `async gen` function
+
+error: attribute cannot be applied to a `async`, `gen` or `async gen` function
+  --> $DIR/invalid.rs:141:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | gen fn gen_foo() {}
+   | ---------------- `async`, `gen` or `async gen` function
+
+error: attribute cannot be applied to a `async`, `gen` or `async gen` function
+  --> $DIR/invalid.rs:145:1
+   |
+LL | #[rustc_force_inline]
+   | ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | async gen fn async_gen_foo() {}
+   | ---------------------------- `async`, `gen` or `async gen` function
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:150:14
+   |
+LL |     let _x = #[rustc_force_inline] || { };
+   |              ^^^^^^^^^^^^^^^^^^^^^ ------ not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:152:14
+   |
+LL |     let _y = #[rustc_force_inline] 3 + 4;
+   |              ^^^^^^^^^^^^^^^^^^^^^ - not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:154:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     let _z = 3;
+   |     ----------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:159:9
+   |
+LL |         #[rustc_force_inline]
+   |         ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |         1 => (),
+   |         ------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:98:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     type Foo;
+   |     --------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:101:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     const Bar: i32;
+   |     --------------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:105:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     fn foo() {}
+   |     ----------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:117:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     fn foo() {}
+   |     ----------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:54:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     static X: &'static u32;
+   |     ----------------------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:58:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     type Y;
+   |     ------- not a function definition
+
+error: attribute should be applied to a function
+  --> $DIR/invalid.rs:62:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     fn foo();
+   |     --------- not a function definition
+
+error: aborting due to 38 previous errors
+
diff --git a/tests/ui/force-inlining/shims.rs b/tests/ui/force-inlining/shims.rs
new file mode 100644
index 00000000000..03b7d07cda3
--- /dev/null
+++ b/tests/ui/force-inlining/shims.rs
@@ -0,0 +1,9 @@
+//@ build-pass
+#![allow(internal_features)]
+#![feature(rustc_attrs)]
+
+#[rustc_force_inline]
+fn f() {}
+fn g<T: FnOnce()>(t: T) { t(); }
+
+fn main() { g(f); }
diff --git a/tests/ui/inline-const/collect-scopes-in-pat.rs b/tests/ui/inline-const/collect-scopes-in-pat.rs
new file mode 100644
index 00000000000..024fde53741
--- /dev/null
+++ b/tests/ui/inline-const/collect-scopes-in-pat.rs
@@ -0,0 +1,16 @@
+// @compile-flags: -Zlint-mir
+//@ check-pass
+
+#![feature(inline_const_pat)]
+
+fn main() {
+    match 1 {
+        const {
+            || match 0 {
+                x => 0,
+            };
+            0
+        } => (),
+        _ => (),
+    }
+}
diff --git a/tests/ui/issues/issue-25901.rs b/tests/ui/issues/issue-25901.rs
index eae038c71a0..bfcee1ac503 100644
--- a/tests/ui/issues/issue-25901.rs
+++ b/tests/ui/issues/issue-25901.rs
@@ -2,7 +2,7 @@ struct A;
 struct B;
 
 static S: &'static B = &A;
-//~^ ERROR cannot call conditionally-const method
+//~^ ERROR cannot perform conditionally-const deref coercion
 
 use std::ops::Deref;
 
diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/issues/issue-25901.stderr
index 655a8b78c6a..a954f38af83 100644
--- a/tests/ui/issues/issue-25901.stderr
+++ b/tests/ui/issues/issue-25901.stderr
@@ -1,9 +1,16 @@
-error[E0658]: cannot call conditionally-const method `<A as Deref>::deref` in statics
+error[E0658]: cannot perform conditionally-const deref coercion on `A` in statics
   --> $DIR/issue-25901.rs:4:24
    |
 LL | static S: &'static B = &A;
    |                        ^^
    |
+   = note: attempting to deref into `B`
+note: deref defined here
+  --> $DIR/issue-25901.rs:10:5
+   |
+LL |     type Target = B;
+   |     ^^^^^^^^^^^
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs
index 5602c4e711f..81dc7285254 100644
--- a/tests/ui/layout/debug.rs
+++ b/tests/ui/layout/debug.rs
@@ -1,4 +1,5 @@
 //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 #![feature(never_type, rustc_attrs, type_alias_impl_trait, repr_simd)]
 #![crate_type = "lib"]
 
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
index bd31665dac1..1fc55511384 100644
--- a/tests/ui/layout/debug.stderr
+++ b/tests/ui/layout/debug.stderr
@@ -1,5 +1,5 @@
 error: unions cannot have zero fields
-  --> $DIR/debug.rs:82:1
+  --> $DIR/debug.rs:83:1
    |
 LL | union EmptyUnion {}
    | ^^^^^^^^^^^^^^^^^^^
@@ -61,6 +61,7 @@ error: layout_of(E) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(12 bytes),
@@ -87,13 +88,15 @@ error: layout_of(E) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:7:1
+  --> $DIR/debug.rs:8:1
    |
 LL | enum E { Foo, Bar(!, i32, i32) }
    | ^^^^^^
@@ -138,8 +141,9 @@ error: layout_of(S) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:10:1
+  --> $DIR/debug.rs:11:1
    |
 LL | struct S { f1: i32, f2: (), f3: i32 }
    | ^^^^^^^^
@@ -162,8 +166,9 @@ error: layout_of(U) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:13:1
+  --> $DIR/debug.rs:14:1
    |
 LL | union U { f1: (i32, i32), f3: i32 }
    | ^^^^^^^
@@ -255,6 +260,7 @@ error: layout_of(Result<i32, i32>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(8 bytes),
@@ -292,13 +298,15 @@ error: layout_of(Result<i32, i32>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:16:1
+  --> $DIR/debug.rs:17:1
    |
 LL | type Test = Result<i32, i32>;
    | ^^^^^^^^^
@@ -325,8 +333,9 @@ error: layout_of(i32) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:19:1
+  --> $DIR/debug.rs:20:1
    |
 LL | type T = impl std::fmt::Debug;
    | ^^^^^^
@@ -349,8 +358,9 @@ error: layout_of(V) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(2 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:25:1
+  --> $DIR/debug.rs:26:1
    |
 LL | pub union V {
    | ^^^^^^^^^^^
@@ -373,8 +383,9 @@ error: layout_of(W) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(2 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:31:1
+  --> $DIR/debug.rs:32:1
    |
 LL | pub union W {
    | ^^^^^^^^^^^
@@ -397,8 +408,9 @@ error: layout_of(Y) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(2 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:37:1
+  --> $DIR/debug.rs:38:1
    |
 LL | pub union Y {
    | ^^^^^^^^^^^
@@ -421,8 +433,9 @@ error: layout_of(P1) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:44:1
+  --> $DIR/debug.rs:45:1
    |
 LL | union P1 { x: u32 }
    | ^^^^^^^^
@@ -445,8 +458,9 @@ error: layout_of(P2) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:48:1
+  --> $DIR/debug.rs:49:1
    |
 LL | union P2 { x: (u32, u32) }
    | ^^^^^^^^
@@ -469,8 +483,9 @@ error: layout_of(P3) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:56:1
+  --> $DIR/debug.rs:57:1
    |
 LL | union P3 { x: F32x4 }
    | ^^^^^^^^
@@ -493,8 +508,9 @@ error: layout_of(P4) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:60:1
+  --> $DIR/debug.rs:61:1
    |
 LL | union P4 { x: E }
    | ^^^^^^^^
@@ -522,8 +538,9 @@ error: layout_of(P5) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:64:1
+  --> $DIR/debug.rs:65:1
    |
 LL | union P5 { zst: [u16; 0], byte: u8 }
    | ^^^^^^^^
@@ -551,20 +568,21 @@ error: layout_of(MaybeUninit<u8>) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/debug.rs:67:1
+  --> $DIR/debug.rs:68:1
    |
 LL | type X = std::mem::MaybeUninit<u8>;
    | ^^^^^^
 
 error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
-  --> $DIR/debug.rs:70:1
+  --> $DIR/debug.rs:71:1
    |
 LL | const C: () = ();
    | ^^^^^^^^^^^
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/debug.rs:78:19
+  --> $DIR/debug.rs:79:19
    |
 LL | type Impossible = (str, str);
    |                   ^^^^^^^^^^ doesn't have a size known at compile-time
@@ -573,13 +591,13 @@ LL | type Impossible = (str, str);
    = note: only the last element of a tuple may have a dynamically sized type
 
 error: the type `EmptyUnion` has an unknown layout
-  --> $DIR/debug.rs:82:1
+  --> $DIR/debug.rs:83:1
    |
 LL | union EmptyUnion {}
    | ^^^^^^^^^^^^^^^^
 
 error: `#[rustc_layout]` can only be applied to `struct`/`enum`/`union` declarations and type aliases
-  --> $DIR/debug.rs:74:5
+  --> $DIR/debug.rs:75:5
    |
 LL |     const C: () = ();
    |     ^^^^^^^^^^^
diff --git a/tests/ui/layout/hexagon-enum.rs b/tests/ui/layout/hexagon-enum.rs
index e3a5c53671d..5fa12e479e7 100644
--- a/tests/ui/layout/hexagon-enum.rs
+++ b/tests/ui/layout/hexagon-enum.rs
@@ -1,4 +1,5 @@
 //@ compile-flags: --target hexagon-unknown-linux-musl
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 //@ needs-llvm-components: hexagon
 //
 // Verify that the hexagon targets implement the repr(C) for enums correctly.
diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr
index 59fe667923f..96f0a8c8740 100644
--- a/tests/ui/layout/hexagon-enum.stderr
+++ b/tests/ui/layout/hexagon-enum.stderr
@@ -61,13 +61,15 @@ error: layout_of(A) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/hexagon-enum.rs:16:1
+  --> $DIR/hexagon-enum.rs:17:1
    |
 LL | enum A { Apple }
    | ^^^^^^
@@ -135,13 +137,15 @@ error: layout_of(B) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/hexagon-enum.rs:20:1
+  --> $DIR/hexagon-enum.rs:21:1
    |
 LL | enum B { Banana = 255, }
    | ^^^^^^
@@ -209,13 +213,15 @@ error: layout_of(C) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(2 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(2 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/hexagon-enum.rs:24:1
+  --> $DIR/hexagon-enum.rs:25:1
    |
 LL | enum C { Chaenomeles = 256, }
    | ^^^^^^
@@ -283,13 +289,15 @@ error: layout_of(P) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/hexagon-enum.rs:28:1
+  --> $DIR/hexagon-enum.rs:29:1
    |
 LL | enum P { Peach = 0x1000_0000isize, }
    | ^^^^^^
@@ -357,13 +365,15 @@ error: layout_of(T) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/hexagon-enum.rs:34:1
+  --> $DIR/hexagon-enum.rs:35:1
    |
 LL | enum T { Tangerine = TANGERINE as isize }
    | ^^^^^^
diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
index 328d204aa3c..ab7e0897ce3 100644
--- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
+++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs
@@ -1,4 +1,5 @@
 //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN"
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 #![crate_type = "lib"]
 #![feature(rustc_attrs)]
 
diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
index ca041fb539b..cd9e4c02781 100644
--- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
+++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
@@ -83,6 +83,7 @@ error: layout_of(MissingPayloadField) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(1 bytes),
@@ -103,13 +104,15 @@ error: layout_of(MissingPayloadField) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1
+  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:17:1
    |
 LL | pub enum MissingPayloadField {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -201,6 +204,7 @@ error: layout_of(CommonPayloadField) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -238,13 +242,15 @@ error: layout_of(CommonPayloadField) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1
+  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:26:1
    |
 LL | pub enum CommonPayloadField {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -334,6 +340,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -370,13 +377,15 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1
+  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:34:1
    |
 LL | pub enum CommonPayloadFieldIsMaybeUninit {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -482,6 +491,7 @@ error: layout_of(NicheFirst) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(0 bytes),
@@ -502,6 +512,7 @@ error: layout_of(NicheFirst) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(0 bytes),
@@ -522,13 +533,15 @@ error: layout_of(NicheFirst) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1
+  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:42:1
    |
 LL | pub enum NicheFirst {
    | ^^^^^^^^^^^^^^^^^^^
@@ -634,6 +647,7 @@ error: layout_of(NicheSecond) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(0 bytes),
@@ -654,6 +668,7 @@ error: layout_of(NicheSecond) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(0 bytes),
@@ -674,13 +689,15 @@ error: layout_of(NicheSecond) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1
+  --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:51:1
    |
 LL | pub enum NicheSecond {
    | ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/layout/issue-96185-overaligned-enum.rs b/tests/ui/layout/issue-96185-overaligned-enum.rs
index 341233a7890..19da169105c 100644
--- a/tests/ui/layout/issue-96185-overaligned-enum.rs
+++ b/tests/ui/layout/issue-96185-overaligned-enum.rs
@@ -1,4 +1,5 @@
 //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN"
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 #![crate_type = "lib"]
 #![feature(rustc_attrs)]
 
diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr
index bc40a2aa482..15a3f6004f5 100644
--- a/tests/ui/layout/issue-96185-overaligned-enum.stderr
+++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr
@@ -57,6 +57,7 @@ error: layout_of(Aligned1) = Layout {
                            Align(8 bytes),
                        ),
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(8 bytes),
@@ -79,6 +80,7 @@ error: layout_of(Aligned1) = Layout {
                            Align(8 bytes),
                        ),
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
@@ -86,8 +88,9 @@ error: layout_of(Aligned1) = Layout {
                Align(8 bytes),
            ),
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/issue-96185-overaligned-enum.rs:8:1
+  --> $DIR/issue-96185-overaligned-enum.rs:9:1
    |
 LL | pub enum Aligned1 {
    | ^^^^^^^^^^^^^^^^^
@@ -157,6 +160,7 @@ error: layout_of(Aligned2) = Layout {
                            Align(1 bytes),
                        ),
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(1 bytes),
@@ -179,6 +183,7 @@ error: layout_of(Aligned2) = Layout {
                            Align(1 bytes),
                        ),
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
@@ -186,8 +191,9 @@ error: layout_of(Aligned2) = Layout {
                Align(1 bytes),
            ),
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/issue-96185-overaligned-enum.rs:16:1
+  --> $DIR/issue-96185-overaligned-enum.rs:17:1
    |
 LL | pub enum Aligned2 {
    | ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/layout/randomize.rs b/tests/ui/layout/randomize.rs
new file mode 100644
index 00000000000..27e99327a31
--- /dev/null
+++ b/tests/ui/layout/randomize.rs
@@ -0,0 +1,62 @@
+//@ run-pass
+//@ revisions: normal randomize-layout
+//@ [randomize-layout]compile-flags: -Zrandomize-layout -Zlayout-seed=2
+
+#![feature(offset_of_enum)]
+
+use std::ptr;
+
+
+// these types only have their field offsets taken, they're never constructed
+#[allow(dead_code)]
+pub struct Foo<T>(u32, T, u8);
+#[allow(dead_code)]
+pub struct Wrapper<T>(T);
+#[repr(transparent)]
+#[allow(dead_code)]
+pub struct TransparentWrapper(u16);
+
+const _: () = {
+    // Behavior of the current non-randomized implementation, not guaranteed
+    #[cfg(not(randomize_layout))]
+    assert!(std::mem::offset_of!(Foo::<u16>, 1) == std::mem::offset_of!(Foo::<Wrapper<u16>>, 1));
+
+    // under randomization Foo<T> != Foo<U>
+    #[cfg(randomize_layout)]
+    assert!(std::mem::offset_of!(Foo::<u16>, 1) != std::mem::offset_of!(Foo::<Wrapper<u16>>, 1));
+
+    // Even transparent wrapper inner types get a different layout since associated type
+    // specialization could result in the outer type behaving differently depending on the exact
+    // inner type.
+    #[cfg(randomize_layout)]
+    assert!(
+        std::mem::offset_of!(Foo::<u16>, 1) != std::mem::offset_of!(Foo::<TransparentWrapper>, 1)
+    );
+
+    // Currently all fn pointers are treated interchangably even with randomization. Not guaranteed.
+    // Associated type specialization could also break this.
+    assert!(
+        std::mem::offset_of!(Foo::<fn(u32)>, 1) == std::mem::offset_of!(Foo::<fn() -> usize>, 1)
+    );
+
+    // But subtype coercions must always result in the same layout.
+    assert!(
+        std::mem::offset_of!(Foo::<fn(&u32)>, 1) == std::mem::offset_of!(Foo::<fn(&'static u32)>, 1)
+    );
+
+    // Randomization must uphold NPO guarantees
+    assert!(std::mem::offset_of!(Option::<&usize>, Some.0) == 0);
+    assert!(std::mem::offset_of!(Result::<&usize, ()>, Ok.0) == 0);
+};
+
+#[allow(dead_code)]
+struct Unsizable<T: ?Sized>(usize, T);
+
+fn main() {
+    // offset_of doesn't let us probe the unsized field, check at runtime.
+    let x = &Unsizable::<[u32; 4]>(0, [0; 4]);
+    let y: &Unsizable::<[u32]> = x;
+
+    // type coercion must not change the layout.
+    assert_eq!(ptr::from_ref(&x.1).addr(), ptr::from_ref(&y.1).addr());
+}
diff --git a/tests/ui/layout/thumb-enum.rs b/tests/ui/layout/thumb-enum.rs
index 57a9a2d8137..2381d9d0292 100644
--- a/tests/ui/layout/thumb-enum.rs
+++ b/tests/ui/layout/thumb-enum.rs
@@ -1,4 +1,5 @@
 //@ compile-flags: --target thumbv8m.main-none-eabihf
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 //@ needs-llvm-components: arm
 //
 // Verify that thumb targets implement the repr(C) for enums correctly.
diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr
index bf043af586b..120081d193c 100644
--- a/tests/ui/layout/thumb-enum.stderr
+++ b/tests/ui/layout/thumb-enum.stderr
@@ -61,13 +61,15 @@ error: layout_of(A) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/thumb-enum.rs:16:1
+  --> $DIR/thumb-enum.rs:17:1
    |
 LL | enum A { Apple }
    | ^^^^^^
@@ -135,13 +137,15 @@ error: layout_of(B) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/thumb-enum.rs:20:1
+  --> $DIR/thumb-enum.rs:21:1
    |
 LL | enum B { Banana = 255, }
    | ^^^^^^
@@ -209,13 +213,15 @@ error: layout_of(C) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(2 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(2 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/thumb-enum.rs:24:1
+  --> $DIR/thumb-enum.rs:25:1
    |
 LL | enum C { Chaenomeles = 256, }
    | ^^^^^^
@@ -283,13 +289,15 @@ error: layout_of(P) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/thumb-enum.rs:28:1
+  --> $DIR/thumb-enum.rs:29:1
    |
 LL | enum P { Peach = 0x1000_0000isize, }
    | ^^^^^^
@@ -357,13 +365,15 @@ error: layout_of(T) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/thumb-enum.rs:34:1
+  --> $DIR/thumb-enum.rs:35:1
    |
 LL | enum T { Tangerine = TANGERINE as isize }
    | ^^^^^^
diff --git a/tests/ui/layout/zero-sized-array-enum-niche.rs b/tests/ui/layout/zero-sized-array-enum-niche.rs
index 152f44bd863..d3ff016d8aa 100644
--- a/tests/ui/layout/zero-sized-array-enum-niche.rs
+++ b/tests/ui/layout/zero-sized-array-enum-niche.rs
@@ -1,4 +1,5 @@
 //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN"
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 #![crate_type = "lib"]
 #![feature(rustc_attrs)]
 
diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr
index d61408098df..b6fcc14c063 100644
--- a/tests/ui/layout/zero-sized-array-enum-niche.stderr
+++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr
@@ -59,6 +59,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -92,13 +93,15 @@ error: layout_of(Result<[u32; 0], bool>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/zero-sized-array-enum-niche.rs:13:1
+  --> $DIR/zero-sized-array-enum-niche.rs:14:1
    |
 LL | type AlignedResult = Result<[u32; 0], bool>;
    | ^^^^^^^^^^^^^^^^^^
@@ -164,6 +167,7 @@ error: layout_of(MultipleAlignments) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(2 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(4 bytes),
@@ -188,6 +192,7 @@ error: layout_of(MultipleAlignments) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -221,13 +226,15 @@ error: layout_of(MultipleAlignments) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/zero-sized-array-enum-niche.rs:21:1
+  --> $DIR/zero-sized-array-enum-niche.rs:22:1
    |
 LL | enum MultipleAlignments {
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -293,6 +300,7 @@ error: layout_of(Result<[u32; 0], Packed<NonZero<u16>>>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(3 bytes),
@@ -326,13 +334,15 @@ error: layout_of(Result<[u32; 0], Packed<NonZero<u16>>>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/zero-sized-array-enum-niche.rs:37:1
+  --> $DIR/zero-sized-array-enum-niche.rs:38:1
    |
 LL | type NicheLosesToTagged = Result<[u32; 0], Packed<std::num::NonZero<u16>>>;
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -402,6 +412,7 @@ error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -435,13 +446,15 @@ error: layout_of(Result<[u32; 0], Packed<U16IsZero>>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/zero-sized-array-enum-niche.rs:44:1
+  --> $DIR/zero-sized-array-enum-niche.rs:45:1
    |
 LL | type NicheWinsOverTagged = Result<[u32; 0], Packed<U16IsZero>>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs
index 09ee9accccd..66e6eb91a22 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.rs
@@ -1,6 +1,6 @@
 fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) {
-    *v = x;
     //~^ ERROR lifetime may not live long enough
+    *v = x;
 }
 
 fn main() { }
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr
index 30083b5ef54..e7cab52084d 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr
@@ -1,13 +1,15 @@
 error: lifetime may not live long enough
-  --> $DIR/ex3-both-anon-regions-2.rs:2:5
+  --> $DIR/ex3-both-anon-regions-2.rs:1:14
    |
 LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) {
-   |                                   -             - let's call the lifetime of this reference `'1`
-   |                                   |
-   |                                   let's call the lifetime of this reference `'2`
-LL |     *v = x;
-   |     ^^^^^^ assignment requires that `'1` must outlive `'2`
+   |              ^^^^^^^^^            -             - let's call the lifetime of this reference `'1`
+   |              |                    |
+   |              |                    let's call the lifetime of this reference `'2`
+   |              assignment requires that `'1` must outlive `'2`
    |
+   = note: requirement occurs because of a mutable reference to `&u8`
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 help: consider introducing a named lifetime parameter
    |
 LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) {
diff --git a/tests/ui/lint/invalid_value.stderr b/tests/ui/lint/invalid_value.stderr
index b4e7421829f..cc6a2a1c8e5 100644
--- a/tests/ui/lint/invalid_value.stderr
+++ b/tests/ui/lint/invalid_value.stderr
@@ -323,7 +323,7 @@ LL |         let _val: (NonZero<u32>, i32) = mem::zeroed();
    |                                         ^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
    = note: `std::num::NonZero<u32>` must be non-null
-   = note: because `core::num::nonzero::private::NonZeroU32Inner` must be non-null
+   = note: because `core::num::niche_types::NonZeroU32Inner` must be non-null
 
 error: the type `(NonZero<u32>, i32)` does not permit being left uninitialized
   --> $DIR/invalid_value.rs:95:41
@@ -332,7 +332,7 @@ LL |         let _val: (NonZero<u32>, i32) = mem::uninitialized();
    |                                         ^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
    = note: `std::num::NonZero<u32>` must be non-null
-   = note: because `core::num::nonzero::private::NonZeroU32Inner` must be non-null
+   = note: because `core::num::niche_types::NonZeroU32Inner` must be non-null
    = note: integers must be initialized
 
 error: the type `*const dyn Send` does not permit zero-initialization
@@ -415,7 +415,7 @@ note: because `std::num::NonZero<u32>` must be non-null (in this field of the on
    |
 LL |     Banana(NonZero<u32>),
    |            ^^^^^^^^^^^^
-   = note: because `core::num::nonzero::private::NonZeroU32Inner` must be non-null
+   = note: because `core::num::niche_types::NonZeroU32Inner` must be non-null
 
 error: the type `OneFruitNonZero` does not permit being left uninitialized
   --> $DIR/invalid_value.rs:107:37
@@ -429,7 +429,7 @@ note: because `std::num::NonZero<u32>` must be non-null (in this field of the on
    |
 LL |     Banana(NonZero<u32>),
    |            ^^^^^^^^^^^^
-   = note: because `core::num::nonzero::private::NonZeroU32Inner` must be non-null
+   = note: because `core::num::niche_types::NonZeroU32Inner` must be non-null
    = note: integers must be initialized
 
 error: the type `bool` does not permit being left uninitialized
@@ -602,7 +602,7 @@ LL |         let _val: NonZero<u32> = mem::transmute(0);
    |                                  ^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
    |
    = note: `std::num::NonZero<u32>` must be non-null
-   = note: because `core::num::nonzero::private::NonZeroU32Inner` must be non-null
+   = note: because `core::num::niche_types::NonZeroU32Inner` must be non-null
 
 error: the type `NonNull<i32>` does not permit zero-initialization
   --> $DIR/invalid_value.rs:156:34
diff --git a/tests/ui/methods/bad-wf-when-selecting-method.rs b/tests/ui/methods/bad-wf-when-selecting-method.rs
new file mode 100644
index 00000000000..638d1ffa982
--- /dev/null
+++ b/tests/ui/methods/bad-wf-when-selecting-method.rs
@@ -0,0 +1,18 @@
+trait Wf {
+    type Assoc;
+}
+
+struct Wrapper<T: Wf<Assoc = U>, U>(T);
+
+trait Trait {
+    fn needs_sized(self);
+}
+
+fn test<T>(t: T) {
+    Wrapper(t).needs_sized();
+    //~^ ERROR the trait bound `T: Wf` is not satisfied
+    //~| ERROR the trait bound `T: Wf` is not satisfied
+    //~| the method `needs_sized` exists for struct `Wrapper<T, _>`, but its trait bounds were not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/methods/bad-wf-when-selecting-method.stderr b/tests/ui/methods/bad-wf-when-selecting-method.stderr
new file mode 100644
index 00000000000..e6d50034967
--- /dev/null
+++ b/tests/ui/methods/bad-wf-when-selecting-method.stderr
@@ -0,0 +1,54 @@
+error[E0277]: the trait bound `T: Wf` is not satisfied
+  --> $DIR/bad-wf-when-selecting-method.rs:12:13
+   |
+LL |     Wrapper(t).needs_sized();
+   |     ------- ^ the trait `Wf` is not implemented for `T`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `Wrapper`
+  --> $DIR/bad-wf-when-selecting-method.rs:5:19
+   |
+LL | struct Wrapper<T: Wf<Assoc = U>, U>(T);
+   |                   ^^^^^^^^^^^^^ required by this bound in `Wrapper`
+help: consider restricting type parameter `T` with trait `Wf`
+   |
+LL | fn test<T: Wf>(t: T) {
+   |          ++++
+
+error[E0277]: the trait bound `T: Wf` is not satisfied
+  --> $DIR/bad-wf-when-selecting-method.rs:12:5
+   |
+LL |     Wrapper(t).needs_sized();
+   |     ^^^^^^^^^^ the trait `Wf` is not implemented for `T`
+   |
+note: required by a bound in `Wrapper`
+  --> $DIR/bad-wf-when-selecting-method.rs:5:19
+   |
+LL | struct Wrapper<T: Wf<Assoc = U>, U>(T);
+   |                   ^^^^^^^^^^^^^ required by this bound in `Wrapper`
+help: consider restricting type parameter `T` with trait `Wf`
+   |
+LL | fn test<T: Wf>(t: T) {
+   |          ++++
+
+error[E0599]: the method `needs_sized` exists for struct `Wrapper<T, _>`, but its trait bounds were not satisfied
+  --> $DIR/bad-wf-when-selecting-method.rs:12:16
+   |
+LL | struct Wrapper<T: Wf<Assoc = U>, U>(T);
+   | ----------------------------------- method `needs_sized` not found for this struct
+...
+LL |     Wrapper(t).needs_sized();
+   |                ^^^^^^^^^^^ method cannot be called on `Wrapper<T, _>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `T: Wf`
+help: consider restricting the type parameter to satisfy the trait bound
+   |
+LL | fn test<T>(t: T) where T: Wf {
+   |                  +++++++++++
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/print_type_sizes/niche-filling.stdout b/tests/ui/print_type_sizes/niche-filling.stdout
index eeb5de53241..70612490a47 100644
--- a/tests/ui/print_type_sizes/niche-filling.stdout
+++ b/tests/ui/print_type_sizes/niche-filling.stdout
@@ -68,7 +68,7 @@ print-type-size type: `Union2<std::num::NonZero<u32>, u32>`: 4 bytes, alignment:
 print-type-size     variant `Union2`: 4 bytes
 print-type-size         field `.a`: 4 bytes
 print-type-size         field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
-print-type-size type: `core::num::nonzero::private::NonZeroU32Inner`: 4 bytes, alignment: 4 bytes
+print-type-size type: `core::num::niche_types::NonZeroU32Inner`: 4 bytes, alignment: 4 bytes
 print-type-size     field `.0`: 4 bytes
 print-type-size type: `std::num::NonZero<u32>`: 4 bytes, alignment: 4 bytes
 print-type-size     field `.0`: 4 bytes
diff --git a/tests/ui/proc-macro/quote-debug.stdout b/tests/ui/proc-macro/quote-debug.stdout
deleted file mode 100644
index d84b4e051e8..00000000000
--- a/tests/ui/proc-macro/quote-debug.stdout
+++ /dev/null
@@ -1,49 +0,0 @@
-#![feature(prelude_import)]
-#![no_std]
-//@ check-pass
-//@ force-host
-//@ no-prefer-dynamic
-//@ compile-flags: -Z unpretty=expanded
-//@ needs-unwind compiling proc macros with panic=abort causes a warning
-//
-// This file is not actually used as a proc-macro - instead,
-// it's just used to show the output of the `quote!` macro
-
-#![feature(proc_macro_quote)]
-#![crate_type = "proc-macro"]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
-#[macro_use]
-extern crate std;
-
-extern crate proc_macro;
-
-fn main() {
-    [crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("let",
-                                    crate::Span::recover_proc_macro_span(0)))),
-                        crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello",
-                                    crate::Span::recover_proc_macro_span(1)))),
-                        crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('=',
-                                    crate::Spacing::Alone))),
-                        crate::TokenStream::from(crate::TokenTree::Literal({
-                                    let mut iter =
-                                        "\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
-                                    if let (Some(crate::TokenTree::Literal(mut lit)), None) =
-                                                (iter.next(), iter.next()) {
-                                            lit.set_span(crate::Span::recover_proc_macro_span(2));
-                                            lit
-                                        } else {
-                                           ::core::panicking::panic("internal error: entered unreachable code")
-                                       }
-                                })),
-                        crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new(';',
-                                    crate::Spacing::Alone)))].iter().cloned().collect::<crate::TokenStream>()
-}
-const _: () =
-    {
-        extern crate proc_macro;
-        #[rustc_proc_macro_decls]
-        #[used]
-        #[allow(deprecated)]
-        static _DECLS: &[proc_macro::bridge::client::ProcMacro] = &[];
-    };
diff --git a/tests/ui/proc-macro/quote/auxiliary/basic.rs b/tests/ui/proc-macro/quote/auxiliary/basic.rs
new file mode 100644
index 00000000000..ef726bbfbe3
--- /dev/null
+++ b/tests/ui/proc-macro/quote/auxiliary/basic.rs
@@ -0,0 +1,361 @@
+#![feature(proc_macro_quote)]
+#![feature(proc_macro_totokens)]
+
+extern crate proc_macro;
+
+use std::borrow::Cow;
+use std::ffi::{CStr, CString};
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn run_tests(_: TokenStream) -> TokenStream {
+    test_quote_impl();
+    test_substitution();
+    test_advanced();
+    test_integer();
+    test_floating();
+    test_char();
+    test_str();
+    test_string();
+    test_c_str();
+    test_c_string();
+    test_interpolated_literal();
+    test_ident();
+    test_underscore();
+    test_duplicate();
+    test_empty_quote();
+    test_box_str();
+    test_cow();
+    test_append_tokens();
+    test_outer_line_comment();
+    test_inner_line_comment();
+    test_outer_block_comment();
+    test_inner_block_comment();
+    test_outer_attr();
+    test_inner_attr();
+    test_quote_raw_id();
+
+    TokenStream::new()
+}
+
+// Based on https://github.com/dtolnay/quote/blob/0245506323a3616daa2ee41c6ad0b871e4d78ae4/tests/test.rs
+//
+// FIXME(quote):
+// The following tests are removed because they are not supported yet in `proc_macro::quote!`
+//
+// - quote_spanned:
+//   - fn test_quote_spanned_impl
+//   - fn test_type_inference_for_span
+//   - wrong-type-span.rs
+// - format_ident:
+//   - fn test_format_ident
+//   - fn test_format_ident_strip_raw
+// - repetition:
+//   - fn test_iter
+//   - fn test_array
+//   - fn test_fancy_repetition
+//   - fn test_nested_fancy_repetition
+//   - fn test_duplicate_name_repetition
+//   - fn test_duplicate_name_repetition_no_copy
+//   - fn test_btreeset_repetition
+//   - fn test_variable_name_conflict
+//   - fn test_nonrep_in_repetition
+//   - fn test_closure
+//   - fn test_star_after_repetition
+
+struct X;
+
+impl ToTokens for X {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Ident::new("X", Span::call_site()).to_tokens(tokens)
+    }
+}
+
+fn test_quote_impl() {
+    let tokens = quote! {
+        impl<'a, T: ToTokens> ToTokens for &'a T {
+            fn to_tokens(&self, tokens: &mut TokenStream) {
+                (**self).to_tokens(tokens)
+            }
+        }
+    };
+
+    let expected = r#"impl < 'a, T : ToTokens > ToTokens for & 'a T
+{
+    fn to_tokens(& self, tokens : & mut TokenStream)
+    { (** self).to_tokens(tokens) }
+}"#;
+
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_substitution() {
+    let x = X;
+    let tokens = quote!($x <$x> ($x) [$x] {$x});
+
+    let expected = "X <X > (X) [X] { X }";
+
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_advanced() {
+    let generics = quote!( <'a, T> );
+
+    let where_clause = quote!( where T: Serialize );
+
+    let field_ty = quote!(String);
+
+    let item_ty = quote!(Cow<'a, str>);
+
+    let path = quote!(SomeTrait::serialize_with);
+
+    let value = quote!(self.x);
+
+    let tokens = quote! {
+        struct SerializeWith $generics $where_clause {
+            value: &'a $field_ty,
+            phantom: ::std::marker::PhantomData<$item_ty>,
+        }
+
+        impl $generics ::serde::Serialize for SerializeWith $generics $where_clause {
+            fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
+                where S: ::serde::Serializer
+            {
+                $path(self.value, s)
+            }
+        }
+
+        SerializeWith {
+            value: $value,
+            phantom: ::std::marker::PhantomData::<$item_ty>,
+        }
+    };
+
+    let expected = r#"struct SerializeWith < 'a, T > where T : Serialize
+{
+    value : & 'a String, phantom : :: std :: marker :: PhantomData <Cow < 'a,
+    str > >,
+} impl < 'a, T > :: serde :: Serialize for SerializeWith < 'a, T > where T :
+Serialize
+{
+    fn serialize < S > (& self, s : & mut S) -> Result < (), S :: Error >
+    where S : :: serde :: Serializer
+    { SomeTrait :: serialize_with(self.value, s) }
+} SerializeWith
+{
+    value : self.x, phantom : :: std :: marker :: PhantomData ::<Cow < 'a, str
+    > >,
+}"#;
+
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_integer() {
+    let ii8 = -1i8;
+    let ii16 = -1i16;
+    let ii32 = -1i32;
+    let ii64 = -1i64;
+    let ii128 = -1i128;
+    let iisize = -1isize;
+    let uu8 = 1u8;
+    let uu16 = 1u16;
+    let uu32 = 1u32;
+    let uu64 = 1u64;
+    let uu128 = 1u128;
+    let uusize = 1usize;
+
+    let tokens = quote! {
+        1 1i32 1u256
+        $ii8 $ii16 $ii32 $ii64 $ii128 $iisize
+        $uu8 $uu16 $uu32 $uu64 $uu128 $uusize
+    };
+    let expected = r#"1 1i32 1u256 -1i8 -1i16 -1i32 -1i64 -1i128 -1isize 1u8 1u16 1u32 1u64 1u128
+1usize"#;
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_floating() {
+    let e32 = 2.345f32;
+
+    let e64 = 2.345f64;
+
+    let tokens = quote! {
+        $e32
+        $e64
+    };
+    let expected = concat!("2.345f32 2.345f64");
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_char() {
+    let zero = '\u{1}';
+    let dollar = '$';
+    let pound = '#';
+    let quote = '"';
+    let apost = '\'';
+    let newline = '\n';
+    let heart = '\u{2764}';
+
+    let tokens = quote! {
+        $zero $dollar $pound $quote $apost $newline $heart
+    };
+    let expected = "'\\u{1}' '$' '#' '\"' '\\'' '\\n' '\u{2764}'";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_str() {
+    let s = "\u{1} a 'b \" c";
+    let tokens = quote!($s);
+    let expected = "\"\\u{1} a 'b \\\" c\"";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_string() {
+    let s = "\u{1} a 'b \" c".to_string();
+    let tokens = quote!($s);
+    let expected = "\"\\u{1} a 'b \\\" c\"";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_c_str() {
+    let s = CStr::from_bytes_with_nul(b"\x01 a 'b \" c\0").unwrap();
+    let tokens = quote!($s);
+    let expected = "c\"\\u{1} a 'b \\\" c\"";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_c_string() {
+    let s = CString::new(&b"\x01 a 'b \" c"[..]).unwrap();
+    let tokens = quote!($s);
+    let expected = "c\"\\u{1} a 'b \\\" c\"";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_interpolated_literal() {
+    macro_rules! m {
+        ($literal:literal) => {
+            quote!($literal)
+        };
+    }
+
+    let tokens = m!(1);
+    let expected = "1";
+    assert_eq!(expected, tokens.to_string());
+
+    let tokens = m!(-1);
+    let expected = "- 1";
+    assert_eq!(expected, tokens.to_string());
+
+    let tokens = m!(true);
+    let expected = "true";
+    assert_eq!(expected, tokens.to_string());
+
+    let tokens = m!(-true);
+    let expected = "- true";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_ident() {
+    let foo = Ident::new("Foo", Span::call_site());
+    let bar = Ident::new(&format!("Bar{}", 7), Span::call_site());
+    let tokens = quote!(struct $foo; enum $bar {});
+    let expected = "struct Foo; enum Bar7 {}";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_underscore() {
+    let tokens = quote!(let _;);
+    let expected = "let _;";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_duplicate() {
+    let ch = 'x';
+
+    let tokens = quote!($ch $ch);
+
+    let expected = "'x' 'x'";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_empty_quote() {
+    let tokens = quote!();
+    assert_eq!("", tokens.to_string());
+}
+
+fn test_box_str() {
+    let b = "str".to_owned().into_boxed_str();
+    let tokens = quote! { $b };
+    assert_eq!("\"str\"", tokens.to_string());
+}
+
+fn test_cow() {
+    let owned: Cow<Ident> = Cow::Owned(Ident::new("owned", Span::call_site()));
+
+    let ident = Ident::new("borrowed", Span::call_site());
+    let borrowed = Cow::Borrowed(&ident);
+
+    let tokens = quote! { $owned $borrowed };
+    assert_eq!("owned borrowed", tokens.to_string());
+}
+
+fn test_append_tokens() {
+    let mut a = quote!(a);
+    let b = quote!(b);
+    a.extend(b);
+    assert_eq!("a b", a.to_string());
+}
+
+fn test_outer_line_comment() {
+    let tokens = quote! {
+        /// doc
+    };
+    let expected = "#[doc = \" doc\"]";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_inner_line_comment() {
+    let tokens = quote! {
+        //! doc
+    };
+    let expected = "# ! [doc = \" doc\"]";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_outer_block_comment() {
+    let tokens = quote! {
+        /** doc */
+    };
+    let expected = "#[doc = \" doc \"]";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_inner_block_comment() {
+    let tokens = quote! {
+        /*! doc */
+    };
+    let expected = "# ! [doc = \" doc \"]";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_outer_attr() {
+    let tokens = quote! {
+        #[inline]
+    };
+    let expected = "#[inline]";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_inner_attr() {
+    let tokens = quote! {
+        #![no_std]
+    };
+    let expected = "#! [no_std]";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_quote_raw_id() {
+    let id = quote!(r#raw_id);
+    assert_eq!(id.to_string(), "r#raw_id");
+}
diff --git a/tests/ui/proc-macro/quote/basic.rs b/tests/ui/proc-macro/quote/basic.rs
new file mode 100644
index 00000000000..0336dbb7856
--- /dev/null
+++ b/tests/ui/proc-macro/quote/basic.rs
@@ -0,0 +1,8 @@
+//@ run-pass
+//@ proc-macro: basic.rs
+
+extern crate basic;
+
+fn main() {
+    basic::run_tests!();
+}
diff --git a/tests/ui/proc-macro/quote-debug.rs b/tests/ui/proc-macro/quote/debug.rs
index 11d144d609f..ce113079e56 100644
--- a/tests/ui/proc-macro/quote-debug.rs
+++ b/tests/ui/proc-macro/quote/debug.rs
@@ -15,5 +15,6 @@ extern crate proc_macro;
 fn main() {
     proc_macro::quote! {
         let hello = "world";
+        let r#raw_ident = r#"raw"literal"#;
     }
 }
diff --git a/tests/ui/proc-macro/quote/debug.stdout b/tests/ui/proc-macro/quote/debug.stdout
new file mode 100644
index 00000000000..3eaad9eb969
--- /dev/null
+++ b/tests/ui/proc-macro/quote/debug.stdout
@@ -0,0 +1,72 @@
+#![feature(prelude_import)]
+#![no_std]
+//@ check-pass
+//@ force-host
+//@ no-prefer-dynamic
+//@ compile-flags: -Z unpretty=expanded
+//@ needs-unwind compiling proc macros with panic=abort causes a warning
+//
+// This file is not actually used as a proc-macro - instead,
+// it's just used to show the output of the `quote!` macro
+
+#![feature(proc_macro_quote)]
+#![crate_type = "proc-macro"]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+extern crate proc_macro;
+
+fn main() {
+    {
+        let mut ts = crate::TokenStream::new();
+        crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("let",
+                        crate::Span::recover_proc_macro_span(0))), &mut ts);
+        crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("hello",
+                        crate::Span::recover_proc_macro_span(1))), &mut ts);
+        crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new('=',
+                        crate::Spacing::Alone)), &mut ts);
+        crate::ToTokens::to_tokens(&crate::TokenTree::Literal({
+                        let mut iter =
+                            "\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
+                        if let (Some(crate::TokenTree::Literal(mut lit)), None) =
+                                    (iter.next(), iter.next()) {
+                                lit.set_span(crate::Span::recover_proc_macro_span(2));
+                                lit
+                            } else {
+                               ::core::panicking::panic("internal error: entered unreachable code")
+                           }
+                    }), &mut ts);
+        crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(';',
+                        crate::Spacing::Alone)), &mut ts);
+        crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("let",
+                        crate::Span::recover_proc_macro_span(3))), &mut ts);
+        crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new_raw("raw_ident",
+                        crate::Span::recover_proc_macro_span(4))), &mut ts);
+        crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new('=',
+                        crate::Spacing::Alone)), &mut ts);
+        crate::ToTokens::to_tokens(&crate::TokenTree::Literal({
+                        let mut iter =
+                            "r#\"raw\"literal\"#".parse::<crate::TokenStream>().unwrap().into_iter();
+                        if let (Some(crate::TokenTree::Literal(mut lit)), None) =
+                                    (iter.next(), iter.next()) {
+                                lit.set_span(crate::Span::recover_proc_macro_span(5));
+                                lit
+                            } else {
+                               ::core::panicking::panic("internal error: entered unreachable code")
+                           }
+                    }), &mut ts);
+        crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(';',
+                        crate::Spacing::Alone)), &mut ts);
+        ts
+    }
+}
+const _: () =
+    {
+        extern crate proc_macro;
+        #[rustc_proc_macro_decls]
+        #[used]
+        #[allow(deprecated)]
+        static _DECLS: &[proc_macro::bridge::client::ProcMacro] = &[];
+    };
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs
new file mode 100644
index 00000000000..2f67ae1bc6e
--- /dev/null
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs
@@ -0,0 +1,17 @@
+// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is
+// expected to be incorrect.
+//@ known-bug: #54722
+
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::quote;
+
+fn main() {
+    let nonrep = "";
+
+    // Without some protection against repetitions with no iterator somewhere
+    // inside, this would loop infinitely.
+    quote!($($nonrep $nonrep)*);
+}
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr
new file mode 100644
index 00000000000..5f28a46f318
--- /dev/null
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr
@@ -0,0 +1,10 @@
+error: proc macro panicked
+  --> $DIR/does-not-have-iter-interpolated-dup.rs:16:5
+   |
+LL |     quote!($($nonrep $nonrep)*);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: message: `$` must be followed by an ident or `$` in `quote!`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs
new file mode 100644
index 00000000000..1efb3eac642
--- /dev/null
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs
@@ -0,0 +1,17 @@
+// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is
+// expected to be incorrect.
+//@ known-bug: #54722
+
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::quote;
+
+fn main() {
+    let nonrep = "";
+
+    // Without some protection against repetitions with no iterator somewhere
+    // inside, this would loop infinitely.
+    quote!($($nonrep)*);
+}
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr
new file mode 100644
index 00000000000..595aa858763
--- /dev/null
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr
@@ -0,0 +1,10 @@
+error: proc macro panicked
+  --> $DIR/does-not-have-iter-interpolated.rs:16:5
+   |
+LL |     quote!($($nonrep)*);
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: message: `$` must be followed by an ident or `$` in `quote!`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs b/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs
new file mode 100644
index 00000000000..5f2ddabc390
--- /dev/null
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs
@@ -0,0 +1,13 @@
+// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is
+// expected to be incorrect.
+//@ known-bug: #54722
+
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::quote;
+
+fn main() {
+    quote!($(a b),*);
+}
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr
new file mode 100644
index 00000000000..f6f5d7e007d
--- /dev/null
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr
@@ -0,0 +1,10 @@
+error: proc macro panicked
+  --> $DIR/does-not-have-iter-separated.rs:12:5
+   |
+LL |     quote!($(a b),*);
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: message: `$` must be followed by an ident or `$` in `quote!`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter.rs b/tests/ui/proc-macro/quote/does-not-have-iter.rs
new file mode 100644
index 00000000000..25ffd786cc6
--- /dev/null
+++ b/tests/ui/proc-macro/quote/does-not-have-iter.rs
@@ -0,0 +1,13 @@
+// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is
+// expected to be incorrect.
+//@ known-bug: #54722
+
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::quote;
+
+fn main() {
+    quote!($(a b)*);
+}
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter.stderr b/tests/ui/proc-macro/quote/does-not-have-iter.stderr
new file mode 100644
index 00000000000..0ed1daffc8c
--- /dev/null
+++ b/tests/ui/proc-macro/quote/does-not-have-iter.stderr
@@ -0,0 +1,10 @@
+error: proc macro panicked
+  --> $DIR/does-not-have-iter.rs:12:5
+   |
+LL |     quote!($(a b)*);
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: message: `$` must be followed by an ident or `$` in `quote!`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/proc-macro/quote/not-quotable.rs b/tests/ui/proc-macro/quote/not-quotable.rs
new file mode 100644
index 00000000000..7e38b441052
--- /dev/null
+++ b/tests/ui/proc-macro/quote/not-quotable.rs
@@ -0,0 +1,12 @@
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use std::net::Ipv4Addr;
+
+use proc_macro::quote;
+
+fn main() {
+    let ip = Ipv4Addr::LOCALHOST;
+    let _ = quote! { $ip }; //~ ERROR the trait bound `Ipv4Addr: ToTokens` is not satisfied
+}
diff --git a/tests/ui/proc-macro/quote/not-quotable.stderr b/tests/ui/proc-macro/quote/not-quotable.stderr
new file mode 100644
index 00000000000..e349b2dce53
--- /dev/null
+++ b/tests/ui/proc-macro/quote/not-quotable.stderr
@@ -0,0 +1,24 @@
+error[E0277]: the trait bound `Ipv4Addr: ToTokens` is not satisfied
+  --> $DIR/not-quotable.rs:11:13
+   |
+LL |     let _ = quote! { $ip };
+   |             ^^^^^^^^^^^^^^
+   |             |
+   |             the trait `ToTokens` is not implemented for `Ipv4Addr`
+   |             required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `ToTokens`:
+             &T
+             &mut T
+             Box<T>
+             CString
+             Cow<'_, T>
+             Option<T>
+             Rc<T>
+             bool
+           and 24 others
+   = note: this error originates in the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/proc-macro/quote/not-repeatable.rs b/tests/ui/proc-macro/quote/not-repeatable.rs
new file mode 100644
index 00000000000..d115da73181
--- /dev/null
+++ b/tests/ui/proc-macro/quote/not-repeatable.rs
@@ -0,0 +1,16 @@
+// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is
+// expected to be incorrect.
+//@ known-bug: #54722
+
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::quote;
+
+struct Ipv4Addr;
+
+fn main() {
+    let ip = Ipv4Addr;
+    let _ = quote! { $($ip)* };
+}
diff --git a/tests/ui/proc-macro/quote/not-repeatable.stderr b/tests/ui/proc-macro/quote/not-repeatable.stderr
new file mode 100644
index 00000000000..18fbcd73798
--- /dev/null
+++ b/tests/ui/proc-macro/quote/not-repeatable.stderr
@@ -0,0 +1,10 @@
+error: proc macro panicked
+  --> $DIR/not-repeatable.rs:15:13
+   |
+LL |     let _ = quote! { $($ip)* };
+   |             ^^^^^^^^^^^^^^^^^^
+   |
+   = help: message: `$` must be followed by an ident or `$` in `quote!`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr
index 350ac287507..c4aebfb0e20 100644
--- a/tests/ui/repeat-expr/repeat_count.stderr
+++ b/tests/ui/repeat-expr/repeat_count.stderr
@@ -16,6 +16,12 @@ LL |     let b = [0; ()];
    |                 ^^ expected `usize`, found `()`
 
 error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:31:17
+   |
+LL |     let g = [0; G { g: () }];
+   |                 ^^^^^^^^^^^ expected `usize`, found `G`
+
+error[E0308]: mismatched types
   --> $DIR/repeat_count.rs:10:17
    |
 LL |     let c = [0; true];
@@ -34,12 +40,6 @@ LL |     let e = [0; "foo"];
    |                 ^^^^^ expected `usize`, found `&str`
 
 error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:31:17
-   |
-LL |     let g = [0; G { g: () }];
-   |                 ^^^^^^^^^^^ expected `usize`, found `G`
-
-error[E0308]: mismatched types
   --> $DIR/repeat_count.rs:19:17
    |
 LL |     let f = [0; -4_isize];
diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr
index 64a0cb7f31a..8e8f1d159b7 100644
--- a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr
+++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr
@@ -55,13 +55,15 @@ error: layout_of(Univariant) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:38:1
+  --> $DIR/repr-c-dead-variants.rs:39:1
    |
 LL | enum Univariant {
    | ^^^^^^^^^^^^^^^
@@ -137,6 +139,7 @@ error: layout_of(TwoVariants) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(8 bytes),
@@ -173,13 +176,15 @@ error: layout_of(TwoVariants) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:45:1
+  --> $DIR/repr-c-dead-variants.rs:46:1
    |
 LL | enum TwoVariants {
    | ^^^^^^^^^^^^^^^^
@@ -247,6 +252,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                            Align(8 bytes),
                        ),
                        unadjusted_abi_align: Align(8 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(16 bytes),
@@ -271,6 +277,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(8 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
@@ -278,8 +285,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                Align(8 bytes),
            ),
            unadjusted_abi_align: Align(8 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:57:1
+  --> $DIR/repr-c-dead-variants.rs:58:1
    |
 LL | enum DeadBranchHasOtherField {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr
index 5c4daa6d519..2cd0960ce3e 100644
--- a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr
+++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr
@@ -55,13 +55,15 @@ error: layout_of(Univariant) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:38:1
+  --> $DIR/repr-c-dead-variants.rs:39:1
    |
 LL | enum Univariant {
    | ^^^^^^^^^^^^^^^
@@ -137,6 +139,7 @@ error: layout_of(TwoVariants) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -173,13 +176,15 @@ error: layout_of(TwoVariants) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:45:1
+  --> $DIR/repr-c-dead-variants.rs:46:1
    |
 LL | enum TwoVariants {
    | ^^^^^^^^^^^^^^^^
@@ -247,6 +252,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                            Align(8 bytes),
                        ),
                        unadjusted_abi_align: Align(8 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(16 bytes),
@@ -271,6 +277,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(8 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
@@ -278,8 +285,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                Align(8 bytes),
            ),
            unadjusted_abi_align: Align(8 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:57:1
+  --> $DIR/repr-c-dead-variants.rs:58:1
    |
 LL | enum DeadBranchHasOtherField {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr
index 64a0cb7f31a..8e8f1d159b7 100644
--- a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr
+++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr
@@ -55,13 +55,15 @@ error: layout_of(Univariant) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:38:1
+  --> $DIR/repr-c-dead-variants.rs:39:1
    |
 LL | enum Univariant {
    | ^^^^^^^^^^^^^^^
@@ -137,6 +139,7 @@ error: layout_of(TwoVariants) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(8 bytes),
@@ -173,13 +176,15 @@ error: layout_of(TwoVariants) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:45:1
+  --> $DIR/repr-c-dead-variants.rs:46:1
    |
 LL | enum TwoVariants {
    | ^^^^^^^^^^^^^^^^
@@ -247,6 +252,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                            Align(8 bytes),
                        ),
                        unadjusted_abi_align: Align(8 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(16 bytes),
@@ -271,6 +277,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(8 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
@@ -278,8 +285,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                Align(8 bytes),
            ),
            unadjusted_abi_align: Align(8 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:57:1
+  --> $DIR/repr-c-dead-variants.rs:58:1
    |
 LL | enum DeadBranchHasOtherField {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/repr/repr-c-dead-variants.rs b/tests/ui/repr/repr-c-dead-variants.rs
index 3e8ae3d096d..99f20982a99 100644
--- a/tests/ui/repr/repr-c-dead-variants.rs
+++ b/tests/ui/repr/repr-c-dead-variants.rs
@@ -7,6 +7,7 @@
 // See also: repr-c-int-dead-variants.rs
 
 //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 
 // This test depends on the value of the `c_enum_min_bits` target option.
 // As there's no way to actually check it from UI test, we only run this test on a subset of archs.
diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr
index 64a0cb7f31a..8e8f1d159b7 100644
--- a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr
+++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr
@@ -55,13 +55,15 @@ error: layout_of(Univariant) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:38:1
+  --> $DIR/repr-c-dead-variants.rs:39:1
    |
 LL | enum Univariant {
    | ^^^^^^^^^^^^^^^
@@ -137,6 +139,7 @@ error: layout_of(TwoVariants) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(8 bytes),
@@ -173,13 +176,15 @@ error: layout_of(TwoVariants) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:45:1
+  --> $DIR/repr-c-dead-variants.rs:46:1
    |
 LL | enum TwoVariants {
    | ^^^^^^^^^^^^^^^^
@@ -247,6 +252,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                            Align(8 bytes),
                        ),
                        unadjusted_abi_align: Align(8 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(16 bytes),
@@ -271,6 +277,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(8 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
@@ -278,8 +285,9 @@ error: layout_of(DeadBranchHasOtherField) = Layout {
                Align(8 bytes),
            ),
            unadjusted_abi_align: Align(8 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-dead-variants.rs:57:1
+  --> $DIR/repr-c-dead-variants.rs:58:1
    |
 LL | enum DeadBranchHasOtherField {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/repr/repr-c-int-dead-variants.rs b/tests/ui/repr/repr-c-int-dead-variants.rs
index 627569e080d..723e5730244 100644
--- a/tests/ui/repr/repr-c-int-dead-variants.rs
+++ b/tests/ui/repr/repr-c-int-dead-variants.rs
@@ -4,6 +4,7 @@
 // See also: repr-c-dead-variants.rs
 
 //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 
 // A simple uninhabited type.
 enum Void {}
diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr
index 75005a64523..fa08b323dec 100644
--- a/tests/ui/repr/repr-c-int-dead-variants.stderr
+++ b/tests/ui/repr/repr-c-int-dead-variants.stderr
@@ -55,13 +55,15 @@ error: layout_of(UnivariantU8) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-int-dead-variants.rs:14:1
+  --> $DIR/repr-c-int-dead-variants.rs:15:1
    |
 LL | enum UnivariantU8 {
    | ^^^^^^^^^^^^^^^^^
@@ -137,6 +139,7 @@ error: layout_of(TwoVariantsU8) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -173,13 +176,15 @@ error: layout_of(TwoVariantsU8) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(1 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-int-dead-variants.rs:21:1
+  --> $DIR/repr-c-int-dead-variants.rs:22:1
    |
 LL | enum TwoVariantsU8 {
    | ^^^^^^^^^^^^^^^^^^
@@ -247,6 +252,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout {
                            Align(8 bytes),
                        ),
                        unadjusted_abi_align: Align(8 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(16 bytes),
@@ -271,6 +277,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(8 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
@@ -278,8 +285,9 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout {
                Align(8 bytes),
            ),
            unadjusted_abi_align: Align(8 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/repr-c-int-dead-variants.rs:33:1
+  --> $DIR/repr-c-int-dead-variants.rs:34:1
    |
 LL | enum DeadBranchHasOtherFieldU8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
index cf4c219215e..90b63249eca 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
@@ -4,6 +4,7 @@ error[E0658]: cannot call conditionally-const method `<R as Deref>::deref` in co
 LL |         self.0
    |         ^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
diff --git a/tests/ui/traits/const-traits/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr
index 09bf9c023c8..7cdde5a079f 100644
--- a/tests/ui/traits/const-traits/cross-crate.stock.stderr
+++ b/tests/ui/traits/const-traits/cross-crate.stock.stderr
@@ -1,9 +1,10 @@
 error[E0658]: cannot call conditionally-const method `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:22:5
+  --> $DIR/cross-crate.rs:22:11
    |
 LL |     Const.func();
-   |     ^^^^^^^^^^^^
+   |           ^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
diff --git a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
index e52e5609b01..2358731c901 100644
--- a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
+++ b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
@@ -1,19 +1,21 @@
 error[E0658]: cannot call conditionally-const method `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:19:5
+  --> $DIR/cross-crate.rs:19:14
    |
 LL |     NonConst.func();
-   |     ^^^^^^^^^^^^^^^
+   |              ^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: cannot call conditionally-const method `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:22:5
+  --> $DIR/cross-crate.rs:22:11
    |
 LL |     Const.func();
-   |     ^^^^^^^^^^^^
+   |           ^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr
index bf7466b8e16..400c76fcaf4 100644
--- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr
+++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr
@@ -4,6 +4,7 @@ error[E0658]: cannot call conditionally-const associated function `<staged_api::
 LL |     Unstable::func();
    |     ^^^^^^^^^^^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
index 8abda1c8f8a..024db4b6d68 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
@@ -39,11 +39,12 @@ LL | #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)]
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: cannot call conditionally-const method `<T as Foo>::a` in constant functions
-  --> $DIR/super-traits-fail-3.rs:36:5
+  --> $DIR/super-traits-fail-3.rs:36:7
    |
 LL |     x.a();
-   |     ^^^^^
+   |       ^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr
index 8abda1c8f8a..024db4b6d68 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr
@@ -39,11 +39,12 @@ LL | #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)]
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: cannot call conditionally-const method `<T as Foo>::a` in constant functions
-  --> $DIR/super-traits-fail-3.rs:36:5
+  --> $DIR/super-traits-fail-3.rs:36:7
    |
 LL |     x.a();
-   |     ^^^^^
+   |       ^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
diff --git a/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs
index cf73fd8d31f..f776a6ce4c1 100644
--- a/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs
+++ b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs
@@ -1,3 +1,5 @@
+// Sets some arbitrarily large width for more consistent output (see #135288).
+//@ compile-flags: --diagnostic-width=120
 struct Argument;
 struct Return;
 
diff --git a/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr
index 5b89158b0db..ba0af763975 100644
--- a/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr
+++ b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `fn(Argument) -> Return {function}: Trait` is not satisfied
-  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:12:11
+  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11
    |
 LL |     takes(function);
    |     ----- ^^^^^^^^ the trait `Trait` is not implemented for fn item `fn(Argument) -> Return {function}`
@@ -7,7 +7,7 @@ LL |     takes(function);
    |     required by a bound introduced by this call
    |
 note: required by a bound in `takes`
-  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:9:18
+  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:11:18
    |
 LL | fn takes(_: impl Trait) {}
    |                  ^^^^^ required by this bound in `takes`
@@ -16,18 +16,18 @@ help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`,
 LL |     takes(function as fn(Argument) -> Return);
    |                    +++++++++++++++++++++++++
 
-error[E0277]: the trait bound `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11: 14:34}: Trait` is not satisfied
-  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11
+error[E0277]: the trait bound `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:16:11: 16:34}: Trait` is not satisfied
+  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:16:11
    |
 LL |     takes(|_: Argument| -> Return { todo!() });
    |     ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Trait` is not implemented for closure `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11: 14:34}`
+   = help: the trait `Trait` is not implemented for closure `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:16:11: 16:34}`
    = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
 note: required by a bound in `takes`
-  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:9:18
+  --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:11:18
    |
 LL | fn takes(_: impl Trait) {}
    |                  ^^^^^ required by this bound in `takes`
diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs
index ff87444b49e..446a33195c8 100644
--- a/tests/ui/type/pattern_types/range_patterns.rs
+++ b/tests/ui/type/pattern_types/range_patterns.rs
@@ -3,6 +3,7 @@
 #![allow(incomplete_features)]
 
 //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 
 use std::pat::pattern_type;
 
diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr
index 0eed7c2ce1c..7da8cfd4dbc 100644
--- a/tests/ui/type/pattern_types/range_patterns.stderr
+++ b/tests/ui/type/pattern_types/range_patterns.stderr
@@ -36,8 +36,9 @@ error: layout_of(NonZero<u32>) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/range_patterns.rs:10:1
+  --> $DIR/range_patterns.rs:11:1
    |
 LL | type X = std::num::NonZeroU32;
    | ^^^^^^
@@ -73,8 +74,9 @@ error: layout_of((u32) is 1..=) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/range_patterns.rs:12:1
+  --> $DIR/range_patterns.rs:13:1
    |
 LL | type Y = pattern_type!(u32 is 1..);
    | ^^^^^^
@@ -137,6 +139,7 @@ error: layout_of(Option<(u32) is 1..=>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(4 bytes),
@@ -176,13 +179,15 @@ error: layout_of(Option<(u32) is 1..=>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/range_patterns.rs:14:1
+  --> $DIR/range_patterns.rs:15:1
    |
 LL | type Z = Option<pattern_type!(u32 is 1..)>;
    | ^^^^^^
@@ -245,6 +250,7 @@ error: layout_of(Option<NonZero<u32>>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(1 bytes),
+                       randomization_seed: $SEED,
                    },
                    Layout {
                        size: Size(4 bytes),
@@ -284,13 +290,15 @@ error: layout_of(Option<NonZero<u32>>) = Layout {
                        },
                        max_repr_align: None,
                        unadjusted_abi_align: Align(4 bytes),
+                       randomization_seed: $SEED,
                    },
                ],
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/range_patterns.rs:16:1
+  --> $DIR/range_patterns.rs:17:1
    |
 LL | type A = Option<std::num::NonZeroU32>;
    | ^^^^^^
@@ -333,8 +341,9 @@ error: layout_of(NonZeroU32New) = Layout {
            },
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
+           randomization_seed: $SEED,
        }
-  --> $DIR/range_patterns.rs:18:1
+  --> $DIR/range_patterns.rs:19:1
    |
 LL | struct NonZeroU32New(pattern_type!(u32 is 1..));
    | ^^^^^^^^^^^^^^^^^^^^