about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock38
-rw-r--r--RELEASES.md2
-rw-r--r--compiler/rustc_abi/Cargo.toml2
-rw-r--r--compiler/rustc_abi/src/extern_abi.rs3
-rw-r--r--compiler/rustc_ast/src/ast.rs4
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs6
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/deprecation.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/inline.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/must_use.rs24
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/prototype.rs140
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/test_attrs.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs23
-rw-r--r--compiler/rustc_attr_parsing/src/lints.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs9
-rw-r--r--compiler/rustc_borrowck/messages.ftl2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs61
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs773
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs24
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/from.rs71
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs183
-rw-r--r--compiler/rustc_codegen_llvm/src/back/mod.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs54
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs94
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs68
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs2
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs164
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs13
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs65
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs4
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs31
-rw-r--r--compiler/rustc_error_messages/Cargo.toml2
-rw-r--r--compiler/rustc_error_messages/src/diagnostic_impls.rs205
-rw-r--r--compiler/rustc_error_messages/src/lib.rs53
-rw-r--r--compiler/rustc_errors/Cargo.toml6
-rw-r--r--compiler/rustc_errors/src/codes.rs2
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs52
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs303
-rw-r--r--compiler/rustc_errors/src/emitter.rs4
-rw-r--r--compiler/rustc_errors/src/lib.rs20
-rw-r--r--compiler/rustc_expand/messages.ftl2
-rw-r--r--compiler/rustc_expand/src/errors.rs1
-rw-r--r--compiler/rustc_expand/src/expand.rs42
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs24
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs178
-rw-r--r--compiler/rustc_expand/src/module.rs2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs17
-rw-r--r--compiler/rustc_feature/src/removed.rs3
-rw-r--r--compiler/rustc_feature/src/unstable.rs6
-rw-r--r--compiler/rustc_hir/Cargo.toml2
-rw-r--r--compiler/rustc_hir/src/attrs/data_structures.rs45
-rw-r--r--compiler/rustc_hir/src/attrs/encode_cross_crate.rs1
-rw-r--r--compiler/rustc_hir/src/def.rs14
-rw-r--r--compiler/rustc_hir/src/hir.rs13
-rw-r--r--compiler/rustc_hir/src/lib.rs6
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs21
-rw-r--r--compiler/rustc_hir/src/target.rs2
-rw-r--r--compiler/rustc_hir/src/version.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs6
-rw-r--r--compiler/rustc_hir_id/Cargo.toml13
-rw-r--r--compiler/rustc_hir_id/src/lib.rs (renamed from compiler/rustc_hir/src/hir_id.rs)31
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs3
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs22
-rw-r--r--compiler/rustc_interface/src/interface.rs4
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lint/messages.ftl2
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/context.rs10
-rw-r--r--compiler/rustc_lint/src/early/diagnostics.rs10
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs2
-rw-r--r--compiler/rustc_lint/src/internal.rs132
-rw-r--r--compiler/rustc_lint/src/lints.rs3
-rw-r--r--compiler/rustc_lint_defs/Cargo.toml2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs12
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs21
-rw-r--r--compiler/rustc_llvm/build.rs1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp208
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp88
-rw-r--r--compiler/rustc_macros/src/print_attribute.rs60
-rw-r--r--compiler/rustc_metadata/src/creader.rs5
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs16
-rw-r--r--compiler/rustc_middle/src/lint.rs29
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs21
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs42
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs5
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs9
-rw-r--r--compiler/rustc_middle/src/query/erase.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs12
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs51
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs23
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs16
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs40
-rw-r--r--compiler/rustc_mir_build/src/builder/custom/mod.rs65
-rw-r--r--compiler/rustc_mir_build/src/builder/mod.rs9
-rw-r--r--compiler/rustc_mir_build/src/check_tail_calls.rs41
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs10
-rw-r--r--compiler/rustc_mir_dataflow/Cargo.toml1
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs24
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs17
-rw-r--r--compiler/rustc_parse/messages.ftl3
-rw-r--r--compiler/rustc_parse/src/errors.rs21
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs3
-rw-r--r--compiler/rustc_parse/src/lib.rs16
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs4
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs11
-rw-r--r--compiler/rustc_parse/src/parser/item.rs2
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs23
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs147
-rw-r--r--compiler/rustc_passes/messages.ftl24
-rw-r--r--compiler/rustc_passes/src/check_attr.rs151
-rw-r--r--compiler/rustc_passes/src/errors.rs49
-rw-r--r--compiler/rustc_resolve/messages.ftl5
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs20
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs32
-rw-r--r--compiler/rustc_resolve/src/errors.rs11
-rw-r--r--compiler/rustc_resolve/src/ident.rs2
-rw-r--r--compiler/rustc_resolve/src/imports.rs14
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs9
-rw-r--r--compiler/rustc_session/messages.ftl2
-rw-r--r--compiler/rustc_session/src/errors.rs4
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/session.rs27
-rw-r--r--compiler/rustc_span/src/caching_source_map_view.rs30
-rw-r--r--compiler/rustc_span/src/symbol.rs11
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs50
-rw-r--r--compiler/rustc_target/Cargo.toml1
-rw-r--r--compiler/rustc_target/src/callconv/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs13
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld27
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs2
-rw-r--r--compiler/rustc_target/src/target_features.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs61
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs8
-rw-r--r--compiler/rustc_traits/Cargo.toml1
-rw-r--r--compiler/rustc_traits/src/coroutine_witnesses.rs2
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs2
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs1
-rw-r--r--compiler/rustc_type_ir/Cargo.toml2
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs6
-rw-r--r--compiler/rustc_type_ir/src/ir_print.rs49
-rw-r--r--library/Cargo.lock6
-rw-r--r--library/Cargo.toml1
-rw-r--r--library/alloc/src/alloc.rs1
-rw-r--r--library/core/src/array/mod.rs8
-rw-r--r--library/core/src/cmp.rs15
-rw-r--r--library/core/src/fmt/num.rs331
-rw-r--r--library/core/src/intrinsics/mod.rs51
-rw-r--r--library/core/src/lib.rs7
-rw-r--r--library/core/src/net/ip_addr.rs12
-rw-r--r--library/core/src/num/dec2flt/mod.rs2
-rw-r--r--library/core/src/num/int_macros.rs51
-rw-r--r--library/core/src/num/nonzero.rs48
-rw-r--r--library/core/src/num/saturating.rs4
-rw-r--r--library/core/src/num/uint_macros.rs61
-rw-r--r--library/core/src/num/wrapping.rs4
-rw-r--r--library/core/src/option.rs12
-rw-r--r--library/core/src/pin/unsafe_pinned.rs4
-rw-r--r--library/core/src/prelude/v1.rs7
-rw-r--r--library/core/src/unicode/mod.rs4
-rw-r--r--library/coretests/benches/fmt.rs180
-rw-r--r--library/coretests/tests/lib.rs2
-rw-r--r--library/coretests/tests/nonzero.rs108
-rw-r--r--library/coretests/tests/num/int_macros.rs40
-rw-r--r--library/coretests/tests/num/uint_macros.rs34
-rw-r--r--library/std/Cargo.toml1
-rw-r--r--library/std/src/collections/mod.rs12
-rw-r--r--library/std/src/ffi/os_str.rs2
-rw-r--r--library/std/src/fs.rs21
-rw-r--r--library/std/src/io/buffered/bufreader/buffer.rs2
-rw-r--r--library/std/src/io/copy.rs7
-rw-r--r--library/std/src/io/error.rs2
-rw-r--r--library/std/src/io/mod.rs9
-rw-r--r--library/std/src/lib.rs9
-rw-r--r--library/std/src/os/unix/net/stream.rs10
-rw-r--r--library/std/src/os/unix/process.rs12
-rw-r--r--library/std/src/path.rs67
-rw-r--r--library/std/src/sync/nonpoison/mutex.rs2
-rw-r--r--library/std/src/sync/poison/mutex.rs2
-rw-r--r--library/std/src/sync/reentrant_lock.rs9
-rw-r--r--library/std/src/sys/alloc/mod.rs30
-rw-r--r--library/std/src/sys/alloc/unix.rs10
-rw-r--r--library/std/src/sys/anonymous_pipe/mod.rs10
-rw-r--r--library/std/src/sys/args/mod.rs27
-rw-r--r--library/std/src/sys/cmath.rs111
-rw-r--r--library/std/src/sys/env/mod.rs31
-rw-r--r--library/std/src/sys/env/wasi.rs7
-rw-r--r--library/std/src/sys/exit_guard.rs7
-rw-r--r--library/std/src/sys/fd/mod.rs14
-rw-r--r--library/std/src/sys/fs/mod.rs37
-rw-r--r--library/std/src/sys/fs/unix.rs44
-rw-r--r--library/std/src/sys/io/mod.rs29
-rw-r--r--library/std/src/sys/mod.rs2
-rw-r--r--library/std/src/sys/net/connection/socket.rs56
-rw-r--r--library/std/src/sys/net/connection/socket/unix.rs34
-rw-r--r--library/std/src/sys/net/mod.rs21
-rw-r--r--library/std/src/sys/os_str/mod.rs10
-rw-r--r--library/std/src/sys/pal/mod.rs54
-rw-r--r--library/std/src/sys/pal/uefi/time.rs13
-rw-r--r--library/std/src/sys/pal/unix/futex.rs10
-rw-r--r--library/std/src/sys/pal/unix/mod.rs32
-rw-r--r--library/std/src/sys/pal/unix/os.rs23
-rw-r--r--library/std/src/sys/pal/unix/pipe.rs9
-rw-r--r--library/std/src/sys/pal/unix/thread.rs68
-rw-r--r--library/std/src/sys/pal/wasi/thread.rs28
-rw-r--r--library/std/src/sys/pal/wasm/mod.rs7
-rw-r--r--library/std/src/sys/pal/windows/c.rs12
-rw-r--r--library/std/src/sys/pal/windows/mod.rs20
-rw-r--r--library/std/src/sys/path/mod.rs19
-rw-r--r--library/std/src/sys/personality/gcc.rs22
-rw-r--r--library/std/src/sys/personality/mod.rs15
-rw-r--r--library/std/src/sys/process/mod.rs13
-rw-r--r--library/std/src/sys/process/unix/common.rs17
-rw-r--r--library/std/src/sys/process/unix/mod.rs13
-rw-r--r--library/std/src/sys/process/unix/unix.rs19
-rw-r--r--library/std/src/sys/random/mod.rs68
-rw-r--r--library/std/src/sys/random/uefi.rs7
-rw-r--r--library/std/src/sys/stdio/mod.rs37
-rw-r--r--library/std/src/sys/sync/condvar/mod.rs26
-rw-r--r--library/std/src/sys/sync/mutex/mod.rs29
-rw-r--r--library/std/src/sys/sync/once/mod.rs14
-rw-r--r--library/std/src/sys/sync/rwlock/mod.rs20
-rw-r--r--library/std/src/sys/sync/thread_parking/mod.rs26
-rw-r--r--library/std/src/sys/thread_local/mod.rs60
-rw-r--r--library/std/src/thread/current.rs13
-rw-r--r--library/std/src/thread/mod.rs14
-rw-r--r--library/std/tests/env_modify.rs9
-rw-r--r--library/std/tests/thread.rs1
-rw-r--r--library/std_detect/Cargo.toml5
-rw-r--r--library/std_detect/src/detect/arch/loongarch.rs3
-rw-r--r--library/std_detect/src/detect/arch/mod.rs36
-rw-r--r--library/std_detect/src/detect/arch/riscv.rs197
-rw-r--r--library/std_detect/src/detect/arch/x86.rs6
-rw-r--r--library/std_detect/src/detect/cache.rs14
-rw-r--r--library/std_detect/src/detect/mod.rs36
-rw-r--r--library/std_detect/src/detect/os/freebsd/mod.rs13
-rw-r--r--library/std_detect/src/detect/os/linux/auxvec.rs9
-rw-r--r--library/std_detect/src/detect/os/linux/auxvec/tests.rs8
-rw-r--r--library/std_detect/src/detect/os/linux/loongarch.rs13
-rw-r--r--library/std_detect/src/detect/os/linux/mod.rs25
-rw-r--r--library/std_detect/src/detect/os/riscv.rs22
-rw-r--r--library/std_detect/src/detect/os/x86.rs66
-rw-r--r--library/std_detect/src/lib.rs2
-rw-r--r--library/std_detect/tests/macro_trailing_commas.rs2
-rw-r--r--library/unwind/Cargo.toml1
-rw-r--r--library/unwind/src/lib.rs61
-rw-r--r--library/unwind/src/libunwind.rs353
-rw-r--r--library/unwind/src/wasm.rs7
-rw-r--r--src/bootstrap/src/bin/rustc.rs10
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs352
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs33
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs138
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs105
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs8
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs18
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs27
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs37
-rw-r--r--src/bootstrap/src/core/builder/tests.rs89
-rw-r--r--src/bootstrap/src/core/config/config.rs4
-rw-r--r--src/bootstrap/src/core/config/flags.rs12
-rw-r--r--src/bootstrap/src/core/config/mod.rs2
-rw-r--r--src/bootstrap/src/core/config/target_selection.rs2
-rw-r--r--src/bootstrap/src/lib.rs38
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs10
-rw-r--r--src/bootstrap/src/utils/tracing.rs93
-rw-r--r--src/build_helper/src/util.rs11
-rw-r--r--src/ci/docker/host-x86_64/tidy/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/tidy/eslint.version2
-rw-r--r--src/ci/github-actions/jobs.yml45
-rw-r--r--src/ci/scripts/free-disk-space-windows-wait.py21
-rw-r--r--src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md8
-rw-r--r--src/doc/rustc-dev-guide/src/sanitizers.md2
-rw-r--r--src/doc/rustc/src/codegen-options/index.md2
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/doc/rustc/src/platform-support/apple-darwin.md5
-rw-r--r--src/doc/rustc/src/platform-support/openharmony.md2
-rw-r--r--src/doc/rustc/src/target-tier-policy.md18
-rw-r--r--src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md19
-rw-r--r--src/doc/unstable-book/src/language-features/no-sanitize.md29
-rw-r--r--src/doc/unstable-book/src/language-features/sanitize.md73
-rw-r--r--src/etc/completions/x.fish1
-rw-r--r--src/etc/completions/x.ps11
-rw-r--r--src/etc/completions/x.py.fish1
-rw-r--r--src/etc/completions/x.py.ps11
-rw-r--r--src/etc/completions/x.py.sh6
-rw-r--r--src/etc/completions/x.py.zsh1
-rw-r--r--src/etc/completions/x.sh6
-rw-r--r--src/etc/completions/x.zsh1
-rwxr-xr-xsrc/etc/htmldocck.py6
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/build.rs1
-rw-r--r--src/librustdoc/clean/types.rs8
-rw-r--r--src/librustdoc/formats/cache.rs8
-rw-r--r--src/librustdoc/formats/item_type.rs52
-rw-r--r--src/librustdoc/html/layout.rs1
-rw-r--r--src/librustdoc/html/render/context.rs14
-rw-r--r--src/librustdoc/html/render/mod.rs165
-rw-r--r--src/librustdoc/html/render/print_item.rs1
-rw-r--r--src/librustdoc/html/render/search_index.rs2177
-rw-r--r--src/librustdoc/html/render/search_index/encode.rs244
-rw-r--r--src/librustdoc/html/render/write_shared.rs78
-rw-r--r--src/librustdoc/html/render/write_shared/tests.rs33
-rw-r--r--src/librustdoc/html/sources.rs1
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css408
-rw-r--r--src/librustdoc/html/static/js/main.js387
-rw-r--r--src/librustdoc/html/static/js/rustdoc.d.ts261
-rw-r--r--src/librustdoc/html/static/js/scrape-examples.js45
-rw-r--r--src/librustdoc/html/static/js/search.js5151
-rw-r--r--src/librustdoc/html/static/js/settings.js86
-rw-r--r--src/librustdoc/html/static/js/storage.js67
-rw-r--r--src/librustdoc/html/static/js/stringdex.d.ts165
-rw-r--r--src/librustdoc/html/static/js/stringdex.js3217
-rw-r--r--src/librustdoc/html/static/js/tsconfig.json2
-rw-r--r--src/librustdoc/html/static_files.rs1
-rw-r--r--src/librustdoc/html/templates/page.html19
-rw-r--r--src/librustdoc/html/templates/print_item.html4
-rw-r--r--src/tools/build-manifest/src/main.rs2
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/duplicate_mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_line_after.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_nesting.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils/mod.rs2
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr2
-rw-r--r--src/tools/compiletest/src/common.rs7
-rw-r--r--src/tools/compiletest/src/directives.rs6
-rw-r--r--src/tools/compiletest/src/lib.rs22
-rw-r--r--src/tools/compiletest/src/runtest.rs7
-rw-r--r--src/tools/html-checker/main.rs2
-rw-r--r--src/tools/miri/src/machine.rs2
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs2
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs34
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr25
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr33
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs8
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr14
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr8
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs4
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr10
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs4
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr14
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr4
-rw-r--r--src/tools/miri/tests/pass/prefetch.rs23
-rw-r--r--src/tools/nix-dev-shell/shell.nix1
-rw-r--r--src/tools/rustdoc-js/tester.js207
-rw-r--r--src/tools/rustfmt/src/items.rs2
-rw-r--r--src/tools/rustfmt/src/modules.rs7
-rw-r--r--src/tools/rustfmt/src/visitor.rs2
-rw-r--r--src/tools/tidy/src/extra_checks/mod.rs47
-rw-r--r--src/tools/tidy/src/lib.rs66
-rw-r--r--src/tools/tidy/src/main.rs1
-rw-r--r--tests/assembly-llvm/regparm-module-flag.rs70
-rw-r--r--tests/assembly-llvm/x86_64-indirect-branch-cs-prefix.rs27
-rw-r--r--tests/auxiliary/minicore.rs7
-rw-r--r--tests/codegen-llvm/enum/enum-aggregate.rs8
-rw-r--r--tests/codegen-llvm/enum/enum-match.rs2
-rw-r--r--tests/codegen-llvm/enum/enum-transparent-extract.rs2
-rw-r--r--tests/codegen-llvm/function-arguments.rs20
-rw-r--r--tests/codegen-llvm/indirect-branch-cs-prefix.rs18
-rw-r--r--tests/codegen-llvm/intrinsics/prefetch.rs72
-rw-r--r--tests/codegen-llvm/issues/issue-122734-match-eq.rs78
-rw-r--r--tests/codegen-llvm/range-attribute.rs2
-rw-r--r--tests/codegen-llvm/read-only-capture-opt.rs18
-rw-r--r--tests/codegen-llvm/repeat-operand-zero-len.rs4
-rw-r--r--tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs (renamed from tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs)6
-rw-r--r--tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs4
-rw-r--r--tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-sanitize-off.rs (renamed from tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs)6
-rw-r--r--tests/codegen-llvm/sanitizer/sanitize-off-asan-kasan.rs42
-rw-r--r--tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs (renamed from tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs)6
-rw-r--r--tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs (renamed from tests/codegen-llvm/sanitizer/no-sanitize.rs)22
-rw-r--r--tests/codegen-llvm/sanitizer/sanitize-off.rs138
-rw-r--r--tests/codegen-llvm/sanitizer/scs-attr-check.rs4
-rw-r--r--tests/codegen-llvm/transmute-scalar.rs13
-rw-r--r--tests/codegen-llvm/uninhabited-transparent-return-abi.rs2
-rw-r--r--tests/codegen-llvm/vec-calloc.rs20
-rw-r--r--tests/debuginfo/recursive-struct.rs9
-rw-r--r--tests/mir-opt/inline/inline_compatibility.rs22
-rw-r--r--tests/run-make/emit-shared-files/rmake.rs2
-rw-r--r--tests/run-make/linker-warning/short-error.txt2
-rw-r--r--tests/run-make/rustdoc-determinism/rmake.rs4
-rw-r--r--tests/run-make/rustdoc-scrape-examples-paths/rmake.rs16
-rw-r--r--tests/rustdoc-gui/code-example-buttons.goml8
-rw-r--r--tests/rustdoc-gui/copy-code.goml2
-rw-r--r--tests/rustdoc-gui/cursor.goml7
-rw-r--r--tests/rustdoc-gui/docblock-code-block-line-number.goml8
-rw-r--r--tests/rustdoc-gui/escape-key.goml11
-rw-r--r--tests/rustdoc-gui/font-serif-change.goml4
-rw-r--r--tests/rustdoc-gui/globals.goml5
-rw-r--r--tests/rustdoc-gui/help-page.goml18
-rw-r--r--tests/rustdoc-gui/hide-mobile-topbar.goml9
-rw-r--r--tests/rustdoc-gui/huge-logo.goml5
-rw-r--r--tests/rustdoc-gui/item-info.goml2
-rw-r--r--tests/rustdoc-gui/mobile-crate-name.goml14
-rw-r--r--tests/rustdoc-gui/mobile.goml2
-rw-r--r--tests/rustdoc-gui/notable-trait.goml26
-rw-r--r--tests/rustdoc-gui/pocket-menu.goml67
-rw-r--r--tests/rustdoc-gui/scrape-examples-color.goml2
-rw-r--r--tests/rustdoc-gui/scrape-examples-layout.goml8
-rw-r--r--tests/rustdoc-gui/scrape-examples-toggle.goml2
-rw-r--r--tests/rustdoc-gui/search-about-this-result.goml2
-rw-r--r--tests/rustdoc-gui/search-corrections.goml75
-rw-r--r--tests/rustdoc-gui/search-error.goml1
-rw-r--r--tests/rustdoc-gui/search-filter.goml16
-rw-r--r--tests/rustdoc-gui/search-form-elements.goml19
-rw-r--r--tests/rustdoc-gui/search-input-mobile.goml13
-rw-r--r--tests/rustdoc-gui/search-keyboard.goml21
-rw-r--r--tests/rustdoc-gui/search-reexport.goml11
-rw-r--r--tests/rustdoc-gui/search-result-color.goml7
-rw-r--r--tests/rustdoc-gui/search-result-description.goml1
-rw-r--r--tests/rustdoc-gui/search-result-display.goml9
-rw-r--r--tests/rustdoc-gui/search-result-go-to-first.goml3
-rw-r--r--tests/rustdoc-gui/search-result-impl-disambiguation.goml15
-rw-r--r--tests/rustdoc-gui/search-result-keyword.goml7
-rw-r--r--tests/rustdoc-gui/search-tab-change-title-fn-sig.goml32
-rw-r--r--tests/rustdoc-gui/search-tab.goml3
-rw-r--r--tests/rustdoc-gui/search-title.goml6
-rw-r--r--tests/rustdoc-gui/setting-auto-hide-content-large-items.goml2
-rw-r--r--tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml2
-rw-r--r--tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml2
-rw-r--r--tests/rustdoc-gui/setting-go-to-only-result.goml4
-rw-r--r--tests/rustdoc-gui/settings-button.goml2
-rw-r--r--tests/rustdoc-gui/settings.goml42
-rw-r--r--tests/rustdoc-gui/shortcuts.goml4
-rw-r--r--tests/rustdoc-gui/sidebar-mobile.goml8
-rw-r--r--tests/rustdoc-gui/sidebar-resize-close-popover.goml4
-rw-r--r--tests/rustdoc-gui/sidebar-resize-setting.goml24
-rw-r--r--tests/rustdoc-gui/sidebar-source-code-display.goml2
-rw-r--r--tests/rustdoc-gui/sidebar-source-code.goml2
-rw-r--r--tests/rustdoc-gui/sidebar.goml6
-rw-r--r--tests/rustdoc-gui/source-anchor-scroll.goml8
-rw-r--r--tests/rustdoc-gui/source-code-page.goml32
-rw-r--r--tests/rustdoc-gui/source-code-wrapping.goml4
-rw-r--r--tests/rustdoc-gui/theme-change.goml4
-rw-r--r--tests/rustdoc-gui/theme-defaults.goml4
-rw-r--r--tests/rustdoc-gui/toggle-click-deadspace.goml2
-rw-r--r--tests/rustdoc-gui/toggle-docs-mobile.goml12
-rw-r--r--tests/rustdoc-gui/toggle-docs.goml2
-rw-r--r--tests/rustdoc-gui/type-declation-overflow.goml22
-rw-r--r--tests/rustdoc-gui/utils.goml37
-rw-r--r--tests/rustdoc-js-std/alias-1.js5
-rw-r--r--tests/rustdoc-js-std/alias-2.js4
-rw-r--r--tests/rustdoc-js-std/basic.js2
-rw-r--r--tests/rustdoc-js-std/parser-bindings.js28
-rw-r--r--tests/rustdoc-js-std/parser-errors.js18
-rw-r--r--tests/rustdoc-js-std/parser-filter.js22
-rw-r--r--tests/rustdoc-js-std/parser-generics.js12
-rw-r--r--tests/rustdoc-js-std/parser-hof.js106
-rw-r--r--tests/rustdoc-js-std/parser-ident.js14
-rw-r--r--tests/rustdoc-js-std/parser-literal.js2
-rw-r--r--tests/rustdoc-js-std/parser-paths.js18
-rw-r--r--tests/rustdoc-js-std/parser-quote.js4
-rw-r--r--tests/rustdoc-js-std/parser-reference.js84
-rw-r--r--tests/rustdoc-js-std/parser-returned.js20
-rw-r--r--tests/rustdoc-js-std/parser-separators.js20
-rw-r--r--tests/rustdoc-js-std/parser-slice-array.js36
-rw-r--r--tests/rustdoc-js-std/parser-tuple.js38
-rw-r--r--tests/rustdoc-js-std/path-end-empty.js3
-rw-r--r--tests/rustdoc-js-std/path-maxeditdistance.js6
-rw-r--r--tests/rustdoc-js-std/return-specific-literal.js2
-rw-r--r--tests/rustdoc-js-std/return-specific.js2
-rw-r--r--tests/rustdoc-js/doc-alias.js13
-rw-r--r--tests/rustdoc-js/generics-trait.js21
-rw-r--r--tests/rustdoc-js/non-english-identifier.js8
-rw-r--r--tests/rustdoc-js/ordering.js9
-rw-r--r--tests/rustdoc-js/ordering.rs3
-rw-r--r--tests/rustdoc-js/type-parameters.js6
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs6
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-transitive/s.rs6
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs4
-rw-r--r--tests/rustdoc/cross-crate-info/cargo-two/e.rs4
-rw-r--r--tests/rustdoc/cross-crate-info/index-on-last/e.rs4
-rw-r--r--tests/rustdoc/cross-crate-info/kitchen-sink/i.rs8
-rw-r--r--tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs2
-rw-r--r--tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs2
-rw-r--r--tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs4
-rw-r--r--tests/rustdoc/masked.rs2
-rw-r--r--tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs6
-rw-r--r--tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs8
-rw-r--r--tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs2
-rw-r--r--tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs2
-rw-r--r--tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs6
-rw-r--r--tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs6
-rw-r--r--tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs6
-rw-r--r--tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs2
-rw-r--r--tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs2
-rw-r--r--tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs2
-rw-r--r--tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs2
-rw-r--r--tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs2
-rw-r--r--tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs6
-rw-r--r--tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs6
-rw-r--r--tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs2
-rw-r--r--tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs4
-rw-r--r--tests/rustdoc/no-unit-struct-field.rs9
-rw-r--r--tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs2
-rw-r--r--tests/rustdoc/search-index-summaries.rs2
-rw-r--r--tests/rustdoc/search-index.rs4
-rw-r--r--tests/ui-fulldeps/internal-lints/query_stability.rs13
-rw-r--r--tests/ui-fulldeps/internal-lints/query_stability.stderr34
-rw-r--r--tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr6
-rw-r--r--tests/ui/abi/debug.generic.stderr2
-rw-r--r--tests/ui/abi/debug.riscv64.stderr2
-rw-r--r--tests/ui/abi/unsupported.aarch64.stderr2
-rw-r--r--tests/ui/abi/unsupported.arm.stderr2
-rw-r--r--tests/ui/abi/unsupported.riscv32.stderr2
-rw-r--r--tests/ui/abi/unsupported.riscv64.stderr2
-rw-r--r--tests/ui/abi/unsupported.x64.stderr2
-rw-r--r--tests/ui/abi/unsupported.x64_win.stderr2
-rw-r--r--tests/ui/array-slice-vec/matching-on-vector-slice-option-8498.rs (renamed from tests/ui/issues/issue-8498.rs)1
-rw-r--r--tests/ui/array-slice-vec/pattern-matching-fixed-length-vectors-7784.rs (renamed from tests/ui/issues/issue-7784.rs)1
-rw-r--r--tests/ui/array-slice-vec/slice-mut-2.stderr6
-rw-r--r--tests/ui/associated-consts/ambiguous-associated-type-error-78622.rs (renamed from tests/ui/issues/issue-78622.rs)1
-rw-r--r--tests/ui/associated-consts/ambiguous-associated-type-error-78622.stderr (renamed from tests/ui/issues/issue-78622.stderr)2
-rw-r--r--tests/ui/associated-consts/associated-const-type-parameters.stderr2
-rw-r--r--tests/ui/associated-type-bounds/rpit.stderr2
-rw-r--r--tests/ui/associated-types/associated-types-issue-20220.stderr2
-rw-r--r--tests/ui/associated-types/associated-types-nested-projections.stderr2
-rw-r--r--tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr2
-rw-r--r--tests/ui/async-await/async-closures/type-name.rs18
-rw-r--r--tests/ui/async-await/recursive-async-auto-trait-overflow-only-parent-args.rs17
-rw-r--r--tests/ui/attributes/invalid-attributes-on-const-params-78957.rs (renamed from tests/ui/issues/issue-78957.rs)1
-rw-r--r--tests/ui/attributes/invalid-attributes-on-const-params-78957.stderr (renamed from tests/ui/issues/issue-78957.stderr)20
-rw-r--r--tests/ui/attributes/key-value-expansion-scope.stderr14
-rw-r--r--tests/ui/attributes/lint_on_root.rs2
-rw-r--r--tests/ui/attributes/lint_on_root.stderr8
-rw-r--r--tests/ui/attributes/malformed-attrs.rs4
-rw-r--r--tests/ui/attributes/malformed-attrs.stderr34
-rw-r--r--tests/ui/attributes/malformed-reprs.stderr20
-rw-r--r--tests/ui/attributes/no-sanitize.rs45
-rw-r--r--tests/ui/attributes/no-sanitize.stderr80
-rw-r--r--tests/ui/attributes/rustc_confusables.rs1
-rw-r--r--tests/ui/auto-traits/auto-traits.stderr2
-rw-r--r--tests/ui/binding/invalid-assignment-in-while-loop-77218.fixed (renamed from tests/ui/issues/issue-77218/issue-77218.fixed)1
-rw-r--r--tests/ui/binding/invalid-assignment-in-while-loop-77218.rs (renamed from tests/ui/issues/issue-77218/issue-77218.rs)1
-rw-r--r--tests/ui/binding/invalid-assignment-in-while-loop-77218.stderr (renamed from tests/ui/issues/issue-77218/issue-77218.stderr)2
-rw-r--r--tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-access-permissions.stderr7
-rw-r--r--tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr2
-rw-r--r--tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr2
-rw-r--r--tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr6
-rw-r--r--tests/ui/borrowck/incorrect-use-after-storage-end-78192.rs (renamed from tests/ui/issues/issue-78192.rs)1
-rw-r--r--tests/ui/borrowck/rvalue-lifetime-match-equivalence-7660.rs (renamed from tests/ui/issues/issue-7660.rs)2
-rw-r--r--tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.fixed21
-rw-r--r--tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.rs21
-rw-r--r--tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.stderr38
-rw-r--r--tests/ui/borrowck/suggestions/overloaded-index-without-indexmut.rs16
-rw-r--r--tests/ui/borrowck/suggestions/overloaded-index-without-indexmut.stderr9
-rw-r--r--tests/ui/borrowck/trait-impl-argument-difference-ice.stderr2
-rw-r--r--tests/ui/cast/cast-rfc0401-vtable-kinds.stderr2
-rw-r--r--tests/ui/cast/coercion-as-explicit-cast.stderr2
-rw-r--r--tests/ui/cast/fat-ptr-cast-rpass.stderr2
-rw-r--r--tests/ui/check-cfg/target_feature.stderr1
-rw-r--r--tests/ui/closures/2229_closure_analysis/match/issue-87097.stderr4
-rw-r--r--tests/ui/closures/issue-1460.stderr2
-rw-r--r--tests/ui/closures/moved-upvar-mut-rebind-11958.stderr4
-rw-r--r--tests/ui/closures/old-closure-expr-precedence.stderr2
-rw-r--r--tests/ui/closures/unused-closure-ice-16256.stderr2
-rw-r--r--tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs1
-rw-r--r--tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs1
-rw-r--r--tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs1
-rw-r--r--tests/ui/codegen/i128-shift-overflow-check-76042.rs (renamed from tests/ui/issues/issue-76042.rs)1
-rw-r--r--tests/ui/coercion/issue-14589.stderr2
-rw-r--r--tests/ui/coercion/method-return-trait-object-14399.stderr2
-rw-r--r--tests/ui/coercion/mut-trait-coercion-8248.rs (renamed from tests/ui/issues/issue-8248.rs)1
-rw-r--r--tests/ui/coercion/mut-trait-coercion-8248.stderr (renamed from tests/ui/issues/issue-8248.stderr)4
-rw-r--r--tests/ui/coercion/mut-trait-object-coercion-8398.rs (renamed from tests/ui/issues/issue-8398.rs)1
-rw-r--r--tests/ui/coercion/trait-object-coercion-distribution-9951.stderr2
-rw-r--r--tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr2
-rw-r--r--tests/ui/coherence/coherence-fn-inputs.stderr2
-rw-r--r--tests/ui/coherence/coherence-subtyping.stderr2
-rw-r--r--tests/ui/coherence/orphan-check-alias.classic.stderr2
-rw-r--r--tests/ui/coherence/orphan-check-alias.next.stderr2
-rw-r--r--tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr2
-rw-r--r--tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr2
-rw-r--r--tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr2
-rw-r--r--tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr2
-rw-r--r--tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr2
-rw-r--r--tests/ui/coherence/orphan-check-projections-not-covering.next.stderr2
-rw-r--r--tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr2
-rw-r--r--tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr2
-rw-r--r--tests/ui/const-generics/dyn-supertraits.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/function-call.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr2
-rw-r--r--tests/ui/const-generics/invariant.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-69654-run-pass.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-83466.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-86535-2.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-86535.stderr2
-rw-r--r--tests/ui/const-generics/min_const_generics/complex-expression.stderr2
-rw-r--r--tests/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr2
-rw-r--r--tests/ui/consts/const-block-item.stderr2
-rw-r--r--tests/ui/consts/const-eval/const_panic_stability.e2018.stderr2
-rw-r--r--tests/ui/consts/const-range-matching-76191.rs (renamed from tests/ui/issues/issue-76191.rs)1
-rw-r--r--tests/ui/consts/const-range-matching-76191.stderr (renamed from tests/ui/issues/issue-76191.stderr)6
-rw-r--r--tests/ui/consts/const_let_assign2.stderr2
-rw-r--r--tests/ui/consts/const_refs_to_static-ice-121413.stderr2
-rw-r--r--tests/ui/consts/packed_pattern.stderr2
-rw-r--r--tests/ui/consts/packed_pattern2.stderr2
-rw-r--r--tests/ui/coroutine/gen_block_panic.stderr2
-rw-r--r--tests/ui/coroutine/issue-52398.stderr2
-rw-r--r--tests/ui/coroutine/issue-57084.stderr2
-rw-r--r--tests/ui/coroutine/match-bindings.stderr2
-rw-r--r--tests/ui/coroutine/reborrow-mut-upvar.stderr2
-rw-r--r--tests/ui/coroutine/too-live-local-in-immovable-gen.stderr2
-rw-r--r--tests/ui/coroutine/yield-in-args-rev.stderr2
-rw-r--r--tests/ui/coroutine/yield-in-initializer.stderr2
-rw-r--r--tests/ui/coroutine/yield-subtype.stderr2
-rw-r--r--tests/ui/coverage-attr/name-value.stderr4
-rw-r--r--tests/ui/coverage-attr/word-only.stderr10
-rw-r--r--tests/ui/cross-crate/auxiliary/aux-7899.rs (renamed from tests/ui/issues/auxiliary/issue-7899.rs)0
-rw-r--r--tests/ui/cross-crate/auxiliary/aux-8259.rs (renamed from tests/ui/issues/auxiliary/issue-8259.rs)0
-rw-r--r--tests/ui/cross-crate/static-regions-in-cross-crate-8259.rs (renamed from tests/ui/issues/issue-8259.rs)6
-rw-r--r--tests/ui/cross-crate/tuple-like-structs-cross-crate-7899.rs10
-rw-r--r--tests/ui/delegation/target-expr-pass.stderr2
-rw-r--r--tests/ui/deprecation/deprecation-sanity.rs5
-rw-r--r--tests/ui/deprecation/deprecation-sanity.stderr2
-rw-r--r--tests/ui/deriving/deriving-all-codegen.rs18
-rw-r--r--tests/ui/deriving/deriving-all-codegen.stdout2
-rw-r--r--tests/ui/deriving/deriving-from-wrong-target.rs5
-rw-r--r--tests/ui/deriving/deriving-from-wrong-target.stderr52
-rw-r--r--tests/ui/deriving/deriving-from.rs2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr6
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr6
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr2
-rw-r--r--tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr2
-rw-r--r--tests/ui/drop/drop-struct-as-object.stderr2
-rw-r--r--tests/ui/drop/generic-drop-trait-bound-15858.stderr2
-rw-r--r--tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr2
-rw-r--r--tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr2
-rw-r--r--tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr2
-rw-r--r--tests/ui/dyn-keyword/auxiliary/aux-8401.rs (renamed from tests/ui/issues/auxiliary/issue-8401.rs)0
-rw-r--r--tests/ui/dyn-keyword/methods-with-mut-trait-and-polymorphic-objects-issue-8401.rs7
-rw-r--r--tests/ui/dynamically-sized-types/dst-coercions.stderr2
-rw-r--r--tests/ui/editions/never-type-fallback-breaking.e2021.stderr12
-rw-r--r--tests/ui/enum/enum-discriminant-type-mismatch-8761.rs (renamed from tests/ui/issues/issue-8761.rs)1
-rw-r--r--tests/ui/enum/enum-discriminant-type-mismatch-8761.stderr (renamed from tests/ui/issues/issue-8761.stderr)4
-rw-r--r--tests/ui/enum/enum-variant-field-error-80607.rs (renamed from tests/ui/issues/issue-80607.rs)1
-rw-r--r--tests/ui/enum/enum-variant-field-error-80607.stderr (renamed from tests/ui/issues/issue-80607.stderr)2
-rw-r--r--tests/ui/enum/simple-enum-usage-8506.rs (renamed from tests/ui/issues/issue-8506.rs)1
-rw-r--r--tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr2
-rw-r--r--tests/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr2
-rw-r--r--tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.rs15
-rw-r--r--tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.stderr12
-rw-r--r--tests/ui/explicit-tail-calls/ret-ty-modulo-anonymization.rs16
-rw-r--r--tests/ui/expr/if/if-ret.stderr2
-rw-r--r--tests/ui/extern/function-definition-in-extern-block-75283.rs (renamed from tests/ui/issues/issue-75283.rs)1
-rw-r--r--tests/ui/extern/function-definition-in-extern-block-75283.stderr (renamed from tests/ui/issues/issue-75283.stderr)2
-rw-r--r--tests/ui/extern/issue-47725.rs3
-rw-r--r--tests/ui/extern/issue-47725.stderr6
-rw-r--r--tests/ui/extern/no-mangle-associated-fn.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-derive-from.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-derive-from.stderr12
-rw-r--r--tests/ui/feature-gates/feature-gate-macro-derive.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-macro-derive.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-no_sanitize.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-no_sanitize.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-repr-simd.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-sanitize.rs7
-rw-r--r--tests/ui/feature-gates/feature-gate-sanitize.stderr23
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs2
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr4
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs91
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr401
-rw-r--r--tests/ui/fn/error-recovery-mismatch.stderr2
-rw-r--r--tests/ui/frontmatter/auxiliary/makro.rs2
-rw-r--r--tests/ui/frontmatter/proc-macro-observer.rs5
-rw-r--r--tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr6
-rw-r--r--tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr6
-rw-r--r--tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr6
-rw-r--r--tests/ui/generic-associated-types/collectivity-regression.stderr2
-rw-r--r--tests/ui/generic-associated-types/extended/lending_iterator.stderr6
-rw-r--r--tests/ui/generics/duplicate-generic-parameter-error-86756.rs (renamed from tests/ui/issues/issue-86756.rs)1
-rw-r--r--tests/ui/generics/duplicate-generic-parameter-error-86756.stderr (renamed from tests/ui/issues/issue-86756.stderr)12
-rw-r--r--tests/ui/generics/empty-generic-brackets-equiv.stderr2
-rw-r--r--tests/ui/generics/invalid-type-param-default.stderr8
-rw-r--r--tests/ui/generics/overlapping-errors-span-issue-123861.stderr4
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr2
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr2
-rw-r--r--tests/ui/impl-trait/example-st.stderr2
-rw-r--r--tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/expeced-refree-to-map-to-reearlybound-ice-108580.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/refine-captures.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/unconstrained-lt.stderr2
-rw-r--r--tests/ui/impl-trait/precise-capturing/parenthesized.rs8
-rw-r--r--tests/ui/impl-trait/precise-capturing/parenthesized.stderr14
-rw-r--r--tests/ui/impl-trait/type-alias-generic-param.stderr2
-rw-r--r--tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr12
-rw-r--r--tests/ui/imports/ambiguous-10.stderr4
-rw-r--r--tests/ui/imports/ambiguous-12.stderr4
-rw-r--r--tests/ui/imports/ambiguous-13.stderr4
-rw-r--r--tests/ui/imports/ambiguous-14.stderr4
-rw-r--r--tests/ui/imports/ambiguous-15.stderr4
-rw-r--r--tests/ui/imports/ambiguous-16.stderr4
-rw-r--r--tests/ui/imports/ambiguous-17.stderr4
-rw-r--r--tests/ui/imports/ambiguous-3.stderr4
-rw-r--r--tests/ui/imports/ambiguous-5.stderr4
-rw-r--r--tests/ui/imports/ambiguous-6.stderr4
-rw-r--r--tests/ui/imports/ambiguous-9.stderr6
-rw-r--r--tests/ui/imports/duplicate.stderr4
-rw-r--r--tests/ui/imports/local-modularized-tricky-fail-2.stderr6
-rw-r--r--tests/ui/imports/unresolved-seg-after-ambiguous.stderr4
-rw-r--r--tests/ui/inference/inference-variable-behind-raw-pointer.stderr2
-rw-r--r--tests/ui/inference/inference_unstable.stderr2
-rw-r--r--tests/ui/inference/issue-72616.stderr12
-rw-r--r--tests/ui/instrument-coverage/link-regex-crate-with-instrument-coverage-85461.rs (renamed from tests/ui/issues/issue-85461.rs)1
-rw-r--r--tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr4
-rw-r--r--tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs21
-rw-r--r--tests/ui/invalid/invalid-no-sanitize.rs5
-rw-r--r--tests/ui/invalid/invalid-no-sanitize.stderr10
-rw-r--r--tests/ui/issues/issue-17351.stderr2
-rw-r--r--tests/ui/issues/issue-20055-box-trait.stderr2
-rw-r--r--tests/ui/issues/issue-23485.stderr2
-rw-r--r--tests/ui/issues/issue-26217.stderr6
-rw-r--r--tests/ui/issues/issue-28344.stderr2
-rw-r--r--tests/ui/issues/issue-2989.stderr2
-rw-r--r--tests/ui/issues/issue-34503.stderr2
-rw-r--r--tests/ui/issues/issue-39367.stderr2
-rw-r--r--tests/ui/issues/issue-47094.stderr6
-rw-r--r--tests/ui/issues/issue-58734.stderr2
-rw-r--r--tests/ui/issues/issue-72278.stderr2
-rw-r--r--tests/ui/issues/issue-7575.stderr10
-rw-r--r--tests/ui/issues/issue-77218/issue-77218-2.fixed6
-rw-r--r--tests/ui/issues/issue-77218/issue-77218-2.rs6
-rw-r--r--tests/ui/issues/issue-77218/issue-77218-2.stderr16
-rw-r--r--tests/ui/issues/issue-7899.rs10
-rw-r--r--tests/ui/issues/issue-8044.rs10
-rw-r--r--tests/ui/issues/issue-8401.rs7
-rw-r--r--tests/ui/issues/issue-9123.rs7
-rw-r--r--tests/ui/iterators/into-iter-on-arrays-2018.stderr2
-rw-r--r--tests/ui/iterators/into-iter-on-arrays-lint.stderr2
-rw-r--r--tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr2
-rw-r--r--tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr2
-rw-r--r--tests/ui/iterators/iterator-scope-collect-suggestion-81584.fixed (renamed from tests/ui/issues/issue-81584.fixed)1
-rw-r--r--tests/ui/iterators/iterator-scope-collect-suggestion-81584.rs (renamed from tests/ui/issues/issue-81584.rs)1
-rw-r--r--tests/ui/iterators/iterator-scope-collect-suggestion-81584.stderr (renamed from tests/ui/issues/issue-81584.stderr)2
-rw-r--r--tests/ui/lang-items/issue-83471.stderr2
-rw-r--r--tests/ui/lifetimes/issue-105507.fixed4
-rw-r--r--tests/ui/lifetimes/issue-105507.rs4
-rw-r--r--tests/ui/lifetimes/issue-105507.stderr4
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.stderr4
-rw-r--r--tests/ui/link-native-libs/link-attr-validation-early.stderr6
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr2
-rw-r--r--tests/ui/lint/bare-trait-objects-path.stderr2
-rw-r--r--tests/ui/lint/forbid-group-member.stderr4
-rw-r--r--tests/ui/lint/future-incompatible-lint-group.stderr2
-rw-r--r--tests/ui/lint/let_underscore/let_underscore_lock.stderr2
-rw-r--r--tests/ui/lint/lint-non-uppercase-usages.stderr2
-rw-r--r--tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.rs22
-rw-r--r--tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.stderr23
-rw-r--r--tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr2
-rw-r--r--tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr4
-rw-r--r--tests/ui/lint/special-upper-lower-cases.stderr6
-rw-r--r--tests/ui/lint/static-mut-refs.e2021.stderr2
-rw-r--r--tests/ui/lint/static-mut-refs.e2024.stderr2
-rw-r--r--tests/ui/lint/unused/issue-70041.stderr4
-rw-r--r--tests/ui/lint/unused/unused_attributes-must_use.fixed63
-rw-r--r--tests/ui/lint/unused/unused_attributes-must_use.rs63
-rw-r--r--tests/ui/lint/unused/unused_attributes-must_use.stderr193
-rw-r--r--tests/ui/macros/issue-111749.stderr4
-rw-r--r--tests/ui/macros/lint-trailing-macro-call.stderr4
-rw-r--r--tests/ui/macros/macro-context.stderr4
-rw-r--r--tests/ui/macros/macro-in-expression-context.fixed2
-rw-r--r--tests/ui/macros/macro-in-expression-context.rs2
-rw-r--r--tests/ui/macros/macro-in-expression-context.stderr4
-rw-r--r--tests/ui/macros/macro-invocation-span-error-7970.rs (renamed from tests/ui/issues/issue-7970a.rs)5
-rw-r--r--tests/ui/macros/macro-invocation-span-error-7970.stderr (renamed from tests/ui/issues/issue-7970a.stderr)6
-rw-r--r--tests/ui/macros/macro-path-type-bounds-8521.rs (renamed from tests/ui/issues/issue-8521.rs)1
-rw-r--r--tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr6
-rw-r--r--tests/ui/macros/macro-rules-derive-error.rs51
-rw-r--r--tests/ui/macros/macro-rules-derive-error.stderr75
-rw-r--r--tests/ui/macros/macro-rules-derive.rs71
-rw-r--r--tests/ui/macros/macro-rules-derive.run.stdout17
-rw-r--r--tests/ui/macros/macro-self-mutability-7911.rs (renamed from tests/ui/issues/issue-7911.rs)1
-rw-r--r--tests/ui/macros/macro-self-mutability-7911.stderr (renamed from tests/ui/issues/issue-7911.stderr)4
-rw-r--r--tests/ui/macros/missing-derive-3.stderr15
-rw-r--r--tests/ui/macros/non-fmt-panic.stderr2
-rw-r--r--tests/ui/malformed/malformed-regressions.stderr12
-rw-r--r--tests/ui/match/mismatched-types-in-match-pattern-7867.rs (renamed from tests/ui/issues/issue-7867.rs)1
-rw-r--r--tests/ui/match/mismatched-types-in-match-pattern-7867.stderr (renamed from tests/ui/issues/issue-7867.stderr)2
-rw-r--r--tests/ui/methods/method-call-lifetime-args-unresolved.stderr2
-rw-r--r--tests/ui/methods/method-recursive-blanket-impl.stderr2
-rw-r--r--tests/ui/methods/method-two-trait-defer-resolution-2.stderr2
-rw-r--r--tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr2
-rw-r--r--tests/ui/methods/trait-method-self-param-error-7575.rs (renamed from tests/ui/issues/issue-7575.rs)1
-rw-r--r--tests/ui/methods/trait-method-self-param-error-7575.stderr10
-rw-r--r--tests/ui/mir/mir-cfg-unpretty-check-81918.rs (renamed from tests/ui/issues/issue-81918.rs)1
-rw-r--r--tests/ui/mir/mir_raw_fat_ptr.stderr2
-rw-r--r--tests/ui/mismatched_types/closure-arg-type-mismatch.stderr2
-rw-r--r--tests/ui/mismatched_types/mismatched-types-in-trait-implementation-87490.rs (renamed from tests/ui/issues/issue-87490.rs)1
-rw-r--r--tests/ui/mismatched_types/mismatched-types-in-trait-implementation-87490.stderr (renamed from tests/ui/issues/issue-87490.stderr)2
-rw-r--r--tests/ui/moves/issue-22536-copy-mustnt-zero.stderr2
-rw-r--r--tests/ui/never_type/defaulted-never-note.nofallback.stderr4
-rw-r--r--tests/ui/never_type/dependency-on-fallback-to-unit.stderr6
-rw-r--r--tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr6
-rw-r--r--tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr4
-rw-r--r--tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr4
-rw-r--r--tests/ui/never_type/fallback-closure-ret.nofallback.stderr4
-rw-r--r--tests/ui/never_type/impl_trait_fallback.stderr4
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr22
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr22
-rw-r--r--tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr2
-rw-r--r--tests/ui/nll/issue-48623-coroutine.stderr2
-rw-r--r--tests/ui/nll/local-outlives-static-via-hrtb.stderr12
-rw-r--r--tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr6
-rw-r--r--tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr6
-rw-r--r--tests/ui/nll/type-test-universe.stderr6
-rw-r--r--tests/ui/overloaded/issue-14958.stderr2
-rw-r--r--tests/ui/overloaded/overloaded-index-in-field.stderr2
-rw-r--r--tests/ui/parser/macro/macro-attr-bad.rs4
-rw-r--r--tests/ui/parser/macro/macro-attr-bad.stderr4
-rw-r--r--tests/ui/parser/macro/macro-attr-recovery.rs2
-rw-r--r--tests/ui/parser/macro/macro-attr-recovery.stderr2
-rw-r--r--tests/ui/parser/macro/macro-derive-bad.rs43
-rw-r--r--tests/ui/parser/macro/macro-derive-bad.stderr90
-rw-r--r--tests/ui/parser/recover/recover-pat-ranges.stderr2
-rw-r--r--tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr2
-rw-r--r--tests/ui/parser/trait-object-lifetime-parens.e2015.stderr4
-rw-r--r--tests/ui/parser/trait-object-lifetime-parens.e2021.stderr4
-rw-r--r--tests/ui/parser/trait-object-lifetime-parens.rs4
-rw-r--r--tests/ui/parser/trait-object-trait-parens.stderr2
-rw-r--r--tests/ui/pattern/match-with-at-binding-8391.rs (renamed from tests/ui/issues/issue-8391.rs)1
-rw-r--r--tests/ui/pattern/ref-in-function-parameter-patterns-8860.rs (renamed from tests/ui/issues/issue-8860.rs)1
-rw-r--r--tests/ui/pattern/skipped-ref-pats-issue-125058.stderr4
-rw-r--r--tests/ui/privacy/inaccessible-fields-pattern-matching-76077.fixed (renamed from tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.fixed)1
-rw-r--r--tests/ui/privacy/inaccessible-fields-pattern-matching-76077.rs (renamed from tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.rs)1
-rw-r--r--tests/ui/privacy/inaccessible-fields-pattern-matching-76077.stderr (renamed from tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.stderr)4
-rw-r--r--tests/ui/privacy/macro-private-reexport.stderr4
-rw-r--r--tests/ui/privacy/private-field-struct-construction-76077.rs (renamed from tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077.rs)1
-rw-r--r--tests/ui/privacy/private-field-struct-construction-76077.stderr (renamed from tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077.stderr)2
-rw-r--r--tests/ui/proc-macro/derive-helper-shadowing.stderr4
-rw-r--r--tests/ui/proc-macro/generate-mod.stderr10
-rw-r--r--tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr4
-rw-r--r--tests/ui/proc-macro/proc-macro-attributes.stderr10
-rw-r--r--tests/ui/pub/pub-reexport-priv-extern-crate.stderr4
-rw-r--r--tests/ui/reachable/expr_cast.rs24
-rw-r--r--tests/ui/reachable/expr_cast.stderr24
-rw-r--r--tests/ui/reachable/unreachable-try-pattern.rs2
-rw-r--r--tests/ui/reachable/unreachable-try-pattern.stderr11
-rw-r--r--tests/ui/recursion/infinite-function-recursion-error-8727.rs (renamed from tests/ui/issues/issue-8727.rs)2
-rw-r--r--tests/ui/recursion/infinite-function-recursion-error-8727.stderr (renamed from tests/ui/issues/issue-8727.stderr)8
-rw-r--r--tests/ui/repr/conflicting-repr-hints.stderr6
-rw-r--r--tests/ui/resolve/module-import-resolution-7663.rs (renamed from tests/ui/issues/issue-7663.rs)1
-rw-r--r--tests/ui/resolve/path-attr-in-const-block.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.stderr2
-rw-r--r--tests/ui/rust-2018/uniform-paths/macro-rules.stderr4
-rw-r--r--tests/ui/sanitize-attr/invalid-sanitize.rs22
-rw-r--r--tests/ui/sanitize-attr/invalid-sanitize.stderr82
-rw-r--r--tests/ui/sanitize-attr/valid-sanitize.rs115
-rw-r--r--tests/ui/sanitize-attr/valid-sanitize.stderr190
-rw-r--r--tests/ui/sanitizer/inline-always-sanitize.rs (renamed from tests/ui/sanitizer/inline-always.rs)6
-rw-r--r--tests/ui/sanitizer/inline-always-sanitize.stderr15
-rw-r--r--tests/ui/sanitizer/inline-always.stderr15
-rw-r--r--tests/ui/self/self-ctor-nongeneric.stderr2
-rw-r--r--tests/ui/sized/coinductive-2.stderr2
-rw-r--r--tests/ui/span/issue-24690.stderr2
-rw-r--r--tests/ui/static/static-struct-with-option-8578.rs (renamed from tests/ui/issues/issue-8578.rs)1
-rw-r--r--tests/ui/statics/issue-15261.stderr2
-rw-r--r--tests/ui/statics/static-impl.stderr2
-rw-r--r--tests/ui/statics/static-mut-shared-parens.stderr2
-rw-r--r--tests/ui/statics/static-mut-xc.stderr2
-rw-r--r--tests/ui/statics/static-recursive.stderr2
-rw-r--r--tests/ui/std/issue-3563-3.stderr2
-rw-r--r--tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr2
-rw-r--r--tests/ui/structs-enums/auxiliary/aux-8044.rs (renamed from tests/ui/issues/auxiliary/issue-8044.rs)0
-rw-r--r--tests/ui/structs-enums/enum-null-pointer-opt.stderr2
-rw-r--r--tests/ui/structs-enums/struct-and-enum-usage-8044.rs10
-rw-r--r--tests/ui/structs/destructuring-struct-type-inference-8783.rs (renamed from tests/ui/issues/issue-8783.rs)1
-rw-r--r--tests/ui/suggestions/dont-try-removing-the-field.stderr2
-rw-r--r--tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr2
-rw-r--r--tests/ui/suggestions/issue-116434-2015.stderr2
-rw-r--r--tests/ui/suggestions/partialeq_suggest_swap_on_e0277.stderr2
-rw-r--r--tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr2
-rw-r--r--tests/ui/suggestions/try-removing-the-field.stderr2
-rw-r--r--tests/ui/thir-print/break-outside-loop-error-83048.rs (renamed from tests/ui/issues/issue-83048.rs)1
-rw-r--r--tests/ui/thir-print/break-outside-loop-error-83048.stderr (renamed from tests/ui/issues/issue-83048.stderr)2
-rw-r--r--tests/ui/track-diagnostics/track-caller-for-once-87707.rs (renamed from tests/ui/issues/issue-87707.rs)1
-rw-r--r--tests/ui/track-diagnostics/track-caller-for-once-87707.run.stderr (renamed from tests/ui/issues/issue-87707.run.stderr)4
-rw-r--r--tests/ui/trait-bounds/relaxed-bounds-assumed-unsized-87199.rs (renamed from tests/ui/issues/issue-87199.rs)1
-rw-r--r--tests/ui/trait-bounds/relaxed-bounds-assumed-unsized-87199.stderr (renamed from tests/ui/issues/issue-87199.stderr)12
-rw-r--r--tests/ui/traits/alias/bounds.stderr2
-rw-r--r--tests/ui/traits/alias/style_lint.stderr2
-rw-r--r--tests/ui/traits/auxiliary/aux-9123.rs (renamed from tests/ui/issues/auxiliary/issue-9123.rs)0
-rw-r--r--tests/ui/traits/bound/not-on-bare-trait.stderr2
-rw-r--r--tests/ui/traits/const-traits/const-supertraits-dyn-compat.rs18
-rw-r--r--tests/ui/traits/const-traits/const-supertraits-dyn-compat.stderr18
-rw-r--r--tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr2
-rw-r--r--tests/ui/traits/default-method-fn-call-9123.rs7
-rw-r--r--tests/ui/traits/default-method/bound-subst4.stderr2
-rw-r--r--tests/ui/traits/impl-inherent-prefer-over-trait.stderr2
-rw-r--r--tests/ui/traits/impl-object-overlap-issue-23853.stderr2
-rw-r--r--tests/ui/traits/impl.stderr2
-rw-r--r--tests/ui/traits/issue-38033.stderr2
-rw-r--r--tests/ui/traits/issue-6128.stderr2
-rw-r--r--tests/ui/traits/missing-for-type-in-impl.e2015.stderr2
-rw-r--r--tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr2
-rw-r--r--tests/ui/traits/multidispatch-infer-convert-target.stderr2
-rw-r--r--tests/ui/traits/mut-trait-in-struct-8249.rs (renamed from tests/ui/issues/issue-8249.rs)1
-rw-r--r--tests/ui/traits/negative-bounds/negative-metasized.current.stderr39
-rw-r--r--tests/ui/traits/negative-bounds/negative-metasized.next.stderr39
-rw-r--r--tests/ui/traits/negative-bounds/negative-metasized.rs21
-rw-r--r--tests/ui/traits/polymorphic-trait-creation-7673.rs (renamed from tests/ui/issues/issue-7673-cast-generically-implemented-trait.rs)1
-rw-r--r--tests/ui/traits/self-implements-kinds-in-default-methods-8171.rs (renamed from tests/ui/issues/issue-8171-default-method-self-inherit-builtin-trait.rs)1
-rw-r--r--tests/ui/traits/trait-implementation-and-usage-7563.rs (renamed from tests/ui/issues/issue-7563.rs)1
-rw-r--r--tests/ui/traits/trait-upcasting/lifetime.stderr2
-rw-r--r--tests/ui/traits/trait-upcasting/replace-vptr.stderr2
-rw-r--r--tests/ui/traits/unspecified-self-in-trait-ref.stderr2
-rw-r--r--tests/ui/transmutability/references/reject_lifetime_extension.stderr6
-rw-r--r--tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/higher_kinded_params3.rs3
-rw-r--r--tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr11
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden3.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr11
-rw-r--r--tests/ui/typeck/impl-for-nonexistent-type-error-8767.rs (renamed from tests/ui/issues/issue-8767.rs)1
-rw-r--r--tests/ui/typeck/impl-for-nonexistent-type-error-8767.stderr (renamed from tests/ui/issues/issue-8767.stderr)2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr4
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-move-mutable.stderr2
-rw-r--r--tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr2
-rw-r--r--tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr2
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr2
-rw-r--r--tests/ui/where-clauses/unsupported_attribute.stderr4
-rw-r--r--tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr2
-rw-r--r--tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr2
-rw-r--r--triagebot.toml20
-rw-r--r--typos.toml1
968 files changed, 18139 insertions, 10225 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 85df0dda818..6f7a309894c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3367,6 +3367,7 @@ dependencies = [
  "rand 0.9.2",
  "rand_xoshiro",
  "rustc_data_structures",
+ "rustc_error_messages",
  "rustc_hashes",
  "rustc_index",
  "rustc_macros",
@@ -3779,6 +3780,8 @@ dependencies = [
  "icu_locid",
  "icu_provider_adapters",
  "intl-memoizer",
+ "rustc_ast",
+ "rustc_ast_pretty",
  "rustc_baked_icu_data",
  "rustc_data_structures",
  "rustc_macros",
@@ -3795,22 +3798,18 @@ dependencies = [
  "annotate-snippets 0.11.5",
  "derive_setters",
  "rustc_abi",
- "rustc_ast",
- "rustc_ast_pretty",
  "rustc_data_structures",
  "rustc_error_codes",
  "rustc_error_messages",
  "rustc_fluent_macro",
  "rustc_hashes",
- "rustc_hir",
+ "rustc_hir_id",
  "rustc_index",
  "rustc_lexer",
  "rustc_lint_defs",
  "rustc_macros",
  "rustc_serialize",
  "rustc_span",
- "rustc_target",
- "rustc_type_ir",
  "serde",
  "serde_json",
  "termcolor",
@@ -3898,7 +3897,9 @@ dependencies = [
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_data_structures",
+ "rustc_error_messages",
  "rustc_hashes",
+ "rustc_hir_id",
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
@@ -3937,6 +3938,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustc_hir_id"
+version = "0.0.0"
+dependencies = [
+ "rustc_data_structures",
+ "rustc_index",
+ "rustc_macros",
+ "rustc_serialize",
+ "rustc_span",
+]
+
+[[package]]
 name = "rustc_hir_pretty"
 version = "0.0.0"
 dependencies = [
@@ -4127,7 +4139,7 @@ dependencies = [
  "rustc_ast",
  "rustc_data_structures",
  "rustc_error_messages",
- "rustc_hir",
+ "rustc_hir_id",
  "rustc_macros",
  "rustc_serialize",
  "rustc_span",
@@ -4268,7 +4280,6 @@ dependencies = [
  "rustc_errors",
  "rustc_fluent_macro",
  "rustc_graphviz",
- "rustc_hir",
  "rustc_index",
  "rustc_macros",
  "rustc_middle",
@@ -4647,6 +4658,7 @@ dependencies = [
  "object 0.37.2",
  "rustc_abi",
  "rustc_data_structures",
+ "rustc_error_messages",
  "rustc_fs_util",
  "rustc_macros",
  "rustc_serialize",
@@ -4710,7 +4722,6 @@ name = "rustc_traits"
 version = "0.0.0"
 dependencies = [
  "rustc_data_structures",
- "rustc_hir",
  "rustc_infer",
  "rustc_middle",
  "rustc_span",
@@ -4765,6 +4776,7 @@ dependencies = [
  "rustc-hash 2.1.1",
  "rustc_ast_ir",
  "rustc_data_structures",
+ "rustc_error_messages",
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
@@ -4812,6 +4824,7 @@ dependencies = [
  "serde_json",
  "sha2",
  "smallvec",
+ "stringdex",
  "tempfile",
  "threadpool",
  "tracing",
@@ -5226,6 +5239,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "stringdex"
+version = "0.0.1-alpha4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2841fd43df5b1ff1b042e167068a1fe9b163dc93041eae56ab2296859013a9a0"
+dependencies = [
+ "stacker",
+]
+
+[[package]]
 name = "strsim"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/RELEASES.md b/RELEASES.md
index b6dc0628646..33abe45ce46 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1778,7 +1778,7 @@ Language
 - [Undeprecate lint `unstable_features` and make use of it in the compiler.](https://github.com/rust-lang/rust/pull/118639/)
 - [Make inductive cycles in coherence ambiguous always.](https://github.com/rust-lang/rust/pull/118649/)
 - [Get rid of type-driven traversal in const-eval interning](https://github.com/rust-lang/rust/pull/119044/),
-  only as a [future compatiblity lint](https://github.com/rust-lang/rust/pull/122204) for now.
+  only as a [future compatibility lint](https://github.com/rust-lang/rust/pull/122204) for now.
 - [Deny braced macro invocations in let-else.](https://github.com/rust-lang/rust/pull/119062/)
 
 <a id="1.77.0-Compiler"></a>
diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml
index 5f9afc46a1a..83d96d8d04d 100644
--- a/compiler/rustc_abi/Cargo.toml
+++ b/compiler/rustc_abi/Cargo.toml
@@ -9,6 +9,7 @@ bitflags = "2.4.1"
 rand = { version = "0.9.0", default-features = false, optional = true }
 rand_xoshiro = { version = "0.7.0", optional = true }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
+rustc_error_messages = { path = "../rustc_error_messages", optional = true }
 rustc_hashes = { path = "../rustc_hashes" }
 rustc_index = { path = "../rustc_index", default-features = false }
 rustc_macros = { path = "../rustc_macros", optional = true }
@@ -24,6 +25,7 @@ default = ["nightly", "randomize"]
 # without depending on rustc_data_structures, rustc_macros and rustc_serialize
 nightly = [
     "dep:rustc_data_structures",
+    "dep:rustc_error_messages",
     "dep:rustc_macros",
     "dep:rustc_serialize",
     "dep:rustc_span",
diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs
index 29a3678abf3..41d744e1946 100644
--- a/compiler/rustc_abi/src/extern_abi.rs
+++ b/compiler/rustc_abi/src/extern_abi.rs
@@ -223,6 +223,9 @@ impl StableOrd for ExternAbi {
     const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
 }
 
+#[cfg(feature = "nightly")]
+rustc_error_messages::into_diag_arg_using_display!(ExternAbi);
+
 impl ExternAbi {
     /// An ABI "like Rust"
     ///
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 87c9c797ea5..de3e0e0c87f 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3137,7 +3137,7 @@ impl FnRetTy {
 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, Walkable)]
 pub enum Inline {
     Yes,
-    No,
+    No { had_parse_error: Result<(), ErrorGuaranteed> },
 }
 
 /// Module item kind.
@@ -3147,7 +3147,7 @@ pub enum ModKind {
     /// or with definition outlined to a separate file `mod foo;` and already loaded from it.
     /// The inner span is from the first token past `{` to the last token until `}`,
     /// or from the first to the last token in the loaded file.
-    Loaded(ThinVec<Box<Item>>, Inline, ModSpans, Result<(), ErrorGuaranteed>),
+    Loaded(ThinVec<Box<Item>>, Inline, ModSpans),
     /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
     Unloaded,
 }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index e55399adfb8..f4f35a4d2ee 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -907,6 +907,12 @@ impl TokenTreeCursor {
     pub fn bump(&mut self) {
         self.index += 1;
     }
+
+    // For skipping ahead in rare circumstances.
+    #[inline]
+    pub fn bump_to_end(&mut self) {
+        self.index = self.stream.len();
+    }
 }
 
 /// A `TokenStream` cursor that produces `Token`s. It's a bit odd that
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 72817a0a9a0..cd0f9f2403e 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -251,7 +251,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             ItemKind::Mod(_, ident, mod_kind) => {
                 let ident = self.lower_ident(*ident);
                 match mod_kind {
-                    ModKind::Loaded(items, _, spans, _) => {
+                    ModKind::Loaded(items, _, spans) => {
                         hir::ItemKind::Mod(ident, self.lower_mod(items, spans))
                     }
                     ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 0c72f319007..f8ad6504a68 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1169,7 +1169,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
                 }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
-                if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _))
+                if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
                     && !attr::contains_name(&item.attrs, sym::path)
                 {
                     self.check_mod_file_item_asciionly(*ident);
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index 4fb66a81652..067d95a0f48 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -12,9 +12,11 @@ attr_parsing_empty_attribute =
 
 attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target}
     .help = `#[{$name}]` can {$only}be applied to {$applied}
+    .suggestion = remove the attribute
 attr_parsing_invalid_target_lint = `#[{$name}]` attribute cannot be used on {$target}
     .warn = {-attr_parsing_previously_accepted}
     .help = `#[{$name}]` can {$only}be applied to {$applied}
+    .suggestion = remove the attribute
 
 attr_parsing_empty_confusables =
     expected at least one confusable name
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index 8101c91460f..d3a61f3a653 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -54,6 +54,8 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
         Allow(Target::TyAlias),
         Allow(Target::Use),
         Allow(Target::ForeignFn),
+        Allow(Target::ForeignStatic),
+        Allow(Target::ForeignTy),
         Allow(Target::Field),
         Allow(Target::Trait),
         Allow(Target::AssocTy),
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index 6a659a95b85..33c21bad240 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -62,8 +62,8 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
                 }
             }
             ArgParser::NameValue(_) => {
-                let suggestions =
-                    <Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "inline");
+                let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
+                    .suggestions(cx.attr_style, "inline");
                 let span = cx.attr_span;
                 cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
                 return None;
diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
index c9b5dd35fa1..8928129c201 100644
--- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
@@ -107,7 +107,7 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser {
                     }
                 }
                 ArgParser::NameValue(_) => {
-                    let suggestions = MACRO_USE_TEMPLATE.suggestions(false, sym::macro_use);
+                    let suggestions = MACRO_USE_TEMPLATE.suggestions(cx.attr_style, sym::macro_use);
                     cx.emit_err(session_diagnostics::IllFormedAttributeInputLint {
                         num_suggestions: suggestions.len(),
                         suggestions: DiagArgValue::StrListSepByAnd(
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index ed5d1d92b8c..3d6e26a24b8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -43,6 +43,7 @@ pub(crate) mod no_implicit_prelude;
 pub(crate) mod non_exhaustive;
 pub(crate) mod path;
 pub(crate) mod proc_macro_attrs;
+pub(crate) mod prototype;
 pub(crate) mod repr;
 pub(crate) mod rustc_internal;
 pub(crate) mod semantics;
diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
index b6cfc780590..eb2b39298bc 100644
--- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
@@ -1,10 +1,12 @@
 use rustc_errors::DiagArgValue;
 use rustc_feature::{AttributeTemplate, template};
 use rustc_hir::attrs::AttributeKind;
+use rustc_hir::{MethodKind, Target};
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage};
+use crate::context::MaybeWarn::{Allow, Error};
+use crate::context::{AcceptContext, AllowedTargets, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
 pub(crate) struct MustUseParser;
@@ -13,7 +15,21 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
     const PATH: &[Symbol] = &[sym::must_use];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
+        Allow(Target::Fn),
+        Allow(Target::Enum),
+        Allow(Target::Struct),
+        Allow(Target::Union),
+        Allow(Target::Method(MethodKind::Trait { body: false })),
+        Allow(Target::Method(MethodKind::Trait { body: true })),
+        Allow(Target::Method(MethodKind::Inherent)),
+        Allow(Target::ForeignFn),
+        // `impl Trait` in return position can trip
+        // `unused_must_use` if `Trait` is marked as
+        // `#[must_use]`
+        Allow(Target::Trait),
+        Error(Target::WherePredicate),
+    ]);
     const TEMPLATE: AttributeTemplate = template!(
         Word, NameValueStr: "reason",
         "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
@@ -35,8 +51,8 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
                     Some(value_str)
                 }
                 ArgParser::List(_) => {
-                    let suggestions =
-                        <Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "must_use");
+                    let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
+                        .suggestions(cx.attr_style, "must_use");
                     cx.emit_err(session_diagnostics::IllFormedAttributeInputLint {
                         num_suggestions: suggestions.len(),
                         suggestions: DiagArgValue::StrListSepByAnd(
diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs
new file mode 100644
index 00000000000..fb1e47298b4
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs
@@ -0,0 +1,140 @@
+//! Attributes that are only used on function prototypes.
+
+use rustc_feature::{AttributeTemplate, template};
+use rustc_hir::Target;
+use rustc_hir::attrs::{AttributeKind, MirDialect, MirPhase};
+use rustc_span::{Span, Symbol, sym};
+
+use super::{AttributeOrder, OnDuplicate};
+use crate::attributes::SingleAttributeParser;
+use crate::context::{AcceptContext, AllowedTargets, MaybeWarn, Stage};
+use crate::parser::ArgParser;
+
+pub(crate) struct CustomMirParser;
+
+impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
+    const PATH: &[rustc_span::Symbol] = &[sym::custom_mir];
+
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[MaybeWarn::Allow(Target::Fn)]);
+
+    const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let Some(list) = args.list() else {
+            cx.expected_list(cx.attr_span);
+            return None;
+        };
+
+        let mut dialect = None;
+        let mut phase = None;
+        let mut failed = false;
+
+        for item in list.mixed() {
+            let Some(meta_item) = item.meta_item() else {
+                cx.expected_name_value(item.span(), None);
+                failed = true;
+                break;
+            };
+
+            if let Some(arg) = meta_item.word_is(sym::dialect) {
+                extract_value(cx, sym::dialect, arg, meta_item.span(), &mut dialect, &mut failed);
+            } else if let Some(arg) = meta_item.word_is(sym::phase) {
+                extract_value(cx, sym::phase, arg, meta_item.span(), &mut phase, &mut failed);
+            } else if let Some(word) = meta_item.path().word() {
+                let word = word.to_string();
+                cx.unknown_key(meta_item.span(), word, &["dialect", "phase"]);
+                failed = true;
+            } else {
+                cx.expected_name_value(meta_item.span(), None);
+                failed = true;
+            };
+        }
+
+        let dialect = parse_dialect(cx, dialect, &mut failed);
+        let phase = parse_phase(cx, phase, &mut failed);
+
+        if failed {
+            return None;
+        }
+
+        Some(AttributeKind::CustomMir(dialect, phase, cx.attr_span))
+    }
+}
+
+fn extract_value<S: Stage>(
+    cx: &mut AcceptContext<'_, '_, S>,
+    key: Symbol,
+    arg: &ArgParser<'_>,
+    span: Span,
+    out_val: &mut Option<(Symbol, Span)>,
+    failed: &mut bool,
+) {
+    if out_val.is_some() {
+        cx.duplicate_key(span, key);
+        *failed = true;
+        return;
+    }
+
+    let Some(val) = arg.name_value() else {
+        cx.expected_single_argument(arg.span().unwrap_or(span));
+        *failed = true;
+        return;
+    };
+
+    let Some(value_sym) = val.value_as_str() else {
+        cx.expected_string_literal(val.value_span, Some(val.value_as_lit()));
+        *failed = true;
+        return;
+    };
+
+    *out_val = Some((value_sym, val.value_span));
+}
+
+fn parse_dialect<S: Stage>(
+    cx: &mut AcceptContext<'_, '_, S>,
+    dialect: Option<(Symbol, Span)>,
+    failed: &mut bool,
+) -> Option<(MirDialect, Span)> {
+    let (dialect, span) = dialect?;
+
+    let dialect = match dialect {
+        sym::analysis => MirDialect::Analysis,
+        sym::built => MirDialect::Built,
+        sym::runtime => MirDialect::Runtime,
+
+        _ => {
+            cx.expected_specific_argument(span, vec!["analysis", "built", "runtime"]);
+            *failed = true;
+            return None;
+        }
+    };
+
+    Some((dialect, span))
+}
+
+fn parse_phase<S: Stage>(
+    cx: &mut AcceptContext<'_, '_, S>,
+    phase: Option<(Symbol, Span)>,
+    failed: &mut bool,
+) -> Option<(MirPhase, Span)> {
+    let (phase, span) = phase?;
+
+    let phase = match phase {
+        sym::initial => MirPhase::Initial,
+        sym::post_cleanup => MirPhase::PostCleanup,
+        sym::optimized => MirPhase::Optimized,
+
+        _ => {
+            cx.expected_specific_argument(span, vec!["initial", "post-cleanup", "optimized"]);
+            *failed = true;
+            return None;
+        }
+    };
+
+    Some((phase, span))
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 5a26178f84b..c7a809d7d88 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -54,6 +54,7 @@ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
     Allow(Target::Static),
     Allow(Target::ForeignFn),
     Allow(Target::ForeignStatic),
+    Allow(Target::ExternCrate),
 ]);
 
 #[derive(Default)]
diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
index 8b666c3868b..164c680b8a8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
@@ -29,7 +29,7 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
                 ArgParser::NameValue(name_value) => {
                     let Some(str_value) = name_value.value_as_str() else {
                         let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
-                            .suggestions(false, "ignore");
+                            .suggestions(cx.attr_style, "ignore");
                         let span = cx.attr_span;
                         cx.emit_lint(
                             AttributeLintKind::IllFormedAttributeInput { suggestions },
@@ -40,8 +40,8 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
                     Some(str_value)
                 }
                 ArgParser::List(_) => {
-                    let suggestions =
-                        <Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "ignore");
+                    let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
+                        .suggestions(cx.attr_style, "ignore");
                     let span = cx.attr_span;
                     cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
                     return None;
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index bebe3350c4e..c0d3bc99ba9 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -5,7 +5,7 @@ use std::sync::LazyLock;
 
 use itertools::Itertools;
 use private::Sealed;
-use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId};
+use rustc_ast::{self as ast, AttrStyle, LitKind, MetaItemLit, NodeId};
 use rustc_errors::{DiagCtxtHandle, Diagnostic};
 use rustc_feature::{AttributeTemplate, Features};
 use rustc_hir::attrs::AttributeKind;
@@ -46,6 +46,7 @@ use crate::attributes::path::PathParser as PathAttributeParser;
 use crate::attributes::proc_macro_attrs::{
     ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
 };
+use crate::attributes::prototype::CustomMirParser;
 use crate::attributes::repr::{AlignParser, ReprParser};
 use crate::attributes::rustc_internal::{
     RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
@@ -167,6 +168,7 @@ attribute_parsers!(
 
         // tidy-alphabetical-start
         Single<CoverageParser>,
+        Single<CustomMirParser>,
         Single<DeprecationParser>,
         Single<DummyParser>,
         Single<ExportNameParser>,
@@ -313,6 +315,7 @@ pub struct AcceptContext<'f, 'sess, S: Stage> {
     /// The span of the attribute currently being parsed
     pub(crate) attr_span: Span,
 
+    pub(crate) attr_style: AttrStyle,
     /// The expected structure of the attribute.
     ///
     /// Used in reporting errors to give a hint to users what the attribute *should* look like.
@@ -394,6 +397,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
                     i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
                 }),
             },
+            attr_style: self.attr_style,
         })
     }
 
@@ -404,6 +408,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
             reason: AttributeParseErrorReason::ExpectedIntegerLiteral,
+            attr_style: self.attr_style,
         })
     }
 
@@ -414,6 +419,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
             reason: AttributeParseErrorReason::ExpectedList,
+            attr_style: self.attr_style,
         })
     }
 
@@ -424,6 +430,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
             reason: AttributeParseErrorReason::ExpectedNoArgs,
+            attr_style: self.attr_style,
         })
     }
 
@@ -435,6 +442,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
             reason: AttributeParseErrorReason::ExpectedIdentifier,
+            attr_style: self.attr_style,
         })
     }
 
@@ -447,6 +455,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
             reason: AttributeParseErrorReason::ExpectedNameValue(name),
+            attr_style: self.attr_style,
         })
     }
 
@@ -458,6 +467,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
             reason: AttributeParseErrorReason::DuplicateKey(key),
+            attr_style: self.attr_style,
         })
     }
 
@@ -470,6 +480,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
             reason: AttributeParseErrorReason::UnexpectedLiteral,
+            attr_style: self.attr_style,
         })
     }
 
@@ -480,6 +491,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
             reason: AttributeParseErrorReason::ExpectedSingleArgument,
+            attr_style: self.attr_style,
         })
     }
 
@@ -490,6 +502,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
             reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
+            attr_style: self.attr_style,
         })
     }
 
@@ -508,6 +521,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
                 strings: false,
                 list: false,
             },
+            attr_style: self.attr_style,
         })
     }
 
@@ -526,6 +540,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
                 strings: false,
                 list: true,
             },
+            attr_style: self.attr_style,
         })
     }
 
@@ -544,6 +559,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
                 strings: true,
                 list: false,
             },
+            attr_style: self.attr_style,
         })
     }
 
@@ -802,6 +818,7 @@ impl<'sess> AttributeParser<'sess, Early> {
                 },
             },
             attr_span: attr.span,
+            attr_style: attr.style,
             template,
             attr_path: path.get_attribute_path(),
         };
@@ -912,6 +929,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
                                     emit_lint: &mut emit_lint,
                                 },
                                 attr_span: lower_span(attr.span),
+                                attr_style: attr.style,
                                 template: &accept.template,
                                 attr_path: path.get_attribute_path(),
                             };
@@ -1060,6 +1078,9 @@ pub(crate) fn allowed_targets_applied(
         if !features.stmt_expr_attributes() {
             allowed_targets.retain(|t| !matches!(t, Target::Expression | Target::Statement));
         }
+        if !features.extern_types() {
+            allowed_targets.retain(|t| !matches!(t, Target::ForeignTy));
+        }
     }
 
     // We define groups of "similar" targets.
diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs
index 733225bab59..2813fef3148 100644
--- a/compiler/rustc_attr_parsing/src/lints.rs
+++ b/compiler/rustc_attr_parsing/src/lints.rs
@@ -53,6 +53,7 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emi
                     target: target.plural_name(),
                     applied: applied.clone(),
                     only,
+                    attr_span: *span,
                 },
             ),
     }
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 95e85667cd6..aec970a3ce9 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -1,6 +1,6 @@
 use std::num::IntErrorKind;
 
-use rustc_ast as ast;
+use rustc_ast::{self as ast, AttrStyle};
 use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
@@ -489,6 +489,8 @@ pub(crate) struct InvalidTargetLint {
     pub target: &'static str,
     pub applied: String,
     pub only: &'static str,
+    #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
+    pub attr_span: Span,
 }
 
 #[derive(Diagnostic)]
@@ -496,6 +498,7 @@ pub(crate) struct InvalidTargetLint {
 #[diag(attr_parsing_invalid_target)]
 pub(crate) struct InvalidTarget {
     #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
     pub span: Span,
     pub name: Symbol,
     pub target: &'static str,
@@ -579,6 +582,7 @@ pub(crate) enum AttributeParseErrorReason {
 pub(crate) struct AttributeParseError {
     pub(crate) span: Span,
     pub(crate) attr_span: Span,
+    pub(crate) attr_style: AttrStyle,
     pub(crate) template: AttributeTemplate,
     pub(crate) attribute: AttrPath,
     pub(crate) reason: AttributeParseErrorReason,
@@ -717,7 +721,8 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
         if let Some(link) = self.template.docs {
             diag.note(format!("for more information, visit <{link}>"));
         }
-        let suggestions = self.template.suggestions(false, &name);
+        let suggestions = self.template.suggestions(self.attr_style, &name);
+
         diag.span_suggestions(
             self.attr_span,
             if suggestions.len() == 1 {
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index 33b80c4b03d..f59e106c7ac 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -90,7 +90,7 @@ borrowck_lifetime_constraints_error =
     lifetime may not live long enough
 
 borrowck_limitations_implies_static =
-    due to current limitations in the borrow checker, this implies a `'static` lifetime
+    due to a current limitation of the type system, this implies a `'static` lifetime
 
 borrowck_move_closure_suggestion =
     consider adding 'move' keyword before the nested closure
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index b67dba3af96..5642cdf87fd 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -6,7 +6,9 @@ use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
 use rustc_hir::def::{CtorKind, Namespace};
-use rustc_hir::{self as hir, CoroutineKind, LangItem};
+use rustc_hir::{
+    self as hir, CoroutineKind, GenericBound, LangItem, WhereBoundPredicate, WherePredicateKind,
+};
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_infer::infer::{BoundRegionConversionTime, NllRegionVariableOrigin};
 use rustc_infer::traits::SelectionError;
@@ -658,25 +660,66 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
     /// Add a note to region errors and borrow explanations when higher-ranked regions in predicates
     /// implicitly introduce an "outlives `'static`" constraint.
+    ///
+    /// This is very similar to `fn suggest_static_lifetime_for_gat_from_hrtb` which handles this
+    /// note for failed type tests instead of outlives errors.
     fn add_placeholder_from_predicate_note<G: EmissionGuarantee>(
         &self,
-        err: &mut Diag<'_, G>,
+        diag: &mut Diag<'_, G>,
         path: &[OutlivesConstraint<'tcx>],
     ) {
-        let predicate_span = path.iter().find_map(|constraint| {
+        let tcx = self.infcx.tcx;
+        let Some((gat_hir_id, generics)) = path.iter().find_map(|constraint| {
             let outlived = constraint.sub;
             if let Some(origin) = self.regioncx.definitions.get(outlived)
-                && let NllRegionVariableOrigin::Placeholder(_) = origin.origin
-                && let ConstraintCategory::Predicate(span) = constraint.category
+                && let NllRegionVariableOrigin::Placeholder(placeholder) = origin.origin
+                && let Some(id) = placeholder.bound.kind.get_id()
+                && let Some(placeholder_id) = id.as_local()
+                && let gat_hir_id = tcx.local_def_id_to_hir_id(placeholder_id)
+                && let Some(generics_impl) =
+                    tcx.parent_hir_node(tcx.parent_hir_id(gat_hir_id)).generics()
             {
-                Some(span)
+                Some((gat_hir_id, generics_impl))
             } else {
                 None
             }
-        });
+        }) else {
+            return;
+        };
 
-        if let Some(span) = predicate_span {
-            err.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
+        // Look for the where-bound which introduces the placeholder.
+        // As we're using the HIR, we need to handle both `for<'a> T: Trait<'a>`
+        // and `T: for<'a> Trait`<'a>.
+        for pred in generics.predicates {
+            let WherePredicateKind::BoundPredicate(WhereBoundPredicate {
+                bound_generic_params,
+                bounds,
+                ..
+            }) = pred.kind
+            else {
+                continue;
+            };
+            if bound_generic_params
+                .iter()
+                .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
+                .is_some()
+            {
+                diag.span_note(pred.span, fluent::borrowck_limitations_implies_static);
+                return;
+            }
+            for bound in bounds.iter() {
+                if let GenericBound::Trait(bound) = bound {
+                    if bound
+                        .bound_generic_params
+                        .iter()
+                        .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
+                        .is_some()
+                    {
+                        diag.span_note(bound.span, fluent::borrowck_limitations_implies_static);
+                        return;
+                    }
+                }
+            }
         }
     }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index c0ca35f9ff8..ea264c8064a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -3,6 +3,7 @@
 
 use core::ops::ControlFlow;
 
+use either::Either;
 use hir::{ExprKind, Param};
 use rustc_abi::FieldIdx;
 use rustc_errors::{Applicability, Diag};
@@ -12,15 +13,16 @@ use rustc_middle::bug;
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::visit::PlaceContext;
 use rustc_middle::mir::{
-    self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location, Mutability, Place,
-    PlaceRef, ProjectionElem,
+    self, BindingForm, Body, BorrowKind, Local, LocalDecl, LocalInfo, LocalKind, Location,
+    Mutability, Operand, Place, PlaceRef, ProjectionElem, RawPtrKind, Rvalue, Statement,
+    StatementKind, TerminatorKind,
 };
 use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast};
 use rustc_span::{BytePos, DesugaringKind, Span, Symbol, kw, sym};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits;
-use tracing::debug;
+use tracing::{debug, trace};
 
 use crate::diagnostics::BorrowedContentSource;
 use crate::{MirBorrowckCtxt, session_diagnostics};
@@ -31,6 +33,33 @@ pub(crate) enum AccessKind {
     Mutate,
 }
 
+/// Finds all statements that assign directly to local (i.e., X = ...) and returns their
+/// locations.
+fn find_assignments(body: &Body<'_>, local: Local) -> Vec<Location> {
+    use rustc_middle::mir::visit::Visitor;
+
+    struct FindLocalAssignmentVisitor {
+        needle: Local,
+        locations: Vec<Location>,
+    }
+
+    impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
+        fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
+            if self.needle != local {
+                return;
+            }
+
+            if place_context.is_place_assignment() {
+                self.locations.push(location);
+            }
+        }
+    }
+
+    let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] };
+    visitor.visit_body(body);
+    visitor.locations
+}
+
 impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
     pub(crate) fn report_mutability_error(
         &mut self,
@@ -384,7 +413,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 }
             }
 
-            // Also suggest adding mut for upvars
+            // Also suggest adding mut for upvars.
             PlaceRef {
                 local,
                 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
@@ -438,9 +467,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 }
             }
 
-            // complete hack to approximate old AST-borrowck
-            // diagnostic: if the span starts with a mutable borrow of
-            // a local variable, then just suggest the user remove it.
+            // Complete hack to approximate old AST-borrowck diagnostic: if the span starts
+            // with a mutable borrow of a local variable, then just suggest the user remove it.
             PlaceRef { local: _, projection: [] }
                 if self
                     .infcx
@@ -769,7 +797,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         );
     }
 
-    // point to span of upvar making closure call require mutable borrow
+    // Point to span of upvar making closure call that requires a mutable borrow
     fn show_mutating_upvar(
         &self,
         tcx: TyCtxt<'_>,
@@ -825,7 +853,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             } else {
                 bug!("not an upvar")
             };
-            // sometimes we deliberately don't store the name of a place when coming from a macro in
+            // Sometimes we deliberately don't store the name of a place when coming from a macro in
             // another crate. We generally want to limit those diagnostics a little, to hide
             // implementation details (such as those from pin!() or format!()). In that case show a
             // slightly different error message, or none at all if something else happened. In other
@@ -936,8 +964,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let def_id = tcx.hir_enclosing_body_owner(fn_call_id);
         let mut look_at_return = true;
 
-        // If the HIR node is a function or method call gets the def ID
-        // of the called function or method and the span and args of the call expr
+        // If the HIR node is a function or method call, get the DefId
+        // of the callee function or method, the span, and args of the call expr
         let get_call_details = || {
             let hir::Node::Expr(hir::Expr { hir_id, kind, .. }) = node else {
                 return None;
@@ -1051,7 +1079,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             let mut cur_expr = expr;
             while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
                 if path_segment.ident.name == sym::iter {
-                    // check `_ty` has `iter_mut` method
+                    // Check that the type has an `iter_mut` method.
                     let res = self
                         .infcx
                         .tcx
@@ -1081,38 +1109,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         }
     }
 
-    /// Finds all statements that assign directly to local (i.e., X = ...) and returns their
-    /// locations.
-    fn find_assignments(&self, local: Local) -> Vec<Location> {
-        use rustc_middle::mir::visit::Visitor;
-
-        struct FindLocalAssignmentVisitor {
-            needle: Local,
-            locations: Vec<Location>,
-        }
-
-        impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
-            fn visit_local(
-                &mut self,
-                local: Local,
-                place_context: PlaceContext,
-                location: Location,
-            ) {
-                if self.needle != local {
-                    return;
-                }
-
-                if place_context.is_place_assignment() {
-                    self.locations.push(location);
-                }
-            }
-        }
-
-        let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] };
-        visitor.visit_body(self.body);
-        visitor.locations
-    }
-
     fn suggest_make_local_mut(&self, err: &mut Diag<'_>, local: Local, name: Symbol) {
         let local_decl = &self.body.local_decls[local];
 
@@ -1122,7 +1118,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let (is_trait_sig, is_local, local_trait) = self.is_error_in_trait(local);
 
         if is_trait_sig && !is_local {
-            // Do not suggest to change the signature when the trait comes from another crate.
+            // Do not suggest changing the signature when the trait comes from another crate.
             err.span_label(
                 local_decl.source_info.span,
                 format!("this is an immutable {pointer_desc}"),
@@ -1131,11 +1127,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         }
         let decl_span = local_decl.source_info.span;
 
-        let amp_mut_sugg = match *local_decl.local_info() {
+        let (amp_mut_sugg, local_var_ty_info) = match *local_decl.local_info() {
             LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
                 let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
                 let additional = local_trait.map(|span| suggest_ampmut_self(self.infcx.tcx, span));
-                Some(AmpMutSugg { has_sugg: true, span, suggestion, additional })
+                (AmpMutSugg::Type { span, suggestion, additional }, None)
             }
 
             LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
@@ -1143,79 +1139,54 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 opt_ty_info,
                 ..
             })) => {
-                // check if the RHS is from desugaring
+                // Check if the RHS is from desugaring.
+                let first_assignment = find_assignments(&self.body, local).first().copied();
+                let first_assignment_stmt = first_assignment
+                    .and_then(|loc| self.body[loc.block].statements.get(loc.statement_index));
+                trace!(?first_assignment_stmt);
                 let opt_assignment_rhs_span =
-                    self.find_assignments(local).first().map(|&location| {
-                        if let Some(mir::Statement {
-                            source_info: _,
-                            kind:
-                                mir::StatementKind::Assign(box (
-                                    _,
-                                    mir::Rvalue::Use(mir::Operand::Copy(place)),
-                                )),
-                            ..
-                        }) = self.body[location.block].statements.get(location.statement_index)
-                        {
-                            self.body.local_decls[place.local].source_info.span
-                        } else {
-                            self.body.source_info(location).span
-                        }
-                    });
-                match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
-                    // on for loops, RHS points to the iterator part
-                    Some(DesugaringKind::ForLoop) => {
-                        let span = opt_assignment_rhs_span.unwrap();
-                        self.suggest_similar_mut_method_for_for_loop(err, span);
+                    first_assignment.map(|loc| self.body.source_info(loc).span);
+                let mut source_span = opt_assignment_rhs_span;
+                if let Some(mir::Statement {
+                    source_info: _,
+                    kind:
+                        mir::StatementKind::Assign(box (_, mir::Rvalue::Use(mir::Operand::Copy(place)))),
+                    ..
+                }) = first_assignment_stmt
+                {
+                    let local_span = self.body.local_decls[place.local].source_info.span;
+                    // `&self` in async functions have a `desugaring_kind`, but the local we assign
+                    // it with does not, so use the local_span for our checks later.
+                    source_span = Some(local_span);
+                    if let Some(DesugaringKind::ForLoop) = local_span.desugaring_kind() {
+                        // On for loops, RHS points to the iterator part.
+                        self.suggest_similar_mut_method_for_for_loop(err, local_span);
                         err.span_label(
-                            span,
+                            local_span,
                             format!("this iterator yields `{pointer_sigil}` {pointer_desc}s",),
                         );
-                        None
-                    }
-                    // don't create labels for compiler-generated spans
-                    Some(_) => None,
-                    // don't create labels for the span not from user's code
-                    None if opt_assignment_rhs_span
-                        .is_some_and(|span| self.infcx.tcx.sess.source_map().is_imported(span)) =>
-                    {
-                        None
-                    }
-                    None => {
-                        if name != kw::SelfLower {
-                            suggest_ampmut(
-                                self.infcx.tcx,
-                                local_decl.ty,
-                                decl_span,
-                                opt_assignment_rhs_span,
-                                opt_ty_info,
-                            )
-                        } else {
-                            match local_decl.local_info() {
-                                LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
-                                    opt_ty_info: None,
-                                    ..
-                                })) => {
-                                    let (span, sugg) =
-                                        suggest_ampmut_self(self.infcx.tcx, decl_span);
-                                    Some(AmpMutSugg {
-                                        has_sugg: true,
-                                        span,
-                                        suggestion: sugg,
-                                        additional: None,
-                                    })
-                                }
-                                // explicit self (eg `self: &'a Self`)
-                                _ => suggest_ampmut(
-                                    self.infcx.tcx,
-                                    local_decl.ty,
-                                    decl_span,
-                                    opt_assignment_rhs_span,
-                                    opt_ty_info,
-                                ),
-                            }
-                        }
+                        return;
                     }
                 }
+
+                // Don't create labels for compiler-generated spans or spans not from users' code.
+                if source_span.is_some_and(|s| {
+                    s.desugaring_kind().is_some() || self.infcx.tcx.sess.source_map().is_imported(s)
+                }) {
+                    return;
+                }
+
+                // This could be because we're in an `async fn`.
+                if name == kw::SelfLower && opt_ty_info.is_none() {
+                    let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
+                    (AmpMutSugg::Type { span, suggestion, additional: None }, None)
+                } else if let Some(sugg) =
+                    suggest_ampmut(self.infcx, self.body(), first_assignment_stmt)
+                {
+                    (sugg, opt_ty_info)
+                } else {
+                    return;
+                }
             }
 
             LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
@@ -1223,181 +1194,238 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 ..
             })) => {
                 let pattern_span: Span = local_decl.source_info.span;
-                suggest_ref_mut(self.infcx.tcx, pattern_span).map(|span| AmpMutSugg {
-                    has_sugg: true,
-                    span,
-                    suggestion: "mut ".to_owned(),
-                    additional: None,
-                })
+                let Some(span) = suggest_ref_mut(self.infcx.tcx, pattern_span) else {
+                    return;
+                };
+                (AmpMutSugg::Type { span, suggestion: "mut ".to_owned(), additional: None }, None)
             }
 
             _ => unreachable!(),
         };
 
-        match amp_mut_sugg {
-            Some(AmpMutSugg {
-                has_sugg: true,
-                span: err_help_span,
-                suggestion: suggested_code,
-                additional,
-            }) => {
-                let mut sugg = vec![(err_help_span, suggested_code)];
-                if let Some(s) = additional {
-                    sugg.push(s);
-                }
+        let mut suggest = |suggs: Vec<_>, applicability, extra| {
+            if suggs.iter().any(|(span, _)| self.infcx.tcx.sess.source_map().is_imported(*span)) {
+                return;
+            }
 
-                if sugg.iter().all(|(span, _)| !self.infcx.tcx.sess.source_map().is_imported(*span))
-                {
-                    err.multipart_suggestion_verbose(
-                        format!(
-                            "consider changing this to be a mutable {pointer_desc}{}",
-                            if is_trait_sig {
-                                " in the `impl` method and the `trait` definition"
-                            } else {
-                                ""
-                            }
-                        ),
-                        sugg,
-                        Applicability::MachineApplicable,
-                    );
+            err.multipart_suggestion_verbose(
+                format!(
+                    "consider changing this to be a mutable {pointer_desc}{}{extra}",
+                    if is_trait_sig {
+                        " in the `impl` method and the `trait` definition"
+                    } else {
+                        ""
+                    }
+                ),
+                suggs,
+                applicability,
+            );
+        };
+
+        let (mut sugg, add_type_annotation_if_not_exists) = match amp_mut_sugg {
+            AmpMutSugg::Type { span, suggestion, additional } => {
+                let mut sugg = vec![(span, suggestion)];
+                sugg.extend(additional);
+                suggest(sugg, Applicability::MachineApplicable, "");
+                return;
+            }
+            AmpMutSugg::MapGetMut { span, suggestion } => {
+                if self.infcx.tcx.sess.source_map().is_imported(span) {
+                    return;
                 }
+                err.multipart_suggestion_verbose(
+                    "consider using `get_mut`",
+                    vec![(span, suggestion)],
+                    Applicability::MaybeIncorrect,
+                );
+                return;
             }
-            Some(AmpMutSugg {
-                has_sugg: false, span: err_label_span, suggestion: message, ..
-            }) => {
-                let def_id = self.body.source.def_id();
-                let hir_id = if let Some(local_def_id) = def_id.as_local()
-                    && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id)
-                {
-                    BindingFinder { span: err_label_span }.visit_body(&body).break_value()
-                } else {
-                    None
-                };
+            AmpMutSugg::Expr { span, suggestion } => {
+                // `Expr` suggestions should change type annotations if they already exist (probably immut),
+                // but do not add new type annotations.
+                (vec![(span, suggestion)], false)
+            }
+            AmpMutSugg::ChangeBinding => (vec![], true),
+        };
 
-                if let Some(hir_id) = hir_id
-                    && let hir::Node::LetStmt(local) = self.infcx.tcx.hir_node(hir_id)
-                {
-                    let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap());
-                    if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
-                        && let Some(expr) = local.init
-                        && let ty = tables.node_type_opt(expr.hir_id)
-                        && let Some(ty) = ty
-                        && let ty::Ref(..) = ty.kind()
+        // Find a binding's type to make mutable.
+        let (binding_exists, span) = match local_var_ty_info {
+            // If this is a variable binding with an explicit type,
+            // then we will suggest changing it to be mutable.
+            // This is `Applicability::MachineApplicable`.
+            Some(ty_span) => (true, ty_span),
+
+            // Otherwise, we'll suggest *adding* an annotated type, we'll suggest
+            // the RHS's type for that.
+            // This is `Applicability::HasPlaceholders`.
+            None => (false, decl_span),
+        };
+
+        if !binding_exists && !add_type_annotation_if_not_exists {
+            suggest(sugg, Applicability::MachineApplicable, "");
+            return;
+        }
+
+        // If the binding already exists and is a reference with an explicit
+        // lifetime, then we can suggest adding ` mut`. This is special-cased from
+        // the path without an explicit lifetime.
+        let (sugg_span, sugg_str, suggest_now) = if let Ok(src) = self.infcx.tcx.sess.source_map().span_to_snippet(span)
+            && src.starts_with("&'")
+            // Note that `&' a T` is invalid so this is correct.
+            && let Some(ws_pos) = src.find(char::is_whitespace)
+        {
+            let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo();
+            (span, " mut".to_owned(), true)
+        // If there is already a binding, we modify it to be `mut`.
+        } else if binding_exists {
+            // Shrink the span to just after the `&` in `&variable`.
+            let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
+            (span, "mut ".to_owned(), true)
+        } else {
+            // Otherwise, suggest that the user annotates the binding; We provide the
+            // type of the local.
+            let ty = local_decl.ty.builtin_deref(true).unwrap();
+
+            (span, format!("{}mut {}", if local_decl.ty.is_ref() { "&" } else { "*" }, ty), false)
+        };
+
+        if suggest_now {
+            // Suggest changing `&x` to `&mut x` and changing `&T` to `&mut T` at the same time.
+            let has_change = !sugg.is_empty();
+            sugg.push((sugg_span, sugg_str));
+            suggest(
+                sugg,
+                Applicability::MachineApplicable,
+                // FIXME(fee1-dead) this somehow doesn't fire
+                if has_change { " and changing the binding's type" } else { "" },
+            );
+            return;
+        } else if !sugg.is_empty() {
+            suggest(sugg, Applicability::MachineApplicable, "");
+            return;
+        }
+
+        let def_id = self.body.source.def_id();
+        let hir_id = if let Some(local_def_id) = def_id.as_local()
+            && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id)
+        {
+            BindingFinder { span: sugg_span }.visit_body(&body).break_value()
+        } else {
+            None
+        };
+        let node = hir_id.map(|hir_id| self.infcx.tcx.hir_node(hir_id));
+
+        let Some(hir::Node::LetStmt(local)) = node else {
+            err.span_label(
+                sugg_span,
+                format!("consider changing this binding's type to be: `{sugg_str}`"),
+            );
+            return;
+        };
+
+        let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap());
+        if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
+            && let Some(expr) = local.init
+            && let ty = tables.node_type_opt(expr.hir_id)
+            && let Some(ty) = ty
+            && let ty::Ref(..) = ty.kind()
+        {
+            match self
+                .infcx
+                .type_implements_trait_shallow(clone_trait, ty.peel_refs(), self.infcx.param_env)
+                .as_deref()
+            {
+                Some([]) => {
+                    // FIXME: This error message isn't useful, since we're just
+                    // vaguely suggesting to clone a value that already
+                    // implements `Clone`.
+                    //
+                    // A correct suggestion here would take into account the fact
+                    // that inference may be affected by missing types on bindings,
+                    // etc., to improve "tests/ui/borrowck/issue-91206.stderr", for
+                    // example.
+                }
+                None => {
+                    if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = expr.kind
+                        && segment.ident.name == sym::clone
                     {
-                        match self
-                            .infcx
-                            .type_implements_trait_shallow(
-                                clone_trait,
-                                ty.peel_refs(),
-                                self.infcx.param_env,
-                            )
-                            .as_deref()
-                        {
-                            Some([]) => {
-                                // FIXME: This error message isn't useful, since we're just
-                                // vaguely suggesting to clone a value that already
-                                // implements `Clone`.
-                                //
-                                // A correct suggestion here would take into account the fact
-                                // that inference may be affected by missing types on bindings,
-                                // etc., to improve "tests/ui/borrowck/issue-91206.stderr", for
-                                // example.
-                            }
-                            None => {
-                                if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) =
-                                    expr.kind
-                                    && segment.ident.name == sym::clone
-                                {
-                                    err.span_help(
-                                        span,
-                                        format!(
-                                            "`{}` doesn't implement `Clone`, so this call clones \
+                        err.span_help(
+                            span,
+                            format!(
+                                "`{}` doesn't implement `Clone`, so this call clones \
                                              the reference `{ty}`",
-                                            ty.peel_refs(),
-                                        ),
-                                    );
-                                }
-                                // The type doesn't implement Clone.
-                                let trait_ref = ty::Binder::dummy(ty::TraitRef::new(
-                                    self.infcx.tcx,
-                                    clone_trait,
-                                    [ty.peel_refs()],
-                                ));
-                                let obligation = traits::Obligation::new(
-                                    self.infcx.tcx,
-                                    traits::ObligationCause::dummy(),
-                                    self.infcx.param_env,
-                                    trait_ref,
-                                );
-                                self.infcx.err_ctxt().suggest_derive(
-                                    &obligation,
-                                    err,
-                                    trait_ref.upcast(self.infcx.tcx),
-                                );
-                            }
-                            Some(errors) => {
-                                if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) =
-                                    expr.kind
-                                    && segment.ident.name == sym::clone
-                                {
-                                    err.span_help(
-                                        span,
-                                        format!(
-                                            "`{}` doesn't implement `Clone` because its \
+                                ty.peel_refs(),
+                            ),
+                        );
+                    }
+                    // The type doesn't implement Clone.
+                    let trait_ref = ty::Binder::dummy(ty::TraitRef::new(
+                        self.infcx.tcx,
+                        clone_trait,
+                        [ty.peel_refs()],
+                    ));
+                    let obligation = traits::Obligation::new(
+                        self.infcx.tcx,
+                        traits::ObligationCause::dummy(),
+                        self.infcx.param_env,
+                        trait_ref,
+                    );
+                    self.infcx.err_ctxt().suggest_derive(
+                        &obligation,
+                        err,
+                        trait_ref.upcast(self.infcx.tcx),
+                    );
+                }
+                Some(errors) => {
+                    if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = expr.kind
+                        && segment.ident.name == sym::clone
+                    {
+                        err.span_help(
+                            span,
+                            format!(
+                                "`{}` doesn't implement `Clone` because its \
                                              implementations trait bounds could not be met, so \
                                              this call clones the reference `{ty}`",
-                                            ty.peel_refs(),
-                                        ),
-                                    );
-                                    err.note(format!(
-                                        "the following trait bounds weren't met: {}",
-                                        errors
-                                            .iter()
-                                            .map(|e| e.obligation.predicate.to_string())
-                                            .collect::<Vec<_>>()
-                                            .join("\n"),
-                                    ));
-                                }
-                                // The type doesn't implement Clone because of unmet obligations.
-                                for error in errors {
-                                    if let traits::FulfillmentErrorCode::Select(
-                                        traits::SelectionError::Unimplemented,
-                                    ) = error.code
-                                        && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
-                                            pred,
-                                        )) = error.obligation.predicate.kind().skip_binder()
-                                    {
-                                        self.infcx.err_ctxt().suggest_derive(
-                                            &error.obligation,
-                                            err,
-                                            error.obligation.predicate.kind().rebind(pred),
-                                        );
-                                    }
-                                }
-                            }
-                        }
+                                ty.peel_refs(),
+                            ),
+                        );
+                        err.note(format!(
+                            "the following trait bounds weren't met: {}",
+                            errors
+                                .iter()
+                                .map(|e| e.obligation.predicate.to_string())
+                                .collect::<Vec<_>>()
+                                .join("\n"),
+                        ));
                     }
-                    let (changing, span, sugg) = match local.ty {
-                        Some(ty) => ("changing", ty.span, message),
-                        None => {
-                            ("specifying", local.pat.span.shrink_to_hi(), format!(": {message}"))
+                    // The type doesn't implement Clone because of unmet obligations.
+                    for error in errors {
+                        if let traits::FulfillmentErrorCode::Select(
+                            traits::SelectionError::Unimplemented,
+                        ) = error.code
+                            && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
+                                error.obligation.predicate.kind().skip_binder()
+                        {
+                            self.infcx.err_ctxt().suggest_derive(
+                                &error.obligation,
+                                err,
+                                error.obligation.predicate.kind().rebind(pred),
+                            );
                         }
-                    };
-                    err.span_suggestion_verbose(
-                        span,
-                        format!("consider {changing} this binding's type"),
-                        sugg,
-                        Applicability::HasPlaceholders,
-                    );
-                } else {
-                    err.span_label(
-                        err_label_span,
-                        format!("consider changing this binding's type to be: `{message}`"),
-                    );
+                    }
                 }
             }
-            None => {}
         }
+        let (changing, span, sugg) = match local.ty {
+            Some(ty) => ("changing", ty.span, sugg_str),
+            None => ("specifying", local.pat.span.shrink_to_hi(), format!(": {sugg_str}")),
+        };
+        err.span_suggestion_verbose(
+            span,
+            format!("consider {changing} this binding's type"),
+            sugg,
+            Applicability::HasPlaceholders,
+        );
     }
 }
 
@@ -1464,11 +1492,25 @@ fn suggest_ampmut_self(tcx: TyCtxt<'_>, span: Span) -> (Span, String) {
     }
 }
 
-struct AmpMutSugg {
-    has_sugg: bool,
-    span: Span,
-    suggestion: String,
-    additional: Option<(Span, String)>,
+enum AmpMutSugg {
+    /// Type suggestion. Changes `&self` to `&mut self`, `x: &T` to `x: &mut T`,
+    /// `ref x` to `ref mut x`, etc.
+    Type {
+        span: Span,
+        suggestion: String,
+        additional: Option<(Span, String)>,
+    },
+    /// Suggestion for expressions, `&x` to `&mut x`, `&x[i]` to `&mut x[i]`, etc.
+    Expr {
+        span: Span,
+        suggestion: String,
+    },
+    /// Suggests `.get_mut` in the case of `&map[&key]` for Hash/BTreeMap.
+    MapGetMut {
+        span: Span,
+        suggestion: String,
+    },
+    ChangeBinding,
 }
 
 // When we want to suggest a user change a local variable to be a `&mut`, there
@@ -1487,110 +1529,111 @@ struct AmpMutSugg {
 // This implementation attempts to emulate AST-borrowck prioritization
 // by trying (3.), then (2.) and finally falling back on (1.).
 fn suggest_ampmut<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    decl_ty: Ty<'tcx>,
-    decl_span: Span,
-    opt_assignment_rhs_span: Option<Span>,
-    opt_ty_info: Option<Span>,
+    infcx: &crate::BorrowckInferCtxt<'tcx>,
+    body: &Body<'tcx>,
+    opt_assignment_rhs_stmt: Option<&Statement<'tcx>>,
 ) -> Option<AmpMutSugg> {
-    // if there is a RHS and it starts with a `&` from it, then check if it is
+    let tcx = infcx.tcx;
+    // If there is a RHS and it starts with a `&` from it, then check if it is
     // mutable, and if not, put suggest putting `mut ` to make it mutable.
-    // we don't have to worry about lifetime annotations here because they are
+    // We don't have to worry about lifetime annotations here because they are
     // not valid when taking a reference. For example, the following is not valid Rust:
     //
     // let x: &i32 = &'a 5;
     //                ^^ lifetime annotation not allowed
     //
-    if let Some(rhs_span) = opt_assignment_rhs_span
-        && let Ok(rhs_str) = tcx.sess.source_map().span_to_snippet(rhs_span)
-        && let Some(rhs_str_no_amp) = rhs_str.strip_prefix('&')
+    if let Some(rhs_stmt) = opt_assignment_rhs_stmt
+        && let StatementKind::Assign(box (lhs, rvalue)) = &rhs_stmt.kind
+        && let mut rhs_span = rhs_stmt.source_info.span
+        && let Ok(mut rhs_str) = tcx.sess.source_map().span_to_snippet(rhs_span)
     {
-        // Suggest changing `&raw const` to `&raw mut` if applicable.
-        if rhs_str_no_amp.trim_start().strip_prefix("raw const").is_some() {
-            let const_idx = rhs_str.find("const").unwrap() as u32;
-            let const_span = rhs_span
-                .with_lo(rhs_span.lo() + BytePos(const_idx))
-                .with_hi(rhs_span.lo() + BytePos(const_idx + "const".len() as u32));
-
-            return Some(AmpMutSugg {
-                has_sugg: true,
-                span: const_span,
-                suggestion: "mut".to_owned(),
-                additional: None,
-            });
+        let mut rvalue = rvalue;
+
+        // Take some special care when handling `let _x = &*_y`:
+        // We want to know if this is part of an overloaded index, so `let x = &a[0]`,
+        // or whether this is a usertype ascription (`let _x: &T = y`).
+        if let Rvalue::Ref(_, BorrowKind::Shared, place) = rvalue
+            && place.projection.len() == 1
+            && place.projection[0] == ProjectionElem::Deref
+            && let Some(assign) = find_assignments(&body, place.local).first()
+        {
+            // If this is a usertype ascription (`let _x: &T = _y`) then pierce through it as either we want
+            // to suggest `&mut` on the expression (handled here) or we return `None` and let the caller
+            // suggest `&mut` on the type if the expression seems fine (e.g. `let _x: &T = &mut _y`).
+            if let Some(user_ty_projs) = body.local_decls[lhs.local].user_ty.as_ref()
+                && let [user_ty_proj] = user_ty_projs.contents.as_slice()
+                && user_ty_proj.projs.is_empty()
+                && let Either::Left(rhs_stmt_new) = body.stmt_at(*assign)
+                && let StatementKind::Assign(box (_, rvalue_new)) = &rhs_stmt_new.kind
+                && let rhs_span_new = rhs_stmt_new.source_info.span
+                && let Ok(rhs_str_new) = tcx.sess.source_map().span_to_snippet(rhs_span)
+            {
+                (rvalue, rhs_span, rhs_str) = (rvalue_new, rhs_span_new, rhs_str_new);
+            }
+
+            if let Either::Right(call) = body.stmt_at(*assign)
+                && let TerminatorKind::Call {
+                    func: Operand::Constant(box const_operand), args, ..
+                } = &call.kind
+                && let ty::FnDef(method_def_id, method_args) = *const_operand.ty().kind()
+                && let Some(trait_) = tcx.trait_of_assoc(method_def_id)
+                && tcx.is_lang_item(trait_, hir::LangItem::Index)
+            {
+                let trait_ref = ty::TraitRef::from_assoc(
+                    tcx,
+                    tcx.require_lang_item(hir::LangItem::IndexMut, rhs_span),
+                    method_args,
+                );
+                // The type only implements `Index` but not `IndexMut`, we must not suggest `&mut`.
+                if !infcx
+                    .type_implements_trait(trait_ref.def_id, trait_ref.args, infcx.param_env)
+                    .must_apply_considering_regions()
+                {
+                    // Suggest `get_mut` if type is a `BTreeMap` or `HashMap`.
+                    if let ty::Adt(def, _) = trait_ref.self_ty().kind()
+                        && [sym::BTreeMap, sym::HashMap]
+                            .into_iter()
+                            .any(|s| tcx.is_diagnostic_item(s, def.did()))
+                        && let [map, key] = &**args
+                        && let Ok(map) = tcx.sess.source_map().span_to_snippet(map.span)
+                        && let Ok(key) = tcx.sess.source_map().span_to_snippet(key.span)
+                    {
+                        let span = rhs_span;
+                        let suggestion = format!("{map}.get_mut({key}).unwrap()");
+                        return Some(AmpMutSugg::MapGetMut { span, suggestion });
+                    }
+                    return None;
+                }
+            }
         }
 
-        // Figure out if rhs already is `&mut`.
-        let is_mut = if let Some(rest) = rhs_str_no_amp.trim_start().strip_prefix("mut") {
-            match rest.chars().next() {
-                // e.g. `&mut x`
-                Some(c) if c.is_whitespace() => true,
-                // e.g. `&mut(x)`
-                Some('(') => true,
-                // e.g. `&mut{x}`
-                Some('{') => true,
-                // e.g. `&mutablevar`
-                _ => false,
+        let sugg = match rvalue {
+            Rvalue::Ref(_, BorrowKind::Shared, _) if let Some(ref_idx) = rhs_str.find('&') => {
+                // Shrink the span to just after the `&` in `&variable`.
+                Some((
+                    rhs_span.with_lo(rhs_span.lo() + BytePos(ref_idx as u32 + 1)).shrink_to_lo(),
+                    "mut ".to_owned(),
+                ))
             }
-        } else {
-            false
+            Rvalue::RawPtr(RawPtrKind::Const, _) if let Some(const_idx) = rhs_str.find("const") => {
+                // Suggest changing `&raw const` to `&raw mut` if applicable.
+                let const_idx = const_idx as u32;
+                Some((
+                    rhs_span
+                        .with_lo(rhs_span.lo() + BytePos(const_idx))
+                        .with_hi(rhs_span.lo() + BytePos(const_idx + "const".len() as u32)),
+                    "mut".to_owned(),
+                ))
+            }
+            _ => None,
         };
-        // if the reference is already mutable then there is nothing we can do
-        // here.
-        if !is_mut {
-            // shrink the span to just after the `&` in `&variable`
-            let span = rhs_span.with_lo(rhs_span.lo() + BytePos(1)).shrink_to_lo();
-
-            // FIXME(Ezrashaw): returning is bad because we still might want to
-            // update the annotated type, see #106857.
-            return Some(AmpMutSugg {
-                has_sugg: true,
-                span,
-                suggestion: "mut ".to_owned(),
-                additional: None,
-            });
+
+        if let Some((span, suggestion)) = sugg {
+            return Some(AmpMutSugg::Expr { span, suggestion });
         }
     }
 
-    let (binding_exists, span) = match opt_ty_info {
-        // if this is a variable binding with an explicit type,
-        // then we will suggest changing it to be mutable.
-        // this is `Applicability::MachineApplicable`.
-        Some(ty_span) => (true, ty_span),
-
-        // otherwise, we'll suggest *adding* an annotated type, we'll suggest
-        // the RHS's type for that.
-        // this is `Applicability::HasPlaceholders`.
-        None => (false, decl_span),
-    };
-
-    // if the binding already exists and is a reference with an explicit
-    // lifetime, then we can suggest adding ` mut`. this is special-cased from
-    // the path without an explicit lifetime.
-    if let Ok(src) = tcx.sess.source_map().span_to_snippet(span)
-        && src.starts_with("&'")
-        // note that `&     'a T` is invalid so this is correct.
-        && let Some(ws_pos) = src.find(char::is_whitespace)
-    {
-        let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo();
-        Some(AmpMutSugg { has_sugg: true, span, suggestion: " mut".to_owned(), additional: None })
-    // if there is already a binding, we modify it to be `mut`
-    } else if binding_exists {
-        // shrink the span to just after the `&` in `&variable`
-        let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
-        Some(AmpMutSugg { has_sugg: true, span, suggestion: "mut ".to_owned(), additional: None })
-    } else {
-        // otherwise, suggest that the user annotates the binding; we provide the
-        // type of the local.
-        let ty = decl_ty.builtin_deref(true).unwrap();
-
-        Some(AmpMutSugg {
-            has_sugg: false,
-            span,
-            suggestion: format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty),
-            additional: None,
-        })
-    }
+    Some(AmpMutSugg::ChangeBinding)
 }
 
 /// If the type is a `Coroutine`, `Closure`, or `CoroutineClosure`
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 2b74f1a48f7..fe4e1b6011e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -215,7 +215,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         diag: &mut Diag<'_>,
         lower_bound: RegionVid,
     ) {
-        let mut suggestions = vec![];
         let tcx = self.infcx.tcx;
 
         // find generic associated types in the given region 'lower_bound'
@@ -237,9 +236,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             .collect::<Vec<_>>();
         debug!(?gat_id_and_generics);
 
-        // find higher-ranked trait bounds bounded to the generic associated types
+        // Look for the where-bound which introduces the placeholder.
+        // As we're using the HIR, we need to handle both `for<'a> T: Trait<'a>`
+        // and `T: for<'a> Trait`<'a>.
         let mut hrtb_bounds = vec![];
-        gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| {
+        gat_id_and_generics.iter().flatten().for_each(|&(gat_hir_id, generics)| {
             for pred in generics.predicates {
                 let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) =
                     pred.kind
@@ -248,17 +249,32 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 };
                 if bound_generic_params
                     .iter()
-                    .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
+                    .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
                     .is_some()
                 {
                     for bound in *bounds {
                         hrtb_bounds.push(bound);
                     }
+                } else {
+                    for bound in *bounds {
+                        if let Trait(trait_bound) = bound {
+                            if trait_bound
+                                .bound_generic_params
+                                .iter()
+                                .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
+                                .is_some()
+                            {
+                                hrtb_bounds.push(bound);
+                                return;
+                            }
+                        }
+                    }
                 }
             }
         });
         debug!(?hrtb_bounds);
 
+        let mut suggestions = vec![];
         hrtb_bounds.iter().for_each(|bound| {
             let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }) = bound else {
                 return;
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index a960b96b91c..8db2904cfd7 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1895,7 +1895,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             if !output_ty
                 .is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env))
             {
-                span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
+                span_mirbug!(self, term, "call to non-diverging function {:?} w/o dest", sig);
             }
         } else {
             let dest_ty = destination.ty(self.body, tcx).ty;
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 84ca9bad2c1..7ac2dff12f7 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -124,8 +124,13 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
         // by using `ty_vid rel B` and then finally and end by equating `ty_vid` to
         // the opaque.
         let mut enable_subtyping = |ty, opaque_is_expected| {
-            let ty_vid = infcx.next_ty_var_id_in_universe(self.span(), ty::UniverseIndex::ROOT);
-
+            // We create the fresh inference variable in the highest universe.
+            // In theory we could limit it to the highest universe in the args of
+            // the opaque but that isn't really worth the effort.
+            //
+            // We'll make sure that the opaque type can actually name everything
+            // in its hidden type later on.
+            let ty_vid = infcx.next_ty_vid(self.span());
             let variance = if opaque_is_expected {
                 self.ambient_variance
             } else {
diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs
index ef0e6ca324a..ab25de7c917 100644
--- a/compiler/rustc_builtin_macros/src/deriving/from.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/from.rs
@@ -27,21 +27,39 @@ pub(crate) fn expand_deriving_from(
         cx.dcx().bug("derive(From) used on something else than an item");
     };
 
-    // #[derive(From)] is currently usable only on structs with exactly one field.
-    let field = if let ItemKind::Struct(_, _, data) = &item.kind
-        && let [field] = data.fields()
-    {
-        Some(field.clone())
-    } else {
-        None
+    let err_span = || {
+        let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span);
+        MultiSpan::from_spans(vec![span, item_span])
     };
 
-    let from_type = match &field {
-        Some(field) => Ty::AstTy(field.ty.clone()),
-        // We don't have a type to put into From<...> if we don't have a single field, so just put
-        // unit there.
-        None => Ty::Unit,
+    // `#[derive(From)]` is currently usable only on structs with exactly one field.
+    let field = match &item.kind {
+        ItemKind::Struct(_, _, data) => {
+            if let [field] = data.fields() {
+                Ok(field.clone())
+            } else {
+                let guar = cx.dcx().emit_err(errors::DeriveFromWrongFieldCount {
+                    span: err_span(),
+                    multiple_fields: data.fields().len() > 1,
+                });
+                Err(guar)
+            }
+        }
+        ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => {
+            let guar = cx.dcx().emit_err(errors::DeriveFromWrongTarget {
+                span: err_span(),
+                kind: &format!("{} {}", item.kind.article(), item.kind.descr()),
+            });
+            Err(guar)
+        }
+        _ => cx.dcx().bug("Invalid derive(From) ADT input"),
     };
+
+    let from_type = Ty::AstTy(match field {
+        Ok(ref field) => field.ty.clone(),
+        Err(guar) => cx.ty(span, ast::TyKind::Err(guar)),
+    });
+
     let path =
         Path::new_(pathvec_std!(convert::From), vec![Box::new(from_type.clone())], PathKind::Std);
 
@@ -71,34 +89,17 @@ pub(crate) fn expand_deriving_from(
             attributes: thin_vec![cx.attr_word(sym::inline, span)],
             fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
             combine_substructure: combine_substructure(Box::new(|cx, span, substructure| {
-                let Some(field) = &field else {
-                    let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span);
-                    let err_span = MultiSpan::from_spans(vec![span, item_span]);
-                    let error = match &item.kind {
-                        ItemKind::Struct(_, _, data) => {
-                            cx.dcx().emit_err(errors::DeriveFromWrongFieldCount {
-                                span: err_span,
-                                multiple_fields: data.fields().len() > 1,
-                            })
-                        }
-                        ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => {
-                            cx.dcx().emit_err(errors::DeriveFromWrongTarget {
-                                span: err_span,
-                                kind: &format!("{} {}", item.kind.article(), item.kind.descr()),
-                            })
-                        }
-                        _ => cx.dcx().bug("Invalid derive(From) ADT input"),
-                    };
-
-                    return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(error)));
+                let field = match field {
+                    Ok(ref field) => field,
+                    Err(guar) => {
+                        return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(guar)));
+                    }
                 };
 
                 let self_kw = Ident::new(kw::SelfUpper, span);
                 let expr: Box<ast::Expr> = match substructure.fields {
                     SubstructureFields::StaticStruct(variant, _) => match variant {
-                        // Self {
-                        //     field: value
-                        // }
+                        // Self { field: value }
                         VariantData::Struct { .. } => cx.expr_struct_ident(
                             span,
                             self_kw,
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 86a4927f390..1bcea95fbb7 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -8,7 +8,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
-#![feature(autodiff)]
 #![feature(box_patterns)]
 #![feature(decl_macro)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index e803f3be82b..a9d91f77560 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -141,7 +141,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
         if let ast::ItemKind::Mod(
             _,
             _,
-            ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }, _),
+            ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }),
         ) = item.kind
         {
             let prev_tests = mem::take(&mut self.tests);
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 043123fcab2..399f8b6e762 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -42,12 +42,13 @@ trait ArgAttributesExt {
 const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] =
     [(ArgAttribute::InReg, llvm::AttributeKind::InReg)];
 
-const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 5] = [
+const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 6] = [
     (ArgAttribute::NoAlias, llvm::AttributeKind::NoAlias),
     (ArgAttribute::NoCapture, llvm::AttributeKind::NoCapture),
     (ArgAttribute::NonNull, llvm::AttributeKind::NonNull),
     (ArgAttribute::ReadOnly, llvm::AttributeKind::ReadOnly),
     (ArgAttribute::NoUndef, llvm::AttributeKind::NoUndef),
+    (ArgAttribute::CapturesReadOnly, llvm::AttributeKind::CapturesReadOnly),
 ];
 
 fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 8]> {
@@ -83,6 +84,10 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
         }
         for (attr, llattr) in OPTIMIZATION_ATTRIBUTES {
             if regular.contains(attr) {
+                // captures(address, read_provenance) is only available since LLVM 21.
+                if attr == ArgAttribute::CapturesReadOnly && llvm_util::get_version() < (21, 0, 0) {
+                    continue;
+                }
                 attrs.push(llattr.create_attr(cx.llcx));
             }
         }
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index a6daacd95ef..5affb26483a 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -420,6 +420,16 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
     {
         to_add.push(create_alloc_family_attr(cx.llcx));
+        if let Some(zv) =
+            cx.tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant)
+            && let Some(name) = zv.value_str()
+        {
+            to_add.push(llvm::CreateAttrStringValue(
+                cx.llcx,
+                "alloc-variant-zeroed",
+                &mangle_internal_symbol(cx.tcx, name.as_str()),
+            ));
+        }
         // apply to argument place instead of function
         let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
         attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]);
@@ -497,7 +507,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
             to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", module));
 
             let name =
-                codegen_fn_attrs.link_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id()));
+                codegen_fn_attrs.symbol_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id()));
             let name = name.as_str();
             to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name));
         }
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 0a161442933..7a340ae83f3 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -1,104 +1,21 @@
 //! A helper class for dealing with static archives
 
-use std::ffi::{CStr, CString, c_char, c_void};
-use std::path::{Path, PathBuf};
-use std::{io, mem, ptr, str};
+use std::ffi::{CStr, c_char, c_void};
+use std::io;
 
 use rustc_codegen_ssa::back::archive::{
-    ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder,
-    DEFAULT_OBJECT_READER, ObjectReader, UnknownArchiveKind, try_extract_macho_fat_archive,
+    ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, ObjectReader,
 };
 use rustc_session::Session;
 
-use crate::llvm::archive_ro::{ArchiveRO, Child};
-use crate::llvm::{self, ArchiveKind, last_error};
-
-/// Helper for adding many files to an archive.
-#[must_use = "must call build() to finish building the archive"]
-pub(crate) struct LlvmArchiveBuilder<'a> {
-    sess: &'a Session,
-    additions: Vec<Addition>,
-}
-
-enum Addition {
-    File { path: PathBuf, name_in_archive: String },
-    Archive { path: PathBuf, archive: ArchiveRO, skip: Box<dyn FnMut(&str) -> bool> },
-}
-
-impl Addition {
-    fn path(&self) -> &Path {
-        match self {
-            Addition::File { path, .. } | Addition::Archive { path, .. } => path,
-        }
-    }
-}
-
-fn is_relevant_child(c: &Child<'_>) -> bool {
-    match c.name() {
-        Some(name) => !name.contains("SYMDEF"),
-        None => false,
-    }
-}
-
-impl<'a> ArchiveBuilder for LlvmArchiveBuilder<'a> {
-    fn add_archive(
-        &mut self,
-        archive: &Path,
-        skip: Box<dyn FnMut(&str) -> bool + 'static>,
-    ) -> io::Result<()> {
-        let mut archive = archive.to_path_buf();
-        if self.sess.target.llvm_target.contains("-apple-macosx") {
-            if let Some(new_archive) = try_extract_macho_fat_archive(self.sess, &archive)? {
-                archive = new_archive
-            }
-        }
-        let archive_ro = match ArchiveRO::open(&archive) {
-            Ok(ar) => ar,
-            Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
-        };
-        if self.additions.iter().any(|ar| ar.path() == archive) {
-            return Ok(());
-        }
-        self.additions.push(Addition::Archive {
-            path: archive,
-            archive: archive_ro,
-            skip: Box::new(skip),
-        });
-        Ok(())
-    }
-
-    /// Adds an arbitrary file to this archive
-    fn add_file(&mut self, file: &Path) {
-        let name = file.file_name().unwrap().to_str().unwrap();
-        self.additions
-            .push(Addition::File { path: file.to_path_buf(), name_in_archive: name.to_owned() });
-    }
-
-    /// Combine the provided files, rlibs, and native libraries into a single
-    /// `Archive`.
-    fn build(mut self: Box<Self>, output: &Path) -> bool {
-        match self.build_with_llvm(output) {
-            Ok(any_members) => any_members,
-            Err(error) => {
-                self.sess.dcx().emit_fatal(ArchiveBuildFailure { path: output.to_owned(), error })
-            }
-        }
-    }
-}
+use crate::llvm;
 
 pub(crate) struct LlvmArchiveBuilderBuilder;
 
 impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
     fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
-        // Keeping LlvmArchiveBuilder around in case of a regression caused by using
-        // ArArchiveBuilder.
-        // FIXME(#128955) remove a couple of months after #128936 gets merged in case
-        // no regression is found.
-        if false {
-            Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
-        } else {
-            Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER))
-        }
+        // Use the `object` crate to build archives, with a little bit of help from LLVM.
+        Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER))
     }
 }
 
@@ -178,91 +95,3 @@ fn llvm_is_64_bit_object_file(buf: &[u8]) -> bool {
 fn llvm_is_ec_object_file(buf: &[u8]) -> bool {
     unsafe { llvm::LLVMRustIsECObject(buf.as_ptr(), buf.len()) }
 }
-
-impl<'a> LlvmArchiveBuilder<'a> {
-    fn build_with_llvm(&mut self, output: &Path) -> io::Result<bool> {
-        let kind = &*self.sess.target.archive_format;
-        let kind = kind
-            .parse::<ArchiveKind>()
-            .map_err(|_| kind)
-            .unwrap_or_else(|kind| self.sess.dcx().emit_fatal(UnknownArchiveKind { kind }));
-
-        let mut additions = mem::take(&mut self.additions);
-        // Values in the `members` list below will contain pointers to the strings allocated here.
-        // So they need to get dropped after all elements of `members` get freed.
-        let mut strings = Vec::new();
-        let mut members = Vec::new();
-
-        let dst = CString::new(output.to_str().unwrap())?;
-
-        unsafe {
-            for addition in &mut additions {
-                match addition {
-                    Addition::File { path, name_in_archive } => {
-                        let path = CString::new(path.to_str().unwrap())?;
-                        let name = CString::new(name_in_archive.as_bytes())?;
-                        members.push(llvm::LLVMRustArchiveMemberNew(
-                            path.as_ptr(),
-                            name.as_ptr(),
-                            None,
-                        ));
-                        strings.push(path);
-                        strings.push(name);
-                    }
-                    Addition::Archive { archive, skip, .. } => {
-                        for child in archive.iter() {
-                            let child = child.map_err(string_to_io_error)?;
-                            if !is_relevant_child(&child) {
-                                continue;
-                            }
-                            let child_name = child.name().unwrap();
-                            if skip(child_name) {
-                                continue;
-                            }
-
-                            // It appears that LLVM's archive writer is a little
-                            // buggy if the name we pass down isn't just the
-                            // filename component, so chop that off here and
-                            // pass it in.
-                            //
-                            // See LLVM bug 25877 for more info.
-                            let child_name =
-                                Path::new(child_name).file_name().unwrap().to_str().unwrap();
-                            let name = CString::new(child_name)?;
-                            let m = llvm::LLVMRustArchiveMemberNew(
-                                ptr::null(),
-                                name.as_ptr(),
-                                Some(child.raw),
-                            );
-                            members.push(m);
-                            strings.push(name);
-                        }
-                    }
-                }
-            }
-
-            let r = llvm::LLVMRustWriteArchive(
-                dst.as_ptr(),
-                members.len() as libc::size_t,
-                members.as_ptr() as *const &_,
-                true,
-                kind,
-                self.sess.target.arch == "arm64ec",
-            );
-            let ret = if r.into_result().is_err() {
-                let msg = last_error().unwrap_or_else(|| "failed to write archive".into());
-                Err(io::Error::new(io::ErrorKind::Other, msg))
-            } else {
-                Ok(!members.is_empty())
-            };
-            for member in members {
-                llvm::LLVMRustArchiveMemberFree(member);
-            }
-            ret
-        }
-    }
-}
-
-fn string_to_io_error(s: String) -> io::Error {
-    io::Error::new(io::ErrorKind::Other, format!("bad archive: {s}"))
-}
diff --git a/compiler/rustc_codegen_llvm/src/back/mod.rs b/compiler/rustc_codegen_llvm/src/back/mod.rs
new file mode 100644
index 00000000000..6cb89f80ab8
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/back/mod.rs
@@ -0,0 +1,5 @@
+pub(crate) mod archive;
+pub(crate) mod lto;
+pub(crate) mod owned_target_machine;
+mod profiling;
+pub(crate) mod write;
diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
index 8e82013e94a..6d8178320fe 100644
--- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
+++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
@@ -1,4 +1,5 @@
-use std::ffi::{CStr, c_char};
+use std::assert_matches::assert_matches;
+use std::ffi::CStr;
 use std::marker::PhantomData;
 use std::ptr::NonNull;
 
@@ -41,11 +42,9 @@ impl OwnedTargetMachine {
         args_cstr_buff: &[u8],
         use_wasm_eh: bool,
     ) -> Result<Self, LlvmError<'static>> {
-        assert!(args_cstr_buff.len() > 0);
-        assert!(
-            *args_cstr_buff.last().unwrap() == 0,
-            "The last character must be a null terminator."
-        );
+        // The argument list is passed as the concatenation of one or more C strings.
+        // This implies that there must be a last byte, and it must be 0.
+        assert_matches!(args_cstr_buff, [.., b'\0'], "the last byte must be a NUL terminator");
 
         // SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data
         let tm_ptr = unsafe {
@@ -71,7 +70,7 @@ impl OwnedTargetMachine {
                 output_obj_file.as_ptr(),
                 debug_info_compression.as_ptr(),
                 use_emulated_tls,
-                args_cstr_buff.as_ptr() as *const c_char,
+                args_cstr_buff.as_ptr(),
                 args_cstr_buff.len(),
                 use_wasm_eh,
             )
@@ -99,7 +98,7 @@ impl Drop for OwnedTargetMachine {
         // llvm::LLVMRustCreateTargetMachine OwnedTargetMachine is not copyable so there is no
         // double free or use after free.
         unsafe {
-            llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_mut());
+            llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_ptr());
         }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index cb98df59c1b..427c75d40e9 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1453,7 +1453,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         instance: Option<Instance<'tcx>>,
     ) {
         let call = self.call(llty, fn_attrs, Some(fn_abi), llfn, args, funclet, instance);
-        llvm::LLVMRustSetTailCallKind(call, llvm::TailCallKind::MustTail);
+        llvm::LLVMSetTailCallKind(call, llvm::TailCallKind::MustTail);
 
         match &fn_abi.ret.mode {
             PassMode::Ignore | PassMode::Indirect { .. } => self.ret_void(),
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index b0f3494ea68..4a7de7d2e69 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -377,6 +377,15 @@ pub(crate) unsafe fn create_module<'ll>(
         }
     }
 
+    if let Some(regparm_count) = sess.opts.unstable_opts.regparm {
+        llvm::add_module_flag_u32(
+            llmod,
+            llvm::ModuleFlagMergeBehavior::Error,
+            "NumRegisterParameters",
+            regparm_count,
+        );
+    }
+
     if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
         if sess.target.arch == "aarch64" {
             llvm::add_module_flag_u32(
@@ -462,6 +471,15 @@ pub(crate) unsafe fn create_module<'ll>(
         }
     }
 
+    if sess.opts.unstable_opts.indirect_branch_cs_prefix {
+        llvm::add_module_flag_u32(
+            llmod,
+            llvm::ModuleFlagMergeBehavior::Override,
+            "indirect_branch_cs_prefix",
+            1,
+        );
+    }
+
     match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support())
     {
         // Set up the small-data optimization limit for architectures that use
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index d1502d2b1e6..18a783a348a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -276,7 +276,7 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
         && let ty::Adt(adt_def, args) = ty.kind()
     {
         let def_id = adt_def.did();
-        // If any sub type reference the original type definition and the sub type has a type
+        // If any child type references the original type definition and the child type has a type
         // parameter that strictly contains the original parameter, the original type is a recursive
         // type that can expanding indefinitely. Example,
         // ```
@@ -285,21 +285,43 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
         //     Item(T),
         // }
         // ```
-        let is_expanding_recursive = adt_def.is_enum()
-            && debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| {
-                if def_id == *parent_def_id {
-                    args.iter().zip(parent_args.iter()).any(|(arg, parent_arg)| {
-                        if let (Some(arg), Some(parent_arg)) = (arg.as_type(), parent_arg.as_type())
-                        {
-                            arg != parent_arg && arg.contains(parent_arg)
-                        } else {
-                            false
-                        }
-                    })
-                } else {
-                    false
-                }
-            });
+        let is_expanding_recursive = {
+            let stack = debug_context(cx).adt_stack.borrow();
+            stack
+                .iter()
+                .enumerate()
+                .rev()
+                .skip(1)
+                .filter(|(_, (ancestor_def_id, _))| def_id == *ancestor_def_id)
+                .any(|(ancestor_index, (_, ancestor_args))| {
+                    args.iter()
+                        .zip(ancestor_args.iter())
+                        .filter_map(|(arg, ancestor_arg)| arg.as_type().zip(ancestor_arg.as_type()))
+                        .any(|(arg, ancestor_arg)|
+                            // Strictly contains.
+                            (arg != ancestor_arg && arg.contains(ancestor_arg))
+                            // Check all types between current and ancestor use the
+                            // ancestor_arg.
+                            // Otherwise, duplicate wrappers in normal recursive type may be
+                            // regarded as expanding.
+                            // ```
+                            // struct Recursive {
+                            //     a: Box<Box<Recursive>>,
+                            // }
+                            // ```
+                            // It can produce an ADT stack like this,
+                            // - Box<Recursive>
+                            // - Recursive
+                            // - Box<Box<Recursive>>
+                            && stack[ancestor_index + 1..stack.len()].iter().all(
+                                |(_, intermediate_args)|
+                                    intermediate_args
+                                        .iter()
+                                        .filter_map(|arg| arg.as_type())
+                                        .any(|mid_arg| mid_arg.contains(ancestor_arg))
+                            ))
+                })
+        };
         if is_expanding_recursive {
             // FIXME: indicate that this is an expanding recursive type in stub metadata?
             return DINodeCreationResult::new(stub_info.metadata, false);
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 4935f8d7dff..06c3d8ed6bc 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -330,10 +330,16 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     _ => bug!(),
                 };
                 let ptr = args[0].immediate();
+                let locality = fn_args.const_at(1).to_value().valtree.unwrap_leaf().to_u32() as i32;
                 self.call_intrinsic(
                     "llvm.prefetch",
                     &[self.val_ty(ptr)],
-                    &[ptr, self.const_i32(rw), args[1].immediate(), self.const_i32(cache_type)],
+                    &[
+                        ptr,
+                        self.const_i32(rw),
+                        self.const_i32(locality),
+                        self.const_i32(cache_type),
+                    ],
                 )
             }
             sym::carrying_mul_add => {
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 79e80db6f55..0fcf31d7993 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -46,18 +46,11 @@ use rustc_session::Session;
 use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest};
 use rustc_span::Symbol;
 
-mod back {
-    pub(crate) mod archive;
-    pub(crate) mod lto;
-    pub(crate) mod owned_target_machine;
-    mod profiling;
-    pub(crate) mod write;
-}
-
 mod abi;
 mod allocator;
 mod asm;
 mod attributes;
+mod back;
 mod base;
 mod builder;
 mod callee;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs b/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs
deleted file mode 100644
index 51bcc4d123d..00000000000
--- a/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-//! A wrapper around LLVM's archive (.a) code
-
-use std::path::Path;
-use std::{slice, str};
-
-use rustc_fs_util::path_to_c_string;
-
-pub(crate) struct ArchiveRO {
-    pub raw: &'static mut super::Archive,
-}
-
-unsafe impl Send for ArchiveRO {}
-
-pub(crate) struct Iter<'a> {
-    raw: &'a mut super::ArchiveIterator<'a>,
-}
-
-pub(crate) struct Child<'a> {
-    pub raw: &'a mut super::ArchiveChild<'a>,
-}
-
-impl ArchiveRO {
-    /// Opens a static archive for read-only purposes. This is more optimized
-    /// than the `open` method because it uses LLVM's internal `Archive` class
-    /// rather than shelling out to `ar` for everything.
-    ///
-    /// If this archive is used with a mutable method, then an error will be
-    /// raised.
-    pub(crate) fn open(dst: &Path) -> Result<ArchiveRO, String> {
-        unsafe {
-            let s = path_to_c_string(dst);
-            let ar = super::LLVMRustOpenArchive(s.as_ptr()).ok_or_else(|| {
-                super::last_error().unwrap_or_else(|| "failed to open archive".to_owned())
-            })?;
-            Ok(ArchiveRO { raw: ar })
-        }
-    }
-
-    pub(crate) fn iter(&self) -> Iter<'_> {
-        unsafe { Iter { raw: super::LLVMRustArchiveIteratorNew(self.raw) } }
-    }
-}
-
-impl Drop for ArchiveRO {
-    fn drop(&mut self) {
-        unsafe {
-            super::LLVMRustDestroyArchive(&mut *(self.raw as *mut _));
-        }
-    }
-}
-
-impl<'a> Iterator for Iter<'a> {
-    type Item = Result<Child<'a>, String>;
-
-    fn next(&mut self) -> Option<Result<Child<'a>, String>> {
-        unsafe {
-            match super::LLVMRustArchiveIteratorNext(self.raw) {
-                Some(raw) => Some(Ok(Child { raw })),
-                None => super::last_error().map(Err),
-            }
-        }
-    }
-}
-
-impl<'a> Drop for Iter<'a> {
-    fn drop(&mut self) {
-        unsafe {
-            super::LLVMRustArchiveIteratorFree(&mut *(self.raw as *mut _));
-        }
-    }
-}
-
-impl<'a> Child<'a> {
-    pub(crate) fn name(&self) -> Option<&'a str> {
-        unsafe {
-            let mut name_len = 0;
-            let name_ptr = super::LLVMRustArchiveChildName(self.raw, &mut name_len);
-            if name_ptr.is_null() {
-                None
-            } else {
-                let name = slice::from_raw_parts(name_ptr as *const u8, name_len as usize);
-                str::from_utf8(name).ok().map(|s| s.trim())
-            }
-        }
-    }
-}
-
-impl<'a> Drop for Child<'a> {
-    fn drop(&mut self) {
-        unsafe {
-            super::LLVMRustArchiveChildFree(&mut *(self.raw as *mut _));
-        }
-    }
-}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index ad3c3d5932e..2461f70a86e 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -97,6 +97,7 @@ pub(crate) enum ModuleFlagMergeBehavior {
 
 // Consts for the LLVM CallConv type, pre-cast to usize.
 
+/// Must match the layout of `LLVMTailCallKind`.
 #[derive(Copy, Clone, PartialEq, Debug)]
 #[repr(C)]
 #[allow(dead_code)]
@@ -250,6 +251,7 @@ pub(crate) enum AttributeKind {
     Writable = 42,
     DeadOnUnwind = 43,
     DeadOnReturn = 44,
+    CapturesReadOnly = 45,
 }
 
 /// LLVMIntPredicate
@@ -332,10 +334,15 @@ impl RealPredicate {
     }
 }
 
-/// LLVMTypeKind
-#[derive(Copy, Clone, PartialEq, Debug)]
+/// Must match the layout of `LLVMTypeKind`.
+///
+/// Use [`RawEnum<TypeKind>`] for values of `LLVMTypeKind` returned from LLVM,
+/// to avoid risk of UB if LLVM adds new enum values.
+///
+/// All of LLVM's variants should be declared here, even if no Rust-side code refers
+/// to them, because unknown variants will cause [`RawEnum::to_rust`] to panic.
+#[derive(Copy, Clone, PartialEq, Debug, TryFromU32)]
 #[repr(C)]
-#[expect(dead_code, reason = "Some variants are unused, but are kept to match LLVM-C")]
 pub(crate) enum TypeKind {
     Void = 0,
     Half = 1,
@@ -610,17 +617,6 @@ pub(crate) enum DiagnosticLevel {
     Remark,
 }
 
-/// LLVMRustArchiveKind
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub(crate) enum ArchiveKind {
-    K_GNU,
-    K_BSD,
-    K_DARWIN,
-    K_COFF,
-    K_AIXBIG,
-}
-
 unsafe extern "C" {
     // LLVMRustThinLTOData
     pub(crate) type ThinLTOData;
@@ -769,19 +765,12 @@ pub(crate) struct Builder<'a>(InvariantOpaque<'a>);
 pub(crate) struct PassManager<'a>(InvariantOpaque<'a>);
 unsafe extern "C" {
     pub type TargetMachine;
-    pub(crate) type Archive;
 }
-#[repr(C)]
-pub(crate) struct ArchiveIterator<'a>(InvariantOpaque<'a>);
-#[repr(C)]
-pub(crate) struct ArchiveChild<'a>(InvariantOpaque<'a>);
 unsafe extern "C" {
     pub(crate) type Twine;
     pub(crate) type DiagnosticInfo;
     pub(crate) type SMDiagnostic;
 }
-#[repr(C)]
-pub(crate) struct RustArchiveMember<'a>(InvariantOpaque<'a>);
 /// Opaque pointee of `LLVMOperandBundleRef`.
 #[repr(C)]
 pub(crate) struct OperandBundle<'a>(InvariantOpaque<'a>);
@@ -1046,6 +1035,8 @@ unsafe extern "C" {
         CanThrow: llvm::Bool,
     ) -> &'ll Value;
 
+    pub(crate) safe fn LLVMGetTypeKind(Ty: &Type) -> RawEnum<TypeKind>;
+
     // Operations on integer types
     pub(crate) fn LLVMInt1TypeInContext(C: &Context) -> &Type;
     pub(crate) fn LLVMInt8TypeInContext(C: &Context) -> &Type;
@@ -1197,7 +1188,7 @@ unsafe extern "C" {
     pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
     pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
     pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
-    pub(crate) safe fn LLVMRustSetTailCallKind(CallInst: &Value, Kind: TailCallKind);
+    pub(crate) safe fn LLVMSetTailCallKind(CallInst: &Value, kind: TailCallKind);
 
     // Operations on attributes
     pub(crate) fn LLVMCreateStringAttribute(
@@ -1841,9 +1832,6 @@ unsafe extern "C" {
     // Create and destroy contexts.
     pub(crate) fn LLVMRustContextCreate(shouldDiscardNames: bool) -> &'static mut Context;
 
-    /// See llvm::LLVMTypeKind::getTypeID.
-    pub(crate) fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind;
-
     // Operations on all values
     pub(crate) fn LLVMRustGlobalAddMetadata<'a>(
         Val: &'a Value,
@@ -2438,7 +2426,7 @@ unsafe extern "C" {
         OutputObjFile: *const c_char,
         DebugInfoCompression: *const c_char,
         UseEmulatedTls: bool,
-        ArgsCstrBuff: *const c_char,
+        ArgsCstrBuff: *const c_uchar, // See "PTR_LEN_STR".
         ArgsCstrBuffLen: usize,
         UseWasmEH: bool,
     ) -> *mut TargetMachine;
@@ -2505,19 +2493,6 @@ unsafe extern "C" {
     pub(crate) fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char);
     pub(crate) fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t);
 
-    pub(crate) fn LLVMRustOpenArchive(path: *const c_char) -> Option<&'static mut Archive>;
-    pub(crate) fn LLVMRustArchiveIteratorNew(AR: &Archive) -> &mut ArchiveIterator<'_>;
-    pub(crate) fn LLVMRustArchiveIteratorNext<'a>(
-        AIR: &ArchiveIterator<'a>,
-    ) -> Option<&'a mut ArchiveChild<'a>>;
-    pub(crate) fn LLVMRustArchiveChildName(
-        ACR: &ArchiveChild<'_>,
-        size: &mut size_t,
-    ) -> *const c_char;
-    pub(crate) fn LLVMRustArchiveChildFree<'a>(ACR: &'a mut ArchiveChild<'a>);
-    pub(crate) fn LLVMRustArchiveIteratorFree<'a>(AIR: &'a mut ArchiveIterator<'a>);
-    pub(crate) fn LLVMRustDestroyArchive(AR: &'static mut Archive);
-
     pub(crate) fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
 
     pub(crate) fn LLVMRustUnpackOptimizationDiagnostic<'a>(
@@ -2555,21 +2530,6 @@ unsafe extern "C" {
         num_ranges: &mut usize,
     ) -> bool;
 
-    pub(crate) fn LLVMRustWriteArchive(
-        Dst: *const c_char,
-        NumMembers: size_t,
-        Members: *const &RustArchiveMember<'_>,
-        WriteSymbtab: bool,
-        Kind: ArchiveKind,
-        isEC: bool,
-    ) -> LLVMRustResult;
-    pub(crate) fn LLVMRustArchiveMemberNew<'a>(
-        Filename: *const c_char,
-        Name: *const c_char,
-        Child: Option<&ArchiveChild<'a>>,
-    ) -> &'a mut RustArchiveMember<'a>;
-    pub(crate) fn LLVMRustArchiveMemberFree<'a>(Member: &'a mut RustArchiveMember<'a>);
-
     pub(crate) fn LLVMRustSetDataLayoutFromTargetMachine<'a>(M: &'a Module, TM: &'a TargetMachine);
 
     pub(crate) fn LLVMRustPositionBuilderPastAllocas<'a>(B: &Builder<'a>, Fn: &'a Value);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 0ea0af0c9af..7fea7b79a8c 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -3,7 +3,6 @@
 use std::ffi::{CStr, CString};
 use std::num::NonZero;
 use std::ptr;
-use std::str::FromStr;
 use std::string::FromUtf8Error;
 
 use libc::c_uint;
@@ -16,7 +15,6 @@ pub(crate) use self::MetadataType::*;
 pub(crate) use self::ffi::*;
 use crate::common::AsCCharPtr;
 
-pub(crate) mod archive_ro;
 pub(crate) mod diagnostic;
 pub(crate) mod enzyme_ffi;
 mod ffi;
@@ -152,21 +150,6 @@ pub(crate) enum CodeGenOptSize {
     CodeGenOptSizeAggressive = 2,
 }
 
-impl FromStr for ArchiveKind {
-    type Err = ();
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "gnu" => Ok(ArchiveKind::K_GNU),
-            "bsd" => Ok(ArchiveKind::K_BSD),
-            "darwin" => Ok(ArchiveKind::K_DARWIN),
-            "coff" => Ok(ArchiveKind::K_COFF),
-            "aix_big" => Ok(ArchiveKind::K_AIXBIG),
-            _ => Err(()),
-        }
-    }
-}
-
 pub(crate) fn SetInstructionCallConv(instr: &Value, cc: CallConv) {
     unsafe {
         LLVMSetInstructionCallConv(instr, cc as c_uint);
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 28d2100f478..90f7cd43268 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -277,6 +277,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
         {
             None
         }
+        ("loongarch32" | "loongarch64", "32s") if get_version().0 < 21 => None,
         // Filter out features that are not supported by the current LLVM version
         ("riscv32" | "riscv64", "zacas") if get_version().0 < 20 => None,
         (
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 89365503138..f02d16baf94 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -204,7 +204,7 @@ impl<'ll, CX: Borrow<SCx<'ll>>> BaseTypeCodegenMethods for GenericCx<'ll, CX> {
     }
 
     fn type_kind(&self, ty: &'ll Type) -> TypeKind {
-        unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() }
+        llvm::LLVMGetTypeKind(ty).to_rust().to_generic()
     }
 
     fn type_ptr(&self) -> &'ll Type {
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index b6cfea88363..42ba0154192 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -171,8 +171,8 @@ codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphizati
 
 codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
 
-codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize`
-    .note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
+codegen_ssa_invalid_sanitize = invalid argument for `sanitize`
+    .note = expected one of: `address`, `kernel_address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow_call_stack`, or `thread`
 
 codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 4ebe59dc2a7..c3777f64e9e 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2435,6 +2435,13 @@ fn linker_with_args(
     // Passed after compiler-generated options to support manual overriding when necessary.
     add_user_defined_link_args(cmd, sess);
 
+    // ------------ Builtin configurable linker scripts ------------
+    // The user's link args should be able to overwrite symbols in the compiler's
+    // linker script that were weakly defined (i.e. defined with `PROVIDE()`). For this
+    // to work correctly, the user needs to be able to specify linker arguments like
+    // `--defsym` and `--script` *before* any builtin linker scripts are evaluated.
+    add_link_script(cmd, sess, tmpdir, crate_type);
+
     // ------------ Object code and libraries, order-dependent ------------
 
     // Post-link CRT objects.
@@ -2469,8 +2476,6 @@ fn add_order_independent_options(
 
     let apple_sdk_root = add_apple_sdk(cmd, sess, flavor);
 
-    add_link_script(cmd, sess, tmpdir, crate_type);
-
     if sess.target.os == "fuchsia"
         && crate_type == CrateType::Executable
         && !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 67cd1f4cd41..8abaf201aba 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -858,7 +858,7 @@ pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
     instance: Instance<'tcx>,
 ) -> bool {
     fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-        if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
+        if let Some(name) = tcx.codegen_fn_attrs(def_id).symbol_name {
             name.as_str().starts_with("llvm.")
         } else {
             false
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index af70f0deb07..c8690251bd0 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -6,7 +6,6 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
 use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, UsedBy};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
-use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
 use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
 use rustc_middle::middle::codegen_fn_attrs::{
     CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
@@ -77,32 +76,6 @@ fn parse_instruction_set_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<Instr
     }
 }
 
-// FIXME(jdonszelmann): remove when no_sanitize becomes a parsed attr
-fn parse_no_sanitize_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<SanitizerSet> {
-    let list = attr.meta_item_list()?;
-    let mut sanitizer_set = SanitizerSet::empty();
-
-    for item in list.iter() {
-        match item.name() {
-            Some(sym::address) => {
-                sanitizer_set |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
-            }
-            Some(sym::cfi) => sanitizer_set |= SanitizerSet::CFI,
-            Some(sym::kcfi) => sanitizer_set |= SanitizerSet::KCFI,
-            Some(sym::memory) => sanitizer_set |= SanitizerSet::MEMORY,
-            Some(sym::memtag) => sanitizer_set |= SanitizerSet::MEMTAG,
-            Some(sym::shadow_call_stack) => sanitizer_set |= SanitizerSet::SHADOWCALLSTACK,
-            Some(sym::thread) => sanitizer_set |= SanitizerSet::THREAD,
-            Some(sym::hwaddress) => sanitizer_set |= SanitizerSet::HWADDRESS,
-            _ => {
-                tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() });
-            }
-        }
-    }
-
-    Some(sanitizer_set)
-}
-
 // FIXME(jdonszelmann): remove when patchable_function_entry becomes a parsed attr
 fn parse_patchable_function_entry(
     tcx: TyCtxt<'_>,
@@ -161,7 +134,7 @@ fn parse_patchable_function_entry(
 #[derive(Default)]
 struct InterestingAttributeDiagnosticSpans {
     link_ordinal: Option<Span>,
-    no_sanitize: Option<Span>,
+    sanitize: Option<Span>,
     inline: Option<Span>,
     no_mangle: Option<Span>,
 }
@@ -182,7 +155,7 @@ fn process_builtin_attrs(
             match p {
                 AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
                 AttributeKind::ExportName { name, .. } => {
-                    codegen_fn_attrs.export_name = Some(*name)
+                    codegen_fn_attrs.symbol_name = Some(*name)
                 }
                 AttributeKind::Inline(inline, span) => {
                     codegen_fn_attrs.inline = *inline;
@@ -190,7 +163,13 @@ fn process_builtin_attrs(
                 }
                 AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
                 AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
-                AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name),
+                AttributeKind::LinkName { name, .. } => {
+                    // FIXME Remove check for foreign functions once #[link_name] on non-foreign
+                    // functions is a hard error
+                    if tcx.is_foreign_item(did) {
+                        codegen_fn_attrs.symbol_name = Some(*name);
+                    }
+                }
                 AttributeKind::LinkOrdinal { ordinal, span } => {
                     codegen_fn_attrs.link_ordinal = Some(*ordinal);
                     interesting_spans.link_ordinal = Some(*span);
@@ -330,11 +309,7 @@ fn process_builtin_attrs(
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
             }
             sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
-            sym::no_sanitize => {
-                interesting_spans.no_sanitize = Some(attr.span());
-                codegen_fn_attrs.no_sanitize |=
-                    parse_no_sanitize_attr(tcx, attr).unwrap_or_default();
-            }
+            sym::sanitize => interesting_spans.sanitize = Some(attr.span()),
             sym::instruction_set => {
                 codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr)
             }
@@ -358,6 +333,8 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
     codegen_fn_attrs.alignment =
         Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment);
 
+    // Compute the disabled sanitizers.
+    codegen_fn_attrs.no_sanitize |= tcx.disabled_sanitizers_for(did);
     // On trait methods, inherit the `#[align]` of the trait's method prototype.
     codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.inherited_align(did));
 
@@ -410,7 +387,7 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
             // * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way
             //   both for exports and imports through foreign items. This is handled further,
             //   during symbol mangling logic.
-        } else if codegen_fn_attrs.link_name.is_some() {
+        } else if codegen_fn_attrs.symbol_name.is_some() {
             // * This can be overridden with the `#[link_name]` attribute
         } else {
             // NOTE: there's one more exception that we cannot apply here. On wasm,
@@ -455,17 +432,17 @@ fn check_result(
     if !codegen_fn_attrs.no_sanitize.is_empty()
         && codegen_fn_attrs.inline.always()
         && let (Some(no_sanitize_span), Some(inline_span)) =
-            (interesting_spans.no_sanitize, interesting_spans.inline)
+            (interesting_spans.sanitize, interesting_spans.inline)
     {
         let hir_id = tcx.local_def_id_to_hir_id(did);
         tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, |lint| {
-            lint.primary_message("`no_sanitize` will have no effect after inlining");
+            lint.primary_message("setting `sanitize` off will have no effect after inlining");
             lint.span_note(inline_span, "inlining requested here");
         })
     }
 
     // error when specifying link_name together with link_ordinal
-    if let Some(_) = codegen_fn_attrs.link_name
+    if let Some(_) = codegen_fn_attrs.symbol_name
         && let Some(_) = codegen_fn_attrs.link_ordinal
     {
         let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
@@ -512,14 +489,11 @@ fn handle_lang_items(
     // strippable by the linker.
     //
     // Additionally weak lang items have predetermined symbol names.
-    if let Some(lang_item) = lang_item {
-        if WEAK_LANG_ITEMS.contains(&lang_item) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
-        }
-        if let Some(link_name) = lang_item.link_name() {
-            codegen_fn_attrs.export_name = Some(link_name);
-            codegen_fn_attrs.link_name = Some(link_name);
-        }
+    if let Some(lang_item) = lang_item
+        && let Some(link_name) = lang_item.link_name()
+    {
+        codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
+        codegen_fn_attrs.symbol_name = Some(link_name);
     }
 
     // error when using no_mangle on a lang item item
@@ -585,6 +559,93 @@ fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
     }
 }
 
+/// For an attr that has the `sanitize` attribute, read the list of
+/// disabled sanitizers. `current_attr` holds the information about
+/// previously parsed attributes.
+fn parse_sanitize_attr(
+    tcx: TyCtxt<'_>,
+    attr: &Attribute,
+    current_attr: SanitizerSet,
+) -> SanitizerSet {
+    let mut result = current_attr;
+    if let Some(list) = attr.meta_item_list() {
+        for item in list.iter() {
+            let MetaItemInner::MetaItem(set) = item else {
+                tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() });
+                break;
+            };
+            let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
+            match segments.as_slice() {
+                // Similar to clang, sanitize(address = ..) and
+                // sanitize(kernel_address = ..) control both ASan and KASan
+                // Source: https://reviews.llvm.org/D44981.
+                [sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::off) => {
+                    result |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
+                }
+                [sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::on) => {
+                    result &= !SanitizerSet::ADDRESS;
+                    result &= !SanitizerSet::KERNELADDRESS;
+                }
+                [sym::cfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::CFI,
+                [sym::cfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::CFI,
+                [sym::kcfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::KCFI,
+                [sym::kcfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::KCFI,
+                [sym::memory] if set.value_str() == Some(sym::off) => {
+                    result |= SanitizerSet::MEMORY
+                }
+                [sym::memory] if set.value_str() == Some(sym::on) => {
+                    result &= !SanitizerSet::MEMORY
+                }
+                [sym::memtag] if set.value_str() == Some(sym::off) => {
+                    result |= SanitizerSet::MEMTAG
+                }
+                [sym::memtag] if set.value_str() == Some(sym::on) => {
+                    result &= !SanitizerSet::MEMTAG
+                }
+                [sym::shadow_call_stack] if set.value_str() == Some(sym::off) => {
+                    result |= SanitizerSet::SHADOWCALLSTACK
+                }
+                [sym::shadow_call_stack] if set.value_str() == Some(sym::on) => {
+                    result &= !SanitizerSet::SHADOWCALLSTACK
+                }
+                [sym::thread] if set.value_str() == Some(sym::off) => {
+                    result |= SanitizerSet::THREAD
+                }
+                [sym::thread] if set.value_str() == Some(sym::on) => {
+                    result &= !SanitizerSet::THREAD
+                }
+                [sym::hwaddress] if set.value_str() == Some(sym::off) => {
+                    result |= SanitizerSet::HWADDRESS
+                }
+                [sym::hwaddress] if set.value_str() == Some(sym::on) => {
+                    result &= !SanitizerSet::HWADDRESS
+                }
+                _ => {
+                    tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() });
+                }
+            }
+        }
+    }
+    result
+}
+
+fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
+    // Backtrack to the crate root.
+    let disabled = match tcx.opt_local_parent(did) {
+        // Check the parent (recursively).
+        Some(parent) => tcx.disabled_sanitizers_for(parent),
+        // We reached the crate root without seeing an attribute, so
+        // there is no sanitizers to exclude.
+        None => SanitizerSet::empty(),
+    };
+
+    // Check for a sanitize annotation directly on this def.
+    if let Some(attr) = tcx.get_attr(did, sym::sanitize) {
+        return parse_sanitize_attr(tcx, attr, disabled);
+    }
+    disabled
+}
+
 /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
 /// applied to the method prototype.
 fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
@@ -709,6 +770,11 @@ pub fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
-    *providers =
-        Providers { codegen_fn_attrs, should_inherit_track_caller, inherited_align, ..*providers };
+    *providers = Providers {
+        codegen_fn_attrs,
+        should_inherit_track_caller,
+        inherited_align,
+        disabled_sanitizers_for,
+        ..*providers
+    };
 }
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 7ac830bcda9..209c78ddeda 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1121,9 +1121,9 @@ impl IntoDiagArg for ExpectedPointerMutability {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa_invalid_no_sanitize)]
+#[diag(codegen_ssa_invalid_sanitize)]
 #[note]
-pub(crate) struct InvalidNoSanitize {
+pub(crate) struct InvalidSanitize {
     #[primary_span]
     pub span: Span,
 }
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 7e4341a8236..b5aa50f4851 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -180,6 +180,7 @@ fn parse_rust_feature_flag<'a>(
             while let Some(new_feature) = new_features.pop() {
                 if features.insert(new_feature) {
                     if let Some(implied_features) = inverse_implied_features.get(&new_feature) {
+                        #[allow(rustc::potential_query_instability)]
                         new_features.extend(implied_features)
                     }
                 }
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 64cb934ac8d..4cb88d44e1b 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -27,8 +27,9 @@ use crate::{enter_trace_span, fluent_generated as fluent};
 pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
     /// Pass a copy of the given operand.
     Copy(OpTy<'tcx, Prov>),
-    /// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
-    /// make the place inaccessible for the duration of the function call.
+    /// Allow for the argument to be passed in-place: destroy the value originally stored at that
+    /// place and make the place inaccessible for the duration of the function call. This *must* be
+    /// an in-memory place so that we can do the proper alias checks.
     InPlace(MPlaceTy<'tcx, Prov>),
 }
 
@@ -379,6 +380,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
         }
 
+        // *Before* pushing the new frame, determine whether the return destination is in memory.
+        // Need to use `place_to_op` to be *sure* we get the mplace if there is one.
+        let destination_mplace = self.place_to_op(destination)?.as_mplace_or_imm().left();
+
+        // Push the "raw" frame -- this leaves locals uninitialized.
         self.push_stack_frame_raw(instance, body, destination, cont)?;
 
         // If an error is raised here, pop the frame again to get an accurate backtrace.
@@ -496,7 +502,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
             // Protect return place for in-place return value passing.
             // We only need to protect anything if this is actually an in-memory place.
-            if let Left(mplace) = destination.as_mplace_or_local() {
+            if let Some(mplace) = destination_mplace {
                 M::protect_in_place_function_argument(self, &mplace)?;
             }
 
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index a8a1ac1c980..9681d89ce35 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -325,8 +325,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let _trace = enter_trace_span!(
             M,
             "instantiate_from_frame_and_normalize_erasing_regions",
-            "{}",
-            frame.instance
+            %frame.instance
         );
         frame
             .instance
@@ -583,6 +582,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         span: Span,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
+        let _trace = enter_trace_span!(M, const_eval::eval_mir_constant, ?val);
         let const_val = val.eval(*self.tcx, self.typing_env, span).map_err(|err| {
                 if M::ALL_CONSTS_ARE_PRECHECKED {
                     match err {
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 53a440b646b..560b0e1ae4e 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -175,6 +175,16 @@ impl<Prov: Provenance> Immediate<Prov> {
         }
         interp_ok(())
     }
+
+    pub fn has_provenance(&self) -> bool {
+        match self {
+            Immediate::Scalar(scalar) => matches!(scalar, Scalar::Ptr { .. }),
+            Immediate::ScalarPair(s1, s2) => {
+                matches!(s1, Scalar::Ptr { .. }) || matches!(s2, Scalar::Ptr { .. })
+            }
+            Immediate::Uninit => false,
+        }
+    }
 }
 
 // ScalarPair needs a type to interpret, so we often have an immediate and a type together
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 3255ffa54aa..a86fdf80f60 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -234,6 +234,12 @@ impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> {
     }
 
     /// A place is either an mplace or some local.
+    ///
+    /// Note that the return value can be different even for logically identical places!
+    /// Specifically, if a local is stored in-memory, this may return `Local` or `MPlaceTy`
+    /// depending on how the place was constructed. In other words, seeing `Local` here does *not*
+    /// imply that this place does not point to memory. Every caller must therefore always handle
+    /// both cases.
     #[inline(always)]
     pub fn as_mplace_or_local(
         &self,
@@ -759,6 +765,13 @@ where
         &mut self,
         dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
+        // If this is an efficiently represented local variable without provenance, skip the
+        // `as_mplace_or_mutable_local` that would otherwise force this local into memory.
+        if let Right(imm) = dest.to_op(self)?.as_mplace_or_imm() {
+            if !imm.has_provenance() {
+                return interp_ok(());
+            }
+        }
         match self.as_mplace_or_mutable_local(&dest.to_place())? {
             Right((local_val, _local_layout, local)) => {
                 local_val.clear_provenance()?;
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index 73cc87508ef..7cabfd96121 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -20,7 +20,7 @@ use super::{
     MemoryKind, Operand, PlaceTy, Pointer, Provenance, ReturnAction, Scalar, from_known_layout,
     interp_ok, throw_ub, throw_unsup,
 };
-use crate::errors;
+use crate::{enter_trace_span, errors};
 
 // The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
 // boundary and dropped in the other thread, it would exit the span in the other thread.
@@ -386,6 +386,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
         for &const_ in body.required_consts() {
+            // We can't use `eval_mir_constant` here as that assumes that all required consts have
+            // already been checked, so we need a separate tracing call.
+            let _trace = enter_trace_span!(M, const_eval::required_consts, ?const_.const_);
             let c =
                 self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
             c.eval(*self.tcx, self.typing_env, const_.span).map_err(|err| {
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index f1995b3f132..084d45cf2cb 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -4,6 +4,7 @@
 
 use either::Either;
 use rustc_abi::{FIRST_VARIANT, FieldIdx};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_index::IndexSlice;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, mir, span_bug};
@@ -389,8 +390,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
     /// Evaluate the arguments of a function call
     fn eval_fn_call_argument(
-        &self,
+        &mut self,
         op: &mir::Operand<'tcx>,
+        move_definitely_disjoint: bool,
     ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
         interp_ok(match op {
             mir::Operand::Copy(_) | mir::Operand::Constant(_) => {
@@ -399,24 +401,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 FnArg::Copy(op)
             }
             mir::Operand::Move(place) => {
-                // If this place lives in memory, preserve its location.
-                // We call `place_to_op` which will be an `MPlaceTy` whenever there exists
-                // an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local`
-                // which can return a local even if that has an mplace.)
                 let place = self.eval_place(*place)?;
-                let op = self.place_to_op(&place)?;
-
-                match op.as_mplace_or_imm() {
-                    Either::Left(mplace) => FnArg::InPlace(mplace),
-                    Either::Right(_imm) => {
-                        // This argument doesn't live in memory, so there's no place
-                        // to make inaccessible during the call.
-                        // We rely on there not being any stray `PlaceTy` that would let the
-                        // caller directly access this local!
-                        // This is also crucial for tail calls, where we want the `FnArg` to
-                        // stay valid when the old stack frame gets popped.
-                        FnArg::Copy(op)
+                if move_definitely_disjoint {
+                    // We still have to ensure that no *other* pointers are used to access this place,
+                    // so *if* it is in memory then we have to treat it as `InPlace`.
+                    // Use `place_to_op` to guarantee that we notice it being in memory.
+                    let op = self.place_to_op(&place)?;
+                    match op.as_mplace_or_imm() {
+                        Either::Left(mplace) => FnArg::InPlace(mplace),
+                        Either::Right(_imm) => FnArg::Copy(op),
                     }
+                } else {
+                    // We have to force this into memory to detect aliasing among `Move` arguments.
+                    FnArg::InPlace(self.force_allocation(&place)?)
                 }
             }
         })
@@ -425,18 +422,46 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Shared part of `Call` and `TailCall` implementation — finding and evaluating all the
     /// necessary information about callee and arguments to make a call.
     fn eval_callee_and_args(
-        &self,
+        &mut self,
         terminator: &mir::Terminator<'tcx>,
         func: &mir::Operand<'tcx>,
         args: &[Spanned<mir::Operand<'tcx>>],
     ) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> {
         let func = self.eval_operand(func, None)?;
+
+        // Evaluating function call arguments. The tricky part here is dealing with `Move`
+        // arguments: we have to ensure no two such arguments alias. This would be most easily done
+        // by just forcing them all into memory and then doing the usual in-place argument
+        // protection, but then we'd force *a lot* of arguments into memory. So we do some syntactic
+        // pre-processing here where if all `move` arguments are syntactically distinct local
+        // variables (and none is indirect), we can skip the in-memory forcing.
+        let move_definitely_disjoint = 'move_definitely_disjoint: {
+            let mut previous_locals = FxHashSet::<mir::Local>::default();
+            for arg in args {
+                let mir::Operand::Move(place) = arg.node else {
+                    continue; // we can skip non-`Move` arguments.
+                };
+                if place.is_indirect_first_projection() {
+                    // An indirect `Move` argument could alias with anything else...
+                    break 'move_definitely_disjoint false;
+                }
+                if !previous_locals.insert(place.local) {
+                    // This local is the base for two arguments! They might overlap.
+                    break 'move_definitely_disjoint false;
+                }
+            }
+            // We found no violation so they are all definitely disjoint.
+            true
+        };
         let args = args
             .iter()
-            .map(|arg| self.eval_fn_call_argument(&arg.node))
+            .map(|arg| self.eval_fn_call_argument(&arg.node, move_definitely_disjoint))
             .collect::<InterpResult<'tcx, Vec<_>>>()?;
 
-        let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
+        let fn_sig_binder = {
+            let _trace = enter_trace_span!(M, "fn_sig", ty = ?func.layout.ty.kind());
+            func.layout.ty.fn_sig(*self.tcx)
+        };
         let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, fn_sig_binder);
         let extra_args = &args[fn_sig.inputs().len()..];
         let extra_args =
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 5e8bee65706..02e3d90f4af 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -1418,7 +1418,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let _trace = enter_trace_span!(
             M,
             "validate_operand",
-            "recursive={recursive}, reset_provenance_and_padding={reset_provenance_and_padding}, val={val:?}"
+            recursive,
+            reset_provenance_and_padding,
+            ?val,
         );
 
         // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 13cc607135a..92096958f2b 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -1,7 +1,7 @@
 use std::fmt::Write;
 
 use rustc_data_structures::intern::Interned;
-use rustc_hir::def_id::CrateNum;
+use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::DisambiguatedDefPathData;
 use rustc_middle::bug;
 use rustc_middle::ty::print::{PrettyPrinter, PrintError, Printer};
@@ -132,6 +132,35 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> {
             Ok(())
         }
     }
+
+    fn print_coroutine_with_kind(
+        &mut self,
+        def_id: DefId,
+        parent_args: &'tcx [GenericArg<'tcx>],
+        kind: Ty<'tcx>,
+    ) -> Result<(), PrintError> {
+        self.print_def_path(def_id, parent_args)?;
+
+        let ty::Coroutine(_, args) = self.tcx.type_of(def_id).instantiate_identity().kind() else {
+            // Could be `ty::Error`.
+            return Ok(());
+        };
+
+        let default_kind = args.as_coroutine().kind_ty();
+
+        match kind.to_opt_closure_kind() {
+            _ if kind == default_kind => {
+                // No need to mark the closure if it's the deduced coroutine kind.
+            }
+            Some(ty::ClosureKind::Fn) | None => {
+                // Should never happen. Just don't mark anything rather than panicking.
+            }
+            Some(ty::ClosureKind::FnMut) => self.path.push_str("::{{call_mut}}"),
+            Some(ty::ClosureKind::FnOnce) => self.path.push_str("::{{call_once}}"),
+        }
+
+        Ok(())
+    }
 }
 
 impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml
index 0951859fa53..552ad672752 100644
--- a/compiler/rustc_error_messages/Cargo.toml
+++ b/compiler/rustc_error_messages/Cargo.toml
@@ -11,6 +11,8 @@ icu_list = "1.2"
 icu_locid = "1.2"
 icu_provider_adapters = "1.2"
 intl-memoizer = "0.5.1"
+rustc_ast = { path = "../rustc_ast" }
+rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_baked_icu_data = { path = "../rustc_baked_icu_data" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_error_messages/src/diagnostic_impls.rs b/compiler/rustc_error_messages/src/diagnostic_impls.rs
new file mode 100644
index 00000000000..3b664cce577
--- /dev/null
+++ b/compiler/rustc_error_messages/src/diagnostic_impls.rs
@@ -0,0 +1,205 @@
+use std::backtrace::Backtrace;
+use std::borrow::Cow;
+use std::fmt;
+use std::num::ParseIntError;
+use std::path::{Path, PathBuf};
+use std::process::ExitStatus;
+
+use rustc_ast as ast;
+use rustc_ast_pretty::pprust;
+use rustc_span::edition::Edition;
+
+use crate::{DiagArgValue, IntoDiagArg};
+
+pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display);
+
+impl IntoDiagArg for DiagArgFromDisplay<'_> {
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        self.0.to_string().into_diag_arg(path)
+    }
+}
+
+impl<'a> From<&'a dyn fmt::Display> for DiagArgFromDisplay<'a> {
+    fn from(t: &'a dyn fmt::Display) -> Self {
+        DiagArgFromDisplay(t)
+    }
+}
+
+impl<'a, T: fmt::Display> From<&'a T> for DiagArgFromDisplay<'a> {
+    fn from(t: &'a T) -> Self {
+        DiagArgFromDisplay(t)
+    }
+}
+
+impl<'a, T: Clone + IntoDiagArg> IntoDiagArg for &'a T {
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        self.clone().into_diag_arg(path)
+    }
+}
+
+#[macro_export]
+macro_rules! into_diag_arg_using_display {
+    ($( $ty:ty ),+ $(,)?) => {
+        $(
+            impl $crate::IntoDiagArg for $ty {
+                fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> $crate::DiagArgValue {
+                    self.to_string().into_diag_arg(path)
+                }
+            }
+        )+
+    }
+}
+
+macro_rules! into_diag_arg_for_number {
+    ($( $ty:ty ),+ $(,)?) => {
+        $(
+            impl $crate::IntoDiagArg for $ty {
+                fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> $crate::DiagArgValue {
+                    // Convert to a string if it won't fit into `Number`.
+                    #[allow(irrefutable_let_patterns)]
+                    if let Ok(n) = TryInto::<i32>::try_into(self) {
+                        $crate::DiagArgValue::Number(n)
+                    } else {
+                        self.to_string().into_diag_arg(path)
+                    }
+                }
+            }
+        )+
+    }
+}
+
+into_diag_arg_using_display!(
+    ast::ParamKindOrd,
+    std::io::Error,
+    Box<dyn std::error::Error>,
+    std::num::NonZero<u32>,
+    Edition,
+    rustc_span::Ident,
+    rustc_span::MacroRulesNormalizedIdent,
+    ParseIntError,
+    ExitStatus,
+);
+
+into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
+
+impl IntoDiagArg for bool {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        if self {
+            DiagArgValue::Str(Cow::Borrowed("true"))
+        } else {
+            DiagArgValue::Str(Cow::Borrowed("false"))
+        }
+    }
+}
+
+impl IntoDiagArg for char {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
+    }
+}
+
+impl IntoDiagArg for Vec<char> {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::StrListSepByAnd(
+            self.into_iter().map(|c| Cow::Owned(format!("{c:?}"))).collect(),
+        )
+    }
+}
+
+impl IntoDiagArg for rustc_span::Symbol {
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        self.to_ident_string().into_diag_arg(path)
+    }
+}
+
+impl<'a> IntoDiagArg for &'a str {
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        self.to_string().into_diag_arg(path)
+    }
+}
+
+impl IntoDiagArg for String {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(self))
+    }
+}
+
+impl<'a> IntoDiagArg for Cow<'a, str> {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(self.into_owned()))
+    }
+}
+
+impl<'a> IntoDiagArg for &'a Path {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(self.display().to_string()))
+    }
+}
+
+impl IntoDiagArg for PathBuf {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(self.display().to_string()))
+    }
+}
+
+impl IntoDiagArg for ast::Expr {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(pprust::expr_to_string(&self)))
+    }
+}
+
+impl IntoDiagArg for ast::Path {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(pprust::path_to_string(&self)))
+    }
+}
+
+impl IntoDiagArg for ast::token::Token {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(pprust::token_to_string(&self))
+    }
+}
+
+impl IntoDiagArg for ast::token::TokenKind {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(pprust::token_kind_to_string(&self))
+    }
+}
+
+impl IntoDiagArg for std::ffi::CString {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned()))
+    }
+}
+
+impl IntoDiagArg for rustc_data_structures::small_c_str::SmallCStr {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned()))
+    }
+}
+
+impl IntoDiagArg for ast::Visibility {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        let s = pprust::vis_to_string(&self);
+        let s = s.trim_end().to_string();
+        DiagArgValue::Str(Cow::Owned(s))
+    }
+}
+
+impl IntoDiagArg for Backtrace {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::from(self.to_string()))
+    }
+}
+
+impl IntoDiagArg for ast::util::parser::ExprPrecedence {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Number(self as i32)
+    }
+}
+
+impl IntoDiagArg for ast::FloatTy {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Borrowed(self.name_str()))
+    }
+}
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 4b3ecad307f..d8bacbe762b 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -23,6 +23,9 @@ use rustc_span::Span;
 use tracing::{instrument, trace};
 pub use unic_langid::{LanguageIdentifier, langid};
 
+mod diagnostic_impls;
+pub use diagnostic_impls::DiagArgFromDisplay;
+
 pub type FluentBundle =
     IntoDynSyncSend<fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>>;
 
@@ -589,3 +592,53 @@ pub fn fluent_value_from_str_list_sep_by_and(l: Vec<Cow<'_, str>>) -> FluentValu
 
     FluentValue::Custom(Box::new(FluentStrListSepByAnd(l)))
 }
+
+/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
+/// `DiagArg` are converted to `FluentArgs` (consuming the collection) at the start of diagnostic
+/// emission.
+pub type DiagArg<'iter> = (&'iter DiagArgName, &'iter DiagArgValue);
+
+/// Name of a diagnostic argument.
+pub type DiagArgName = Cow<'static, str>;
+
+/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
+/// to a `FluentValue` by the emitter to be used in diagnostic translation.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
+pub enum DiagArgValue {
+    Str(Cow<'static, str>),
+    // This gets converted to a `FluentNumber`, which is an `f64`. An `i32`
+    // safely fits in an `f64`. Any integers bigger than that will be converted
+    // to strings in `into_diag_arg` and stored using the `Str` variant.
+    Number(i32),
+    StrListSepByAnd(Vec<Cow<'static, str>>),
+}
+
+/// Converts a value of a type into a `DiagArg` (typically a field of an `Diag` struct).
+/// Implemented as a custom trait rather than `From` so that it is implemented on the type being
+/// converted rather than on `DiagArgValue`, which enables types from other `rustc_*` crates to
+/// implement this.
+pub trait IntoDiagArg {
+    /// Convert `Self` into a `DiagArgValue` suitable for rendering in a diagnostic.
+    ///
+    /// It takes a `path` where "long values" could be written to, if the `DiagArgValue` is too big
+    /// for displaying on the terminal. This path comes from the `Diag` itself. When rendering
+    /// values that come from `TyCtxt`, like `Ty<'_>`, they can use `TyCtxt::short_string`. If a
+    /// value has no shortening logic that could be used, the argument can be safely ignored.
+    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue;
+}
+
+impl IntoDiagArg for DiagArgValue {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        self
+    }
+}
+
+impl From<DiagArgValue> for FluentValue<'static> {
+    fn from(val: DiagArgValue) -> Self {
+        match val {
+            DiagArgValue::Str(s) => From::from(s),
+            DiagArgValue::Number(n) => From::from(n),
+            DiagArgValue::StrListSepByAnd(l) => fluent_value_from_str_list_sep_by_and(l),
+        }
+    }
+}
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 3e8cf6207ae..ad6d29e21fc 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -8,22 +8,18 @@ edition = "2024"
 annotate-snippets = "0.11"
 derive_setters = "0.1.6"
 rustc_abi = { path = "../rustc_abi" }
-rustc_ast = { path = "../rustc_ast" }
-rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_codes = { path = "../rustc_error_codes" }
 rustc_error_messages = { path = "../rustc_error_messages" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
 rustc_hashes = { path = "../rustc_hashes" }
-rustc_hir = { path = "../rustc_hir" }
+rustc_hir_id = { path = "../rustc_hir_id" }
 rustc_index = { path = "../rustc_index" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
-rustc_target = { path = "../rustc_target" }
-rustc_type_ir = { path = "../rustc_type_ir" }
 serde = { version = "1.0.125", features = ["derive"] }
 serde_json = "1.0.59"
 termcolor = "1.2.0"
diff --git a/compiler/rustc_errors/src/codes.rs b/compiler/rustc_errors/src/codes.rs
index 947cf27ca79..787a8af99b1 100644
--- a/compiler/rustc_errors/src/codes.rs
+++ b/compiler/rustc_errors/src/codes.rs
@@ -20,6 +20,8 @@ impl fmt::Display for ErrCode {
     }
 }
 
+rustc_error_messages::into_diag_arg_using_display!(ErrCode);
+
 macro_rules! define_error_code_constants_and_diagnostics_table {
     ($($name:ident: $num:literal,)*) => (
         $(
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index e579370ce4e..183dceddd2c 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -8,7 +8,7 @@ use std::path::PathBuf;
 use std::thread::panicking;
 
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_error_messages::{FluentValue, fluent_value_from_str_list_sep_by_and};
+use rustc_error_messages::{DiagArgName, DiagArgValue, IntoDiagArg};
 use rustc_lint_defs::{Applicability, LintExpectationId};
 use rustc_macros::{Decodable, Encodable};
 use rustc_span::source_map::Spanned;
@@ -22,26 +22,6 @@ use crate::{
     Suggestions,
 };
 
-/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
-/// `DiagArg` are converted to `FluentArgs` (consuming the collection) at the start of diagnostic
-/// emission.
-pub type DiagArg<'iter> = (&'iter DiagArgName, &'iter DiagArgValue);
-
-/// Name of a diagnostic argument.
-pub type DiagArgName = Cow<'static, str>;
-
-/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
-/// to a `FluentValue` by the emitter to be used in diagnostic translation.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
-pub enum DiagArgValue {
-    Str(Cow<'static, str>),
-    // This gets converted to a `FluentNumber`, which is an `f64`. An `i32`
-    // safely fits in an `f64`. Any integers bigger than that will be converted
-    // to strings in `into_diag_arg` and stored using the `Str` variant.
-    Number(i32),
-    StrListSepByAnd(Vec<Cow<'static, str>>),
-}
-
 pub type DiagArgMap = FxIndexMap<DiagArgName, DiagArgValue>;
 
 /// Trait for types that `Diag::emit` can return as a "guarantee" (or "proof")
@@ -143,36 +123,6 @@ where
     }
 }
 
-/// Converts a value of a type into a `DiagArg` (typically a field of an `Diag` struct).
-/// Implemented as a custom trait rather than `From` so that it is implemented on the type being
-/// converted rather than on `DiagArgValue`, which enables types from other `rustc_*` crates to
-/// implement this.
-pub trait IntoDiagArg {
-    /// Convert `Self` into a `DiagArgValue` suitable for rendering in a diagnostic.
-    ///
-    /// It takes a `path` where "long values" could be written to, if the `DiagArgValue` is too big
-    /// for displaying on the terminal. This path comes from the `Diag` itself. When rendering
-    /// values that come from `TyCtxt`, like `Ty<'_>`, they can use `TyCtxt::short_string`. If a
-    /// value has no shortening logic that could be used, the argument can be safely ignored.
-    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue;
-}
-
-impl IntoDiagArg for DiagArgValue {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        self
-    }
-}
-
-impl From<DiagArgValue> for FluentValue<'static> {
-    fn from(val: DiagArgValue) -> Self {
-        match val {
-            DiagArgValue::Str(s) => From::from(s),
-            DiagArgValue::Number(n) => From::from(n),
-            DiagArgValue::StrListSepByAnd(l) => fluent_value_from_str_list_sep_by_and(l),
-        }
-    }
-}
-
 /// Trait implemented by error types. This should not be implemented manually. Instead, use
 /// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
 #[rustc_diagnostic_item = "Subdiagnostic"]
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index eca5806fac5..435d16a8380 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -1,317 +1,22 @@
-use std::backtrace::Backtrace;
 use std::borrow::Cow;
-use std::fmt;
-use std::num::ParseIntError;
-use std::path::{Path, PathBuf};
-use std::process::ExitStatus;
 
 use rustc_abi::TargetDataLayoutErrors;
-use rustc_ast::util::parser::ExprPrecedence;
-use rustc_ast_pretty::pprust;
-use rustc_hir::RustcVersion;
+use rustc_error_messages::{DiagArgValue, IntoDiagArg};
 use rustc_macros::Subdiagnostic;
-use rustc_span::edition::Edition;
-use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol};
-use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTuple};
-use rustc_type_ir::{ClosureKind, FloatTy};
-use {rustc_ast as ast, rustc_hir as hir};
+use rustc_span::{Span, Symbol};
 
 use crate::diagnostic::DiagLocation;
 use crate::{
-    Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level,
-    Subdiagnostic, fluent_generated as fluent,
+    Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic,
+    fluent_generated as fluent,
 };
 
-pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display);
-
-impl IntoDiagArg for DiagArgFromDisplay<'_> {
-    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        self.0.to_string().into_diag_arg(path)
-    }
-}
-
-impl<'a> From<&'a dyn fmt::Display> for DiagArgFromDisplay<'a> {
-    fn from(t: &'a dyn fmt::Display) -> Self {
-        DiagArgFromDisplay(t)
-    }
-}
-
-impl<'a, T: fmt::Display> From<&'a T> for DiagArgFromDisplay<'a> {
-    fn from(t: &'a T) -> Self {
-        DiagArgFromDisplay(t)
-    }
-}
-
-impl<'a, T: Clone + IntoDiagArg> IntoDiagArg for &'a T {
-    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        self.clone().into_diag_arg(path)
-    }
-}
-
-#[macro_export]
-macro_rules! into_diag_arg_using_display {
-    ($( $ty:ty ),+ $(,)?) => {
-        $(
-            impl IntoDiagArg for $ty {
-                fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-                    self.to_string().into_diag_arg(path)
-                }
-            }
-        )+
-    }
-}
-
-macro_rules! into_diag_arg_for_number {
-    ($( $ty:ty ),+ $(,)?) => {
-        $(
-            impl IntoDiagArg for $ty {
-                fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-                    // Convert to a string if it won't fit into `Number`.
-                    #[allow(irrefutable_let_patterns)]
-                    if let Ok(n) = TryInto::<i32>::try_into(self) {
-                        DiagArgValue::Number(n)
-                    } else {
-                        self.to_string().into_diag_arg(path)
-                    }
-                }
-            }
-        )+
-    }
-}
-
-into_diag_arg_using_display!(
-    ast::ParamKindOrd,
-    std::io::Error,
-    Box<dyn std::error::Error>,
-    std::num::NonZero<u32>,
-    hir::Target,
-    Edition,
-    Ident,
-    MacroRulesNormalizedIdent,
-    ParseIntError,
-    StackProtector,
-    &TargetTuple,
-    SplitDebuginfo,
-    ExitStatus,
-    ErrCode,
-    rustc_abi::ExternAbi,
-);
-
-impl IntoDiagArg for RustcVersion {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(self.to_string()))
-    }
-}
-
-impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::TraitRef<I> {
-    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        self.to_string().into_diag_arg(path)
-    }
-}
-
-impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::ExistentialTraitRef<I> {
-    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        self.to_string().into_diag_arg(path)
-    }
-}
-
-impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst<I> {
-    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        format!("{self:?}").into_diag_arg(path)
-    }
-}
-
-impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::FnSig<I> {
-    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        format!("{self:?}").into_diag_arg(path)
-    }
-}
-
-impl<I: rustc_type_ir::Interner, T> IntoDiagArg for rustc_type_ir::Binder<I, T>
-where
-    T: IntoDiagArg,
-{
-    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        self.skip_binder().into_diag_arg(path)
-    }
-}
-
-into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
-
-impl IntoDiagArg for bool {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        if self {
-            DiagArgValue::Str(Cow::Borrowed("true"))
-        } else {
-            DiagArgValue::Str(Cow::Borrowed("false"))
-        }
-    }
-}
-
-impl IntoDiagArg for char {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
-    }
-}
-
-impl IntoDiagArg for Vec<char> {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::StrListSepByAnd(
-            self.into_iter().map(|c| Cow::Owned(format!("{c:?}"))).collect(),
-        )
-    }
-}
-
-impl IntoDiagArg for Symbol {
-    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        self.to_ident_string().into_diag_arg(path)
-    }
-}
-
-impl<'a> IntoDiagArg for &'a str {
-    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        self.to_string().into_diag_arg(path)
-    }
-}
-
-impl IntoDiagArg for String {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(self))
-    }
-}
-
-impl<'a> IntoDiagArg for Cow<'a, str> {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(self.into_owned()))
-    }
-}
-
-impl<'a> IntoDiagArg for &'a Path {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(self.display().to_string()))
-    }
-}
-
-impl IntoDiagArg for PathBuf {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(self.display().to_string()))
-    }
-}
-
-impl IntoDiagArg for PanicStrategy {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(self.desc().to_string()))
-    }
-}
-
-impl IntoDiagArg for hir::ConstContext {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Borrowed(match self {
-            hir::ConstContext::ConstFn => "const_fn",
-            hir::ConstContext::Static(_) => "static",
-            hir::ConstContext::Const { .. } => "const",
-        }))
-    }
-}
-
-impl IntoDiagArg for ast::Expr {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(pprust::expr_to_string(&self)))
-    }
-}
-
-impl IntoDiagArg for ast::Path {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(pprust::path_to_string(&self)))
-    }
-}
-
-impl IntoDiagArg for ast::token::Token {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(pprust::token_to_string(&self))
-    }
-}
-
-impl IntoDiagArg for ast::token::TokenKind {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(pprust::token_kind_to_string(&self))
-    }
-}
-
-impl IntoDiagArg for FloatTy {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Borrowed(self.name_str()))
-    }
-}
-
-impl IntoDiagArg for std::ffi::CString {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned()))
-    }
-}
-
-impl IntoDiagArg for rustc_data_structures::small_c_str::SmallCStr {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned()))
-    }
-}
-
-impl IntoDiagArg for ast::Visibility {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        let s = pprust::vis_to_string(&self);
-        let s = s.trim_end().to_string();
-        DiagArgValue::Str(Cow::Owned(s))
-    }
-}
-
-impl IntoDiagArg for rustc_lint_defs::Level {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Borrowed(self.to_cmd_flag()))
-    }
-}
-
-impl<Id> IntoDiagArg for hir::def::Res<Id> {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Borrowed(self.descr()))
-    }
-}
-
 impl IntoDiagArg for DiagLocation {
     fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
         DiagArgValue::Str(Cow::from(self.to_string()))
     }
 }
 
-impl IntoDiagArg for Backtrace {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::from(self.to_string()))
-    }
-}
-
-impl IntoDiagArg for Level {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::from(self.to_string()))
-    }
-}
-
-impl IntoDiagArg for ClosureKind {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(self.as_str().into())
-    }
-}
-
-impl IntoDiagArg for hir::def::Namespace {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Str(Cow::Borrowed(self.descr()))
-    }
-}
-
-impl IntoDiagArg for ExprPrecedence {
-    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
-        DiagArgValue::Number(self as i32)
-    }
-}
-
 #[derive(Clone)]
 pub struct DiagSymbolList<S = Symbol>(Vec<S>);
 
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 97c47fa9b9a..749bba5de12 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -17,7 +17,7 @@ use std::path::Path;
 use std::sync::Arc;
 
 use derive_setters::Setters;
-use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sync::{DynSend, IntoDynSyncSend};
 use rustc_error_messages::{FluentArgs, SpanLabel};
 use rustc_lexer;
@@ -1853,7 +1853,7 @@ impl HumanEmitter {
                             && line_idx + 1 == annotated_file.lines.len(),
                     );
 
-                    let mut to_add = FxHashMap::default();
+                    let mut to_add = FxIndexMap::default();
 
                     for (depth, style) in depths {
                         // FIXME(#120456) - is `swap_remove` correct?
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 2534cddf105..a775b70dbee 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -41,12 +41,11 @@ use std::{fmt, panic};
 use Level::*;
 pub use codes::*;
 pub use diagnostic::{
-    BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
-    Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
-    Subdiagnostic,
+    BugAbort, Diag, DiagArgMap, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee,
+    FatalAbort, LintDiagnostic, StringPart, Subdiag, Subdiagnostic,
 };
 pub use diagnostic_impls::{
-    DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
+    DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
     IndicateAnonymousLifetime, SingleLabelManySpans,
 };
 pub use emitter::ColorConfig;
@@ -56,11 +55,12 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{DynSend, Lock};
 pub use rustc_error_messages::{
-    DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
-    SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
+    DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg,
+    LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
+    fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display,
 };
 use rustc_hashes::Hash128;
-use rustc_hir::HirId;
+use rustc_hir_id::HirId;
 pub use rustc_lint_defs::{Applicability, listify, pluralize};
 use rustc_lint_defs::{Lint, LintExpectationId};
 use rustc_macros::{Decodable, Encodable};
@@ -1999,6 +1999,12 @@ impl Level {
     }
 }
 
+impl IntoDiagArg for Level {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::from(self.to_string()))
+    }
+}
+
 // FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
 pub fn elided_lifetime_in_path_suggestion(
     source_map: &SourceMap,
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 1f8f3be6809..61ba716d082 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -70,7 +70,7 @@ expand_invalid_fragment_specifier =
     invalid fragment specifier `{$fragment}`
     .help = {$help}
 
-expand_macro_args_bad_delim = macro attribute argument matchers require parentheses
+expand_macro_args_bad_delim = `{$rule_kw}` rule argument matchers require parentheses
 expand_macro_args_bad_delim_sugg = the delimiters should be `(` and `)`
 
 expand_macro_body_stability =
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index e58269991fc..ba9d76970f0 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -490,6 +490,7 @@ pub(crate) struct MacroArgsBadDelim {
     pub span: Span,
     #[subdiagnostic]
     pub sugg: MacroArgsBadDelimSugg,
+    pub rule_kw: Symbol,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 670f5c91bb9..755275d3cda 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -16,6 +16,7 @@ use rustc_attr_parsing::{EvalConfigResult, ShouldEmit};
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_errors::PResult;
 use rustc_feature::Features;
+use rustc_hir::def::MacroKinds;
 use rustc_parse::parser::{
     AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
     token_descr,
@@ -565,6 +566,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                                 .map(|DeriveResolution { path, item, exts: _, is_const }| {
                                     // FIXME: Consider using the derive resolutions (`_exts`)
                                     // instead of enqueuing the derives to be resolved again later.
+                                    // Note that this can result in duplicate diagnostics.
                                     let expn_id = LocalExpnId::fresh_empty();
                                     derive_invocations.push((
                                         Invocation {
@@ -799,7 +801,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                                     ItemKind::Mod(
                                         _,
                                         _,
-                                        ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _, _),
+                                        ModKind::Unloaded
+                                            | ModKind::Loaded(_, Inline::No { .. }, _),
                                     )
                                 ) =>
                         {
@@ -922,6 +925,35 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     }
                     fragment
                 }
+                SyntaxExtensionKind::MacroRules(expander)
+                    if expander.kinds().contains(MacroKinds::DERIVE) =>
+                {
+                    if is_const {
+                        let guar = self
+                            .cx
+                            .dcx()
+                            .span_err(span, "macro `derive` does not support const derives");
+                        return ExpandResult::Ready(fragment_kind.dummy(span, guar));
+                    }
+                    let body = item.to_tokens();
+                    match expander.expand_derive(self.cx, span, &body) {
+                        Ok(tok_result) => {
+                            let fragment =
+                                self.parse_ast_fragment(tok_result, fragment_kind, &path, span);
+                            if macro_stats {
+                                update_derive_macro_stats(
+                                    self.cx,
+                                    fragment_kind,
+                                    span,
+                                    &path,
+                                    &fragment,
+                                );
+                            }
+                            fragment
+                        }
+                        Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
+                    }
+                }
                 _ => unreachable!(),
             },
             InvocationKind::GlobDelegation { item, of_trait } => {
@@ -1004,7 +1036,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             fn visit_item(&mut self, item: &'ast ast::Item) {
                 match &item.kind {
                     ItemKind::Mod(_, _, mod_kind)
-                        if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) =>
+                        if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
                     {
                         feature_err(
                             self.sess,
@@ -1315,7 +1347,7 @@ impl InvocationCollectorNode for Box<ast::Item> {
         let ItemKind::Mod(_, ident, ref mut mod_kind) = node.kind else { unreachable!() };
         let ecx = &mut collector.cx;
         let (file_path, dir_path, dir_ownership) = match mod_kind {
-            ModKind::Loaded(_, inline, _, _) => {
+            ModKind::Loaded(_, inline, _) => {
                 // Inline `mod foo { ... }`, but we still need to push directories.
                 let (dir_path, dir_ownership) = mod_dir_path(
                     ecx.sess,
@@ -1329,7 +1361,7 @@ impl InvocationCollectorNode for Box<ast::Item> {
                 // This lets `parse_external_mod` catch cycles if it's self-referential.
                 let file_path = match inline {
                     Inline::Yes => None,
-                    Inline::No => mod_file_path_from_attr(ecx.sess, &attrs, &dir_path),
+                    Inline::No { .. } => mod_file_path_from_attr(ecx.sess, &attrs, &dir_path),
                 };
                 node.attrs = attrs;
                 (file_path, dir_path, dir_ownership)
@@ -1365,7 +1397,7 @@ impl InvocationCollectorNode for Box<ast::Item> {
                     );
                 }
 
-                *mod_kind = ModKind::Loaded(items, Inline::No, spans, had_parse_error);
+                *mod_kind = ModKind::Loaded(items, Inline::No { had_parse_error }, spans);
                 node.attrs = attrs;
                 if node.attrs.len() > old_attrs_len {
                     // If we loaded an out-of-line module and added some inner attributes,
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 80433b7be91..f5edaf50edd 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -14,14 +14,22 @@ use super::macro_rules::{MacroRule, NoopTracker, parser_from_cx};
 use crate::expand::{AstFragmentKind, parse_ast_fragment};
 use crate::mbe::macro_parser::ParseResult::*;
 use crate::mbe::macro_parser::{MatcherLoc, NamedParseResult, TtParser};
-use crate::mbe::macro_rules::{Tracker, try_match_macro, try_match_macro_attr};
+use crate::mbe::macro_rules::{
+    Tracker, try_match_macro, try_match_macro_attr, try_match_macro_derive,
+};
+
+pub(super) enum FailedMacro<'a> {
+    Func,
+    Attr(&'a TokenStream),
+    Derive,
+}
 
 pub(super) fn failed_to_match_macro(
     psess: &ParseSess,
     sp: Span,
     def_span: Span,
     name: Ident,
-    attr_args: Option<&TokenStream>,
+    args: FailedMacro<'_>,
     body: &TokenStream,
     rules: &[MacroRule],
 ) -> (Span, ErrorGuaranteed) {
@@ -36,10 +44,12 @@ pub(super) fn failed_to_match_macro(
     // diagnostics.
     let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);
 
-    let try_success_result = if let Some(attr_args) = attr_args {
-        try_match_macro_attr(psess, name, attr_args, body, rules, &mut tracker)
-    } else {
-        try_match_macro(psess, name, body, rules, &mut tracker)
+    let try_success_result = match args {
+        FailedMacro::Func => try_match_macro(psess, name, body, rules, &mut tracker),
+        FailedMacro::Attr(attr_args) => {
+            try_match_macro_attr(psess, name, attr_args, body, rules, &mut tracker)
+        }
+        FailedMacro::Derive => try_match_macro_derive(psess, name, body, rules, &mut tracker),
     };
 
     if try_success_result.is_ok() {
@@ -90,7 +100,7 @@ pub(super) fn failed_to_match_macro(
     }
 
     // Check whether there's a missing comma in this macro call, like `println!("{}" a);`
-    if attr_args.is_none()
+    if let FailedMacro::Func = args
         && let Some((body, comma_span)) = body.add_comma()
     {
         for rule in rules {
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 334f57f9d62..8b43f852b26 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -27,10 +27,10 @@ use rustc_session::Session;
 use rustc_session::parse::{ParseSess, feature_err};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::Transparency;
-use rustc_span::{Ident, Span, kw, sym};
+use rustc_span::{Ident, Span, Symbol, kw, sym};
 use tracing::{debug, instrument, trace, trace_span};
 
-use super::diagnostics::failed_to_match_macro;
+use super::diagnostics::{FailedMacro, failed_to_match_macro};
 use super::macro_parser::{NamedMatches, NamedParseResult};
 use super::{SequenceRepetition, diagnostics};
 use crate::base::{
@@ -138,6 +138,8 @@ pub(super) enum MacroRule {
         body_span: Span,
         rhs: mbe::TokenTree,
     },
+    /// A derive rule, for use with `#[m]`
+    Derive { body: Vec<MatcherLoc>, body_span: Span, rhs: mbe::TokenTree },
 }
 
 pub struct MacroRulesMacroExpander {
@@ -157,6 +159,7 @@ impl MacroRulesMacroExpander {
             MacroRule::Attr { args_span, body_span, ref rhs, .. } => {
                 (MultiSpan::from_spans(vec![args_span, body_span]), rhs)
             }
+            MacroRule::Derive { body_span, ref rhs, .. } => (MultiSpan::from_span(body_span), rhs),
         };
         if has_compile_error_macro(rhs) { None } else { Some((&self.name, span)) }
     }
@@ -164,6 +167,63 @@ impl MacroRulesMacroExpander {
     pub fn kinds(&self) -> MacroKinds {
         self.kinds
     }
+
+    pub fn expand_derive(
+        &self,
+        cx: &mut ExtCtxt<'_>,
+        sp: Span,
+        body: &TokenStream,
+    ) -> Result<TokenStream, ErrorGuaranteed> {
+        // This is similar to `expand_macro`, but they have very different signatures, and will
+        // diverge further once derives support arguments.
+        let Self { name, ref rules, node_id, .. } = *self;
+        let psess = &cx.sess.psess;
+
+        if cx.trace_macros() {
+            let msg = format!("expanding `#[derive({name})] {}`", pprust::tts_to_string(body));
+            trace_macros_note(&mut cx.expansions, sp, msg);
+        }
+
+        match try_match_macro_derive(psess, name, body, rules, &mut NoopTracker) {
+            Ok((rule_index, rule, named_matches)) => {
+                let MacroRule::Derive { rhs, .. } = rule else {
+                    panic!("try_match_macro_derive returned non-derive rule");
+                };
+                let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else {
+                    cx.dcx().span_bug(sp, "malformed macro derive rhs");
+                };
+
+                let id = cx.current_expansion.id;
+                let tts = transcribe(psess, &named_matches, rhs, *rhs_span, self.transparency, id)
+                    .map_err(|e| e.emit())?;
+
+                if cx.trace_macros() {
+                    let msg = format!("to `{}`", pprust::tts_to_string(&tts));
+                    trace_macros_note(&mut cx.expansions, sp, msg);
+                }
+
+                if is_defined_in_current_crate(node_id) {
+                    cx.resolver.record_macro_rule_usage(node_id, rule_index);
+                }
+
+                Ok(tts)
+            }
+            Err(CanRetry::No(guar)) => Err(guar),
+            Err(CanRetry::Yes) => {
+                let (_, guar) = failed_to_match_macro(
+                    cx.psess(),
+                    sp,
+                    self.span,
+                    name,
+                    FailedMacro::Derive,
+                    body,
+                    rules,
+                );
+                cx.macro_error_and_trace_macros_diag();
+                Err(guar)
+            }
+        }
+    }
 }
 
 impl TTMacroExpander for MacroRulesMacroExpander {
@@ -325,8 +385,15 @@ fn expand_macro<'cx>(
         }
         Err(CanRetry::Yes) => {
             // Retry and emit a better error.
-            let (span, guar) =
-                failed_to_match_macro(cx.psess(), sp, def_span, name, None, &arg, rules);
+            let (span, guar) = failed_to_match_macro(
+                cx.psess(),
+                sp,
+                def_span,
+                name,
+                FailedMacro::Func,
+                &arg,
+                rules,
+            );
             cx.macro_error_and_trace_macros_diag();
             DummyResult::any(span, guar)
         }
@@ -388,8 +455,15 @@ fn expand_macro_attr(
         Err(CanRetry::No(guar)) => Err(guar),
         Err(CanRetry::Yes) => {
             // Retry and emit a better error.
-            let (_, guar) =
-                failed_to_match_macro(cx.psess(), sp, def_span, name, Some(&args), &body, rules);
+            let (_, guar) = failed_to_match_macro(
+                cx.psess(),
+                sp,
+                def_span,
+                name,
+                FailedMacro::Attr(&args),
+                &body,
+                rules,
+            );
             cx.trace_macros_diag();
             Err(guar)
         }
@@ -522,6 +596,7 @@ pub(super) fn try_match_macro_attr<'matcher, T: Tracker<'matcher>>(
         match result {
             Success(body_named_matches) => {
                 psess.gated_spans.merge(gated_spans_snapshot);
+                #[allow(rustc::potential_query_instability)]
                 named_matches.extend(body_named_matches);
                 return Ok((i, rule, named_matches));
             }
@@ -536,6 +611,44 @@ pub(super) fn try_match_macro_attr<'matcher, T: Tracker<'matcher>>(
     Err(CanRetry::Yes)
 }
 
+/// Try expanding the macro derive. Returns the index of the successful arm and its
+/// named_matches if it was successful, and nothing if it failed. On failure, it's the caller's job
+/// to use `track` accordingly to record all errors correctly.
+#[instrument(level = "debug", skip(psess, body, rules, track), fields(tracking = %T::description()))]
+pub(super) fn try_match_macro_derive<'matcher, T: Tracker<'matcher>>(
+    psess: &ParseSess,
+    name: Ident,
+    body: &TokenStream,
+    rules: &'matcher [MacroRule],
+    track: &mut T,
+) -> Result<(usize, &'matcher MacroRule, NamedMatches), CanRetry> {
+    // This uses the same strategy as `try_match_macro`
+    let body_parser = parser_from_cx(psess, body.clone(), T::recovery());
+    let mut tt_parser = TtParser::new(name);
+    for (i, rule) in rules.iter().enumerate() {
+        let MacroRule::Derive { body, .. } = rule else { continue };
+
+        let mut gated_spans_snapshot = mem::take(&mut *psess.gated_spans.spans.borrow_mut());
+
+        let result = tt_parser.parse_tt(&mut Cow::Borrowed(&body_parser), body, track);
+        track.after_arm(true, &result);
+
+        match result {
+            Success(named_matches) => {
+                psess.gated_spans.merge(gated_spans_snapshot);
+                return Ok((i, rule, named_matches));
+            }
+            Failure(_) => {
+                mem::swap(&mut gated_spans_snapshot, &mut psess.gated_spans.spans.borrow_mut())
+            }
+            Error(_, _) => return Err(CanRetry::Yes),
+            ErrorReported(guar) => return Err(CanRetry::No(guar)),
+        }
+    }
+
+    Err(CanRetry::Yes)
+}
+
 /// Converts a macro item into a syntax extension.
 pub fn compile_declarative_macro(
     sess: &Session,
@@ -569,7 +682,7 @@ pub fn compile_declarative_macro(
     let mut rules = Vec::new();
 
     while p.token != token::Eof {
-        let args = if p.eat_keyword_noexpect(sym::attr) {
+        let (args, is_derive) = if p.eat_keyword_noexpect(sym::attr) {
             kinds |= MacroKinds::ATTR;
             if !features.macro_attr() {
                 feature_err(sess, sym::macro_attr, span, "`macro_rules!` attributes are unstable")
@@ -579,16 +692,46 @@ pub fn compile_declarative_macro(
                 return dummy_syn_ext(guar);
             }
             let args = p.parse_token_tree();
-            check_args_parens(sess, &args);
+            check_args_parens(sess, sym::attr, &args);
             let args = parse_one_tt(args, RulePart::Pattern, sess, node_id, features, edition);
             check_emission(check_lhs(sess, node_id, &args));
             if let Some(guar) = check_no_eof(sess, &p, "expected macro attr body") {
                 return dummy_syn_ext(guar);
             }
-            Some(args)
+            (Some(args), false)
+        } else if p.eat_keyword_noexpect(sym::derive) {
+            kinds |= MacroKinds::DERIVE;
+            let derive_keyword_span = p.prev_token.span;
+            if !features.macro_derive() {
+                feature_err(sess, sym::macro_attr, span, "`macro_rules!` derives are unstable")
+                    .emit();
+            }
+            if let Some(guar) = check_no_eof(sess, &p, "expected `()` after `derive`") {
+                return dummy_syn_ext(guar);
+            }
+            let args = p.parse_token_tree();
+            check_args_parens(sess, sym::derive, &args);
+            let args_empty_result = check_args_empty(sess, &args);
+            let args_not_empty = args_empty_result.is_err();
+            check_emission(args_empty_result);
+            if let Some(guar) = check_no_eof(sess, &p, "expected macro derive body") {
+                return dummy_syn_ext(guar);
+            }
+            // If the user has `=>` right after the `()`, they might have forgotten the empty
+            // parentheses.
+            if p.token == token::FatArrow {
+                let mut err = sess
+                    .dcx()
+                    .struct_span_err(p.token.span, "expected macro derive body, got `=>`");
+                if args_not_empty {
+                    err.span_label(derive_keyword_span, "need `()` after this `derive`");
+                }
+                return dummy_syn_ext(err.emit());
+            }
+            (None, true)
         } else {
             kinds |= MacroKinds::BANG;
-            None
+            (None, false)
         };
         let lhs_tt = p.parse_token_tree();
         let lhs_tt = parse_one_tt(lhs_tt, RulePart::Pattern, sess, node_id, features, edition);
@@ -619,6 +762,8 @@ pub fn compile_declarative_macro(
             let args = mbe::macro_parser::compute_locs(&delimited.tts);
             let body_span = lhs_span;
             rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs: rhs_tt });
+        } else if is_derive {
+            rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs: rhs_tt });
         } else {
             rules.push(MacroRule::Func { lhs, lhs_span, rhs: rhs_tt });
         }
@@ -665,7 +810,7 @@ fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option<Err
     None
 }
 
-fn check_args_parens(sess: &Session, args: &tokenstream::TokenTree) {
+fn check_args_parens(sess: &Session, rule_kw: Symbol, args: &tokenstream::TokenTree) {
     // This does not handle the non-delimited case; that gets handled separately by `check_lhs`.
     if let tokenstream::TokenTree::Delimited(dspan, _, delim, _) = args
         && *delim != Delimiter::Parenthesis
@@ -673,10 +818,21 @@ fn check_args_parens(sess: &Session, args: &tokenstream::TokenTree) {
         sess.dcx().emit_err(errors::MacroArgsBadDelim {
             span: dspan.entire(),
             sugg: errors::MacroArgsBadDelimSugg { open: dspan.open, close: dspan.close },
+            rule_kw,
         });
     }
 }
 
+fn check_args_empty(sess: &Session, args: &tokenstream::TokenTree) -> Result<(), ErrorGuaranteed> {
+    match args {
+        tokenstream::TokenTree::Delimited(.., delimited) if delimited.is_empty() => Ok(()),
+        _ => {
+            let msg = "`derive` rules do not accept arguments; `derive` must be followed by `()`";
+            Err(sess.dcx().span_err(args.span(), msg))
+        }
+    }
+}
+
 fn check_lhs(sess: &Session, node_id: NodeId, lhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed> {
     let e1 = check_lhs_nt_follows(sess, node_id, lhs);
     let e2 = check_lhs_no_empty_seq(sess, slice::from_ref(lhs));
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index 662c67f2d3f..6666ea33cd3 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -120,7 +120,7 @@ pub(crate) fn mod_dir_path(
 
             (dir_path, dir_ownership)
         }
-        Inline::No => {
+        Inline::No { .. } => {
             // FIXME: This is a subset of `parse_external_mod` without actual parsing,
             // check whether the logic for unloaded, loaded and inline modules can be unified.
             let file_path = mod_file_path(sess, ident, attrs, &module.dir_path, dir_ownership)
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 6fbedaf5b10..8f632bcebc7 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -6,6 +6,7 @@ use AttributeDuplicates::*;
 use AttributeGate::*;
 use AttributeType::*;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::AttrStyle;
 use rustc_hir::attrs::EncodeCrossCrate;
 use rustc_span::edition::Edition;
 use rustc_span::{Symbol, sym};
@@ -132,9 +133,12 @@ pub struct AttributeTemplate {
 }
 
 impl AttributeTemplate {
-    pub fn suggestions(&self, inner: bool, name: impl std::fmt::Display) -> Vec<String> {
+    pub fn suggestions(&self, style: AttrStyle, name: impl std::fmt::Display) -> Vec<String> {
         let mut suggestions = vec![];
-        let inner = if inner { "!" } else { "" };
+        let inner = match style {
+            AttrStyle::Outer => "",
+            AttrStyle::Inner => "!",
+        };
         if self.word {
             suggestions.push(format!("#{inner}[{name}]"));
         }
@@ -741,9 +745,8 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         ErrorPreceding, EncodeCrossCrate::No
     ),
     gated!(
-        no_sanitize, Normal,
-        template!(List: &["address, kcfi, memory, thread"]), DuplicatesOk,
-        EncodeCrossCrate::No, experimental!(no_sanitize)
+        sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding,
+        EncodeCrossCrate::No, sanitize, experimental!(sanitize),
     ),
     gated!(
         coverage, Normal, template!(OneOf: &[sym::off, sym::on]),
@@ -993,6 +996,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing,
         EncodeCrossCrate::No,
     ),
+    rustc_attr!(
+        rustc_allocator_zeroed_variant, Normal, template!(NameValueStr: "function"), ErrorPreceding,
+        EncodeCrossCrate::Yes,
+    ),
     gated!(
         default_lib_allocator, Normal, template!(Word), WarnFollowing,
         EncodeCrossCrate::No, allocator_internals, experimental!(default_lib_allocator),
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 04f261ada06..e37fc6b7bfc 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -190,6 +190,9 @@ declare_features! (
     (removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`"), 114656),
     /// Allows `#[no_debug]`.
     (removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand"), 69667),
+    // Allows the use of `no_sanitize` attribute.
+    /// The feature was renamed to `sanitize` and the attribute to `#[sanitize(xyz = "on|off")]`
+    (removed, no_sanitize, "CURRENT_RUSTC_VERSION", Some(39699), Some(r#"renamed to sanitize(xyz = "on|off")"#), 142681),
     /// Note: this feature was previously recorded in a separate
     /// `STABLE_REMOVED` list because it, uniquely, was once stable but was
     /// then removed. But there was no utility storing it separately, so now
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 07f928b8c88..746871982ce 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -556,6 +556,8 @@ declare_features! (
     (incomplete, loop_match, "1.90.0", Some(132306)),
     /// Allow `macro_rules!` attribute rules
     (unstable, macro_attr, "CURRENT_RUSTC_VERSION", Some(83527)),
+    /// Allow `macro_rules!` derive rules
+    (unstable, macro_derive, "CURRENT_RUSTC_VERSION", Some(143549)),
     /// Give access to additional metadata about declarative macro meta-variables.
     (unstable, macro_metavar_expr, "1.61.0", Some(83527)),
     /// Provides a way to concatenate identifiers using metavariable expressions.
@@ -592,8 +594,6 @@ declare_features! (
     (unstable, new_range, "1.86.0", Some(123741)),
     /// Allows `#![no_core]`.
     (unstable, no_core, "1.3.0", Some(29639)),
-    /// Allows the use of `no_sanitize` attribute.
-    (unstable, no_sanitize, "1.42.0", Some(39699)),
     /// Allows using the `non_exhaustive_omitted_patterns` lint.
     (unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)),
     /// Allows `for<T>` binders in where-clauses
@@ -626,6 +626,8 @@ declare_features! (
     (unstable, return_type_notation, "1.70.0", Some(109417)),
     /// Allows `extern "rust-cold"`.
     (unstable, rust_cold_cc, "1.63.0", Some(97544)),
+    /// Allows the use of the `sanitize` attribute.
+    (unstable, sanitize, "CURRENT_RUSTC_VERSION", Some(39699)),
     /// Allows the use of SIMD types in functions declared in `extern` blocks.
     (unstable, simd_ffi, "1.0.0", Some(27731)),
     /// Allows specialization of implementations (RFC 1210).
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index 71496b7ec32..1008a3e787d 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -12,7 +12,9 @@ rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_error_messages = { path = "../rustc_error_messages" }
 rustc_hashes = { path = "../rustc_hashes" }
+rustc_hir_id = { path = "../rustc_hir_id" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index 510fc832978..a17350f0392 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -1,7 +1,11 @@
+use std::borrow::Cow;
+use std::path::PathBuf;
+
 pub use ReprAttr::*;
 use rustc_abi::Align;
 use rustc_ast::token::CommentKind;
 use rustc_ast::{AttrStyle, ast};
+use rustc_error_messages::{DiagArgValue, IntoDiagArg};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
 use rustc_span::def_id::DefId;
 use rustc_span::hygiene::Transparency;
@@ -205,6 +209,44 @@ pub enum Linkage {
     WeakODR,
 }
 
+#[derive(Clone, Copy, Decodable, Debug, Encodable, PartialEq)]
+#[derive(HashStable_Generic, PrintAttribute)]
+pub enum MirDialect {
+    Analysis,
+    Built,
+    Runtime,
+}
+
+impl IntoDiagArg for MirDialect {
+    fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> DiagArgValue {
+        let arg = match self {
+            MirDialect::Analysis => "analysis",
+            MirDialect::Built => "built",
+            MirDialect::Runtime => "runtime",
+        };
+        DiagArgValue::Str(Cow::Borrowed(arg))
+    }
+}
+
+#[derive(Clone, Copy, Decodable, Debug, Encodable, PartialEq)]
+#[derive(HashStable_Generic, PrintAttribute)]
+pub enum MirPhase {
+    Initial,
+    PostCleanup,
+    Optimized,
+}
+
+impl IntoDiagArg for MirPhase {
+    fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> DiagArgValue {
+        let arg = match self {
+            MirPhase::Initial => "initial",
+            MirPhase::PostCleanup => "post-cleanup",
+            MirPhase::Optimized => "optimized",
+        };
+        DiagArgValue::Str(Cow::Borrowed(arg))
+    }
+}
+
 /// Represents parsed *built-in* inert attributes.
 ///
 /// ## Overview
@@ -324,6 +366,9 @@ pub enum AttributeKind {
     /// Represents `#[coverage(..)]`.
     Coverage(Span, CoverageAttrKind),
 
+    /// Represents `#[custom_mir]`.
+    CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
+
     ///Represents `#[rustc_deny_explicit_impl]`.
     DenyExplicitImpl(Span),
 
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 84a975523f2..defabdccc02 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -31,6 +31,7 @@ impl AttributeKind {
             ConstTrait(..) => No,
             Coroutine(..) => No,
             Coverage(..) => No,
+            CustomMir(_, _, _) => Yes,
             DenyExplicitImpl(..) => No,
             Deprecation { .. } => Yes,
             DoNotImplementViaObject(..) => No,
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 79319e24266..8af4740f376 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -1,10 +1,12 @@
 use std::array::IntoIter;
+use std::borrow::Cow;
 use std::fmt::Debug;
 
 use rustc_ast as ast;
 use rustc_ast::NodeId;
 use rustc_data_structures::stable_hasher::ToStableHashKey;
 use rustc_data_structures::unord::UnordMap;
+use rustc_error_messages::{DiagArgValue, IntoDiagArg};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::Symbol;
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -586,6 +588,12 @@ pub enum Res<Id = hir::HirId> {
     Err,
 }
 
+impl<Id> IntoDiagArg for Res<Id> {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Borrowed(self.descr()))
+    }
+}
+
 /// The result of resolving a path before lowering to HIR,
 /// with "module" segments resolved and associated item
 /// segments deferred to type checking.
@@ -673,6 +681,12 @@ impl Namespace {
     }
 }
 
+impl IntoDiagArg for Namespace {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Borrowed(self.descr()))
+    }
+}
+
 impl<CTX: crate::HashStableContext> ToStableHashKey<CTX> for Namespace {
     type KeyType = Namespace;
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 2c8986b7c7d..39696f74d51 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,4 +1,5 @@
 // ignore-tidy-filelength
+use std::borrow::Cow;
 use std::fmt;
 
 use rustc_abi::ExternAbi;
@@ -17,6 +18,7 @@ pub use rustc_ast::{
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::tagged_ptr::TaggedRef;
+use rustc_error_messages::{DiagArgValue, IntoDiagArg};
 use rustc_index::IndexVec;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::def_id::LocalDefId;
@@ -2259,8 +2261,15 @@ impl fmt::Display for ConstContext {
     }
 }
 
-// NOTE: `IntoDiagArg` impl for `ConstContext` lives in `rustc_errors`
-// due to a cyclical dependency between hir and that crate.
+impl IntoDiagArg for ConstContext {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Borrowed(match self {
+            ConstContext::ConstFn => "const_fn",
+            ConstContext::Static(_) => "static",
+            ConstContext::Const { .. } => "const",
+        }))
+    }
+}
 
 /// A literal.
 pub type Lit = Spanned<LitKind>;
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index f1212d07ff6..78fc63753a2 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -3,14 +3,11 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
 // tidy-alphabetical-start
-#![allow(internal_features)]
 #![feature(associated_type_defaults)]
 #![feature(closure_track_caller)]
 #![feature(debug_closure_helpers)]
 #![feature(exhaustive_patterns)]
-#![feature(negative_impls)]
 #![feature(never_type)]
-#![feature(rustc_attrs)]
 #![feature(variant_count)]
 #![recursion_limit = "256"]
 // tidy-alphabetical-end
@@ -25,7 +22,7 @@ pub mod definitions;
 pub mod diagnostic_items;
 pub use rustc_span::def_id;
 mod hir;
-pub mod hir_id;
+pub use rustc_hir_id::{self as hir_id, *};
 pub mod intravisit;
 pub mod lang_items;
 pub mod lints;
@@ -41,7 +38,6 @@ mod tests;
 
 #[doc(no_inline)]
 pub use hir::*;
-pub use hir_id::*;
 pub use lang_items::{LangItem, LanguageItems};
 pub use stability::*;
 pub use stable_hash_impls::HashStableContext;
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index ecc608d437b..16e8bac3d8a 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -5,7 +5,7 @@ use crate::HashIgnoredAttrId;
 use crate::hir::{
     AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
 };
-use crate::hir_id::{HirId, ItemLocalId};
+use crate::hir_id::ItemLocalId;
 use crate::lints::DelayedLints;
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
@@ -15,25 +15,6 @@ pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStabl
     fn hash_attr_id(&mut self, id: &HashIgnoredAttrId, hasher: &mut StableHasher);
 }
 
-impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
-    type KeyType = (DefPathHash, ItemLocalId);
-
-    #[inline]
-    fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
-        let def_path_hash = self.owner.def_id.to_stable_hash_key(hcx);
-        (def_path_hash, self.local_id)
-    }
-}
-
-impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemLocalId {
-    type KeyType = ItemLocalId;
-
-    #[inline]
-    fn to_stable_hash_key(&self, _: &HirCtx) -> ItemLocalId {
-        *self
-    }
-}
-
 impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for BodyId {
     type KeyType = (DefPathHash, ItemLocalId);
 
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index f68dad3a5e8..dcac51b10b4 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -79,6 +79,8 @@ impl Display for Target {
     }
 }
 
+rustc_error_messages::into_diag_arg_using_display!(Target);
+
 impl Target {
     pub fn is_associated_item(self) -> bool {
         match self {
diff --git a/compiler/rustc_hir/src/version.rs b/compiler/rustc_hir/src/version.rs
index ab5ab026b4c..bc2c38a4935 100644
--- a/compiler/rustc_hir/src/version.rs
+++ b/compiler/rustc_hir/src/version.rs
@@ -1,6 +1,8 @@
+use std::borrow::Cow;
 use std::fmt::{self, Display};
 use std::sync::OnceLock;
 
+use rustc_error_messages::{DiagArgValue, IntoDiagArg};
 use rustc_macros::{
     Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version,
 };
@@ -45,3 +47,9 @@ impl Display for RustcVersion {
         write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
     }
 }
+
+impl IntoDiagArg for RustcVersion {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index f50aed0b3c2..cfc6bc2f3a0 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -136,6 +136,10 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
         | sym::round_ties_even_f64
         | sym::round_ties_even_f128
         | sym::autodiff
+        | sym::prefetch_read_data
+        | sym::prefetch_write_data
+        | sym::prefetch_read_instruction
+        | sym::prefetch_write_instruction
         | sym::const_eval_select => hir::Safety::Safe,
         _ => hir::Safety::Unsafe,
     };
@@ -218,7 +222,7 @@ pub(crate) fn check_intrinsic_type(
         | sym::prefetch_write_data
         | sym::prefetch_read_instruction
         | sym::prefetch_write_instruction => {
-            (1, 0, vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.i32], tcx.types.unit)
+            (1, 1, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.unit)
         }
         sym::needs_drop => (1, 0, vec![], tcx.types.bool),
 
diff --git a/compiler/rustc_hir_id/Cargo.toml b/compiler/rustc_hir_id/Cargo.toml
new file mode 100644
index 00000000000..c357a4f62d9
--- /dev/null
+++ b/compiler/rustc_hir_id/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "rustc_hir_id"
+version = "0.0.0"
+edition = "2024"
+
+[dependencies]
+# tidy-alphabetical-start
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_index = { path = "../rustc_index" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_serialize = { path = "../rustc_serialize" }
+rustc_span = { path = "../rustc_span" }
+# tidy-alphabetical-end
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir_id/src/lib.rs
index b48a081d371..d07bc88e66a 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir_id/src/lib.rs
@@ -1,11 +1,15 @@
+//! Library containing Id types from `rustc_hir`, split out so crates can use it without depending
+//! on all of `rustc_hir` (which is large and depends on other large things like `rustc_target`).
+#![allow(internal_features)]
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+
 use std::fmt::{self, Debug};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
-use rustc_span::HashStableContext;
-use rustc_span::def_id::DefPathHash;
-
-use crate::def_id::{CRATE_DEF_ID, DefId, DefIndex, LocalDefId};
+pub use rustc_span::HashStableContext;
+use rustc_span::def_id::{CRATE_DEF_ID, DefId, DefIndex, DefPathHash, LocalDefId};
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
 pub struct OwnerId {
@@ -171,3 +175,22 @@ pub const CRATE_HIR_ID: HirId =
     HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::ZERO };
 
 pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID };
+
+impl<CTX: rustc_span::HashStableContext> ToStableHashKey<CTX> for HirId {
+    type KeyType = (DefPathHash, ItemLocalId);
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &CTX) -> (DefPathHash, ItemLocalId) {
+        let def_path_hash = self.owner.def_id.to_stable_hash_key(hcx);
+        (def_path_hash, self.local_id)
+    }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for ItemLocalId {
+    type KeyType = ItemLocalId;
+
+    #[inline]
+    fn to_stable_hash_key(&self, _: &CTX) -> ItemLocalId {
+        *self
+    }
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 0498a938366..940f0e3708d 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -290,6 +290,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | ExprKind::Let(..)
             | ExprKind::Loop(..)
             | ExprKind::Match(..) => {}
+            // Do not warn on `as` casts from never to any,
+            // they are sometimes required to appeal typeck.
+            ExprKind::Cast(_, _) => {}
             // If `expr` is a result of desugaring the try block and is an ok-wrapped
             // diverging expression (e.g. it arose from desugaring of `try { return }`),
             // we skip issuing a warning because it is autogenerated code.
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 82d4856df39..9ff06bda89b 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -782,22 +782,30 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner.borrow_mut().type_variables().num_vars()
     }
 
-    pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> {
-        self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None })
+    pub fn next_ty_vid(&self, span: Span) -> TyVid {
+        self.next_ty_vid_with_origin(TypeVariableOrigin { span, param_def_id: None })
     }
 
-    pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin);
-        Ty::new_var(self.tcx, vid)
+    pub fn next_ty_vid_with_origin(&self, origin: TypeVariableOrigin) -> TyVid {
+        self.inner.borrow_mut().type_variables().new_var(self.universe(), origin)
     }
 
-    pub fn next_ty_var_id_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid {
+    pub fn next_ty_vid_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid {
         let origin = TypeVariableOrigin { span, param_def_id: None };
         self.inner.borrow_mut().type_variables().new_var(universe, origin)
     }
 
+    pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> {
+        self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None })
+    }
+
+    pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
+        let vid = self.next_ty_vid_with_origin(origin);
+        Ty::new_var(self.tcx, vid)
+    }
+
     pub fn next_ty_var_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> Ty<'tcx> {
-        let vid = self.next_ty_var_id_in_universe(span, universe);
+        let vid = self.next_ty_vid_in_universe(span, universe);
         Ty::new_var(self.tcx, vid)
     }
 
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index c46e879b976..8f131f45bbd 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -285,7 +285,9 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
                     .expecteds
                     .entry(name.name)
                     .and_modify(|v| match v {
-                        ExpectedValues::Some(v) if !values_any_specified => {
+                        ExpectedValues::Some(v) if !values_any_specified =>
+                        {
+                            #[allow(rustc::potential_query_instability)]
                             v.extend(values.clone())
                         }
                         ExpectedValues::Some(_) => *v = ExpectedValues::Any,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 0a764808f95..4425877308a 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -807,6 +807,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(hint_mostly_unused, true);
     tracked!(human_readable_cgu_names, true);
     tracked!(incremental_ignore_spans, true);
+    tracked!(indirect_branch_cs_prefix, true);
     tracked!(inline_mir, Some(true));
     tracked!(inline_mir_hint_threshold, Some(123));
     tracked!(inline_mir_threshold, Some(123));
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index c485e6fc849..f26e5f05e1a 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -732,7 +732,7 @@ lint_pattern_in_foreign = patterns aren't allowed in foreign function declaratio
 lint_private_extern_crate_reexport = extern crate `{$ident}` is private and cannot be re-exported
     .suggestion = consider making the `extern crate` item publicly accessible
 
-lint_proc_macro_derive_resolution_fallback = cannot find {$ns} `{$ident}` in this scope
+lint_proc_macro_derive_resolution_fallback = cannot find {$ns_descr} `{$ident}` in this scope
     .label = names from parent modules are not accessible without an explicit import
 
 lint_query_instability = using `{$query}` can result in unstable query results
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 8006cfcf30f..c3c0a34df71 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -3097,7 +3097,7 @@ impl EarlyLintPass for SpecialModuleName {
             if let ast::ItemKind::Mod(
                 _,
                 ident,
-                ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _, _),
+                ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No { .. }, _),
             ) = item.kind
             {
                 if item.attrs.iter().any(|a| a.has_name(sym::path)) {
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index cb159a0b914..e9bd9dccdf1 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -24,7 +24,7 @@ use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
 use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
 use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintBuffer, LintExpectationId, LintId};
-use rustc_session::{LintStoreMarker, Session};
+use rustc_session::{DynLintStore, Session};
 use rustc_span::edit_distance::find_best_match_for_names;
 use rustc_span::{Ident, Span, Symbol, sym};
 use tracing::debug;
@@ -62,7 +62,13 @@ pub struct LintStore {
     lint_groups: FxIndexMap<&'static str, LintGroup>,
 }
 
-impl LintStoreMarker for LintStore {}
+impl DynLintStore for LintStore {
+    fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
+        Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
+            rustc_session::LintGroup { name, lints, is_externally_loaded }
+        }))
+    }
+}
 
 /// The target of the `by_name` map, which accounts for renaming/deprecation.
 #[derive(Debug)]
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index 678d3d1f8ed..0e283ed923a 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -64,10 +64,12 @@ pub fn decorate_builtin_lint(
             }
             .decorate_lint(diag);
         }
-        BuiltinLintDiag::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident } => {
-            lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident }
-                .decorate_lint(diag)
-        }
+        BuiltinLintDiag::ProcMacroDeriveResolutionFallback {
+            span: macro_span,
+            ns_descr,
+            ident,
+        } => lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns_descr, ident }
+            .decorate_lint(diag),
         BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => {
             lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def }
                 .decorate_lint(diag)
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index 759e6c927b8..3267e70f1de 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -179,7 +179,7 @@ impl ClashingExternDeclarations {
 /// symbol's name.
 fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName {
     if let Some((overridden_link_name, overridden_link_name_span)) =
-        tcx.codegen_fn_attrs(fi).link_name.map(|overridden_link_name| {
+        tcx.codegen_fn_attrs(fi).symbol_name.map(|overridden_link_name| {
             // FIXME: Instead of searching through the attributes again to get span
             // information, we could have codegen_fn_attrs also give span information back for
             // where the attribute was defined. However, until this is found to be a
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 016ff17f5d7..e1fbe39222b 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -1,10 +1,10 @@
 //! Some lints that are only useful in the compiler or crates that use compiler internals, such as
 //! Clippy.
 
-use rustc_hir::HirId;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
+use rustc_hir::{Expr, ExprKind, HirId};
+use rustc_middle::ty::{self, ClauseKind, GenericArgsRef, PredicatePolarity, TraitPredicate, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::{Span, sym};
@@ -56,25 +56,6 @@ impl LateLintPass<'_> for DefaultHashTypes {
     }
 }
 
-/// Helper function for lints that check for expressions with calls and use typeck results to
-/// get the `DefId` and `GenericArgsRef` of the function.
-fn typeck_results_of_method_fn<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &hir::Expr<'_>,
-) -> Option<(Span, DefId, ty::GenericArgsRef<'tcx>)> {
-    match expr.kind {
-        hir::ExprKind::MethodCall(segment, ..)
-            if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
-        {
-            Some((segment.ident.span, def_id, cx.typeck_results().node_args(expr.hir_id)))
-        }
-        _ => match cx.typeck_results().node_type(expr.hir_id).kind() {
-            &ty::FnDef(def_id, args) => Some((expr.span, def_id, args)),
-            _ => None,
-        },
-    }
-}
-
 declare_tool_lint! {
     /// The `potential_query_instability` lint detects use of methods which can lead to
     /// potential query instability, such as iterating over a `HashMap`.
@@ -101,10 +82,12 @@ declare_tool_lint! {
 
 declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]);
 
-impl LateLintPass<'_> for QueryStability {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
-        let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return };
-        if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, args)
+impl<'tcx> LateLintPass<'tcx> for QueryStability {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let Some((callee_def_id, span, generic_args, _recv, _args)) =
+            get_callee_span_generic_args_and_args(cx, expr)
+            && let Ok(Some(instance)) =
+                ty::Instance::try_resolve(cx.tcx, cx.typing_env(), callee_def_id, generic_args)
         {
             let def_id = instance.def_id();
             if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
@@ -113,7 +96,15 @@ impl LateLintPass<'_> for QueryStability {
                     span,
                     QueryInstability { query: cx.tcx.item_name(def_id) },
                 );
+            } else if has_unstable_into_iter_predicate(cx, callee_def_id, generic_args) {
+                let call_span = span.with_hi(expr.span.hi());
+                cx.emit_span_lint(
+                    POTENTIAL_QUERY_INSTABILITY,
+                    call_span,
+                    QueryInstability { query: sym::into_iter },
+                );
             }
+
             if cx.tcx.has_attr(def_id, sym::rustc_lint_untracked_query_information) {
                 cx.emit_span_lint(
                     UNTRACKED_QUERY_INFORMATION,
@@ -125,6 +116,64 @@ impl LateLintPass<'_> for QueryStability {
     }
 }
 
+fn has_unstable_into_iter_predicate<'tcx>(
+    cx: &LateContext<'tcx>,
+    callee_def_id: DefId,
+    generic_args: GenericArgsRef<'tcx>,
+) -> bool {
+    let Some(into_iterator_def_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) else {
+        return false;
+    };
+    let Some(into_iter_fn_def_id) = cx.tcx.lang_items().into_iter_fn() else {
+        return false;
+    };
+    let predicates = cx.tcx.predicates_of(callee_def_id).instantiate(cx.tcx, generic_args);
+    for (predicate, _) in predicates {
+        let ClauseKind::Trait(TraitPredicate { trait_ref, polarity: PredicatePolarity::Positive }) =
+            predicate.kind().skip_binder()
+        else {
+            continue;
+        };
+        // Does the function or method require any of its arguments to implement `IntoIterator`?
+        if trait_ref.def_id != into_iterator_def_id {
+            continue;
+        }
+        let Ok(Some(instance)) =
+            ty::Instance::try_resolve(cx.tcx, cx.typing_env(), into_iter_fn_def_id, trait_ref.args)
+        else {
+            continue;
+        };
+        // Does the input type's `IntoIterator` implementation have the
+        // `rustc_lint_query_instability` attribute on its `into_iter` method?
+        if cx.tcx.has_attr(instance.def_id(), sym::rustc_lint_query_instability) {
+            return true;
+        }
+    }
+    false
+}
+
+/// Checks whether an expression is a function or method call and, if so, returns its `DefId`,
+/// `Span`, `GenericArgs`, and arguments. This is a slight augmentation of a similarly named Clippy
+/// function, `get_callee_generic_args_and_args`.
+fn get_callee_span_generic_args_and_args<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+) -> Option<(DefId, Span, GenericArgsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
+    if let ExprKind::Call(callee, args) = expr.kind
+        && let callee_ty = cx.typeck_results().expr_ty(callee)
+        && let ty::FnDef(callee_def_id, generic_args) = callee_ty.kind()
+    {
+        return Some((*callee_def_id, callee.span, generic_args, None, args));
+    }
+    if let ExprKind::MethodCall(segment, recv, args, _) = expr.kind
+        && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+    {
+        let generic_args = cx.typeck_results().node_args(expr.hir_id);
+        return Some((method_def_id, segment.ident.span, generic_args, Some(recv), args));
+    }
+    None
+}
+
 declare_tool_lint! {
     /// The `usage_of_ty_tykind` lint detects usages of `ty::TyKind::<kind>`,
     /// where `ty::<kind>` would suffice.
@@ -461,33 +510,22 @@ declare_tool_lint! {
 declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]);
 
 impl LateLintPass<'_> for Diagnostics {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
+    fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
         let collect_args_tys_and_spans = |args: &[hir::Expr<'_>], reserve_one_extra: bool| {
             let mut result = Vec::with_capacity(args.len() + usize::from(reserve_one_extra));
             result.extend(args.iter().map(|arg| (cx.typeck_results().expr_ty(arg), arg.span)));
             result
         };
         // Only check function calls and method calls.
-        let (span, def_id, fn_gen_args, arg_tys_and_spans) = match expr.kind {
-            hir::ExprKind::Call(callee, args) => {
-                match cx.typeck_results().node_type(callee.hir_id).kind() {
-                    &ty::FnDef(def_id, fn_gen_args) => {
-                        (callee.span, def_id, fn_gen_args, collect_args_tys_and_spans(args, false))
-                    }
-                    _ => return, // occurs for fns passed as args
-                }
-            }
-            hir::ExprKind::MethodCall(_segment, _recv, args, _span) => {
-                let Some((span, def_id, fn_gen_args)) = typeck_results_of_method_fn(cx, expr)
-                else {
-                    return;
-                };
-                let mut args = collect_args_tys_and_spans(args, true);
-                args.insert(0, (cx.tcx.types.self_param, _recv.span)); // dummy inserted for `self`
-                (span, def_id, fn_gen_args, args)
-            }
-            _ => return,
+        let Some((def_id, span, fn_gen_args, recv, args)) =
+            get_callee_span_generic_args_and_args(cx, expr)
+        else {
+            return;
         };
+        let mut arg_tys_and_spans = collect_args_tys_and_spans(args, recv.is_some());
+        if let Some(recv) = recv {
+            arg_tys_and_spans.insert(0, (cx.tcx.types.self_param, recv.span)); // dummy inserted for `self`
+        }
 
         Self::diagnostic_outside_of_impl(cx, span, expr.hir_id, def_id, fn_gen_args);
         Self::untranslatable_diagnostic(cx, def_id, &arg_tys_and_spans);
@@ -496,7 +534,7 @@ impl LateLintPass<'_> for Diagnostics {
 
 impl Diagnostics {
     // Is the type `{D,Subd}iagMessage`?
-    fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: MiddleTy<'cx>) -> bool {
+    fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: Ty<'cx>) -> bool {
         if let Some(adt_def) = ty.ty_adt_def()
             && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
             && matches!(name, sym::DiagMessage | sym::SubdiagMessage)
@@ -510,7 +548,7 @@ impl Diagnostics {
     fn untranslatable_diagnostic<'cx>(
         cx: &LateContext<'cx>,
         def_id: DefId,
-        arg_tys_and_spans: &[(MiddleTy<'cx>, Span)],
+        arg_tys_and_spans: &[(Ty<'cx>, Span)],
     ) {
         let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
         let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates;
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index a6d59af6900..a1e26bf1503 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -8,7 +8,6 @@ use rustc_errors::{
     EmissionGuarantee, LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle,
 };
 use rustc_hir as hir;
-use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::VisitorExt;
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
@@ -2769,7 +2768,7 @@ pub(crate) struct AbsPathWithModuleSugg {
 pub(crate) struct ProcMacroDeriveResolutionFallback {
     #[label]
     pub span: Span,
-    pub ns: Namespace,
+    pub ns_descr: &'static str,
     pub ident: Ident,
 }
 
diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml
index 9ab350daf69..152eb4fb380 100644
--- a/compiler/rustc_lint_defs/Cargo.toml
+++ b/compiler/rustc_lint_defs/Cargo.toml
@@ -9,7 +9,7 @@ rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_messages = { path = "../rustc_error_messages" }
-rustc_hir = { path = "../rustc_hir" }
+rustc_hir_id = { path = "../rustc_hir_id" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a0083a7df3d..97aa1065967 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2301,18 +2301,18 @@ declare_lint! {
 
 declare_lint! {
     /// The `inline_no_sanitize` lint detects incompatible use of
-    /// [`#[inline(always)]`][inline] and [`#[no_sanitize(...)]`][no_sanitize].
+    /// [`#[inline(always)]`][inline] and [`#[sanitize(xyz = "off")]`][sanitize].
     ///
     /// [inline]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute
-    /// [no_sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html
+    /// [sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html
     ///
     /// ### Example
     ///
     /// ```rust
-    /// #![feature(no_sanitize)]
+    /// #![feature(sanitize)]
     ///
     /// #[inline(always)]
-    /// #[no_sanitize(address)]
+    /// #[sanitize(address = "off")]
     /// fn x() {}
     ///
     /// fn main() {
@@ -2325,11 +2325,11 @@ declare_lint! {
     /// ### Explanation
     ///
     /// The use of the [`#[inline(always)]`][inline] attribute prevents the
-    /// the [`#[no_sanitize(...)]`][no_sanitize] attribute from working.
+    /// the [`#[sanitize(xyz = "off")]`][sanitize] attribute from working.
     /// Consider temporarily removing `inline` attribute.
     pub INLINE_NO_SANITIZE,
     Warn,
-    "detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`",
+    r#"detects incompatible use of `#[inline(always)]` and `#[sanitize(... = "off")]`"#,
 }
 
 declare_lint! {
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 3bb7bbce567..d1f5cc21277 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
 use rustc_abi::ExternAbi;
 use rustc_ast::AttrId;
 use rustc_ast::attr::AttributeExt;
@@ -6,11 +8,10 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::stable_hasher::{
     HashStable, StableCompare, StableHasher, ToStableHashKey,
 };
-use rustc_error_messages::{DiagMessage, MultiSpan};
-use rustc_hir::def::Namespace;
-use rustc_hir::def_id::DefPathHash;
-use rustc_hir::{HashStableContext, HirId, ItemLocalId};
+use rustc_error_messages::{DiagArgValue, DiagMessage, IntoDiagArg, MultiSpan};
+use rustc_hir_id::{HashStableContext, HirId, ItemLocalId};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
+use rustc_span::def_id::DefPathHash;
 pub use rustc_span::edition::Edition;
 use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym};
 use serde::{Deserialize, Serialize};
@@ -138,7 +139,7 @@ impl LintExpectationId {
     }
 }
 
-impl<HCX: rustc_hir::HashStableContext> HashStable<HCX> for LintExpectationId {
+impl<HCX: HashStableContext> HashStable<HCX> for LintExpectationId {
     #[inline]
     fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
         match self {
@@ -156,7 +157,7 @@ impl<HCX: rustc_hir::HashStableContext> HashStable<HCX> for LintExpectationId {
     }
 }
 
-impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectationId {
+impl<HCX: HashStableContext> ToStableHashKey<HCX> for LintExpectationId {
     type KeyType = (DefPathHash, ItemLocalId, u16, u16);
 
     #[inline]
@@ -297,6 +298,12 @@ impl Level {
     }
 }
 
+impl IntoDiagArg for Level {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Borrowed(self.to_cmd_flag()))
+    }
+}
+
 /// Specification of a single lint.
 #[derive(Copy, Clone, Debug)]
 pub struct Lint {
@@ -617,7 +624,7 @@ pub enum BuiltinLintDiag {
     AbsPathWithModule(Span),
     ProcMacroDeriveResolutionFallback {
         span: Span,
-        ns: Namespace,
+        ns_descr: &'static str,
         ident: Ident,
     },
     MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 1394edcee6b..d01f79dcade 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -226,7 +226,6 @@ fn main() {
     rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper"));
     cfg.file("llvm-wrapper/PassWrapper.cpp")
         .file("llvm-wrapper/RustWrapper.cpp")
-        .file("llvm-wrapper/ArchiveWrapper.cpp")
         .file("llvm-wrapper/CoverageMappingWrapper.cpp")
         .file("llvm-wrapper/SymbolWrapper.cpp")
         .file("llvm-wrapper/Linker.cpp")
diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
deleted file mode 100644
index feac6a5649c..00000000000
--- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-#include "LLVMWrapper.h"
-
-#include "llvm/Object/Archive.h"
-#include "llvm/Object/ArchiveWriter.h"
-#include "llvm/Support/Path.h"
-
-using namespace llvm;
-using namespace llvm::object;
-
-struct RustArchiveMember {
-  const char *Filename;
-  const char *Name;
-  Archive::Child Child;
-
-  RustArchiveMember()
-      : Filename(nullptr), Name(nullptr), Child(nullptr, nullptr, nullptr) {}
-  ~RustArchiveMember() {}
-};
-
-struct RustArchiveIterator {
-  bool First;
-  Archive::child_iterator Cur;
-  Archive::child_iterator End;
-  std::unique_ptr<Error> Err;
-
-  RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End,
-                      std::unique_ptr<Error> Err)
-      : First(true), Cur(Cur), End(End), Err(std::move(Err)) {}
-};
-
-enum class LLVMRustArchiveKind {
-  GNU,
-  BSD,
-  DARWIN,
-  COFF,
-  AIX_BIG,
-};
-
-static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
-  switch (Kind) {
-  case LLVMRustArchiveKind::GNU:
-    return Archive::K_GNU;
-  case LLVMRustArchiveKind::BSD:
-    return Archive::K_BSD;
-  case LLVMRustArchiveKind::DARWIN:
-    return Archive::K_DARWIN;
-  case LLVMRustArchiveKind::COFF:
-    return Archive::K_COFF;
-  case LLVMRustArchiveKind::AIX_BIG:
-    return Archive::K_AIXBIG;
-  default:
-    report_fatal_error("Bad ArchiveKind.");
-  }
-}
-
-typedef OwningBinary<Archive> *LLVMRustArchiveRef;
-typedef RustArchiveMember *LLVMRustArchiveMemberRef;
-typedef Archive::Child *LLVMRustArchiveChildRef;
-typedef Archive::Child const *LLVMRustArchiveChildConstRef;
-typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
-
-extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
-  ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr = MemoryBuffer::getFile(
-      Path, /*IsText*/ false, /*RequiresNullTerminator=*/false);
-  if (!BufOr) {
-    LLVMRustSetLastError(BufOr.getError().message().c_str());
-    return nullptr;
-  }
-
-  Expected<std::unique_ptr<Archive>> ArchiveOr =
-      Archive::create(BufOr.get()->getMemBufferRef());
-
-  if (!ArchiveOr) {
-    LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
-    return nullptr;
-  }
-
-  OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
-      std::move(ArchiveOr.get()), std::move(BufOr.get()));
-
-  return Ret;
-}
-
-extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
-  delete RustArchive;
-}
-
-extern "C" LLVMRustArchiveIteratorRef
-LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
-  Archive *Archive = RustArchive->getBinary();
-  std::unique_ptr<Error> Err = std::make_unique<Error>(Error::success());
-  auto Cur = Archive->child_begin(*Err);
-  if (*Err) {
-    LLVMRustSetLastError(toString(std::move(*Err)).c_str());
-    return nullptr;
-  }
-  auto End = Archive->child_end();
-  return new RustArchiveIterator(Cur, End, std::move(Err));
-}
-
-extern "C" LLVMRustArchiveChildConstRef
-LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
-  if (RAI->Cur == RAI->End)
-    return nullptr;
-
-  // Advancing the iterator validates the next child, and this can
-  // uncover an error. LLVM requires that we check all Errors,
-  // so we only advance the iterator if we actually need to fetch
-  // the next child.
-  // This means we must not advance the iterator in the *first* call,
-  // but instead advance it *before* fetching the child in all later calls.
-  if (!RAI->First) {
-    ++RAI->Cur;
-    if (*RAI->Err) {
-      LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str());
-      return nullptr;
-    }
-  } else {
-    RAI->First = false;
-  }
-
-  if (RAI->Cur == RAI->End)
-    return nullptr;
-
-  const Archive::Child &Child = *RAI->Cur.operator->();
-  Archive::Child *Ret = new Archive::Child(Child);
-
-  return Ret;
-}
-
-extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
-  delete Child;
-}
-
-extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
-  delete RAI;
-}
-
-extern "C" const char *
-LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
-  Expected<StringRef> NameOrErr = Child->getName();
-  if (!NameOrErr) {
-    // rustc_codegen_llvm currently doesn't use this error string, but it might
-    // be useful in the future, and in the meantime this tells LLVM that the
-    // error was not ignored and that it shouldn't abort the process.
-    LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
-    return nullptr;
-  }
-  StringRef Name = NameOrErr.get();
-  *Size = Name.size();
-  return Name.data();
-}
-
-extern "C" LLVMRustArchiveMemberRef
-LLVMRustArchiveMemberNew(char *Filename, char *Name,
-                         LLVMRustArchiveChildRef Child) {
-  RustArchiveMember *Member = new RustArchiveMember;
-  Member->Filename = Filename;
-  Member->Name = Name;
-  if (Child)
-    Member->Child = *Child;
-  return Member;
-}
-
-extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
-  delete Member;
-}
-
-extern "C" LLVMRustResult LLVMRustWriteArchive(
-    char *Dst, size_t NumMembers, const LLVMRustArchiveMemberRef *NewMembers,
-    bool WriteSymbtab, LLVMRustArchiveKind RustKind, bool isEC) {
-
-  std::vector<NewArchiveMember> Members;
-  auto Kind = fromRust(RustKind);
-
-  for (size_t I = 0; I < NumMembers; I++) {
-    auto Member = NewMembers[I];
-    assert(Member->Name);
-    if (Member->Filename) {
-      Expected<NewArchiveMember> MOrErr =
-          NewArchiveMember::getFile(Member->Filename, true);
-      if (!MOrErr) {
-        LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
-        return LLVMRustResult::Failure;
-      }
-      MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
-      Members.push_back(std::move(*MOrErr));
-    } else {
-      Expected<NewArchiveMember> MOrErr =
-          NewArchiveMember::getOldMember(Member->Child, true);
-      if (!MOrErr) {
-        LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
-        return LLVMRustResult::Failure;
-      }
-      Members.push_back(std::move(*MOrErr));
-    }
-  }
-
-  auto SymtabMode = WriteSymbtab ? SymtabWritingMode::NormalSymtab
-                                 : SymtabWritingMode::NoSymtab;
-  auto Result =
-      writeArchive(Dst, Members, SymtabMode, Kind, true, false, nullptr, isEC);
-  if (!Result)
-    return LLVMRustResult::Success;
-  LLVMRustSetLastError(toString(std::move(Result)).c_str());
-
-  return LLVMRustResult::Failure;
-}
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index cd4f80f808c..e699e4b9c13 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -278,6 +278,7 @@ enum class LLVMRustAttributeKind {
   Writable = 42,
   DeadOnUnwind = 43,
   DeadOnReturn = 44,
+  CapturesReadOnly = 45,
 };
 
 static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
@@ -376,6 +377,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
 #else
     report_fatal_error("DeadOnReturn attribute requires LLVM 21 or later");
 #endif
+  case LLVMRustAttributeKind::CapturesReadOnly:
+    report_fatal_error("Should be handled separately");
   }
   report_fatal_error("bad LLVMRustAttributeKind");
 }
@@ -430,6 +433,11 @@ LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
   if (RustAttr == LLVMRustAttributeKind::NoCapture) {
     return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none()));
   }
+  if (RustAttr == LLVMRustAttributeKind::CapturesReadOnly) {
+    return wrap(Attribute::getWithCaptureInfo(
+        *unwrap(C), CaptureInfo(CaptureComponents::Address |
+                                CaptureComponents::ReadProvenance)));
+  }
 #endif
   return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
 }
@@ -1460,60 +1468,6 @@ LLVMRustGetDiagInfoKind(LLVMDiagnosticInfoRef DI) {
   return toRust((DiagnosticKind)unwrap(DI)->getKind());
 }
 
-// This is kept distinct from LLVMGetTypeKind, because when
-// a new type kind is added, the Rust-side enum must be
-// updated or UB will result.
-extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
-  switch (unwrap(Ty)->getTypeID()) {
-  case Type::VoidTyID:
-    return LLVMVoidTypeKind;
-  case Type::HalfTyID:
-    return LLVMHalfTypeKind;
-  case Type::FloatTyID:
-    return LLVMFloatTypeKind;
-  case Type::DoubleTyID:
-    return LLVMDoubleTypeKind;
-  case Type::X86_FP80TyID:
-    return LLVMX86_FP80TypeKind;
-  case Type::FP128TyID:
-    return LLVMFP128TypeKind;
-  case Type::PPC_FP128TyID:
-    return LLVMPPC_FP128TypeKind;
-  case Type::LabelTyID:
-    return LLVMLabelTypeKind;
-  case Type::MetadataTyID:
-    return LLVMMetadataTypeKind;
-  case Type::IntegerTyID:
-    return LLVMIntegerTypeKind;
-  case Type::FunctionTyID:
-    return LLVMFunctionTypeKind;
-  case Type::StructTyID:
-    return LLVMStructTypeKind;
-  case Type::ArrayTyID:
-    return LLVMArrayTypeKind;
-  case Type::PointerTyID:
-    return LLVMPointerTypeKind;
-  case Type::FixedVectorTyID:
-    return LLVMVectorTypeKind;
-  case Type::TokenTyID:
-    return LLVMTokenTypeKind;
-  case Type::ScalableVectorTyID:
-    return LLVMScalableVectorTypeKind;
-  case Type::BFloatTyID:
-    return LLVMBFloatTypeKind;
-  case Type::X86_AMXTyID:
-    return LLVMX86_AMXTypeKind;
-  default: {
-    std::string error;
-    auto stream = llvm::raw_string_ostream(error);
-    stream << "Rust does not support the TypeID: " << unwrap(Ty)->getTypeID()
-           << " for the type: " << *unwrap(Ty);
-    stream.flush();
-    report_fatal_error(error.c_str());
-  }
-  }
-}
-
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef)
 
 extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(LLVMDiagnosticInfoRef DI,
@@ -1993,29 +1947,3 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) {
   MD.NoHWAddress = true;
   GV.setSanitizerMetadata(MD);
 }
-
-enum class LLVMRustTailCallKind {
-  None = 0,
-  Tail = 1,
-  MustTail = 2,
-  NoTail = 3
-};
-
-extern "C" void LLVMRustSetTailCallKind(LLVMValueRef Call,
-                                        LLVMRustTailCallKind Kind) {
-  CallInst *CI = unwrap<CallInst>(Call);
-  switch (Kind) {
-  case LLVMRustTailCallKind::None:
-    CI->setTailCallKind(CallInst::TCK_None);
-    break;
-  case LLVMRustTailCallKind::Tail:
-    CI->setTailCallKind(CallInst::TCK_Tail);
-    break;
-  case LLVMRustTailCallKind::MustTail:
-    CI->setTailCallKind(CallInst::TCK_MustTail);
-    break;
-  case LLVMRustTailCallKind::NoTail:
-    CI->setTailCallKind(CallInst::TCK_NoTail);
-    break;
-  }
-}
diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs
index 9023520c750..0114e0dfde0 100644
--- a/compiler/rustc_macros/src/print_attribute.rs
+++ b/compiler/rustc_macros/src/print_attribute.rs
@@ -4,7 +4,7 @@ use syn::spanned::Spanned;
 use syn::{Data, Fields, Ident};
 use synstructure::Structure;
 
-fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, TokenStream) {
+fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream) {
     let string_name = name.to_string();
     let mut disps = vec![quote! {let mut __printed_anything = false;}];
 
@@ -43,7 +43,6 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                     #(#disps)*
                     __p.word("}");
                 },
-                quote! { true },
             )
         }
         Fields::Unnamed(fields_unnamed) => {
@@ -76,10 +75,9 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                     #(#disps)*
                     __p.pclose();
                 },
-                quote! { true },
             )
         }
-        Fields::Unit => (quote! {}, quote! { __p.word(#string_name) }, quote! { true }),
+        Fields::Unit => (quote! {}, quote! { __p.word(#string_name) }),
     }
 }
 
@@ -89,51 +87,33 @@ pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream {
     };
 
     // Must be applied to an enum type.
-    let (code, printed) = match &input.ast().data {
+    let code = match &input.ast().data {
         Data::Enum(e) => {
-            let (arms, printed) = e
+            let arms = e
                 .variants
                 .iter()
                 .map(|x| {
                     let ident = &x.ident;
-                    let (pat, code, printed) = print_fields(ident, &x.fields);
+                    let (pat, code) = print_fields(ident, &x.fields);
 
-                    (
-                        quote! {
-                            Self::#ident #pat => {#code}
-                        },
-                        quote! {
-                            Self::#ident #pat => {#printed}
-                        },
-                    )
+                    quote! {
+                        Self::#ident #pat => {#code}
+                    }
                 })
-                .unzip::<_, _, Vec<_>, Vec<_>>();
+                .collect::<Vec<_>>();
 
-            (
-                quote! {
-                    match self {
-                        #(#arms)*
-                    }
-                },
-                quote! {
-                    match self {
-                        #(#printed)*
-                    }
-                },
-            )
+            quote! {
+                match self {
+                    #(#arms)*
+                }
+            }
         }
         Data::Struct(s) => {
-            let (pat, code, printed) = print_fields(&input.ast().ident, &s.fields);
-            (
-                quote! {
-                    let Self #pat = self;
-                    #code
-                },
-                quote! {
-                    let Self #pat = self;
-                    #printed
-                },
-            )
+            let (pat, code) = print_fields(&input.ast().ident, &s.fields);
+            quote! {
+                let Self #pat = self;
+                #code
+            }
         }
         Data::Union(u) => {
             return span_error(u.union_token.span(), "can't derive PrintAttribute on unions");
@@ -144,7 +124,7 @@ pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream {
     input.gen_impl(quote! {
         #[allow(unused)]
         gen impl PrintAttribute for @Self {
-            fn should_render(&self) -> bool { #printed }
+            fn should_render(&self) -> bool { true }
             fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code }
         }
     })
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 6bfb3769f24..5d776ea581d 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -32,6 +32,7 @@ use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateS
 use rustc_session::lint::{self, BuiltinLintDiag};
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
+use rustc_span::def_id::DefId;
 use rustc_span::edition::Edition;
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
 use rustc_target::spec::{PanicStrategy, Target};
@@ -275,6 +276,10 @@ impl CStore {
             .filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
     }
 
+    pub fn all_proc_macro_def_ids(&self) -> impl Iterator<Item = DefId> {
+        self.iter_crate_data().flat_map(|(krate, data)| data.proc_macros_for_crate(krate, self))
+    }
+
     fn push_dependencies_in_postorder(&self, deps: &mut IndexSet<CrateNum>, cnum: CrateNum) {
         if !deps.contains(&cnum) {
             let data = self.get_crate_data(cnum);
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 958e314efab..63f1b51df1c 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -701,7 +701,7 @@ impl<'tcx> Collector<'tcx> {
             .link_ordinal
             .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
 
-        let name = codegen_fn_attrs.link_name.unwrap_or_else(|| self.tcx.item_name(item));
+        let name = codegen_fn_attrs.symbol_name.unwrap_or_else(|| self.tcx.item_name(item));
 
         if self.tcx.sess.target.binary_format == BinaryFormat::Elf {
             let name = name.as_str();
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 548c56a97bc..110b26c62ef 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -2014,6 +2014,22 @@ impl CrateMetadata {
         self.root.is_proc_macro_crate()
     }
 
+    pub(crate) fn proc_macros_for_crate(
+        &self,
+        krate: CrateNum,
+        cstore: &CStore,
+    ) -> impl Iterator<Item = DefId> {
+        gen move {
+            for def_id in self.root.proc_macro_data.as_ref().into_iter().flat_map(move |data| {
+                data.macros
+                    .decode(CrateMetadataRef { cdata: self, cstore })
+                    .map(move |index| DefId { index, krate })
+            }) {
+                yield def_id;
+            }
+        }
+    }
+
     pub(crate) fn name(&self) -> Symbol {
         self.root.header.name
     }
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 341a735f88f..f70b7b6fad7 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -211,11 +211,28 @@ impl LintExpectation {
 }
 
 fn explain_lint_level_source(
+    sess: &Session,
     lint: &'static Lint,
     level: Level,
     src: LintLevelSource,
     err: &mut Diag<'_, ()>,
 ) {
+    // Find the name of the lint group that contains the given lint.
+    // Assumes the lint only belongs to one group.
+    let lint_group_name = |lint| {
+        let lint_groups_iter = sess.lint_groups_iter();
+        let lint_id = LintId::of(lint);
+        lint_groups_iter
+            .filter(|lint_group| !lint_group.is_externally_loaded)
+            .find(|lint_group| {
+                lint_group
+                    .lints
+                    .iter()
+                    .find(|lint_group_lint| **lint_group_lint == lint_id)
+                    .is_some()
+            })
+            .map(|lint_group| lint_group.name)
+    };
     let name = lint.name_lower();
     if let Level::Allow = level {
         // Do not point at `#[allow(compat_lint)]` as the reason for a compatibility lint
@@ -224,7 +241,15 @@ fn explain_lint_level_source(
     }
     match src {
         LintLevelSource::Default => {
-            err.note_once(format!("`#[{}({})]` on by default", level.as_str(), name));
+            let level_str = level.as_str();
+            match lint_group_name(lint) {
+                Some(group_name) => {
+                    err.note_once(format!("`#[{level_str}({name})]` (part of `#[{level_str}({group_name})]`) on by default"));
+                }
+                None => {
+                    err.note_once(format!("`#[{level_str}({name})]` on by default"));
+                }
+            }
         }
         LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
             let flag = orig_level.to_cmd_flag();
@@ -427,7 +452,7 @@ pub fn lint_level(
             decorate(&mut err);
         }
 
-        explain_lint_level_source(lint, level, src, &mut err);
+        explain_lint_level_source(sess, lint, level, src, &mut err);
         err.emit()
     }
     lint_level_impl(sess, lint, level, span, Box::new(decorate))
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 7d2fc0995aa..347319b07c9 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -35,14 +35,10 @@ pub struct CodegenFnAttrs {
     pub inline: InlineAttr,
     /// Parsed representation of the `#[optimize]` attribute
     pub optimize: OptimizeAttr,
-    /// The `#[export_name = "..."]` attribute, indicating a custom symbol a
-    /// function should be exported under
-    pub export_name: Option<Symbol>,
-    /// The `#[link_name = "..."]` attribute, indicating a custom symbol an
-    /// imported function should be imported as. Note that `export_name`
-    /// probably isn't set when this is set, this is for foreign items while
-    /// `#[export_name]` is for Rust-defined functions.
-    pub link_name: Option<Symbol>,
+    /// The name this function will be imported/exported under. This can be set
+    /// using the `#[export_name = "..."]` or `#[link_name = "..."]` attribute
+    /// depending on if this is a function definition or foreign function.
+    pub symbol_name: Option<Symbol>,
     /// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an
     /// imported function has in the dynamic library. Note that this must not
     /// be set when `link_name` is set. This is for foreign items with the
@@ -61,8 +57,8 @@ pub struct CodegenFnAttrs {
     /// The `#[link_section = "..."]` attribute, or what executable section this
     /// should be placed in.
     pub link_section: Option<Symbol>,
-    /// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which
-    /// instrumentation should be disabled inside the annotated function.
+    /// The `#[sanitize(xyz = "off")]` attribute. Indicates sanitizers for which
+    /// instrumentation should be disabled inside the function.
     pub no_sanitize: SanitizerSet,
     /// The `#[instruction_set(set)]` attribute. Indicates if the generated code should
     /// be generated against a specific instruction set. Only usable on architectures which allow
@@ -167,8 +163,7 @@ impl CodegenFnAttrs {
             flags: CodegenFnAttrFlags::empty(),
             inline: InlineAttr::None,
             optimize: OptimizeAttr::Default,
-            export_name: None,
-            link_name: None,
+            symbol_name: None,
             link_ordinal: None,
             target_features: vec![],
             safe_target_features: false,
@@ -196,7 +191,7 @@ impl CodegenFnAttrs {
 
         self.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
             || self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
-            || self.export_name.is_some()
+            || self.symbol_name.is_some()
             || match self.linkage {
                 // These are private, so make sure we don't try to consider
                 // them external.
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index c55c7fc6002..c977e5329c2 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -115,48 +115,6 @@ impl MirPhase {
             MirPhase::Runtime(runtime_phase) => (3, 1 + runtime_phase as usize),
         }
     }
-
-    /// Parses a `MirPhase` from a pair of strings. Panics if this isn't possible for any reason.
-    pub fn parse(dialect: String, phase: Option<String>) -> Self {
-        match &*dialect.to_ascii_lowercase() {
-            "built" => {
-                assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR");
-                MirPhase::Built
-            }
-            "analysis" => Self::Analysis(AnalysisPhase::parse(phase)),
-            "runtime" => Self::Runtime(RuntimePhase::parse(phase)),
-            _ => bug!("Unknown MIR dialect: '{}'", dialect),
-        }
-    }
-}
-
-impl AnalysisPhase {
-    pub fn parse(phase: Option<String>) -> Self {
-        let Some(phase) = phase else {
-            return Self::Initial;
-        };
-
-        match &*phase.to_ascii_lowercase() {
-            "initial" => Self::Initial,
-            "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
-            _ => bug!("Unknown analysis phase: '{}'", phase),
-        }
-    }
-}
-
-impl RuntimePhase {
-    pub fn parse(phase: Option<String>) -> Self {
-        let Some(phase) = phase else {
-            return Self::Initial;
-        };
-
-        match &*phase.to_ascii_lowercase() {
-            "initial" => Self::Initial,
-            "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
-            "optimized" => Self::Optimized,
-            _ => bug!("Unknown runtime phase: '{}'", phase),
-        }
-    }
 }
 
 /// Where a specific `mir::Body` comes from.
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index f2d5b13cbc8..128ae8549f7 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -929,7 +929,10 @@ impl<'tcx> TerminatorKind<'tcx> {
             }
             Yield { value, resume_arg, .. } => write!(fmt, "{resume_arg:?} = yield({value:?})"),
             Unreachable => write!(fmt, "unreachable"),
-            Drop { place, .. } => write!(fmt, "drop({place:?})"),
+            Drop { place, async_fut: None, .. } => write!(fmt, "drop({place:?})"),
+            Drop { place, async_fut: Some(async_fut), .. } => {
+                write!(fmt, "async drop({place:?}; poll={async_fut:?})")
+            }
             Call { func, args, destination, .. } => {
                 write!(fmt, "{destination:?} = ")?;
                 write!(fmt, "{func:?}(")?;
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 42a68b29ec7..904d78d69b6 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -531,13 +531,20 @@ macro_rules! make_mir_visitor {
                         unwind: _,
                         replace: _,
                         drop: _,
-                        async_fut: _,
+                        async_fut,
                     } => {
                         self.visit_place(
                             place,
                             PlaceContext::MutatingUse(MutatingUseContext::Drop),
                             location
                         );
+                        if let Some(async_fut) = async_fut {
+                            self.visit_local(
+                                $(&$mutability)? *async_fut,
+                                PlaceContext::MutatingUse(MutatingUseContext::Borrow),
+                                location
+                            );
+                        }
                     }
 
                     TerminatorKind::Call {
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index a8b357bf105..ea62461ebeb 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -343,6 +343,7 @@ trivial! {
     rustc_span::Symbol,
     rustc_span::Ident,
     rustc_target::spec::PanicStrategy,
+    rustc_target::spec::SanitizerSet,
     rustc_type_ir::Variance,
     u32,
     usize,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index f4d0120a2e7..3bb8353f49e 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -100,7 +100,7 @@ use rustc_session::lint::LintExpectationId;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::source_map::Spanned;
 use rustc_span::{DUMMY_SP, Span, Symbol};
-use rustc_target::spec::PanicStrategy;
+use rustc_target::spec::{PanicStrategy, SanitizerSet};
 use {rustc_abi as abi, rustc_ast as ast, rustc_hir as hir};
 
 use crate::infer::canonical::{self, Canonical};
@@ -2686,6 +2686,16 @@ rustc_queries! {
         desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
+
+    /// Checks for the nearest `#[sanitize(xyz = "off")]` or
+    /// `#[sanitize(xyz = "on")]` on this def and any enclosing defs, up to the
+    /// crate root.
+    ///
+    /// Returns the set of sanitizers that is explicitly disabled for this def.
+    query disabled_sanitizers_for(key: LocalDefId) -> SanitizerSet {
+        desc { |tcx| "checking what set of sanitizers are enabled on `{}`", tcx.def_path_str(key) }
+        feedable
+    }
 }
 
 rustc_with_all_queries! { define_callbacks! }
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index a7ac3442898..546791135ba 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -645,34 +645,29 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> {
         let parent = Option::<LocalDefId>::decode(self);
         let tag: u8 = Decodable::decode(self);
 
-        if tag == TAG_PARTIAL_SPAN {
-            return Span::new(BytePos(0), BytePos(0), ctxt, parent);
-        } else if tag == TAG_RELATIVE_SPAN {
-            let dlo = u32::decode(self);
-            let dto = u32::decode(self);
-
-            let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked();
-            let span = Span::new(
-                enclosing.lo + BytePos::from_u32(dlo),
-                enclosing.lo + BytePos::from_u32(dto),
-                ctxt,
-                parent,
-            );
-
-            return span;
-        } else {
-            debug_assert_eq!(tag, TAG_FULL_SPAN);
-        }
-
-        let file_lo_index = SourceFileIndex::decode(self);
-        let line_lo = usize::decode(self);
-        let col_lo = RelativeBytePos::decode(self);
-        let len = BytePos::decode(self);
-
-        let file_lo = self.file_index_to_file(file_lo_index);
-        let lo = file_lo.lines()[line_lo - 1] + col_lo;
-        let lo = file_lo.absolute_position(lo);
-        let hi = lo + len;
+        let (lo, hi) = match tag {
+            TAG_PARTIAL_SPAN => (BytePos(0), BytePos(0)),
+            TAG_RELATIVE_SPAN => {
+                let dlo = u32::decode(self);
+                let dto = u32::decode(self);
+
+                let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked();
+                (enclosing.lo + BytePos::from_u32(dlo), enclosing.lo + BytePos::from_u32(dto))
+            }
+            TAG_FULL_SPAN => {
+                let file_lo_index = SourceFileIndex::decode(self);
+                let line_lo = usize::decode(self);
+                let col_lo = RelativeBytePos::decode(self);
+                let len = BytePos::decode(self);
+
+                let file_lo = self.file_index_to_file(file_lo_index);
+                let lo = file_lo.lines()[line_lo - 1] + col_lo;
+                let lo = file_lo.absolute_position(lo);
+                let hi = lo + len;
+                (lo, hi)
+            }
+            _ => unreachable!(),
+        };
 
         Span::new(lo, hi, ctxt, parent)
     }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 5bdde3a514e..32f91bfba6b 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -760,6 +760,9 @@ pub enum DynCompatibilityViolation {
     // Supertrait has a non-lifetime `for<T>` binder.
     SupertraitNonLifetimeBinder(SmallVec<[Span; 1]>),
 
+    // Trait has a `const Trait` supertrait.
+    SupertraitConst(SmallVec<[Span; 1]>),
+
     /// Method has something illegal.
     Method(Symbol, MethodViolationCode, Span),
 
@@ -785,6 +788,9 @@ impl DynCompatibilityViolation {
             DynCompatibilityViolation::SupertraitNonLifetimeBinder(_) => {
                 "where clause cannot reference non-lifetime `for<...>` variables".into()
             }
+            DynCompatibilityViolation::SupertraitConst(_) => {
+                "it cannot have a `const` supertrait".into()
+            }
             DynCompatibilityViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
                 format!("associated function `{name}` has no `self` parameter").into()
             }
@@ -842,7 +848,8 @@ impl DynCompatibilityViolation {
         match self {
             DynCompatibilityViolation::SizedSelf(_)
             | DynCompatibilityViolation::SupertraitSelf(_)
-            | DynCompatibilityViolation::SupertraitNonLifetimeBinder(..) => {
+            | DynCompatibilityViolation::SupertraitNonLifetimeBinder(..)
+            | DynCompatibilityViolation::SupertraitConst(_) => {
                 DynCompatibilityViolationSolution::None
             }
             DynCompatibilityViolation::Method(
@@ -873,15 +880,17 @@ impl DynCompatibilityViolation {
         match self {
             DynCompatibilityViolation::SupertraitSelf(spans)
             | DynCompatibilityViolation::SizedSelf(spans)
-            | DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(),
+            | DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans)
+            | DynCompatibilityViolation::SupertraitConst(spans) => spans.clone(),
             DynCompatibilityViolation::AssocConst(_, span)
             | DynCompatibilityViolation::GAT(_, span)
-            | DynCompatibilityViolation::Method(_, _, span)
-                if *span != DUMMY_SP =>
-            {
-                smallvec![*span]
+            | DynCompatibilityViolation::Method(_, _, span) => {
+                if *span != DUMMY_SP {
+                    smallvec![*span]
+                } else {
+                    smallvec![]
+                }
             }
-            _ => smallvec![],
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index b3042904a29..b9a6f67ab0d 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -23,7 +23,7 @@ impl IntoDiagArg for Ty<'_> {
     fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
         ty::tls::with(|tcx| {
             let ty = tcx.short_string(self, path);
-            rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(ty))
+            DiagArgValue::Str(std::borrow::Cow::Owned(ty))
         })
     }
 }
@@ -32,7 +32,7 @@ impl IntoDiagArg for Instance<'_> {
     fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
         ty::tls::with(|tcx| {
             let instance = tcx.short_string_namespace(self, path, Namespace::ValueNS);
-            rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(instance))
+            DiagArgValue::Str(std::borrow::Cow::Owned(instance))
         })
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index e6feafea122..9e6f277ef77 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -124,6 +124,15 @@ pub trait Printer<'tcx>: Sized {
         trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError>;
 
+    fn print_coroutine_with_kind(
+        &mut self,
+        def_id: DefId,
+        parent_args: &'tcx [GenericArg<'tcx>],
+        kind: Ty<'tcx>,
+    ) -> Result<(), PrintError> {
+        self.print_path_with_generic_args(|p| p.print_def_path(def_id, parent_args), &[kind.into()])
+    }
+
     // Defaults (should not be overridden):
 
     #[instrument(skip(self), level = "debug")]
@@ -162,9 +171,10 @@ pub trait Printer<'tcx>: Sized {
                             )) = self.tcx().coroutine_kind(def_id)
                                 && args.len() > parent_args.len()
                             {
-                                return self.print_path_with_generic_args(
-                                    |p| p.print_def_path(def_id, parent_args),
-                                    &args[..parent_args.len() + 1][..1],
+                                return self.print_coroutine_with_kind(
+                                    def_id,
+                                    parent_args,
+                                    args[parent_args.len()].expect_ty(),
                                 );
                             } else {
                                 // Closures' own generics are only captures, don't print them.
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 72474a60566..755fc68d86f 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -821,10 +821,38 @@ impl<'tcx> Ty<'tcx> {
     #[inline]
     pub fn new_coroutine_witness(
         tcx: TyCtxt<'tcx>,
-        id: DefId,
+        def_id: DefId,
         args: GenericArgsRef<'tcx>,
     ) -> Ty<'tcx> {
-        Ty::new(tcx, CoroutineWitness(id, args))
+        if cfg!(debug_assertions) {
+            tcx.debug_assert_args_compatible(tcx.typeck_root_def_id(def_id), args);
+        }
+        Ty::new(tcx, CoroutineWitness(def_id, args))
+    }
+
+    pub fn new_coroutine_witness_for_coroutine(
+        tcx: TyCtxt<'tcx>,
+        def_id: DefId,
+        coroutine_args: GenericArgsRef<'tcx>,
+    ) -> Ty<'tcx> {
+        tcx.debug_assert_args_compatible(def_id, coroutine_args);
+        // HACK: Coroutine witness types are lifetime erased, so they
+        // never reference any lifetime args from the coroutine. We erase
+        // the regions here since we may get into situations where a
+        // coroutine is recursively contained within itself, leading to
+        // witness types that differ by region args. This means that
+        // cycle detection in fulfillment will not kick in, which leads
+        // to unnecessary overflows in async code. See the issue:
+        // <https://github.com/rust-lang/rust/issues/145151>.
+        let args =
+            ty::GenericArgs::for_item(tcx, tcx.typeck_root_def_id(def_id), |def, _| {
+                match def.kind {
+                    ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+                    ty::GenericParamDefKind::Type { .. }
+                    | ty::GenericParamDefKind::Const { .. } => coroutine_args[def.index as usize],
+                }
+            });
+        Ty::new_coroutine_witness(tcx, def_id, args)
     }
 
     // misc
@@ -985,6 +1013,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
         Ty::new_coroutine_witness(interner, def_id, args)
     }
 
+    fn new_coroutine_witness_for_coroutine(
+        interner: TyCtxt<'tcx>,
+        def_id: DefId,
+        coroutine_args: ty::GenericArgsRef<'tcx>,
+    ) -> Self {
+        Ty::new_coroutine_witness_for_coroutine(interner, def_id, coroutine_args)
+    }
+
     fn new_ptr(interner: TyCtxt<'tcx>, ty: Self, mutbl: hir::Mutability) -> Self {
         Ty::new_ptr(interner, ty, mutbl)
     }
diff --git a/compiler/rustc_mir_build/src/builder/custom/mod.rs b/compiler/rustc_mir_build/src/builder/custom/mod.rs
index 902a6e7f115..792ad6d782c 100644
--- a/compiler/rustc_mir_build/src/builder/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/custom/mod.rs
@@ -19,10 +19,10 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Attribute, HirId};
+use rustc_hir::{HirId, attrs};
 use rustc_index::{IndexSlice, IndexVec};
+use rustc_middle::bug;
 use rustc_middle::mir::*;
-use rustc_middle::span_bug;
 use rustc_middle::thir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
@@ -39,7 +39,8 @@ pub(super) fn build_custom_mir<'tcx>(
     return_ty: Ty<'tcx>,
     return_ty_span: Span,
     span: Span,
-    attr: &Attribute,
+    dialect: Option<attrs::MirDialect>,
+    phase: Option<attrs::MirPhase>,
 ) -> Body<'tcx> {
     let mut body = Body {
         basic_blocks: BasicBlocks::new(IndexVec::new()),
@@ -72,7 +73,7 @@ pub(super) fn build_custom_mir<'tcx>(
         inlined_parent_scope: None,
         local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }),
     });
-    body.injection_phase = Some(parse_attribute(attr));
+    body.injection_phase = Some(parse_attribute(dialect, phase));
 
     let mut pctxt = ParseCtxt {
         tcx,
@@ -98,40 +99,38 @@ pub(super) fn build_custom_mir<'tcx>(
     body
 }
 
-fn parse_attribute(attr: &Attribute) -> MirPhase {
-    let meta_items = attr.meta_item_list().unwrap();
-    let mut dialect: Option<String> = None;
-    let mut phase: Option<String> = None;
-
-    // Not handling errors properly for this internal attribute; will just abort on errors.
-    for nested in meta_items {
-        let name = nested.name().unwrap();
-        let value = nested.value_str().unwrap().as_str().to_string();
-        match name.as_str() {
-            "dialect" => {
-                assert!(dialect.is_none());
-                dialect = Some(value);
-            }
-            "phase" => {
-                assert!(phase.is_none());
-                phase = Some(value);
-            }
-            other => {
-                span_bug!(
-                    nested.span(),
-                    "Unexpected key while parsing custom_mir attribute: '{}'",
-                    other
-                );
-            }
-        }
-    }
-
+/// Turns the arguments passed to `#[custom_mir(..)]` into a proper
+/// [`MirPhase`]. Panics if this isn't possible for any reason.
+fn parse_attribute(dialect: Option<attrs::MirDialect>, phase: Option<attrs::MirPhase>) -> MirPhase {
     let Some(dialect) = dialect else {
+        // Caught during attribute checking.
         assert!(phase.is_none());
         return MirPhase::Built;
     };
 
-    MirPhase::parse(dialect, phase)
+    match dialect {
+        attrs::MirDialect::Built => {
+            // Caught during attribute checking.
+            assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR");
+            MirPhase::Built
+        }
+        attrs::MirDialect::Analysis => match phase {
+            None | Some(attrs::MirPhase::Initial) => MirPhase::Analysis(AnalysisPhase::Initial),
+
+            Some(attrs::MirPhase::PostCleanup) => MirPhase::Analysis(AnalysisPhase::PostCleanup),
+
+            Some(attrs::MirPhase::Optimized) => {
+                // Caught during attribute checking.
+                bug!("`optimized` dialect is not compatible with the `analysis` dialect")
+            }
+        },
+
+        attrs::MirDialect::Runtime => match phase {
+            None | Some(attrs::MirPhase::Initial) => MirPhase::Runtime(RuntimePhase::Initial),
+            Some(attrs::MirPhase::PostCleanup) => MirPhase::Runtime(RuntimePhase::PostCleanup),
+            Some(attrs::MirPhase::Optimized) => MirPhase::Runtime(RuntimePhase::Optimized),
+        },
+    }
 }
 
 struct ParseCtxt<'a, 'tcx> {
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index 855cd2f3bc0..9570760f943 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -11,9 +11,10 @@ use rustc_ast::attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::{self as hir, BindingMode, ByRef, HirId, ItemLocalId, Node};
+use rustc_hir::{self as hir, BindingMode, ByRef, HirId, ItemLocalId, Node, find_attr};
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -479,8 +480,7 @@ fn construct_fn<'tcx>(
         ty => span_bug!(span_with_body, "unexpected type of body: {ty:?}"),
     };
 
-    if let Some(custom_mir_attr) =
-        tcx.hir_attrs(fn_id).iter().find(|attr| attr.has_name(sym::custom_mir))
+    if let Some((dialect, phase)) = find_attr!(tcx.hir_attrs(fn_id), AttributeKind::CustomMir(dialect, phase, _) => (dialect, phase))
     {
         return custom::build_custom_mir(
             tcx,
@@ -492,7 +492,8 @@ fn construct_fn<'tcx>(
             return_ty,
             return_ty_span,
             span_with_body,
-            custom_mir_attr,
+            dialect.as_ref().map(|(d, _)| *d),
+            phase.as_ref().map(|(p, _)| *p),
         );
     }
 
diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs
index d4b6da2c14b..e0cbe8519ed 100644
--- a/compiler/rustc_mir_build/src/check_tail_calls.rs
+++ b/compiler/rustc_mir_build/src/check_tail_calls.rs
@@ -135,30 +135,23 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
             self.report_abi_mismatch(expr.span, caller_sig.abi, callee_sig.abi);
         }
 
+        // FIXME(explicit_tail_calls): this currently fails for cases where opaques are used.
+        // e.g.
+        // ```
+        // fn a() -> impl Sized { become b() } // ICE
+        // fn b() -> u8 { 0 }
+        // ```
+        // we should think what is the expected behavior here.
+        // (we should probably just accept this by revealing opaques?)
         if caller_sig.inputs_and_output != callee_sig.inputs_and_output {
-            if caller_sig.inputs() != callee_sig.inputs() {
-                self.report_arguments_mismatch(
-                    expr.span,
-                    self.tcx.liberate_late_bound_regions(
-                        CRATE_DEF_ID.to_def_id(),
-                        self.caller_ty.fn_sig(self.tcx),
-                    ),
-                    self.tcx
-                        .liberate_late_bound_regions(CRATE_DEF_ID.to_def_id(), ty.fn_sig(self.tcx)),
-                );
-            }
-
-            // FIXME(explicit_tail_calls): this currently fails for cases where opaques are used.
-            // e.g.
-            // ```
-            // fn a() -> impl Sized { become b() } // ICE
-            // fn b() -> u8 { 0 }
-            // ```
-            // we should think what is the expected behavior here.
-            // (we should probably just accept this by revealing opaques?)
-            if caller_sig.output() != callee_sig.output() {
-                span_bug!(expr.span, "hir typeck should have checked the return type already");
-            }
+            self.report_signature_mismatch(
+                expr.span,
+                self.tcx.liberate_late_bound_regions(
+                    CRATE_DEF_ID.to_def_id(),
+                    self.caller_ty.fn_sig(self.tcx),
+                ),
+                self.tcx.liberate_late_bound_regions(CRATE_DEF_ID.to_def_id(), ty.fn_sig(self.tcx)),
+            );
         }
 
         {
@@ -365,7 +358,7 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
         self.found_errors = Err(err);
     }
 
-    fn report_arguments_mismatch(
+    fn report_signature_mismatch(
         &mut self,
         sp: Span,
         caller_sig: ty::FnSig<'_>,
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 0b6b36640e9..cdab785e842 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -5,8 +5,9 @@ use std::ops::Bound;
 use rustc_ast::AsmMacro;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::DiagArgValue;
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::DefKind;
-use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
+use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, find_attr};
 use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::span_bug;
@@ -1157,7 +1158,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
     // Closures and inline consts are handled by their owner, if it has a body
     assert!(!tcx.is_typeck_child(def.to_def_id()));
     // Also, don't safety check custom MIR
-    if tcx.has_attr(def, sym::custom_mir) {
+    if find_attr!(tcx.get_all_attrs(def), AttributeKind::CustomMir(..) => ()).is_some() {
         return;
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 24d4136c642..9657c4dc839 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -4,11 +4,11 @@
 
 use rustc_data_structures::steal::Steal;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
-use rustc_hir::HirId;
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::{self as hir, HirId, find_attr};
 use rustc_middle::bug;
 use rustc_middle::middle::region;
 use rustc_middle::thir::*;
@@ -111,10 +111,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
             typeck_results,
             rvalue_scopes: &typeck_results.rvalue_scopes,
             body_owner: def.to_def_id(),
-            apply_adjustments: tcx
-                .hir_attrs(hir_id)
-                .iter()
-                .all(|attr| !attr.has_name(rustc_span::sym::custom_mir)),
+            apply_adjustments:
+                !find_attr!(tcx.hir_attrs(hir_id), AttributeKind::CustomMir(..) => ()).is_some(),
         }
     }
 
diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml
index 293bcbef21b..9621f9f20bd 100644
--- a/compiler/rustc_mir_dataflow/Cargo.toml
+++ b/compiler/rustc_mir_dataflow/Cargo.toml
@@ -13,7 +13,6 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
 rustc_graphviz = { path = "../rustc_graphviz" }
-rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index f86a15a8f92..372a3f3a8b8 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -8,7 +8,6 @@ use std::sync::OnceLock;
 use std::{io, ops, str};
 
 use regex::Regex;
-use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::mir::{
     self, BasicBlock, Body, Location, create_dump_file, dump_enabled, graphviz_safe_def_name,
@@ -16,6 +15,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_span::def_id::DefId;
 use rustc_span::{Symbol, sym};
 use tracing::debug;
 use {rustc_ast as ast, rustc_graphviz as dot};
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 1682f332857..a899ec1fa88 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -1,7 +1,7 @@
 use rustc_ast::MetaItem;
-use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{self, Body, Local, Location};
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::def_id::DefId;
 use rustc_span::{Span, Symbol, sym};
 use tracing::{debug, info};
 
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 1bc35e599c7..3e1f48610ff 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -27,7 +27,7 @@ enum CanonicalizeInputKind {
     ParamEnv,
     /// When canonicalizing predicates, we don't keep `'static`. If we're
     /// currently outside of the trait solver and canonicalize the root goal
-    /// during HIR typeck, we replace each occurance of a region with a
+    /// during HIR typeck, we replace each occurrence of a region with a
     /// unique region variable. See the comment on `InferCtxt::in_hir_typeck`
     /// for more details.
     Predicate { is_hir_typeck_root_goal: bool },
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index faa86734d08..d25e74e7335 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -75,17 +75,10 @@ where
             Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()]))
         }
 
-        ty::Coroutine(def_id, args) => {
-            let coroutine_args = args.as_coroutine();
-            Ok(ty::Binder::dummy(vec![
-                coroutine_args.tupled_upvars_ty(),
-                Ty::new_coroutine_witness(
-                    ecx.cx(),
-                    def_id,
-                    ecx.cx().mk_args(coroutine_args.parent_args().as_slice()),
-                ),
-            ]))
-        }
+        ty::Coroutine(def_id, args) => Ok(ty::Binder::dummy(vec![
+            args.as_coroutine().tupled_upvars_ty(),
+            Ty::new_coroutine_witness_for_coroutine(ecx.cx(), def_id, args),
+        ])),
 
         ty::CoroutineWitness(def_id, args) => Ok(ecx
             .cx()
@@ -251,14 +244,9 @@ where
             Movability::Static => Err(NoSolution),
             Movability::Movable => {
                 if ecx.cx().features().coroutine_clone() {
-                    let coroutine = args.as_coroutine();
                     Ok(ty::Binder::dummy(vec![
-                        coroutine.tupled_upvars_ty(),
-                        Ty::new_coroutine_witness(
-                            ecx.cx(),
-                            def_id,
-                            ecx.cx().mk_args(coroutine.parent_args().as_slice()),
-                        ),
+                        args.as_coroutine().tupled_upvars_ty(),
+                        Ty::new_coroutine_witness_for_coroutine(ecx.cx(), def_id, args),
                     ]))
                 } else {
                     Err(NoSolution)
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 04ede365a21..891ecab041a 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -6,8 +6,8 @@ use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind};
 use rustc_type_ir::{
-    self as ty, Interner, Movability, TraitPredicate, TraitRef, TypeVisitableExt as _, TypingMode,
-    Upcast as _, elaborate,
+    self as ty, Interner, Movability, PredicatePolarity, TraitPredicate, TraitRef,
+    TypeVisitableExt as _, TypingMode, Upcast as _, elaborate,
 };
 use tracing::{debug, instrument, trace};
 
@@ -133,19 +133,26 @@ where
             cx: I,
             clause_def_id: I::DefId,
             goal_def_id: I::DefId,
+            polarity: PredicatePolarity,
         ) -> bool {
             clause_def_id == goal_def_id
             // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so
             // check for a `MetaSized` supertrait being matched against a `Sized` assumption.
             //
             // `PointeeSized` bounds are syntactic sugar for a lack of bounds so don't need this.
-                || (cx.is_lang_item(clause_def_id, TraitSolverLangItem::Sized)
+                || (polarity == PredicatePolarity::Positive
+                    && cx.is_lang_item(clause_def_id, TraitSolverLangItem::Sized)
                     && cx.is_lang_item(goal_def_id, TraitSolverLangItem::MetaSized))
         }
 
         if let Some(trait_clause) = assumption.as_trait_clause()
             && trait_clause.polarity() == goal.predicate.polarity
-            && trait_def_id_matches(ecx.cx(), trait_clause.def_id(), goal.predicate.def_id())
+            && trait_def_id_matches(
+                ecx.cx(),
+                trait_clause.def_id(),
+                goal.predicate.def_id(),
+                goal.predicate.polarity,
+            )
             && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
                 goal.predicate.trait_ref.args,
                 trait_clause.skip_binder().trait_ref.args,
@@ -168,6 +175,8 @@ where
         // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so
         // check for a `Sized` subtrait when looking for `MetaSized`. `PointeeSized` bounds
         // are syntactic sugar for a lack of bounds so don't need this.
+        // We don't need to check polarity, `fast_reject_assumption` already rejected non-`Positive`
+        // polarity `Sized` assumptions as matching non-`Positive` `MetaSized` goals.
         if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
             && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
         {
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 9e0075c21b9..a107a682184 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -748,9 +748,6 @@ parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call
     .suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters
     .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
 
-parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
-parse_parenthesized_lifetime_suggestion = remove the parentheses
-
 parse_path_double_colon = path separator must be a double colon
     .suggestion = use a double colon instead
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index a105dd1909e..2c046329e33 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -3163,27 +3163,6 @@ pub(crate) struct ModifierLifetime {
     pub modifier: &'static str,
 }
 
-#[derive(Subdiagnostic)]
-#[multipart_suggestion(
-    parse_parenthesized_lifetime_suggestion,
-    applicability = "machine-applicable"
-)]
-pub(crate) struct RemoveParens {
-    #[suggestion_part(code = "")]
-    pub lo: Span,
-    #[suggestion_part(code = "")]
-    pub hi: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parse_parenthesized_lifetime)]
-pub(crate) struct ParenthesizedLifetime {
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub sugg: RemoveParens,
-}
-
 #[derive(Diagnostic)]
 #[diag(parse_underscore_literal_suffix)]
 pub(crate) struct UnderscoreLiteralSuffix {
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 85af5a615ae..7c7e7e50b27 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -49,6 +49,7 @@ pub(crate) fn lex_token_trees<'psess, 'src>(
     mut src: &'src str,
     mut start_pos: BytePos,
     override_span: Option<Span>,
+    frontmatter_allowed: FrontmatterAllowed,
 ) -> Result<TokenStream, Vec<Diag<'psess>>> {
     // Skip `#!`, if present.
     if let Some(shebang_len) = rustc_lexer::strip_shebang(src) {
@@ -56,7 +57,7 @@ pub(crate) fn lex_token_trees<'psess, 'src>(
         start_pos = start_pos + BytePos::from_usize(shebang_len);
     }
 
-    let cursor = Cursor::new(src, FrontmatterAllowed::Yes);
+    let cursor = Cursor::new(src, frontmatter_allowed);
     let mut lexer = Lexer {
         psess,
         start_pos,
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 2050c5f9608..adad5751871 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -20,6 +20,7 @@ use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{AttrItem, Attribute, MetaItemInner, token};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize};
+use rustc_lexer::FrontmatterAllowed;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{FileName, SourceFile, Span};
@@ -146,7 +147,7 @@ fn new_parser_from_source_file(
     source_file: Arc<SourceFile>,
 ) -> Result<Parser<'_>, Vec<Diag<'_>>> {
     let end_pos = source_file.end_position();
-    let stream = source_file_to_stream(psess, source_file, None)?;
+    let stream = source_file_to_stream(psess, source_file, None, FrontmatterAllowed::Yes)?;
     let mut parser = Parser::new(psess, stream, None);
     if parser.token == token::Eof {
         parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None);
@@ -161,7 +162,9 @@ pub fn source_str_to_stream(
     override_span: Option<Span>,
 ) -> Result<TokenStream, Vec<Diag<'_>>> {
     let source_file = psess.source_map().new_source_file(name, source);
-    source_file_to_stream(psess, source_file, override_span)
+    // used mainly for `proc_macro` and the likes, not for our parsing purposes, so don't parse
+    // frontmatters as frontmatters.
+    source_file_to_stream(psess, source_file, override_span, FrontmatterAllowed::No)
 }
 
 /// Given a source file, produces a sequence of token trees. Returns any buffered errors from
@@ -170,6 +173,7 @@ fn source_file_to_stream<'psess>(
     psess: &'psess ParseSess,
     source_file: Arc<SourceFile>,
     override_span: Option<Span>,
+    frontmatter_allowed: FrontmatterAllowed,
 ) -> Result<TokenStream, Vec<Diag<'psess>>> {
     let src = source_file.src.as_ref().unwrap_or_else(|| {
         psess.dcx().bug(format!(
@@ -178,7 +182,13 @@ fn source_file_to_stream<'psess>(
         ));
     });
 
-    lexer::lex_token_trees(psess, src.as_str(), source_file.start_pos, override_span)
+    lexer::lex_token_trees(
+        psess,
+        src.as_str(),
+        source_file.start_pos,
+        override_span,
+        frontmatter_allowed,
+    )
 }
 
 /// Runs the given subparser `f` on the tokens of the given `attr`'s item.
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index d0604f76317..ea8cd3754a0 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2397,12 +2397,12 @@ impl<'a> Parser<'a> {
         let before = self.prev_token;
         let binder = if self.check_keyword(exp!(For)) {
             let lo = self.token.span;
-            let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
+            let (bound_vars, _) = self.parse_higher_ranked_binder()?;
             let span = lo.to(self.prev_token.span);
 
             self.psess.gated_spans.gate(sym::closure_lifetime_binder, span);
 
-            ClosureBinder::For { span, generic_params: lifetime_defs }
+            ClosureBinder::For { span, generic_params: bound_vars }
         } else {
             ClosureBinder::NotPresent
         };
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 4a8530a2b38..eb684c3a62f 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -172,8 +172,11 @@ impl<'a> Parser<'a> {
         })
     }
 
-    /// Parses a (possibly empty) list of lifetime and type parameters, possibly including
-    /// a trailing comma and erroneous trailing attributes.
+    /// Parse a (possibly empty) list of generic (lifetime, type, const) parameters.
+    ///
+    /// ```ebnf
+    /// GenericParams = (GenericParam ("," GenericParam)* ","?)?
+    /// ```
     pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec<ast::GenericParam>> {
         let mut params = ThinVec::new();
         let mut done = false;
@@ -520,7 +523,7 @@ impl<'a> Parser<'a> {
         // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
         // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
         // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
-        let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
+        let (bound_vars, _) = self.parse_higher_ranked_binder()?;
 
         // Parse type with mandatory colon and (possibly empty) bounds,
         // or with mandatory equality sign and the second type.
@@ -528,7 +531,7 @@ impl<'a> Parser<'a> {
         if self.eat(exp!(Colon)) {
             let bounds = self.parse_generic_bounds()?;
             Ok(ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
-                bound_generic_params: lifetime_defs,
+                bound_generic_params: bound_vars,
                 bounded_ty: ty,
                 bounds,
             }))
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index ca89eb1e2cf..fd9fb65417c 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -43,7 +43,7 @@ impl<'a> Parser<'a> {
             self.expect(exp!(OpenBrace))?;
             let (inner_attrs, items, inner_span) = self.parse_mod(exp!(CloseBrace))?;
             attrs.extend(inner_attrs);
-            ModKind::Loaded(items, Inline::Yes, inner_span, Ok(()))
+            ModKind::Loaded(items, Inline::Yes, inner_span)
         };
         Ok(ItemKind::Mod(safety, ident, mod_kind))
     }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 41ed1f95a01..21f42b54f21 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1388,15 +1388,26 @@ impl<'a> Parser<'a> {
             // matching `CloseDelim` we are *after* the delimited sequence,
             // i.e. at depth `d - 1`.
             let target_depth = self.token_cursor.stack.len() - 1;
-            loop {
-                // Advance one token at a time, so `TokenCursor::next()`
-                // can capture these tokens if necessary.
+
+            if let Capturing::No = self.capture_state.capturing {
+                // We are not capturing tokens, so skip to the end of the
+                // delimited sequence. This is a perf win when dealing with
+                // declarative macros that pass large `tt` fragments through
+                // multiple rules, as seen in the uom-0.37.0 crate.
+                self.token_cursor.curr.bump_to_end();
                 self.bump();
-                if self.token_cursor.stack.len() == target_depth {
-                    debug_assert!(self.token.kind.close_delim().is_some());
-                    break;
+                debug_assert_eq!(self.token_cursor.stack.len(), target_depth);
+            } else {
+                loop {
+                    // Advance one token at a time, so `TokenCursor::next()`
+                    // can capture these tokens if necessary.
+                    self.bump();
+                    if self.token_cursor.stack.len() == target_depth {
+                        break;
+                    }
                 }
             }
+            debug_assert!(self.token.kind.close_delim().is_some());
 
             // Consume close delimiter
             self.bump();
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 290f0a440af..899a43955ab 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -308,11 +308,11 @@ impl<'a> Parser<'a> {
             // Function pointer type or bound list (trait object type) starting with a poly-trait.
             //   `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
             //   `for<'lt> Trait1<'lt> + Trait2 + 'a`
-            let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
+            let (bound_vars, _) = self.parse_higher_ranked_binder()?;
             if self.check_fn_front_matter(false, Case::Sensitive) {
                 self.parse_ty_fn_ptr(
                     lo,
-                    lifetime_defs,
+                    bound_vars,
                     Some(self.prev_token.span.shrink_to_lo()),
                     recover_return_sign,
                 )?
@@ -326,7 +326,7 @@ impl<'a> Parser<'a> {
                     let path = self.parse_path(PathStyle::Type)?;
                     let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
                     let kind = self.parse_remaining_bounds_path(
-                        lifetime_defs,
+                        bound_vars,
                         path,
                         lo,
                         parse_plus,
@@ -359,7 +359,7 @@ impl<'a> Parser<'a> {
                     let path = self.parse_path(PathStyle::Type)?;
                     let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
                     self.parse_remaining_bounds_path(
-                        lifetime_defs,
+                        bound_vars,
                         path,
                         lo,
                         parse_plus,
@@ -443,7 +443,7 @@ impl<'a> Parser<'a> {
             let ty = ts.into_iter().next().unwrap();
             let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();
             match ty.kind {
-                // `(TY_BOUND_NOPAREN) + BOUND + ...`.
+                // `"(" BareTraitBound ")" "+" Bound "+" ...`.
                 TyKind::Path(None, path) if maybe_bounds => self.parse_remaining_bounds_path(
                     ThinVec::new(),
                     path,
@@ -853,10 +853,13 @@ impl<'a> Parser<'a> {
         Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
     }
 
-    fn parse_precise_capturing_args(
-        &mut self,
-    ) -> PResult<'a, (ThinVec<PreciseCapturingArg>, Span)> {
-        let lo = self.token.span;
+    /// Parse a use-bound aka precise capturing list.
+    ///
+    /// ```ebnf
+    /// UseBound = "use" "<" (PreciseCapture ("," PreciseCapture)* ","?)? ">"
+    /// PreciseCapture = "Self" | Ident | Lifetime
+    /// ```
+    fn parse_use_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> {
         self.expect_lt()?;
         let (args, _, _) = self.parse_seq_to_before_tokens(
             &[exp!(Gt)],
@@ -882,7 +885,13 @@ impl<'a> Parser<'a> {
             },
         )?;
         self.expect_gt()?;
-        Ok((args, lo.to(self.prev_token.span)))
+
+        if let ast::Parens::Yes = parens {
+            self.expect(exp!(CloseParen))?;
+            self.report_parenthesized_bound(lo, self.prev_token.span, "precise capturing lists");
+        }
+
+        Ok(GenericBound::Use(args, lo.to(self.prev_token.span)))
     }
 
     /// Is a `dyn B0 + ... + Bn` type allowed here?
@@ -940,9 +949,10 @@ impl<'a> Parser<'a> {
         self.parse_generic_bounds_common(AllowPlus::Yes)
     }
 
-    /// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
+    /// Parse generic bounds.
     ///
-    /// See `parse_generic_bound` for the `BOUND` grammar.
+    /// Only if `allow_plus` this parses a `+`-separated list of bounds (trailing `+` is admitted).
+    /// Otherwise, this only parses a single bound or none.
     fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {
         let mut bounds = Vec::new();
 
@@ -988,48 +998,56 @@ impl<'a> Parser<'a> {
             || self.check_keyword(exp!(Use))
     }
 
-    /// Parses a bound according to the grammar:
+    /// Parse a bound.
+    ///
     /// ```ebnf
-    /// BOUND = TY_BOUND | LT_BOUND
+    /// Bound = LifetimeBound | UseBound | TraitBound
     /// ```
     fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
-        let lo = self.token.span;
         let leading_token = self.prev_token;
+        let lo = self.token.span;
+
+        // We only admit parenthesized *trait* bounds. However, we want to gracefully recover from
+        // other kinds of parenthesized bounds, so parse the opening parenthesis *here*.
+        //
+        // In the future we might want to lift this syntactic restriction and
+        // introduce "`GenericBound::Paren(Box<GenericBound>)`".
         let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No };
 
-        let bound = if self.token.is_lifetime() {
-            self.parse_generic_lt_bound(lo, parens)?
+        if self.token.is_lifetime() {
+            self.parse_lifetime_bound(lo, parens)
         } else if self.eat_keyword(exp!(Use)) {
-            // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
-            // lifetimes and ident params (including SelfUpper). These are validated later
-            // for order, duplication, and whether they actually reference params.
-            let use_span = self.prev_token.span;
-            let (args, args_span) = self.parse_precise_capturing_args()?;
-            GenericBound::Use(args, use_span.to(args_span))
+            self.parse_use_bound(lo, parens)
         } else {
-            self.parse_generic_ty_bound(lo, parens, &leading_token)?
-        };
-
-        Ok(bound)
+            self.parse_trait_bound(lo, parens, &leading_token)
+        }
     }
 
-    /// Parses a lifetime ("outlives") bound, e.g. `'a`, according to:
+    /// Parse a lifetime-bound aka outlives-bound.
+    ///
     /// ```ebnf
-    /// LT_BOUND = LIFETIME
+    /// LifetimeBound = Lifetime
     /// ```
-    fn parse_generic_lt_bound(
-        &mut self,
-        lo: Span,
-        parens: ast::Parens,
-    ) -> PResult<'a, GenericBound> {
+    fn parse_lifetime_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> {
         let lt = self.expect_lifetime();
-        let bound = GenericBound::Outlives(lt);
+
         if let ast::Parens::Yes = parens {
-            // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
-            // possibly introducing `GenericBound::Paren(Box<GenericBound>)`?
-            self.recover_paren_lifetime(lo)?;
+            self.expect(exp!(CloseParen))?;
+            self.report_parenthesized_bound(lo, self.prev_token.span, "lifetime bounds");
         }
-        Ok(bound)
+
+        Ok(GenericBound::Outlives(lt))
+    }
+
+    fn report_parenthesized_bound(&self, lo: Span, hi: Span, kind: &str) -> ErrorGuaranteed {
+        let mut diag =
+            self.dcx().struct_span_err(lo.to(hi), format!("{kind} may not be parenthesized"));
+        diag.multipart_suggestion(
+            "remove the parentheses",
+            vec![(lo, String::new()), (hi, String::new())],
+            Applicability::MachineApplicable,
+        );
+        diag.emit()
     }
 
     /// Emits an error if any trait bound modifiers were present.
@@ -1074,27 +1092,17 @@ impl<'a> Parser<'a> {
         unreachable!("lifetime bound intercepted in `parse_generic_ty_bound` but no modifiers?")
     }
 
-    /// Recover on `('lifetime)` with `(` already eaten.
-    fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> {
-        self.expect(exp!(CloseParen))?;
-        let span = lo.to(self.prev_token.span);
-        let sugg = errors::RemoveParens { lo, hi: self.prev_token.span };
-
-        self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg });
-        Ok(())
-    }
-
     /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `[const] Trait`.
     ///
     /// If no modifiers are present, this does not consume any tokens.
     ///
     /// ```ebnf
-    /// CONSTNESS = [["["] "const" ["]"]]
-    /// ASYNCNESS = ["async"]
-    /// POLARITY = ["?" | "!"]
+    /// Constness = ("const" | "[" "const" "]")?
+    /// Asyncness = "async"?
+    /// Polarity = ("?" | "!")?
     /// ```
     ///
-    /// See `parse_generic_ty_bound` for the complete grammar of trait bound modifiers.
+    /// See `parse_trait_bound` for more context.
     fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
         let modifier_lo = self.token.span;
         let constness = self.parse_bound_constness()?;
@@ -1187,20 +1195,21 @@ impl<'a> Parser<'a> {
         })
     }
 
-    /// Parses a type bound according to:
+    /// Parse a trait bound.
+    ///
     /// ```ebnf
-    /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
-    /// TY_BOUND_NOPAREN = [for<GENERIC_PARAMS> CONSTNESS ASYNCNESS | POLARITY] SIMPLE_PATH
+    /// TraitBound = BareTraitBound | "(" BareTraitBound ")"
+    /// BareTraitBound =
+    ///     (HigherRankedBinder Constness Asyncness | Polarity)
+    ///     TypePath
     /// ```
-    ///
-    /// For example, this grammar accepts `for<'a: 'b> [const] ?m::Trait<'a>`.
-    fn parse_generic_ty_bound(
+    fn parse_trait_bound(
         &mut self,
         lo: Span,
         parens: ast::Parens,
         leading_token: &Token,
     ) -> PResult<'a, GenericBound> {
-        let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?;
+        let (mut bound_vars, binder_span) = self.parse_higher_ranked_binder()?;
 
         let modifiers_lo = self.token.span;
         let modifiers = self.parse_trait_bound_modifiers()?;
@@ -1223,11 +1232,11 @@ impl<'a> Parser<'a> {
         // e.g. `T: for<'a> 'a` or `T: [const] 'a`.
         if self.token.is_lifetime() {
             let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span);
-            return self.parse_generic_lt_bound(lo, parens);
+            return self.parse_lifetime_bound(lo, parens);
         }
 
-        if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? {
-            lifetime_defs.extend(more_lifetime_defs);
+        if let (more_bound_vars, Some(binder_span)) = self.parse_higher_ranked_binder()? {
+            bound_vars.extend(more_bound_vars);
             self.dcx().emit_err(errors::BinderBeforeModifiers { binder_span, modifiers_span });
         }
 
@@ -1287,7 +1296,7 @@ impl<'a> Parser<'a> {
         };
 
         if self.may_recover() && self.token == TokenKind::OpenParen {
-            self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?;
+            self.recover_fn_trait_with_lifetime_params(&mut path, &mut bound_vars)?;
         }
 
         if let ast::Parens::Yes = parens {
@@ -1310,7 +1319,7 @@ impl<'a> Parser<'a> {
         }
 
         let poly_trait =
-            PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span), parens);
+            PolyTraitRef::new(bound_vars, path, modifiers, lo.to(self.prev_token.span), parens);
         Ok(GenericBound::Trait(poly_trait))
     }
 
@@ -1349,8 +1358,12 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Optionally parses `for<$generic_params>`.
-    pub(super) fn parse_late_bound_lifetime_defs(
+    /// Parse an optional higher-ranked binder.
+    ///
+    /// ```ebnf
+    /// HigherRankedBinder = ("for" "<" GenericParams ">")?
+    /// ```
+    pub(super) fn parse_higher_ranked_binder(
         &mut self,
     ) -> PResult<'a, (ThinVec<GenericParam>, Option<Span>)> {
         if self.eat_keyword(exp!(For)) {
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 7481b0ea960..00a41e31a02 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -74,6 +74,16 @@ passes_const_stable_not_stable =
     attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
     .label = attribute specified here
 
+passes_custom_mir_incompatible_dialect_and_phase =
+    The {$dialect} dialect is not compatible with the {$phase} phase
+    .dialect_span = this dialect...
+    .phase_span = ... is not compatible with this phase
+
+passes_custom_mir_phase_requires_dialect =
+    `dialect` key required
+    .phase_span = `phase` argument requires a `dialect` argument
+
+
 passes_dead_codes =
     { $multiple ->
       *[true] multiple {$descr}s are
@@ -422,10 +432,6 @@ passes_must_not_suspend =
     `must_not_suspend` attribute should be applied to a struct, enum, union, or trait
     .label = is not a struct, enum, union, or trait
 
-passes_must_use_no_effect =
-    `#[must_use]` has no effect when applied to {$target}
-    .suggestion = remove the attribute
-
 passes_no_link =
     attribute should be applied to an `extern crate` item
     .label = not an `extern crate` item
@@ -444,10 +450,6 @@ passes_no_main_function =
     .teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/
     .non_function_main = non-function item at `crate::main` is found
 
-passes_no_sanitize =
-    `#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind}
-    .label = not {$accepted_kind}
-
 passes_non_exhaustive_with_default_field_values =
     `#[non_exhaustive]` can't be used to annotate items with default field values
     .label = this struct has default field values
@@ -542,6 +544,12 @@ passes_rustc_pub_transparent =
     attribute should be applied to `#[repr(transparent)]` types
     .label = not a `#[repr(transparent)]` type
 
+passes_sanitize_attribute_not_allowed =
+    sanitize attribute not allowed here
+    .not_fn_impl_mod = not a function, impl block, or module
+    .no_body = function has no body
+    .help = sanitize attribute can be applied to a function (with body), impl block, or module
+
 passes_should_be_applied_to_fn =
     attribute should be applied to a function definition
     .label = {$on_crate ->
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 0e28c51e981..70eae82392c 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -18,7 +18,7 @@ use rustc_feature::{
     ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP,
     BuiltinAttribute,
 };
-use rustc_hir::attrs::{AttributeKind, InlineAttr, ReprAttr};
+use rustc_hir::attrs::{AttributeKind, InlineAttr, MirDialect, MirPhase, ReprAttr};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalModDefId;
 use rustc_hir::intravisit::{self, Visitor};
@@ -194,8 +194,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
                     self.check_may_dangle(hir_id, *attr_span)
                 }
-                Attribute::Parsed(AttributeKind::MustUse { span, .. }) => {
-                    self.check_must_use(hir_id, *span, target)
+                &Attribute::Parsed(AttributeKind::CustomMir(dialect, phase, attr_span)) => {
+                    self.check_custom_mir(dialect, phase, attr_span)
                 }
                 Attribute::Parsed(
                     AttributeKind::BodyStability { .. }
@@ -246,9 +246,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | AttributeKind::Coverage (..)
                     | AttributeKind::ShouldPanic { .. }
                     | AttributeKind::Coroutine(..)
-                    | AttributeKind::Linkage(..),
+                    | AttributeKind::Linkage(..)
+                    | AttributeKind::MustUse { .. },
                 ) => { /* do nothing  */ }
-
                 Attribute::Unparsed(attr_item) => {
                     style = Some(attr_item.style);
                     match attr.path().as_slice() {
@@ -258,8 +258,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [sym::diagnostic, sym::on_unimplemented, ..] => {
                             self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
                         }
-                        [sym::no_sanitize, ..] => {
-                            self.check_no_sanitize(attr, span, target)
+                        [sym::sanitize, ..] => {
+                            self.check_sanitize(attr, span, target)
                         }
                         [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
                         [sym::doc, ..] => self.check_doc_attrs(
@@ -331,8 +331,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             | sym::panic_handler
                             | sym::lang
                             | sym::needs_allocator
-                            | sym::default_lib_allocator
-                            | sym::custom_mir,
+                            | sym::default_lib_allocator,
                             ..
                         ] => {}
                         [name, rest@..] => {
@@ -482,39 +481,43 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) {
+    /// Checks that the `#[sanitize(..)]` attribute is applied to a
+    /// function/closure/method, or to an impl block or module.
+    fn check_sanitize(&self, attr: &Attribute, target_span: Span, target: Target) {
+        let mut not_fn_impl_mod = None;
+        let mut no_body = None;
+
         if let Some(list) = attr.meta_item_list() {
             for item in list.iter() {
-                let sym = item.name();
-                match sym {
-                    Some(s @ sym::address | s @ sym::hwaddress) => {
-                        let is_valid =
-                            matches!(target, Target::Fn | Target::Method(..) | Target::Static);
-                        if !is_valid {
-                            self.dcx().emit_err(errors::NoSanitize {
-                                attr_span: item.span(),
-                                defn_span: span,
-                                accepted_kind: "a function or static",
-                                attr_str: s.as_str(),
-                            });
-                        }
+                let MetaItemInner::MetaItem(set) = item else {
+                    return;
+                };
+                let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
+                match target {
+                    Target::Fn
+                    | Target::Closure
+                    | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
+                    | Target::Impl { .. }
+                    | Target::Mod => return,
+                    Target::Static if matches!(segments.as_slice(), [sym::address]) => return,
+
+                    // These are "functions", but they aren't allowed because they don't
+                    // have a body, so the usual explanation would be confusing.
+                    Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
+                        no_body = Some(target_span);
                     }
+
                     _ => {
-                        let is_valid = matches!(target, Target::Fn | Target::Method(..));
-                        if !is_valid {
-                            self.dcx().emit_err(errors::NoSanitize {
-                                attr_span: item.span(),
-                                defn_span: span,
-                                accepted_kind: "a function",
-                                attr_str: &match sym {
-                                    Some(name) => name.to_string(),
-                                    None => "...".to_string(),
-                                },
-                            });
-                        }
+                        not_fn_impl_mod = Some(target_span);
                     }
                 }
             }
+            self.dcx().emit_err(errors::SanitizeAttributeNotAllowed {
+                attr_span: attr.span(),
+                not_fn_impl_mod,
+                no_body,
+                help: (),
+            });
         }
     }
 
@@ -561,7 +564,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             }
         }
     }
-
     /// Checks if `#[collapse_debuginfo]` is applied to a macro.
     fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
@@ -1259,41 +1261,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    /// Warns against some misuses of `#[must_use]`
-    fn check_must_use(&self, hir_id: HirId, attr_span: Span, target: Target) {
-        if matches!(
-            target,
-            Target::Fn
-                | Target::Enum
-                | Target::Struct
-                | Target::Union
-                | Target::Method(MethodKind::Trait { body: false } | MethodKind::Inherent)
-                | Target::ForeignFn
-                // `impl Trait` in return position can trip
-                // `unused_must_use` if `Trait` is marked as
-                // `#[must_use]`
-                | Target::Trait
-        ) {
-            return;
-        }
-
-        // `#[must_use]` can be applied to a trait method definition with a default body
-        if let Target::Method(MethodKind::Trait { body: true }) = target
-            && let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id
-            && let containing_item = self.tcx.hir_expect_item(parent_def_id)
-            && let hir::ItemKind::Trait(..) = containing_item.kind
-        {
-            return;
-        }
-
-        self.tcx.emit_node_span_lint(
-            UNUSED_ATTRIBUTES,
-            hir_id,
-            attr_span,
-            errors::MustUseNoEffect { target: target.plural_name(), attr_span },
-        );
-    }
-
     /// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait.
     fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) {
         match target {
@@ -2113,6 +2080,48 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span });
         };
     }
+
+    fn check_custom_mir(
+        &self,
+        dialect: Option<(MirDialect, Span)>,
+        phase: Option<(MirPhase, Span)>,
+        attr_span: Span,
+    ) {
+        let Some((dialect, dialect_span)) = dialect else {
+            if let Some((_, phase_span)) = phase {
+                self.dcx()
+                    .emit_err(errors::CustomMirPhaseRequiresDialect { attr_span, phase_span });
+            }
+            return;
+        };
+
+        match dialect {
+            MirDialect::Analysis => {
+                if let Some((MirPhase::Optimized, phase_span)) = phase {
+                    self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase {
+                        dialect,
+                        phase: MirPhase::Optimized,
+                        attr_span,
+                        dialect_span,
+                        phase_span,
+                    });
+                }
+            }
+
+            MirDialect::Built => {
+                if let Some((phase, phase_span)) = phase {
+                    self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase {
+                        dialect,
+                        phase,
+                        attr_span,
+                        dialect_span,
+                        phase_span,
+                    });
+                }
+            }
+            MirDialect::Runtime => {}
+        }
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index c5d5155d0e5..4fec6b0798a 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -7,6 +7,7 @@ use rustc_errors::{
     MultiSpan, Subdiagnostic,
 };
 use rustc_hir::Target;
+use rustc_hir::attrs::{MirDialect, MirPhase};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{MainDefinition, Ty};
 use rustc_span::{DUMMY_SP, Span, Symbol};
@@ -357,14 +358,6 @@ pub(crate) struct BothFfiConstAndPure {
     pub attr_span: Span,
 }
 
-#[derive(LintDiagnostic)]
-#[diag(passes_must_use_no_effect)]
-pub(crate) struct MustUseNoEffect {
-    pub target: &'static str,
-    #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
-    pub attr_span: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(passes_must_not_suspend)]
 pub(crate) struct MustNotSuspend {
@@ -1488,15 +1481,21 @@ pub(crate) struct AttrCrateLevelOnlySugg {
     pub attr: Span,
 }
 
+/// "sanitize attribute not allowed here"
 #[derive(Diagnostic)]
-#[diag(passes_no_sanitize)]
-pub(crate) struct NoSanitize<'a> {
+#[diag(passes_sanitize_attribute_not_allowed)]
+pub(crate) struct SanitizeAttributeNotAllowed {
     #[primary_span]
     pub attr_span: Span,
-    #[label]
-    pub defn_span: Span,
-    pub accepted_kind: &'a str,
-    pub attr_str: &'a str,
+    /// "not a function, impl block, or module"
+    #[label(passes_not_fn_impl_mod)]
+    pub not_fn_impl_mod: Option<Span>,
+    /// "function has no body"
+    #[label(passes_no_body)]
+    pub no_body: Option<Span>,
+    /// "sanitize attribute can be applied to a function (with body), impl block, or module"
+    #[help]
+    pub help: (),
 }
 
 // FIXME(jdonszelmann): move back to rustc_attr
@@ -1570,3 +1569,25 @@ pub(crate) struct ReprAlignShouldBeAlign {
     pub span: Span,
     pub item: &'static str,
 }
+
+#[derive(Diagnostic)]
+#[diag(passes_custom_mir_phase_requires_dialect)]
+pub(crate) struct CustomMirPhaseRequiresDialect {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub phase_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_custom_mir_incompatible_dialect_and_phase)]
+pub(crate) struct CustomMirIncompatibleDialectAndPhase {
+    pub dialect: MirDialect,
+    pub phase: MirPhase,
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub dialect_span: Span,
+    #[label]
+    pub phase_span: Span,
+}
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index d5ff8a4b609..47280a93677 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -93,6 +93,9 @@ resolve_consider_adding_a_derive =
 resolve_consider_adding_macro_export =
     consider adding a `#[macro_export]` to the macro in the imported module
 
+resolve_consider_marking_as_pub_crate =
+    in case you want to use the macro within this crate only, reduce the visibility to `pub(crate)`
+
 resolve_consider_declaring_with_pub =
     consider declaring type or module `{$ident}` with `pub`
 
@@ -249,7 +252,7 @@ resolve_macro_cannot_use_as_attr =
     `{$ident}` exists, but has no `attr` rules
 
 resolve_macro_cannot_use_as_derive =
-     `{$ident}` exists, but a declarative macro cannot be used as a derive macro
+     `{$ident}` exists, but has no `derive` rules
 
 resolve_macro_defined_later =
     a macro with the same name exists, but it appears later
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 1eb4e1199e6..f75a625a279 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -11,7 +11,7 @@ use std::sync::Arc;
 use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
 use rustc_ast::{
     self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem,
-    ForeignItemKind, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias,
+    ForeignItemKind, Inline, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias,
 };
 use rustc_attr_parsing as attr;
 use rustc_attr_parsing::AttributeParser;
@@ -210,6 +210,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
+    /// Add every proc macro accessible from the current crate to the `macro_map` so diagnostics can
+    /// find them for suggestions.
+    pub(crate) fn register_macros_for_all_crates(&mut self) {
+        if !self.all_crate_macros_already_registered {
+            for def_id in self.cstore().all_proc_macro_def_ids() {
+                self.get_macro_by_def_id(def_id);
+            }
+            self.all_crate_macros_already_registered = true;
+        }
+    }
+
     pub(crate) fn build_reduced_graph(
         &mut self,
         fragment: &AstFragment,
@@ -474,6 +485,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             root_span,
             root_id,
             vis,
+            vis_span: item.vis.span,
         });
 
         self.r.indeterminate_imports.push(import);
@@ -801,7 +813,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             ItemKind::Mod(_, ident, ref mod_kind) => {
                 self.r.define_local(parent, ident, TypeNS, res, vis, sp, expansion);
 
-                if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind {
+                if let ast::ModKind::Loaded(_, Inline::No { had_parse_error: Err(_) }, _) = mod_kind
+                {
                     self.r.mods_with_parse_errors.insert(def_id);
                 }
                 self.parent_scope.module = self.r.new_local_module(
@@ -966,6 +979,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             span: item.span,
             module_path: Vec::new(),
             vis,
+            vis_span: item.vis.span,
         });
         if used {
             self.r.import_use_map.insert(import, Used::Other);
@@ -1100,6 +1114,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 span,
                 module_path: Vec::new(),
                 vis: Visibility::Restricted(CRATE_DEF_ID),
+                vis_span: item.vis.span,
             })
         };
 
@@ -1270,6 +1285,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                     span,
                     module_path: Vec::new(),
                     vis,
+                    vis_span: item.vis.span,
                 });
                 self.r.import_use_map.insert(import, Used::Other);
                 let import_binding = self.r.import(binding, import);
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index a437f86e377..64641ecc080 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1469,33 +1469,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         krate: &Crate,
         sugg_span: Option<Span>,
     ) {
-        // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used
-        // for suggestions.
-        self.cm().visit_scopes(
-            ScopeSet::Macro(MacroKind::Derive),
-            &parent_scope,
-            ident.span.ctxt(),
-            |this, scope, _use_prelude, _ctxt| {
-                let Scope::Module(m, _) = scope else {
-                    return None;
-                };
-                for (_, resolution) in this.resolutions(m).borrow().iter() {
-                    let Some(binding) = resolution.borrow().best_binding() else {
-                        continue;
-                    };
-                    let Res::Def(DefKind::Macro(kinds), def_id) = binding.res() else {
-                        continue;
-                    };
-                    if !kinds.intersects(MacroKinds::ATTR | MacroKinds::DERIVE) {
-                        continue;
-                    }
-                    // By doing this all *imported* macros get added to the `macro_map` even if they
-                    // are *unused*, which makes the later suggestions find them and work.
-                    let _ = this.get_macro_by_def_id(def_id);
-                }
-                None::<()>
-            },
-        );
+        // Bring all unused `derive` macros into `macro_map` so we ensure they can be used for
+        // suggestions.
+        self.register_macros_for_all_crates();
 
         let is_expected =
             &|res: Res| res.macro_kinds().is_some_and(|k| k.contains(macro_kind.into()));
@@ -3434,7 +3410,7 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
 
     fn visit_item(&mut self, item: &'tcx ast::Item) {
         if self.target_module == item.id {
-            if let ItemKind::Mod(_, _, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind {
+            if let ItemKind::Mod(_, _, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind {
                 let inject = mod_spans.inject_use_span;
                 if is_span_suitable_for_use_injection(inject) {
                     self.first_legal_span = Some(inject);
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index a1d62ba7a68..63d6fa23a14 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -776,6 +776,17 @@ pub(crate) struct ConsiderAddingMacroExport {
 }
 
 #[derive(Subdiagnostic)]
+#[suggestion(
+    resolve_consider_marking_as_pub_crate,
+    code = "pub(crate)",
+    applicability = "maybe-incorrect"
+)]
+pub(crate) struct ConsiderMarkingAsPubCrate {
+    #[primary_span]
+    pub(crate) vis_span: Span,
+}
+
+#[derive(Subdiagnostic)]
 #[note(resolve_consider_marking_as_pub)]
 pub(crate) struct ConsiderMarkingAsPub {
     #[primary_span]
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index c1b3aff4e69..650154d586f 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -528,7 +528,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                                         orig_ident.span,
                                         BuiltinLintDiag::ProcMacroDeriveResolutionFallback {
                                             span: orig_ident.span,
-                                            ns,
+                                            ns_descr: ns.descr(),
                                             ident,
                                         },
                                     );
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 7c93fdb88ee..d3790394d2a 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -30,7 +30,7 @@ use crate::diagnostics::{DiagMode, Suggestion, import_candidates};
 use crate::errors::{
     CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate,
     CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates,
-    ConsiderAddingMacroExport, ConsiderMarkingAsPub,
+    ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate,
 };
 use crate::{
     AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion,
@@ -184,6 +184,9 @@ pub(crate) struct ImportData<'ra> {
     /// |`use foo`        | `ModuleOrUniformRoot::CurrentScope`           | - |
     pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>,
     pub vis: Visibility,
+
+    /// Span of the visibility.
+    pub vis_span: Span,
 }
 
 /// All imports are unique and allocated on a same arena,
@@ -866,7 +869,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             }
             ImportKind::Glob { .. } => {
                 // FIXME: Use mutable resolver directly as a hack, this should be an output of
-                // specualtive resolution.
+                // speculative resolution.
                 self.get_mut_unchecked().resolve_glob_import(import);
                 return 0;
             }
@@ -903,7 +906,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         // We need the `target`, `source` can be extracted.
                         let imported_binding = this.import(binding, import);
                         // FIXME: Use mutable resolver directly as a hack, this should be an output of
-                        // specualtive resolution.
+                        // speculative resolution.
                         this.get_mut_unchecked().define_binding_local(
                             parent,
                             target,
@@ -917,7 +920,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         if target.name != kw::Underscore {
                             let key = BindingKey::new(target, ns);
                             // FIXME: Use mutable resolver directly as a hack, this should be an output of
-                            // specualtive resolution.
+                            // speculative resolution.
                             this.get_mut_unchecked().update_local_resolution(
                                 parent,
                                 key,
@@ -1368,6 +1371,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                             err.subdiagnostic( ConsiderAddingMacroExport {
                                 span: binding.span,
                             });
+                            err.subdiagnostic( ConsiderMarkingAsPubCrate {
+                                vis_span: import.vis_span,
+                            });
                         }
                         _ => {
                             err.subdiagnostic( ConsiderMarkingAsPub {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 5200f9340e1..679e663f886 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -4270,7 +4270,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                         if path.len() == 2
                             && let [segment] = prefix_path
                         {
-                            // Delay to check whether methond name is an associated function or not
+                            // Delay to check whether method name is an associated function or not
                             // ```
                             // let foo = Foo {};
                             // foo::bar(); // possibly suggest to foo.bar();
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index ca9c124fca6..2063c46124c 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -781,7 +781,10 @@ impl<'ra> std::ops::Deref for Module<'ra> {
 
 impl<'ra> fmt::Debug for Module<'ra> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self.res())
+        match self.kind {
+            ModuleKind::Block => write!(f, "block"),
+            ModuleKind::Def(..) => write!(f, "{:?}", self.res()),
+        }
     }
 }
 
@@ -1267,6 +1270,10 @@ pub struct Resolver<'ra, 'tcx> {
 
     mods_with_parse_errors: FxHashSet<DefId>,
 
+    /// Whether `Resolver::register_macros_for_all_crates` has been called once already, as we
+    /// don't need to run it more than once.
+    all_crate_macros_already_registered: bool = false,
+
     // Stores pre-expansion and pre-placeholder-fragment-insertion names for `impl Trait` types
     // that were encountered during resolution. These names are used to generate item names
     // for APITs, so we don't want to leak details of resolution into these names.
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index 528c52eace7..80754964c43 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -49,6 +49,8 @@ session_hexadecimal_float_literal_not_supported = hexadecimal float literal is n
 session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target
     .note = compatible flavors are: {$compatible_list}
 
+session_indirect_branch_cs_prefix_requires_x86_or_x86_64 = `-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64
+
 session_instrumentation_not_supported = {$us} instrumentation is not supported for this target
 
 session_int_literal_too_large = integer literal is too large
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index bf95014843d..9471807df01 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -472,6 +472,10 @@ pub(crate) struct FunctionReturnRequiresX86OrX8664;
 pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel;
 
 #[derive(Diagnostic)]
+#[diag(session_indirect_branch_cs_prefix_requires_x86_or_x86_64)]
+pub(crate) struct IndirectBranchCsPrefixRequiresX86OrX8664;
+
+#[derive(Diagnostic)]
 #[diag(session_unsupported_regparm)]
 pub(crate) struct UnsupportedRegparm {
     pub(crate) regparm: u32,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 0e112edc733..6d5be2d92cd 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -2295,6 +2295,8 @@ options! {
         - hashes of green query instances
         - hash collisions of query keys
         - hash collisions when creating dep-nodes"),
+    indirect_branch_cs_prefix: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
+        "add `cs` prefix to `call` and `jmp` to indirect thunks (default: no)"),
     inline_llvm: bool = (true, parse_bool, [TRACKED],
         "enable LLVM inlining (default: yes)"),
     inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index c6956cf5f23..bb7ffa2a85d 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -44,6 +44,7 @@ use crate::config::{
     SwitchWithOptPath,
 };
 use crate::filesearch::FileSearch;
+use crate::lint::LintId;
 use crate::parse::{ParseSess, add_feature_diagnostics};
 use crate::search_paths::SearchPath;
 use crate::{errors, filesearch, lint};
@@ -139,7 +140,10 @@ pub struct CompilerIO {
     pub temps_dir: Option<PathBuf>,
 }
 
-pub trait LintStoreMarker: Any + DynSync + DynSend {}
+pub trait DynLintStore: Any + DynSync + DynSend {
+    /// Provides a way to access lint groups without depending on `rustc_lint`
+    fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = LintGroup> + '_>;
+}
 
 /// Represents the data associated with a compilation
 /// session for a single crate.
@@ -164,7 +168,7 @@ pub struct Session {
     pub code_stats: CodeStats,
 
     /// This only ever stores a `LintStore` but we don't want a dependency on that type here.
-    pub lint_store: Option<Arc<dyn LintStoreMarker>>,
+    pub lint_store: Option<Arc<dyn DynLintStore>>,
 
     /// Cap lint level specified by a driver specifically.
     pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -240,6 +244,12 @@ impl CodegenUnits {
     }
 }
 
+pub struct LintGroup {
+    pub name: &'static str,
+    pub lints: Vec<LintId>,
+    pub is_externally_loaded: bool,
+}
+
 impl Session {
     pub fn miri_unleashed_feature(&self, span: Span, feature_gate: Option<Symbol>) {
         self.miri_unleashed_features.lock().push((span, feature_gate));
@@ -596,6 +606,13 @@ impl Session {
             (&*self.target.staticlib_prefix, &*self.target.staticlib_suffix)
         }
     }
+
+    pub fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = LintGroup> + '_> {
+        match self.lint_store {
+            Some(ref lint_store) => lint_store.lint_groups_iter(),
+            None => Box::new(std::iter::empty()),
+        }
+    }
 }
 
 // JUSTIFICATION: defn of the suggested wrapper fns
@@ -1368,6 +1385,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         }
     }
 
+    if sess.opts.unstable_opts.indirect_branch_cs_prefix {
+        if sess.target.arch != "x86" && sess.target.arch != "x86_64" {
+            sess.dcx().emit_err(errors::IndirectBranchCsPrefixRequiresX86OrX8664);
+        }
+    }
+
     if let Some(regparm) = sess.opts.unstable_opts.regparm {
         if regparm > 3 {
             sess.dcx().emit_err(errors::UnsupportedRegparm { regparm });
diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs
index a887b50ec1e..41cfaa3ee34 100644
--- a/compiler/rustc_span/src/caching_source_map_view.rs
+++ b/compiler/rustc_span/src/caching_source_map_view.rs
@@ -123,27 +123,25 @@ impl<'sm> CachingSourceMapView<'sm> {
 
         if lo_cache_idx != -1 && hi_cache_idx != -1 {
             // Cache hit for span lo and hi. Check if they belong to the same file.
-            let result = {
-                let lo = &self.line_cache[lo_cache_idx as usize];
-                let hi = &self.line_cache[hi_cache_idx as usize];
+            let lo_file_index = self.line_cache[lo_cache_idx as usize].file_index;
+            let hi_file_index = self.line_cache[hi_cache_idx as usize].file_index;
 
-                if lo.file_index != hi.file_index {
-                    return None;
-                }
-
-                (
-                    lo.file.stable_id,
-                    lo.line_number,
-                    span_data.lo - lo.line.start,
-                    hi.line_number,
-                    span_data.hi - hi.line.start,
-                )
-            };
+            if lo_file_index != hi_file_index {
+                return None;
+            }
 
             self.line_cache[lo_cache_idx as usize].touch(self.time_stamp);
             self.line_cache[hi_cache_idx as usize].touch(self.time_stamp);
 
-            return Some(result);
+            let lo = &self.line_cache[lo_cache_idx as usize];
+            let hi = &self.line_cache[hi_cache_idx as usize];
+            return Some((
+                lo.file.stable_id,
+                lo.line_number,
+                span_data.lo - lo.line.start,
+                hi.line_number,
+                span_data.hi - hi.line.start,
+            ));
         }
 
         // No cache hit or cache hit for only one of span lo and hi.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index f4a6d0f5891..dcb1becc957 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -447,6 +447,7 @@ symbols! {
         altivec,
         alu32,
         always,
+        analysis,
         and,
         and_then,
         anon,
@@ -589,6 +590,7 @@ symbols! {
         btreemap_contains_key,
         btreemap_insert,
         btreeset_iter,
+        built,
         builtin_syntax,
         c,
         c_dash_variadic,
@@ -855,6 +857,7 @@ symbols! {
         destructuring_assignment,
         diagnostic,
         diagnostic_namespace,
+        dialect,
         direct,
         discriminant_kind,
         discriminant_type,
@@ -1211,6 +1214,7 @@ symbols! {
         infer_static_outlives_requirements,
         inherent_associated_types,
         inherit,
+        initial,
         inlateout,
         inline,
         inline_const,
@@ -1257,6 +1261,7 @@ symbols! {
         iterator,
         iterator_collect_fn,
         kcfi,
+        kernel_address,
         keylocker_x86,
         keyword,
         kind,
@@ -1325,6 +1330,7 @@ symbols! {
         macro_attr,
         macro_attributes_in_derive_output,
         macro_concat,
+        macro_derive,
         macro_escape,
         macro_export,
         macro_lifetime_matcher,
@@ -1546,6 +1552,7 @@ symbols! {
         opt_out_copy,
         optimize,
         optimize_attribute,
+        optimized,
         optin_builtin_traits,
         option,
         option_env,
@@ -1628,6 +1635,7 @@ symbols! {
         pattern_types,
         permissions_from_mode,
         phantom_data,
+        phase,
         pic,
         pie,
         pin,
@@ -1644,6 +1652,7 @@ symbols! {
         poll,
         poll_next,
         position,
+        post_cleanup: "post-cleanup",
         post_dash_lto: "post-lto",
         postfix_match,
         powerpc_target_feature,
@@ -1807,6 +1816,7 @@ symbols! {
         roundf128,
         rt,
         rtm_target_feature,
+        runtime,
         rust,
         rust_2015,
         rust_2018,
@@ -1827,6 +1837,7 @@ symbols! {
         rustc_align,
         rustc_allocator,
         rustc_allocator_zeroed,
+        rustc_allocator_zeroed_variant,
         rustc_allow_const_fn_unstable,
         rustc_allow_incoherent_impl,
         rustc_allowed_through_unstable_modules,
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index f3c96f64190..d97ee956525 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -193,29 +193,20 @@ fn compute_symbol_name<'tcx>(
         // defining crate.
         // Weak lang items automatically get #[rustc_std_internal_symbol]
         // applied by the code computing the CodegenFnAttrs.
-        // We are mangling all #[rustc_std_internal_symbol] items that don't
-        // also have #[no_mangle] as a combination of the rustc version and the
-        // unmangled linkage name. This is to ensure that if we link against a
-        // staticlib compiled by a different rustc version, we don't get symbol
-        // conflicts or even UB due to a different implementation/ABI. Rust
-        // staticlibs currently export all symbols, including those that are
-        // hidden in cdylibs.
+        // We are mangling all #[rustc_std_internal_symbol] items as a
+        // combination of the rustc version and the unmangled linkage name.
+        // This is to ensure that if we link against a staticlib compiled by a
+        // different rustc version, we don't get symbol conflicts or even UB
+        // due to a different implementation/ABI. Rust staticlibs currently
+        // export all symbols, including those that are hidden in cdylibs.
         // We are using the v0 symbol mangling scheme here as we need to be
         // consistent across all crates and in some contexts the legacy symbol
         // mangling scheme can't be used. For example both the GCC backend and
         // Rust-for-Linux don't support some of the characters used by the
         // legacy symbol mangling scheme.
-        let name = if tcx.is_foreign_item(def_id) {
-            if let Some(name) = attrs.link_name { name } else { tcx.item_name(def_id) }
-        } else {
-            if let Some(name) = attrs.export_name { name } else { tcx.item_name(def_id) }
-        };
+        let name = if let Some(name) = attrs.symbol_name { name } else { tcx.item_name(def_id) };
 
-        if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
-            return name.to_string();
-        } else {
-            return v0::mangle_internal_symbol(tcx, name.as_str());
-        }
+        return v0::mangle_internal_symbol(tcx, name.as_str());
     }
 
     let wasm_import_module_exception_force_mangling = {
@@ -240,23 +231,16 @@ fn compute_symbol_name<'tcx>(
             && tcx.wasm_import_module_map(LOCAL_CRATE).contains_key(&def_id.into())
     };
 
-    if let Some(name) = attrs.link_name
-        && !wasm_import_module_exception_force_mangling
-    {
-        // Use provided name
-        return name.to_string();
-    }
-
-    if let Some(name) = attrs.export_name {
-        // Use provided name
-        return name.to_string();
-    }
+    if !wasm_import_module_exception_force_mangling {
+        if let Some(name) = attrs.symbol_name {
+            // Use provided name
+            return name.to_string();
+        }
 
-    if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
-        && !wasm_import_module_exception_force_mangling
-    {
-        // Don't mangle
-        return tcx.item_name(def_id).to_string();
+        if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
+            // Don't mangle
+            return tcx.item_name(def_id).to_string();
+        }
     }
 
     // If we're dealing with an instance of a function that's inlined from
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index 56932c24922..57c90a703f1 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2024"
 bitflags = "2.4.1"
 rustc_abi = { path = "../rustc_abi" }
 rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_error_messages = { path = "../rustc_error_messages" }
 rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 63e56744aec..5f2a6f7ba38 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -119,6 +119,7 @@ mod attr_impl {
             const ReadOnly  = 1 << 4;
             const InReg     = 1 << 5;
             const NoUndef = 1 << 6;
+            const CapturesReadOnly = 1 << 7;
         }
     }
     rustc_data_structures::external_bitflags_debug! { ArgAttribute }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 2aa8ab5d317..399770022b2 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -50,6 +50,7 @@ use rustc_abi::{
     Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors,
 };
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_error_messages::{DiagArgValue, IntoDiagArg, into_diag_arg_using_display};
 use rustc_fs_util::try_canonicalize;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
@@ -875,6 +876,12 @@ impl FromStr for PanicStrategy {
 
 crate::json::serde_deserialize_from_str!(PanicStrategy);
 
+impl IntoDiagArg for PanicStrategy {
+    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(self.desc().to_string()))
+    }
+}
+
 impl ToJson for PanicStrategy {
     fn to_json(&self) -> Json {
         match *self {
@@ -1518,6 +1525,8 @@ impl fmt::Display for SplitDebuginfo {
     }
 }
 
+into_diag_arg_using_display!(SplitDebuginfo);
+
 #[derive(Clone, Debug, PartialEq, Eq, serde_derive::Deserialize)]
 #[serde(tag = "kind")]
 #[serde(rename_all = "kebab-case")]
@@ -1795,6 +1804,8 @@ impl fmt::Display for StackProtector {
     }
 }
 
+into_diag_arg_using_display!(StackProtector);
+
 #[derive(PartialEq, Clone, Debug)]
 pub enum BinaryFormat {
     Coff,
@@ -3806,3 +3817,5 @@ impl fmt::Display for TargetTuple {
         write!(f, "{}", self.debug_tuple())
     }
 }
+
+into_diag_arg_using_display!(&TargetTuple);
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld
index a4783de0183..0f3e6eeee19 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld
+++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld
@@ -17,15 +17,25 @@ PROVIDE(__vcodesig_type = 0);               /* V5_SIG_TYPE_USER     */
 PROVIDE(__vcodesig_owner = 2);              /* V5_SIG_OWNER_PARTNER */
 PROVIDE(__vcodesig_options = 0);            /* none (0)             */
 
-PROVIDE(__user_ram_start = 0x03800000);
-PROVIDE(__user_ram_length = 48M);
-PROVIDE(__user_ram_end = __user_ram_start + __user_ram_length); /* 0x8000000 */
+__user_ram_start = 0x03800000;
+__user_ram_end   = 0x08000000;
+/* (0x48 =) 72 MiB length */
+__user_ram_length = __user_ram_start - __user_ram_end;
 
-PROVIDE(__code_signature_length = 0x20);
+/*
+ * VEXos provides a method for pre-loading a "linked file" at a specified
+ * address in User RAM, conventionally near the end, after the primary
+ * program binary. We need to be sure not to place any data in that location,
+ * so we allow the user of this linker script to inform the start address of
+ * this blob.
+ */
+PROVIDE(__linked_file_length = 0);
+PROVIDE(__linked_file_end = __user_ram_end);
+PROVIDE(__linked_file_start = __linked_file_end - __linked_file_length);
 
 PROVIDE(__stack_length = 4M);
-PROVIDE(__heap_end = __user_ram_end - __stack_length);
-PROVIDE(__user_length = __heap_start - __user_ram_start);
+PROVIDE(__stack_top = __linked_file_start);
+PROVIDE(__stack_bottom = __linked_file_start - __stack_length);
 
 MEMORY {
     USER_RAM (RWX) : ORIGIN = __user_ram_start, LENGTH = __user_ram_length
@@ -44,7 +54,7 @@ SECTIONS {
         LONG(__vcodesig_options)
 
         FILL(0)
-        . = __user_ram_start + __code_signature_length;
+        . = __user_ram_start + 0x20;
     } > USER_RAM
 
     /*
@@ -125,7 +135,8 @@ SECTIONS {
      */
     .heap (NOLOAD) : {
         __heap_start = .;
-        . = __heap_end;
+        . = __stack_bottom;
+        __heap_end = .;
     } > USER_RAM
 
     .stack (NOLOAD) : ALIGN(8) {
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
index 53e2cb469ee..8892c50d844 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
@@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
         llvm_target,
         metadata: TargetMetadata {
             description: Some("x86_64 Apple macOS (10.12+, Sierra+)".into()),
-            tier: Some(1),
+            tier: Some(2),
             host_tools: Some(true),
             std: Some(true),
         },
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 507e938d5cc..e45300b59cc 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -767,6 +767,7 @@ static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
 
 static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
+    ("32s", Unstable(sym::loongarch_target_feature), &[]),
     ("d", Stable, &["f"]),
     ("div32", Unstable(sym::loongarch_target_feature), &[]),
     ("f", Stable, &[]),
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index ea1eed95723..4b493c95d59 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -106,6 +106,10 @@ fn dyn_compatibility_violations_for_trait(
     if !spans.is_empty() {
         violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
     }
+    let spans = super_predicates_are_unconditionally_const(tcx, trait_def_id);
+    if !spans.is_empty() {
+        violations.push(DynCompatibilityViolation::SupertraitConst(spans));
+    }
 
     violations
 }
@@ -247,16 +251,31 @@ fn super_predicates_have_non_lifetime_binders(
     tcx: TyCtxt<'_>,
     trait_def_id: DefId,
 ) -> SmallVec<[Span; 1]> {
-    // If non_lifetime_binders is disabled, then exit early
-    if !tcx.features().non_lifetime_binders() {
-        return SmallVec::new();
-    }
     tcx.explicit_super_predicates_of(trait_def_id)
         .iter_identity_copied()
         .filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(span))
         .collect()
 }
 
+/// Checks for `const Trait` supertraits. We're okay with `[const] Trait`,
+/// supertraits since for a non-const instantiation of that trait, the
+/// conditionally-const supertrait is also not required to be const.
+fn super_predicates_are_unconditionally_const(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+) -> SmallVec<[Span; 1]> {
+    tcx.explicit_super_predicates_of(trait_def_id)
+        .iter_identity_copied()
+        .filter_map(|(pred, span)| {
+            if let ty::ClauseKind::HostEffect(_) = pred.kind().skip_binder() {
+                Some(span)
+            } else {
+                None
+            }
+        })
+        .collect()
+}
+
 fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
     tcx.generics_require_sized_self(trait_def_id)
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 468c42abf48..1dd31990ab7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -4,9 +4,9 @@
 
 use std::assert_matches::assert_matches;
 use std::cell::{Cell, RefCell};
+use std::cmp;
 use std::fmt::{self, Display};
 use std::ops::ControlFlow;
-use std::{cmp, iter};
 
 use hir::def::DefKind;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -2185,32 +2185,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 ty::Binder::dummy(vec![ty])
             }
 
-            ty::Coroutine(coroutine_def_id, args) => {
-                match self.tcx().coroutine_movability(coroutine_def_id) {
-                    hir::Movability::Static => {
-                        unreachable!("tried to assemble `Sized` for static coroutine")
-                    }
-                    hir::Movability::Movable => {
-                        if self.tcx().features().coroutine_clone() {
-                            ty::Binder::dummy(
-                                args.as_coroutine()
-                                    .upvar_tys()
-                                    .iter()
-                                    .chain([Ty::new_coroutine_witness(
-                                        self.tcx(),
-                                        coroutine_def_id,
-                                        self.tcx().mk_args(args.as_coroutine().parent_args()),
-                                    )])
-                                    .collect::<Vec<_>>(),
-                            )
-                        } else {
-                            unreachable!(
-                                "tried to assemble `Sized` for coroutine without enabled feature"
-                            )
-                        }
+            ty::Coroutine(def_id, args) => match self.tcx().coroutine_movability(def_id) {
+                hir::Movability::Static => {
+                    unreachable!("tried to assemble `Clone` for static coroutine")
+                }
+                hir::Movability::Movable => {
+                    if self.tcx().features().coroutine_clone() {
+                        ty::Binder::dummy(vec![
+                            args.as_coroutine().tupled_upvars_ty(),
+                            Ty::new_coroutine_witness_for_coroutine(self.tcx(), def_id, args),
+                        ])
+                    } else {
+                        unreachable!(
+                            "tried to assemble `Clone` for coroutine without enabled feature"
+                        )
                     }
                 }
-            }
+            },
 
             ty::CoroutineWitness(def_id, args) => self
                 .infcx
@@ -2334,25 +2325,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             ty::Coroutine(def_id, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
                 let tcx = self.tcx();
-                let witness = Ty::new_coroutine_witness(
-                    tcx,
-                    def_id,
-                    ty::GenericArgs::for_item(tcx, def_id, |def, _| match def.kind {
-                        // HACK: Coroutine witnesse types are lifetime erased, so they
-                        // never reference any lifetime args from the coroutine. We erase
-                        // the regions here since we may get into situations where a
-                        // coroutine is recursively contained within itself, leading to
-                        // witness types that differ by region args. This means that
-                        // cycle detection in fulfillment will not kick in, which leads
-                        // to unnecessary overflows in async code. See the issue:
-                        // <https://github.com/rust-lang/rust/issues/145151>.
-                        ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-                        ty::GenericParamDefKind::Type { .. }
-                        | ty::GenericParamDefKind::Const { .. } => args[def.index as usize],
-                    }),
-                );
+                let witness = Ty::new_coroutine_witness_for_coroutine(tcx, def_id, args);
                 ty::Binder::dummy(AutoImplConstituents {
-                    types: [ty].into_iter().chain(iter::once(witness)).collect(),
+                    types: vec![ty, witness],
                     assumptions: vec![],
                 })
             }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 83c0969762f..335942d5bcc 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -9,8 +9,8 @@ pub use rustc_infer::traits::util::*;
 use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{
-    self, PolyTraitPredicate, SizedTraitKind, TraitPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
-    TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self, PolyTraitPredicate, PredicatePolarity, SizedTraitKind, TraitPredicate, TraitRef, Ty,
+    TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 pub use rustc_next_trait_solver::placeholder::BoundVarReplacer;
 use rustc_span::Span;
@@ -427,7 +427,9 @@ pub(crate) fn lazily_elaborate_sizedness_candidate<'tcx>(
         return candidate;
     }
 
-    if obligation.predicate.polarity() != candidate.polarity() {
+    if obligation.predicate.polarity() != PredicatePolarity::Positive
+        || candidate.polarity() != PredicatePolarity::Positive
+    {
         return candidate;
     }
 
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index 04aef4e7b9e..9f40f4d5c23 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -6,7 +6,6 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_hir = { path = "../rustc_hir" }
 rustc_infer = { path = "../rustc_infer" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs
index 8a2a0832ddb..20f9b013724 100644
--- a/compiler/rustc_traits/src/coroutine_witnesses.rs
+++ b/compiler/rustc_traits/src/coroutine_witnesses.rs
@@ -1,9 +1,9 @@
-use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::traits::{Obligation, ObligationCause};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions};
+use rustc_span::def_id::DefId;
 use rustc_trait_selection::traits::{ObligationCtxt, with_replaced_escaping_bound_vars};
 
 /// Return the set of types that should be taken into account when checking
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 5eddad39e2b..d33ade7a9e1 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -1,5 +1,4 @@
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_middle::bug;
@@ -7,6 +6,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
 use rustc_middle::ty::{self, GenericArgs, TyCtxt};
 use rustc_span::DUMMY_SP;
+use rustc_span::def_id::DefId;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::dropck_outlives::{
     compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner,
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 89d1dd8cf23..e4ed084b073 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -356,6 +356,7 @@ fn arg_attrs_for_rust_scalar<'tcx>(
 
             if matches!(kind, PointerKind::SharedRef { frozen: true }) && !is_return {
                 attrs.set(ArgAttribute::ReadOnly);
+                attrs.set(ArgAttribute::CapturesReadOnly);
             }
         }
     }
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index e7fee574dd4..d55e9b3b1be 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -12,6 +12,7 @@ indexmap = "2.0.0"
 rustc-hash = "2.0.0"
 rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
+rustc_error_messages = { path = "../rustc_error_messages", optional = true }
 rustc_index = { path = "../rustc_index", default-features = false }
 rustc_macros = { path = "../rustc_macros", optional = true }
 rustc_serialize = { path = "../rustc_serialize", optional = true }
@@ -27,6 +28,7 @@ tracing = "0.1"
 default = ["nightly"]
 nightly = [
     "dep:rustc_data_structures",
+    "dep:rustc_error_messages",
     "dep:rustc_macros",
     "dep:rustc_serialize",
     "dep:rustc_span",
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 1a6c99ce7de..569570b5783 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -91,6 +91,12 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn new_coroutine_witness(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
 
+    fn new_coroutine_witness_for_coroutine(
+        interner: I,
+        def_id: I::DefId,
+        coroutine_args: I::GenericArgs,
+    ) -> Self;
+
     fn new_ptr(interner: I, ty: Self, mutbl: Mutability) -> Self;
 
     fn new_ref(interner: I, region: I::Region, ty: Self, mutbl: Mutability) -> Self;
diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs
index 388ad09cb20..82bb8791b84 100644
--- a/compiler/rustc_type_ir/src/ir_print.rs
+++ b/compiler/rustc_type_ir/src/ir_print.rs
@@ -1,9 +1,9 @@
 use std::fmt;
 
 use crate::{
-    AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
-    HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, PatternKind,
-    ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
+    AliasTerm, AliasTy, Binder, ClosureKind, CoercePredicate, ExistentialProjection,
+    ExistentialTraitRef, FnSig, HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate,
+    PatternKind, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, UnevaluatedConst,
 };
 
 pub trait IrPrint<T> {
@@ -70,3 +70,46 @@ where
         <I as IrPrint<OutlivesPredicate<I, T>>>::print(self, fmt)
     }
 }
+
+#[cfg(feature = "nightly")]
+mod into_diag_arg_impls {
+    use rustc_error_messages::{DiagArgValue, IntoDiagArg};
+
+    use super::*;
+
+    impl<I: Interner> IntoDiagArg for TraitRef<I> {
+        fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+            self.to_string().into_diag_arg(path)
+        }
+    }
+
+    impl<I: Interner> IntoDiagArg for ExistentialTraitRef<I> {
+        fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+            self.to_string().into_diag_arg(path)
+        }
+    }
+
+    impl<I: Interner> IntoDiagArg for UnevaluatedConst<I> {
+        fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+            format!("{self:?}").into_diag_arg(path)
+        }
+    }
+
+    impl<I: Interner> IntoDiagArg for FnSig<I> {
+        fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+            format!("{self:?}").into_diag_arg(path)
+        }
+    }
+
+    impl<I: Interner, T: IntoDiagArg> IntoDiagArg for Binder<I, T> {
+        fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+            self.skip_binder().into_diag_arg(path)
+        }
+    }
+
+    impl IntoDiagArg for ClosureKind {
+        fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
+            DiagArgValue::Str(self.as_str().into())
+        }
+    }
+}
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 4b06f14c7ee..418a5f78397 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -336,10 +336,9 @@ dependencies = [
 name = "std_detect"
 version = "0.1.5"
 dependencies = [
- "alloc",
- "cfg-if",
- "core",
  "libc",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
 ]
 
 [[package]]
@@ -376,7 +375,6 @@ dependencies = [
 name = "unwind"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
  "libc",
  "rustc-std-workspace-core",
  "unwinding",
diff --git a/library/Cargo.toml b/library/Cargo.toml
index a79c17fc4f7..e30e6240942 100644
--- a/library/Cargo.toml
+++ b/library/Cargo.toml
@@ -59,4 +59,3 @@ rustflags = ["-Cpanic=abort"]
 rustc-std-workspace-core = { path = 'rustc-std-workspace-core' }
 rustc-std-workspace-alloc = { path = 'rustc-std-workspace-alloc' }
 rustc-std-workspace-std = { path = 'rustc-std-workspace-std' }
-compiler_builtins = { path = "compiler-builtins/compiler-builtins" }
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index c9b98fa4e5a..76630a746dd 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -17,6 +17,7 @@ unsafe extern "Rust" {
     #[rustc_allocator]
     #[rustc_nounwind]
     #[rustc_std_internal_symbol]
+    #[rustc_allocator_zeroed_variant = "__rust_alloc_zeroed"]
     fn __rust_alloc(size: usize, align: usize) -> *mut u8;
     #[rustc_deallocator]
     #[rustc_nounwind]
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index b3a498570f9..bb75ec74c81 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -621,11 +621,11 @@ impl<T, const N: usize> [T; N] {
     /// assert_eq!(strings.len(), 3);
     /// ```
     #[stable(feature = "array_methods", since = "1.77.0")]
-    #[rustc_const_unstable(feature = "const_array_each_ref", issue = "133289")]
+    #[rustc_const_stable(feature = "const_array_each_ref", since = "CURRENT_RUSTC_VERSION")]
     pub const fn each_ref(&self) -> [&T; N] {
         let mut buf = [null::<T>(); N];
 
-        // FIXME(const-hack): We would like to simply use iterators for this (as in the original implementation), but this is not allowed in constant expressions.
+        // FIXME(const_trait_impl): We would like to simply use iterators for this (as in the original implementation), but this is not allowed in constant expressions.
         let mut i = 0;
         while i < N {
             buf[i] = &raw const self[i];
@@ -652,11 +652,11 @@ impl<T, const N: usize> [T; N] {
     /// assert_eq!(floats, [0.0, 2.7, -1.0]);
     /// ```
     #[stable(feature = "array_methods", since = "1.77.0")]
-    #[rustc_const_unstable(feature = "const_array_each_ref", issue = "133289")]
+    #[rustc_const_stable(feature = "const_array_each_ref", since = "CURRENT_RUSTC_VERSION")]
     pub const fn each_mut(&mut self) -> [&mut T; N] {
         let mut buf = [null_mut::<T>(); N];
 
-        // FIXME(const-hack): We would like to simply use iterators for this (as in the original implementation), but this is not allowed in constant expressions.
+        // FIXME(const_trait_impl): We would like to simply use iterators for this (as in the original implementation), but this is not allowed in constant expressions.
         let mut i = 0;
         while i < N {
             buf[i] = &raw mut self[i];
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index a64fade285b..ab018fa2675 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -1554,6 +1554,9 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
 ///
 /// Returns the first argument if the comparison determines them to be equal.
 ///
+/// The parameter order is preserved when calling the `compare` function, i.e. `v1` is
+/// always passed as the first argument and `v2` as the second.
+///
 /// # Examples
 ///
 /// ```
@@ -1574,7 +1577,7 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
 pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
-    if compare(&v2, &v1).is_lt() { v2 } else { v1 }
+    if compare(&v1, &v2).is_le() { v1 } else { v2 }
 }
 
 /// Returns the element that gives the minimum value from the specified function.
@@ -1646,6 +1649,9 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
 ///
 /// Returns the second argument if the comparison determines them to be equal.
 ///
+/// The parameter order is preserved when calling the `compare` function, i.e. `v1` is
+/// always passed as the first argument and `v2` as the second.
+///
 /// # Examples
 ///
 /// ```
@@ -1666,7 +1672,7 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
 pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
-    if compare(&v2, &v1).is_lt() { v1 } else { v2 }
+    if compare(&v1, &v2).is_gt() { v1 } else { v2 }
 }
 
 /// Returns the element that gives the maximum value from the specified function.
@@ -1745,6 +1751,9 @@ where
 ///
 /// Returns `[v1, v2]` if the comparison determines them to be equal.
 ///
+/// The parameter order is preserved when calling the `compare` function, i.e. `v1` is
+/// always passed as the first argument and `v2` as the second.
+///
 /// # Examples
 ///
 /// ```
@@ -1769,7 +1778,7 @@ pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2]
 where
     F: FnOnce(&T, &T) -> Ordering,
 {
-    if compare(&v2, &v1).is_lt() { [v2, v1] } else { [v1, v2] }
+    if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] }
 }
 
 /// Returns minimum and maximum values with respect to the specified key function.
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index 7d41ae45093..605ba42c541 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -3,164 +3,78 @@
 use crate::fmt::NumBuffer;
 use crate::mem::MaybeUninit;
 use crate::num::fmt as numfmt;
-use crate::ops::{Div, Rem, Sub};
 use crate::{fmt, ptr, slice, str};
 
-#[doc(hidden)]
-trait DisplayInt:
-    PartialEq + PartialOrd + Div<Output = Self> + Rem<Output = Self> + Sub<Output = Self> + Copy
-{
-    fn zero() -> Self;
-    fn from_u8(u: u8) -> Self;
-    fn to_u8(&self) -> u8;
-    #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
-    fn to_u32(&self) -> u32;
-    fn to_u64(&self) -> u64;
-    fn to_u128(&self) -> u128;
-}
+/// Formatting of integers with a non-decimal radix.
+macro_rules! radix_integer {
+    (fmt::$Trait:ident for $Signed:ident and $Unsigned:ident, $prefix:literal, $dig_tab:literal) => {
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl fmt::$Trait for $Unsigned {
+            /// Format unsigned integers in the radix.
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                // Check macro arguments at compile time.
+                const {
+                    assert!($Unsigned::MIN == 0, "need unsigned");
+                    assert!($dig_tab.is_ascii(), "need single-byte entries");
+                }
 
-macro_rules! impl_int {
-    ($($t:ident)*) => (
-        $(impl DisplayInt for $t {
-            fn zero() -> Self { 0 }
-            fn from_u8(u: u8) -> Self { u as Self }
-            fn to_u8(&self) -> u8 { *self as u8 }
-            #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
-            fn to_u32(&self) -> u32 { *self as u32 }
-            fn to_u64(&self) -> u64 { *self as u64 }
-            fn to_u128(&self) -> u128 { *self as u128 }
-        })*
-    )
-}
+                // ASCII digits in ascending order are used as a lookup table.
+                const DIG_TAB: &[u8] = $dig_tab;
+                const BASE: $Unsigned = DIG_TAB.len() as $Unsigned;
+                const MAX_DIG_N: usize = $Unsigned::MAX.ilog(BASE) as usize + 1;
 
-impl_int! {
-    i8 i16 i32 i64 i128 isize
-    u8 u16 u32 u64 u128 usize
-}
+                // Buffer digits of self with right alignment.
+                let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DIG_N];
+                // Count the number of bytes in buf that are not initialized.
+                let mut offset = buf.len();
 
-/// A type that represents a specific radix
-///
-/// # Safety
-///
-/// `digit` must return an ASCII character.
-#[doc(hidden)]
-unsafe trait GenericRadix: Sized {
-    /// The number of digits.
-    const BASE: u8;
-
-    /// A radix-specific prefix string.
-    const PREFIX: &'static str;
-
-    /// Converts an integer to corresponding radix digit.
-    fn digit(x: u8) -> u8;
-
-    /// Format an integer using the radix using a formatter.
-    fn fmt_int<T: DisplayInt>(&self, mut x: T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // The radix can be as low as 2, so we need a buffer of at least 128
-        // characters for a base 2 number.
-        let zero = T::zero();
-        let is_nonnegative = x >= zero;
-        let mut buf = [MaybeUninit::<u8>::uninit(); 128];
-        let mut offset = buf.len();
-        let base = T::from_u8(Self::BASE);
-        if is_nonnegative {
-            // Accumulate each digit of the number from the least significant
-            // to the most significant figure.
-            loop {
-                let n = x % base; // Get the current place value.
-                x = x / base; // Deaccumulate the number.
-                offset -= 1;
-                buf[offset].write(Self::digit(n.to_u8())); // Store the digit in the buffer.
-                if x == zero {
-                    // No more digits left to accumulate.
-                    break;
-                };
-            }
-        } else {
-            // Do the same as above, but accounting for two's complement.
-            loop {
-                let n = zero - (x % base); // Get the current place value.
-                x = x / base; // Deaccumulate the number.
-                offset -= 1;
-                buf[offset].write(Self::digit(n.to_u8())); // Store the digit in the buffer.
-                if x == zero {
-                    // No more digits left to accumulate.
-                    break;
-                };
-            }
-        }
-        // SAFETY: Starting from `offset`, all elements of the slice have been set.
-        let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
-        f.pad_integral(is_nonnegative, Self::PREFIX, buf_slice)
-    }
-}
+                // Accumulate each digit of the number from the least
+                // significant to the most significant figure.
+                let mut remain = *self;
+                loop {
+                    let digit = remain % BASE;
+                    remain /= BASE;
 
-/// A binary (base 2) radix
-#[derive(Clone, PartialEq)]
-struct Binary;
-
-/// An octal (base 8) radix
-#[derive(Clone, PartialEq)]
-struct Octal;
-
-/// A hexadecimal (base 16) radix, formatted with lower-case characters
-#[derive(Clone, PartialEq)]
-struct LowerHex;
-
-/// A hexadecimal (base 16) radix, formatted with upper-case characters
-#[derive(Clone, PartialEq)]
-struct UpperHex;
-
-macro_rules! radix {
-    ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
-        unsafe impl GenericRadix for $T {
-            const BASE: u8 = $base;
-            const PREFIX: &'static str = $prefix;
-            fn digit(x: u8) -> u8 {
-                match x {
-                    $($x => $conv,)+
-                    x => panic!("number not in the range 0..={}: {}", Self::BASE - 1, x),
+                    offset -= 1;
+                    // SAFETY: `remain` will reach 0 and we will break before `offset` wraps
+                    unsafe { core::hint::assert_unchecked(offset < buf.len()) }
+                    buf[offset].write(DIG_TAB[digit as usize]);
+                    if remain == 0 {
+                        break;
+                    }
                 }
+
+                // SAFETY: Starting from `offset`, all elements of the slice have been set.
+                let digits = unsafe { slice_buffer_to_str(&buf, offset) };
+                f.pad_integral(true, $prefix, digits)
             }
         }
-    }
-}
 
-radix! { Binary,    2, "0b", x @  0 ..=  1 => b'0' + x }
-radix! { Octal,     8, "0o", x @  0 ..=  7 => b'0' + x }
-radix! { LowerHex, 16, "0x", x @  0 ..=  9 => b'0' + x, x @ 10 ..= 15 => b'a' + (x - 10) }
-radix! { UpperHex, 16, "0x", x @  0 ..=  9 => b'0' + x, x @ 10 ..= 15 => b'A' + (x - 10) }
-
-macro_rules! int_base {
-    (fmt::$Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl fmt::$Trait for $T {
+        impl fmt::$Trait for $Signed {
+            /// Format signed integers in the two’s-complement form.
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                $Radix.fmt_int(*self as $U, f)
+                fmt::$Trait::fmt(&self.cast_unsigned(), f)
             }
         }
     };
 }
 
-macro_rules! integer {
-    ($Int:ident, $Uint:ident) => {
-        int_base! { fmt::Binary   for $Int as $Uint  -> Binary }
-        int_base! { fmt::Octal    for $Int as $Uint  -> Octal }
-        int_base! { fmt::LowerHex for $Int as $Uint  -> LowerHex }
-        int_base! { fmt::UpperHex for $Int as $Uint  -> UpperHex }
-
-        int_base! { fmt::Binary   for $Uint as $Uint -> Binary }
-        int_base! { fmt::Octal    for $Uint as $Uint -> Octal }
-        int_base! { fmt::LowerHex for $Uint as $Uint -> LowerHex }
-        int_base! { fmt::UpperHex for $Uint as $Uint -> UpperHex }
+/// Formatting of integers with a non-decimal radix.
+macro_rules! radix_integers {
+    ($Signed:ident, $Unsigned:ident) => {
+        radix_integer! { fmt::Binary   for $Signed and $Unsigned, "0b", b"01" }
+        radix_integer! { fmt::Octal    for $Signed and $Unsigned, "0o", b"01234567" }
+        radix_integer! { fmt::LowerHex for $Signed and $Unsigned, "0x", b"0123456789abcdef" }
+        radix_integer! { fmt::UpperHex for $Signed and $Unsigned, "0x", b"0123456789ABCDEF" }
     };
 }
-integer! { isize, usize }
-integer! { i8, u8 }
-integer! { i16, u16 }
-integer! { i32, u32 }
-integer! { i64, u64 }
-integer! { i128, u128 }
+radix_integers! { isize, usize }
+radix_integers! { i8, u8 }
+radix_integers! { i16, u16 }
+radix_integers! { i32, u32 }
+radix_integers! { i64, u64 }
+radix_integers! { i128, u128 }
 
 macro_rules! impl_Debug {
     ($($T:ident)*) => {
@@ -205,16 +119,21 @@ unsafe fn slice_buffer_to_str(buf: &[MaybeUninit<u8>], offset: usize) -> &str {
 }
 
 macro_rules! impl_Display {
-    ($($signed:ident, $unsigned:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => {
+    ($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
 
         $(
+        const _: () = {
+            assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
+            assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
+        };
+
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl fmt::Display for $unsigned {
+        impl fmt::Display for $Unsigned {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 #[cfg(not(feature = "optimize_for_size"))]
                 {
-                    const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1;
-                    // Buffer decimals for $unsigned with right alignment.
+                    const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
+                    // Buffer decimals for self with right alignment.
                     let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
 
                     // SAFETY: `buf` is always big enough to contain all the digits.
@@ -222,18 +141,20 @@ macro_rules! impl_Display {
                 }
                 #[cfg(feature = "optimize_for_size")]
                 {
-                    $gen_name(self.$conv_fn(), true, f)
+                    // Lossless conversion (with as) is asserted at the top of
+                    // this macro.
+                    ${concat($fmt_fn, _small)}(*self as $T, true, f)
                 }
             }
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl fmt::Display for $signed {
+        impl fmt::Display for $Signed {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 #[cfg(not(feature = "optimize_for_size"))]
                 {
-                    const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1;
-                    // Buffer decimals for $unsigned with right alignment.
+                    const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
+                    // Buffer decimals for self with right alignment.
                     let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
 
                     // SAFETY: `buf` is always big enough to contain all the digits.
@@ -241,13 +162,15 @@ macro_rules! impl_Display {
                 }
                 #[cfg(feature = "optimize_for_size")]
                 {
-                    return $gen_name(self.unsigned_abs().$conv_fn(), *self >= 0, f);
+                    // Lossless conversion (with as) is asserted at the top of
+                    // this macro.
+                    return ${concat($fmt_fn, _small)}(self.unsigned_abs() as $T, *self >= 0, f);
                 }
             }
         }
 
         #[cfg(not(feature = "optimize_for_size"))]
-        impl $unsigned {
+        impl $Unsigned {
             #[doc(hidden)]
             #[unstable(
                 feature = "fmt_internals",
@@ -268,7 +191,7 @@ macro_rules! impl_Display {
                 let mut remain = self;
 
                 // Format per four digits from the lookup table.
-                // Four digits need a 16-bit $unsigned or wider.
+                // Four digits need a 16-bit $Unsigned or wider.
                 while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
                     // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
                     // and the while condition ensures at least 4 more decimals.
@@ -327,7 +250,7 @@ macro_rules! impl_Display {
             }
         }
 
-        impl $signed {
+        impl $Signed {
             /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
             /// type [`NumBuffer`] that is passed by the caller by mutable reference.
             ///
@@ -337,15 +260,15 @@ macro_rules! impl_Display {
             /// #![feature(int_format_into)]
             /// use core::fmt::NumBuffer;
             ///
-            #[doc = concat!("let n = 0", stringify!($signed), ";")]
+            #[doc = concat!("let n = 0", stringify!($Signed), ";")]
             /// let mut buf = NumBuffer::new();
             /// assert_eq!(n.format_into(&mut buf), "0");
             ///
-            #[doc = concat!("let n1 = 32", stringify!($signed), ";")]
+            #[doc = concat!("let n1 = 32", stringify!($Signed), ";")]
             /// assert_eq!(n1.format_into(&mut buf), "32");
             ///
-            #[doc = concat!("let n2 = ", stringify!($signed::MAX), ";")]
-            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($signed::MAX), ".to_string());")]
+            #[doc = concat!("let n2 = ", stringify!($Signed::MAX), ";")]
+            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Signed::MAX), ".to_string());")]
             /// ```
             #[unstable(feature = "int_format_into", issue = "138215")]
             pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
@@ -358,7 +281,9 @@ macro_rules! impl_Display {
                 }
                 #[cfg(feature = "optimize_for_size")]
                 {
-                    offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.unsigned_abs().$conv_fn(), &mut buf.buf);
+                    // Lossless conversion (with as) is asserted at the top of
+                    // this macro.
+                    offset = ${concat($fmt_fn, _in_buf_small)}(self.unsigned_abs() as $T, &mut buf.buf);
                 }
                 // Only difference between signed and unsigned are these 4 lines.
                 if self < 0 {
@@ -370,7 +295,7 @@ macro_rules! impl_Display {
             }
         }
 
-        impl $unsigned {
+        impl $Unsigned {
             /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
             /// type [`NumBuffer`] that is passed by the caller by mutable reference.
             ///
@@ -380,15 +305,15 @@ macro_rules! impl_Display {
             /// #![feature(int_format_into)]
             /// use core::fmt::NumBuffer;
             ///
-            #[doc = concat!("let n = 0", stringify!($unsigned), ";")]
+            #[doc = concat!("let n = 0", stringify!($Unsigned), ";")]
             /// let mut buf = NumBuffer::new();
             /// assert_eq!(n.format_into(&mut buf), "0");
             ///
-            #[doc = concat!("let n1 = 32", stringify!($unsigned), ";")]
+            #[doc = concat!("let n1 = 32", stringify!($Unsigned), ";")]
             /// assert_eq!(n1.format_into(&mut buf), "32");
             ///
-            #[doc = concat!("let n2 = ", stringify!($unsigned::MAX), ";")]
-            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($unsigned::MAX), ".to_string());")]
+            #[doc = concat!("let n2 = ", stringify!($Unsigned::MAX), ";")]
+            #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Unsigned::MAX), ".to_string());")]
             /// ```
             #[unstable(feature = "int_format_into", issue = "138215")]
             pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
@@ -401,7 +326,9 @@ macro_rules! impl_Display {
                 }
                 #[cfg(feature = "optimize_for_size")]
                 {
-                    offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.$conv_fn(), &mut buf.buf);
+                    // Lossless conversion (with as) is asserted at the top of
+                    // this macro.
+                    offset = ${concat($fmt_fn, _in_buf_small)}(self as $T, &mut buf.buf);
                 }
                 // SAFETY: Starting from `offset`, all elements of the slice have been set.
                 unsafe { slice_buffer_to_str(&buf.buf, offset) }
@@ -412,7 +339,7 @@ macro_rules! impl_Display {
         )*
 
         #[cfg(feature = "optimize_for_size")]
-        fn ${concat(_inner_slow_integer_to_str, $gen_name)}(mut n: $u, buf: &mut [MaybeUninit::<u8>]) -> usize {
+        fn ${concat($fmt_fn, _in_buf_small)}(mut n: $T, buf: &mut [MaybeUninit::<u8>]) -> usize {
             let mut curr = buf.len();
 
             // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
@@ -433,11 +360,11 @@ macro_rules! impl_Display {
         }
 
         #[cfg(feature = "optimize_for_size")]
-        fn $gen_name(n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1;
+        fn ${concat($fmt_fn, _small)}(n: $T, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            const MAX_DEC_N: usize = $T::MAX.ilog(10) as usize + 1;
             let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
 
-            let offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(n, &mut buf);
+            let offset = ${concat($fmt_fn, _in_buf_small)}(n, &mut buf);
             // SAFETY: Starting from `offset`, all elements of the slice have been set.
             let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
             f.pad_integral(is_nonnegative, "", buf_slice)
@@ -446,9 +373,9 @@ macro_rules! impl_Display {
 }
 
 macro_rules! impl_Exp {
-    ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
-        fn $name(
-            mut n: $u,
+    ($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
+        fn $fmt_fn(
+            mut n: $T,
             is_nonnegative: bool,
             upper: bool,
             f: &mut fmt::Formatter<'_>
@@ -582,32 +509,41 @@ macro_rules! impl_Exp {
 
         $(
             #[stable(feature = "integer_exp_format", since = "1.42.0")]
-            impl fmt::LowerExp for $t {
-                #[allow(unused_comparisons)]
+            impl fmt::LowerExp for $Signed {
                 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     let is_nonnegative = *self >= 0;
                     let n = if is_nonnegative {
-                        self.$conv_fn()
+                        *self as $T
                     } else {
-                        // convert the negative num to positive by summing 1 to its 2s complement
-                        (!self.$conv_fn()).wrapping_add(1)
+                        self.unsigned_abs() as $T
                     };
-                    $name(n, is_nonnegative, false, f)
+                    $fmt_fn(n, is_nonnegative, false, f)
+                }
+            }
+            #[stable(feature = "integer_exp_format", since = "1.42.0")]
+            impl fmt::LowerExp for $Unsigned {
+                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                    $fmt_fn(*self as $T, true, false, f)
                 }
             })*
+
         $(
             #[stable(feature = "integer_exp_format", since = "1.42.0")]
-            impl fmt::UpperExp for $t {
-                #[allow(unused_comparisons)]
+            impl fmt::UpperExp for $Signed {
                 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     let is_nonnegative = *self >= 0;
                     let n = if is_nonnegative {
-                        self.$conv_fn()
+                        *self as $T
                     } else {
-                        // convert the negative num to positive by summing 1 to its 2s complement
-                        (!self.$conv_fn()).wrapping_add(1)
+                        self.unsigned_abs() as $T
                     };
-                    $name(n, is_nonnegative, true, f)
+                    $fmt_fn(n, is_nonnegative, true, f)
+                }
+            }
+            #[stable(feature = "integer_exp_format", since = "1.42.0")]
+            impl fmt::UpperExp for $Unsigned {
+                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                    $fmt_fn(*self as $T, true, true, f)
                 }
             })*
     };
@@ -623,37 +559,20 @@ impl_Debug! {
 #[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
 mod imp {
     use super::*;
-    impl_Display!(
-        i8, u8,
-        i16, u16,
-        i32, u32,
-        i64, u64,
-        isize, usize,
-        ; as u64 via to_u64 named fmt_u64
-    );
-    impl_Exp!(
-        i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
-            as u64 via to_u64 named exp_u64
-    );
+    impl_Display!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into display_u64);
+    impl_Exp!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into exp_u64);
 }
 
 #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
 mod imp {
     use super::*;
-    impl_Display!(
-        i8, u8,
-        i16, u16,
-        i32, u32,
-        isize, usize,
-        ; as u32 via to_u32 named fmt_u32);
-    impl_Display!(
-        i64, u64,
-        ; as u64 via to_u64 named fmt_u64);
-
-    impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
-    impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
+    impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into display_u32);
+    impl_Display!(i64, u64; as u64 into display_u64);
+
+    impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into exp_u32);
+    impl_Exp!(i64, u64; as u64 into exp_u64);
 }
-impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
+impl_Exp!(i128, u128; as u128 into exp_u128);
 
 const U128_MAX_DEC_N: usize = u128::MAX.ilog10() as usize + 1;
 
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index dd838d494bc..904aa52c784 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -261,53 +261,72 @@ pub unsafe fn atomic_fence<const ORD: AtomicOrdering>();
 pub unsafe fn atomic_singlethreadfence<const ORD: AtomicOrdering>();
 
 /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
-/// if supported; otherwise, it is a no-op.
+/// for the given address if supported; otherwise, it is a no-op.
 /// Prefetches have no effect on the behavior of the program but can change its performance
 /// characteristics.
 ///
-/// The `locality` argument must be a constant integer and is a temporal locality specifier
-/// ranging from (0) - no locality, to (3) - extremely local keep in cache.
+/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality,
+/// to (3) - extremely local keep in cache.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn prefetch_read_data<T>(data: *const T, locality: i32);
+#[miri::intrinsic_fallback_is_spec]
+pub const fn prefetch_read_data<T, const LOCALITY: i32>(data: *const T) {
+    // This operation is a no-op, unless it is overridden by the backend.
+    let _ = data;
+}
+
 /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
-/// if supported; otherwise, it is a no-op.
+/// for the given address if supported; otherwise, it is a no-op.
 /// Prefetches have no effect on the behavior of the program but can change its performance
 /// characteristics.
 ///
-/// The `locality` argument must be a constant integer and is a temporal locality specifier
-/// ranging from (0) - no locality, to (3) - extremely local keep in cache.
+/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality,
+/// to (3) - extremely local keep in cache.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn prefetch_write_data<T>(data: *const T, locality: i32);
+#[miri::intrinsic_fallback_is_spec]
+pub const fn prefetch_write_data<T, const LOCALITY: i32>(data: *const T) {
+    // This operation is a no-op, unless it is overridden by the backend.
+    let _ = data;
+}
+
 /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
-/// if supported; otherwise, it is a no-op.
+/// for the given address if supported; otherwise, it is a no-op.
 /// Prefetches have no effect on the behavior of the program but can change its performance
 /// characteristics.
 ///
-/// The `locality` argument must be a constant integer and is a temporal locality specifier
-/// ranging from (0) - no locality, to (3) - extremely local keep in cache.
+/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality,
+/// to (3) - extremely local keep in cache.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn prefetch_read_instruction<T>(data: *const T, locality: i32);
+#[miri::intrinsic_fallback_is_spec]
+pub const fn prefetch_read_instruction<T, const LOCALITY: i32>(data: *const T) {
+    // This operation is a no-op, unless it is overridden by the backend.
+    let _ = data;
+}
+
 /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
-/// if supported; otherwise, it is a no-op.
+/// for the given address if supported; otherwise, it is a no-op.
 /// Prefetches have no effect on the behavior of the program but can change its performance
 /// characteristics.
 ///
-/// The `locality` argument must be a constant integer and is a temporal locality specifier
-/// ranging from (0) - no locality, to (3) - extremely local keep in cache.
+/// The `LOCALITY` argument is a temporal locality specifier ranging from (0) - no locality,
+/// to (3) - extremely local keep in cache.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn prefetch_write_instruction<T>(data: *const T, locality: i32);
+#[miri::intrinsic_fallback_is_spec]
+pub const fn prefetch_write_instruction<T, const LOCALITY: i32>(data: *const T) {
+    // This operation is a no-op, unless it is overridden by the backend.
+    let _ = data;
+}
 
 /// Executes a breakpoint trap, for inspection by a debugger.
 ///
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 6396b8524f2..71abd707374 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -226,6 +226,13 @@ pub mod assert_matches {
     pub use crate::macros::{assert_matches, debug_assert_matches};
 }
 
+#[unstable(feature = "derive_from", issue = "144889")]
+/// Unstable module containing the unstable `From` derive macro.
+pub mod from {
+    #[unstable(feature = "derive_from", issue = "144889")]
+    pub use crate::macros::builtin::From;
+}
+
 // We don't export this through #[macro_export] for now, to avoid breakage.
 #[unstable(feature = "autodiff", issue = "124509")]
 /// Unstable module containing the unstable `autodiff` macro.
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index 87f2110034c..3bf113d017c 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -626,13 +626,13 @@ impl Ipv4Addr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ip_from)]
     /// use std::net::Ipv4Addr;
     ///
     /// let addr = Ipv4Addr::from_octets([13u8, 12u8, 11u8, 10u8]);
     /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
     /// ```
-    #[unstable(feature = "ip_from", issue = "131360")]
+    #[stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     #[inline]
     pub const fn from_octets(octets: [u8; 4]) -> Ipv4Addr {
@@ -1464,7 +1464,6 @@ impl Ipv6Addr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ip_from)]
     /// use std::net::Ipv6Addr;
     ///
     /// let addr = Ipv6Addr::from_segments([
@@ -1479,7 +1478,8 @@ impl Ipv6Addr {
     ///     addr
     /// );
     /// ```
-    #[unstable(feature = "ip_from", issue = "131360")]
+    #[stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     #[inline]
     pub const fn from_segments(segments: [u16; 8]) -> Ipv6Addr {
@@ -2029,7 +2029,6 @@ impl Ipv6Addr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ip_from)]
     /// use std::net::Ipv6Addr;
     ///
     /// let addr = Ipv6Addr::from_octets([
@@ -2044,7 +2043,8 @@ impl Ipv6Addr {
     ///     addr
     /// );
     /// ```
-    #[unstable(feature = "ip_from", issue = "131360")]
+    #[stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     #[inline]
     pub const fn from_octets(octets: [u8; 16]) -> Ipv6Addr {
diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs
index 1844cd98082..3118a6e5ca6 100644
--- a/library/core/src/num/dec2flt/mod.rs
+++ b/library/core/src/num/dec2flt/mod.rs
@@ -124,6 +124,8 @@ macro_rules! from_str_float_impl {
             /// * '2.5E-10'
             /// * '5.'
             /// * '.5', or, equivalently, '0.5'
+            /// * '7'
+            /// * '007'
             /// * 'inf', '-inf', '+infinity', 'NaN'
             ///
             /// Note that alphabetical characters are not case-sensitive.
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index bd2f7445612..25864db5fea 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -209,6 +209,48 @@ macro_rules! int_impl {
             self & self.wrapping_neg()
         }
 
+        /// Returns the index of the highest bit set to one in `self`, or `None`
+        /// if `self` is `0`.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(int_lowest_highest_one)]
+        ///
+        #[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".highest_one(), None);")]
+        #[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".highest_one(), Some(0));")]
+        #[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".highest_one(), Some(4));")]
+        #[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".highest_one(), Some(4));")]
+        /// ```
+        #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn highest_one(self) -> Option<u32> {
+            (self as $UnsignedT).highest_one()
+        }
+
+        /// Returns the index of the lowest bit set to one in `self`, or `None`
+        /// if `self` is `0`.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(int_lowest_highest_one)]
+        ///
+        #[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".lowest_one(), None);")]
+        #[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".lowest_one(), Some(0));")]
+        #[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".lowest_one(), Some(4));")]
+        #[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".lowest_one(), Some(0));")]
+        /// ```
+        #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn lowest_one(self) -> Option<u32> {
+            (self as $UnsignedT).lowest_one()
+        }
+
         /// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size.
         ///
         /// This produces the same result as an `as` cast, but ensures that the bit-width remains
@@ -2494,8 +2536,7 @@ macro_rules! int_impl {
         ///
         /// # Examples
         ///
-        /// Please note that this example is shared between integer types.
-        /// Which explains why `i32` is used here.
+        /// Please note that this example is shared among integer types, which is why `i32` is used.
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
@@ -2525,8 +2566,7 @@ macro_rules! int_impl {
         ///
         /// # Examples
         ///
-        /// Please note that this example is shared between integer types.
-        /// Which explains why `i32` is used here.
+        /// Please note that this example is shared among integer types, which is why `i32` is used.
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
@@ -2563,8 +2603,7 @@ macro_rules! int_impl {
         ///
         /// # Examples
         ///
-        /// Please note that this example is shared between integer types.
-        /// Which explains why `i32` is used here.
+        /// Please note that this example is shared among integer types, which is why `i32` is used.
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 308d722f5d5..e02d9260a16 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -681,6 +681,54 @@ macro_rules! nonzero_integer {
                 unsafe { NonZero::new_unchecked(n) }
             }
 
+            /// Returns the index of the highest bit set to one in `self`.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// #![feature(int_lowest_highest_one)]
+            ///
+            /// # use core::num::NonZero;
+            /// # fn main() { test().unwrap(); }
+            /// # fn test() -> Option<()> {
+            #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1)?.highest_one(), 0);")]
+            #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x10)?.highest_one(), 4);")]
+            #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1f)?.highest_one(), 4);")]
+            /// # Some(())
+            /// # }
+            /// ```
+            #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+            #[must_use = "this returns the result of the operation, \
+                          without modifying the original"]
+            #[inline(always)]
+            pub const fn highest_one(self) -> u32 {
+                Self::BITS - 1 - self.leading_zeros()
+            }
+
+            /// Returns the index of the lowest bit set to one in `self`.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// #![feature(int_lowest_highest_one)]
+            ///
+            /// # use core::num::NonZero;
+            /// # fn main() { test().unwrap(); }
+            /// # fn test() -> Option<()> {
+            #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1)?.lowest_one(), 0);")]
+            #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x10)?.lowest_one(), 4);")]
+            #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::new(0x1f)?.lowest_one(), 0);")]
+            /// # Some(())
+            /// # }
+            /// ```
+            #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+            #[must_use = "this returns the result of the operation, \
+                          without modifying the original"]
+            #[inline(always)]
+            pub const fn lowest_one(self) -> u32 {
+                self.trailing_zeros()
+            }
+
             /// Returns the number of ones in the binary representation of `self`.
             ///
             /// # Examples
diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs
index c7040721b93..365a82a57e0 100644
--- a/library/core/src/num/saturating.rs
+++ b/library/core/src/num/saturating.rs
@@ -729,8 +729,8 @@ macro_rules! saturating_int_impl {
             ///
             /// # Examples
             ///
-            /// Please note that this example is shared between integer types.
-            /// Which explains why `i16` is used here.
+            /// Please note that this example is shared among integer types, which is why `i16`
+            /// is used.
             ///
             /// ```
             /// use std::num::Saturating;
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 0afad09bdc6..10d9498d15e 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -261,6 +261,54 @@ macro_rules! uint_impl {
             self & self.wrapping_neg()
         }
 
+        /// Returns the index of the highest bit set to one in `self`, or `None`
+        /// if `self` is `0`.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(int_lowest_highest_one)]
+        ///
+        #[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".highest_one(), None);")]
+        #[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".highest_one(), Some(0));")]
+        #[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".highest_one(), Some(4));")]
+        #[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".highest_one(), Some(4));")]
+        /// ```
+        #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn highest_one(self) -> Option<u32> {
+            match NonZero::new(self) {
+                Some(v) => Some(v.highest_one()),
+                None => None,
+            }
+        }
+
+        /// Returns the index of the lowest bit set to one in `self`, or `None`
+        /// if `self` is `0`.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(int_lowest_highest_one)]
+        ///
+        #[doc = concat!("assert_eq!(0x0_", stringify!($SelfT), ".lowest_one(), None);")]
+        #[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".lowest_one(), Some(0));")]
+        #[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".lowest_one(), Some(4));")]
+        #[doc = concat!("assert_eq!(0x1f_", stringify!($SelfT), ".lowest_one(), Some(0));")]
+        /// ```
+        #[unstable(feature = "int_lowest_highest_one", issue = "145203")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn lowest_one(self) -> Option<u32> {
+            match NonZero::new(self) {
+                Some(v) => Some(v.lowest_one()),
+                None => None,
+            }
+        }
+
         /// Returns the bit pattern of `self` reinterpreted as a signed integer of the same size.
         ///
         /// This produces the same result as an `as` cast, but ensures that the bit-width remains
@@ -2115,8 +2163,7 @@ macro_rules! uint_impl {
         ///
         /// # Examples
         ///
-        /// Please note that this example is shared between integer types.
-        /// Which explains why `u8` is used here.
+        /// Please note that this example is shared among integer types, which is why `u8` is used.
         ///
         /// ```
         /// assert_eq!(10u8.wrapping_mul(12), 120);
@@ -2606,8 +2653,8 @@ macro_rules! uint_impl {
         ///
         /// # Examples
         ///
-        /// Please note that this example is shared between integer types.
-        /// Which explains why `u32` is used here.
+        /// Please note that this example is shared among integer types, which is why why `u32`
+        /// is used.
         ///
         /// ```
         /// assert_eq!(5u32.overflowing_mul(2), (10, false));
@@ -2633,8 +2680,7 @@ macro_rules! uint_impl {
         ///
         /// # Examples
         ///
-        /// Please note that this example is shared between integer types.
-        /// Which explains why `u32` is used here.
+        /// Please note that this example is shared among integer types, which is why `u32` is used.
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
@@ -2664,8 +2710,7 @@ macro_rules! uint_impl {
         ///
         /// # Examples
         ///
-        /// Please note that this example is shared between integer types.
-        /// Which explains why `u32` is used here.
+        /// Please note that this example is shared among integer types, which is why `u32` is used.
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs
index 9ccad4b6459..881fe615f80 100644
--- a/library/core/src/num/wrapping.rs
+++ b/library/core/src/num/wrapping.rs
@@ -765,8 +765,8 @@ macro_rules! wrapping_int_impl {
             ///
             /// # Examples
             ///
-            /// Please note that this example is shared between integer types.
-            /// Which explains why `i16` is used here.
+            /// Please note that this example is shared among integer types, which is why `i16`
+            /// is used.
             ///
             /// Basic usage:
             ///
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 560d20ce617..e83e77344cf 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -2095,9 +2095,9 @@ impl<T> Option<&mut T> {
 impl<T, E> Option<Result<T, E>> {
     /// Transposes an `Option` of a [`Result`] into a [`Result`] of an `Option`.
     ///
-    /// [`None`] will be mapped to <code>[Ok]\([None])</code>.
-    /// <code>[Some]\([Ok]\(\_))</code> and <code>[Some]\([Err]\(\_))</code> will be mapped to
-    /// <code>[Ok]\([Some]\(\_))</code> and <code>[Err]\(\_)</code>.
+    /// <code>[Some]\([Ok]\(\_))</code> is mapped to <code>[Ok]\([Some]\(\_))</code>,
+    /// <code>[Some]\([Err]\(\_))</code> is mapped to <code>[Err]\(\_)</code>,
+    /// and [`None`] will be mapped to <code>[Ok]\([None])</code>.
     ///
     /// # Examples
     ///
@@ -2105,9 +2105,9 @@ impl<T, E> Option<Result<T, E>> {
     /// #[derive(Debug, Eq, PartialEq)]
     /// struct SomeErr;
     ///
-    /// let x: Result<Option<i32>, SomeErr> = Ok(Some(5));
-    /// let y: Option<Result<i32, SomeErr>> = Some(Ok(5));
-    /// assert_eq!(x, y.transpose());
+    /// let x: Option<Result<i32, SomeErr>> = Some(Ok(5));
+    /// let y: Result<Option<i32>, SomeErr> = Ok(Some(5));
+    /// assert_eq!(x.transpose(), y);
     /// ```
     #[inline]
     #[stable(feature = "transpose_result", since = "1.33.0")]
diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs
index b18b5d7c9ec..ede6e0d6106 100644
--- a/library/core/src/pin/unsafe_pinned.rs
+++ b/library/core/src/pin/unsafe_pinned.rs
@@ -120,8 +120,8 @@ impl<T: ?Sized> UnsafePinned<T> {
     #[inline(always)]
     #[must_use]
     #[unstable(feature = "unsafe_pinned", issue = "125735")]
-    pub const fn raw_get(this: *const Self) -> *const T {
-        this as *const T
+    pub const fn raw_get(this: *const Self) -> *mut T {
+        this as *const T as *mut T
     }
 
     /// Gets a mutable pointer to the wrapped value.
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index d8d82afb0e6..a4be66b90ca 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -117,10 +117,3 @@ pub use crate::macros::builtin::deref;
     reason = "`type_alias_impl_trait` has open design concerns"
 )]
 pub use crate::macros::builtin::define_opaque;
-
-#[unstable(
-    feature = "derive_from",
-    issue = "144889",
-    reason = "`derive(From)` is unstable"
-)]
-pub use crate::macros::builtin::From;
diff --git a/library/core/src/unicode/mod.rs b/library/core/src/unicode/mod.rs
index 49dbdeb1a6d..191fe7711f9 100644
--- a/library/core/src/unicode/mod.rs
+++ b/library/core/src/unicode/mod.rs
@@ -1,5 +1,6 @@
+//! Unicode internals used in liballoc and libstd. Not public API.
 #![unstable(feature = "unicode_internals", issue = "none")]
-#![allow(missing_docs)]
+#![doc(hidden)]
 
 // for use in alloc, not re-exported in std.
 #[rustfmt::skip]
@@ -31,5 +32,4 @@ mod unicode_data;
 ///
 /// The version numbering scheme is explained in
 /// [Unicode 11.0 or later, Section 3.1 Versions of the Unicode Standard](https://www.unicode.org/versions/Unicode11.0.0/ch03.pdf#page=4).
-#[stable(feature = "unicode_version", since = "1.45.0")]
 pub const UNICODE_VERSION: (u8, u8, u8) = unicode_data::UNICODE_VERSION;
diff --git a/library/coretests/benches/fmt.rs b/library/coretests/benches/fmt.rs
index ee8e981b46b..f45b921b939 100644
--- a/library/coretests/benches/fmt.rs
+++ b/library/coretests/benches/fmt.rs
@@ -162,3 +162,183 @@ fn write_u8_min(bh: &mut Bencher) {
         black_box(format!("{}", black_box(u8::MIN)));
     });
 }
+
+#[bench]
+fn write_i8_bin(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:b}", black_box(0_i8)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(100_i8)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(-100_i8)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(1_i8 << 4)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i16_bin(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:b}", black_box(0_i16)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(100_i16)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(-100_i16)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(1_i16 << 8)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i32_bin(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:b}", black_box(0_i32)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(100_i32)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(-100_i32)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(1_i32 << 16)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i64_bin(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:b}", black_box(0_i64)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(100_i64)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(-100_i64)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(1_i64 << 32)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i128_bin(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:b}", black_box(0_i128)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(100_i128)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(-100_i128)).unwrap();
+        write!(black_box(&mut buf), "{:b}", black_box(1_i128 << 64)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i8_oct(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:o}", black_box(0_i8)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(100_i8)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(-100_i8)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(1_i8 << 4)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i16_oct(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:o}", black_box(0_i16)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(100_i16)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(-100_i16)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(1_i16 << 8)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i32_oct(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:o}", black_box(0_i32)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(100_i32)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(-100_i32)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(1_i32 << 16)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i64_oct(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:o}", black_box(0_i64)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(100_i64)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(-100_i64)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(1_i64 << 32)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i128_oct(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:o}", black_box(0_i128)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(100_i128)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(-100_i128)).unwrap();
+        write!(black_box(&mut buf), "{:o}", black_box(1_i128 << 64)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i8_hex(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:x}", black_box(0_i8)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(100_i8)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(-100_i8)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(1_i8 << 4)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i16_hex(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:x}", black_box(0_i16)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(100_i16)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(-100_i16)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(1_i16 << 8)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i32_hex(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:x}", black_box(0_i32)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(100_i32)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(-100_i32)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(1_i32 << 16)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i64_hex(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:x}", black_box(0_i64)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(100_i64)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(-100_i64)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(1_i64 << 32)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
+
+#[bench]
+fn write_i128_hex(bh: &mut Bencher) {
+    let mut buf = String::with_capacity(256);
+    bh.iter(|| {
+        write!(black_box(&mut buf), "{:x}", black_box(0_i128)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(100_i128)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(-100_i128)).unwrap();
+        write!(black_box(&mut buf), "{:x}", black_box(1_i128 << 64)).unwrap();
+        black_box(&mut buf).clear();
+    });
+}
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index ecda8a7fec6..d2281b1df2f 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -54,9 +54,9 @@
 #![feature(generic_assert_internals)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
+#![feature(int_lowest_highest_one)]
 #![feature(int_roundings)]
 #![feature(ip)]
-#![feature(ip_from)]
 #![feature(is_ascii_octdigit)]
 #![feature(isolate_most_least_significant_one)]
 #![feature(iter_advance_by)]
diff --git a/library/coretests/tests/nonzero.rs b/library/coretests/tests/nonzero.rs
index eb06c34fd02..69e4ed9c36b 100644
--- a/library/coretests/tests/nonzero.rs
+++ b/library/coretests/tests/nonzero.rs
@@ -462,3 +462,111 @@ fn test_nonzero_fmt() {
 
     assert_eq!(i, nz);
 }
+
+#[test]
+fn test_nonzero_highest_one() {
+    macro_rules! nonzero_int_impl {
+        ($($T:ty),+) => {
+            $(
+                {
+                    for i in 0..<$T>::BITS {
+                        // Set single bit.
+                        assert_eq!(NonZero::<$T>::new(1 << i).unwrap().highest_one(), i);
+                        if i > <$T>::BITS {
+                            // Set lowest bits.
+                            assert_eq!(
+                                NonZero::<$T>::new(<$T>::MAX >> i).unwrap().highest_one(),
+                                <$T>::BITS - i - 2,
+                            );
+                        }
+                        // Set highest bits.
+                        assert_eq!(
+                            NonZero::<$T>::new(-1 << i).unwrap().highest_one(),
+                            <$T>::BITS - 1,
+                        );
+                    }
+                }
+            )+
+        };
+    }
+
+    macro_rules! nonzero_uint_impl {
+        ($($T:ty),+) => {
+            $(
+                {
+                    for i in 0..<$T>::BITS {
+                        // Set single bit.
+                        assert_eq!(NonZero::<$T>::new(1 << i).unwrap().highest_one(), i);
+                        // Set lowest bits.
+                        assert_eq!(
+                            NonZero::<$T>::new(<$T>::MAX >> i).unwrap().highest_one(),
+                            <$T>::BITS - i - 1,
+                        );
+                        // Set highest bits.
+                        assert_eq!(
+                            NonZero::<$T>::new(<$T>::MAX << i).unwrap().highest_one(),
+                            <$T>::BITS - 1,
+                        );
+                    }
+                }
+            )+
+        };
+    }
+
+    nonzero_int_impl!(i8, i16, i32, i64, i128, isize);
+    nonzero_uint_impl!(u8, u16, u32, u64, u128, usize);
+}
+
+#[test]
+fn test_nonzero_lowest_one() {
+    macro_rules! nonzero_int_impl {
+        ($($T:ty),+) => {
+            $(
+                {
+                    for i in 0..<$T>::BITS {
+                        // Set single bit.
+                        assert_eq!(NonZero::<$T>::new(1 << i).unwrap().lowest_one(), i);
+                        if i > <$T>::BITS {
+                            // Set lowest bits.
+                            assert_eq!(
+                                NonZero::<$T>::new(<$T>::MAX >> i).unwrap().lowest_one(),
+                                0,
+                            );
+                        }
+                        // Set highest bits.
+                        assert_eq!(
+                            NonZero::<$T>::new(-1 << i).unwrap().lowest_one(),
+                            i,
+                        );
+                    }
+                }
+            )+
+        };
+    }
+
+    macro_rules! nonzero_uint_impl {
+        ($($T:ty),+) => {
+            $(
+                {
+                    for i in 0..<$T>::BITS {
+                        // Set single bit.
+                        assert_eq!(NonZero::<$T>::new(1 << i).unwrap().lowest_one(), i);
+                        // Set lowest bits.
+                        assert_eq!(
+                            NonZero::<$T>::new(<$T>::MAX >> i).unwrap().lowest_one(),
+                            0,
+                        );
+                        // Set highest bits.
+                        assert_eq!(
+                            NonZero::<$T>::new(<$T>::MAX << i).unwrap().lowest_one(),
+                            i,
+                        );
+                    }
+                }
+            )+
+        };
+    }
+
+    nonzero_int_impl!(i8, i16, i32, i64, i128, isize);
+    nonzero_uint_impl!(u8, u16, u32, u64, u128, usize);
+}
diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs
index ca32fce861f..1611a6466f5 100644
--- a/library/coretests/tests/num/int_macros.rs
+++ b/library/coretests/tests/num/int_macros.rs
@@ -228,6 +228,46 @@ macro_rules! int_module {
         }
 
         #[test]
+        fn test_highest_one() {
+            const ZERO: $T = 0;
+            const ONE: $T = 1;
+            const MINUS_ONE: $T = -1;
+
+            assert_eq!(ZERO.highest_one(), None);
+
+            for i in 0..<$T>::BITS {
+                // Set single bit.
+                assert_eq!((ONE << i).highest_one(), Some(i));
+                if i != <$T>::BITS - 1 {
+                    // Set lowest bits.
+                    assert_eq!((<$T>::MAX >> i).highest_one(), Some(<$T>::BITS - i - 2));
+                }
+                // Set highest bits.
+                assert_eq!((MINUS_ONE << i).highest_one(), Some(<$T>::BITS - 1));
+            }
+        }
+
+        #[test]
+        fn test_lowest_one() {
+            const ZERO: $T = 0;
+            const ONE: $T = 1;
+            const MINUS_ONE: $T = -1;
+
+            assert_eq!(ZERO.lowest_one(), None);
+
+            for i in 0..<$T>::BITS {
+                // Set single bit.
+                assert_eq!((ONE << i).lowest_one(), Some(i));
+                if i != <$T>::BITS - 1 {
+                    // Set lowest bits.
+                    assert_eq!((<$T>::MAX >> i).lowest_one(), Some(0));
+                }
+                // Set highest bits.
+                assert_eq!((MINUS_ONE << i).lowest_one(), Some(i));
+            }
+        }
+
+        #[test]
         fn test_from_str() {
             fn from_str<T: std::str::FromStr>(t: &str) -> Option<T> {
                 std::str::FromStr::from_str(t).ok()
diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs
index 8f389de70aa..c7d10ea4d88 100644
--- a/library/coretests/tests/num/uint_macros.rs
+++ b/library/coretests/tests/num/uint_macros.rs
@@ -184,6 +184,40 @@ macro_rules! uint_module {
             }
         }
 
+        #[test]
+        fn test_highest_one() {
+            const ZERO: $T = 0;
+            const ONE: $T = 1;
+
+            assert_eq!(ZERO.highest_one(), None);
+
+            for i in 0..<$T>::BITS {
+                // Set single bit.
+                assert_eq!((ONE << i).highest_one(), Some(i));
+                // Set lowest bits.
+                assert_eq!((<$T>::MAX >> i).highest_one(), Some(<$T>::BITS - i - 1));
+                // Set highest bits.
+                assert_eq!((<$T>::MAX << i).highest_one(), Some(<$T>::BITS - 1));
+            }
+        }
+
+        #[test]
+        fn test_lowest_one() {
+            const ZERO: $T = 0;
+            const ONE: $T = 1;
+
+            assert_eq!(ZERO.lowest_one(), None);
+
+            for i in 0..<$T>::BITS {
+                // Set single bit.
+                assert_eq!((ONE << i).lowest_one(), Some(i));
+                // Set lowest bits.
+                assert_eq!((<$T>::MAX >> i).lowest_one(), Some(0));
+                // Set highest bits.
+                assert_eq!((<$T>::MAX << i).lowest_one(), Some(i));
+            }
+        }
+
         fn from_str<T: core::str::FromStr>(t: &str) -> Option<T> {
             core::str::FromStr::from_str(t).ok()
         }
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 7bc52976500..eff2562f031 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -14,6 +14,7 @@ crate-type = ["dylib", "rlib"]
 
 [dependencies]
 alloc = { path = "../alloc", public = true }
+# std no longer uses cfg-if directly, but the included copy of backtrace does.
 cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs
index 889ed3c5380..6104a02c739 100644
--- a/library/std/src/collections/mod.rs
+++ b/library/std/src/collections/mod.rs
@@ -26,7 +26,7 @@
 //! should be considered. Detailed discussions of strengths and weaknesses of
 //! individual collections can be found on their own documentation pages.
 //!
-//! ### Use a `Vec` when:
+//! ### Use a [`Vec`] when:
 //! * You want to collect items up to be processed or sent elsewhere later, and
 //!   don't care about any properties of the actual values being stored.
 //! * You want a sequence of elements in a particular order, and will only be
@@ -35,25 +35,25 @@
 //! * You want a resizable array.
 //! * You want a heap-allocated array.
 //!
-//! ### Use a `VecDeque` when:
+//! ### Use a [`VecDeque`] when:
 //! * You want a [`Vec`] that supports efficient insertion at both ends of the
 //!   sequence.
 //! * You want a queue.
 //! * You want a double-ended queue (deque).
 //!
-//! ### Use a `LinkedList` when:
+//! ### Use a [`LinkedList`] when:
 //! * You want a [`Vec`] or [`VecDeque`] of unknown size, and can't tolerate
 //!   amortization.
 //! * You want to efficiently split and append lists.
 //! * You are *absolutely* certain you *really*, *truly*, want a doubly linked
 //!   list.
 //!
-//! ### Use a `HashMap` when:
+//! ### Use a [`HashMap`] when:
 //! * You want to associate arbitrary keys with an arbitrary value.
 //! * You want a cache.
 //! * You want a map, with no extra functionality.
 //!
-//! ### Use a `BTreeMap` when:
+//! ### Use a [`BTreeMap`] when:
 //! * You want a map sorted by its keys.
 //! * You want to be able to get a range of entries on-demand.
 //! * You're interested in what the smallest or largest key-value pair is.
@@ -65,7 +65,7 @@
 //! * There is no meaningful value to associate with your keys.
 //! * You just want a set.
 //!
-//! ### Use a `BinaryHeap` when:
+//! ### Use a [`BinaryHeap`] when:
 //!
 //! * You want to store a bunch of elements, but only ever want to process the
 //!   "biggest" or "most important" one at any given time.
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 8d7edc732af..1214490caad 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -137,7 +137,7 @@ impl OsString {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     #[inline]
-    #[rustc_const_unstable(feature = "const_pathbuf_osstring_new", issue = "141520")]
+    #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "CURRENT_RUSTC_VERSION")]
     pub const fn new() -> OsString {
         OsString { inner: Buf::from_string(String::new()) }
     }
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index a220a3f56e9..1ed4f2f9f0c 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -3119,7 +3119,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
 /// On UNIX-like systems, this function will update the permission bits
 /// of the file pointed to by the symlink.
 ///
-/// Note that this behavior can lead to privalage escalation vulnerabilities,
+/// Note that this behavior can lead to privilege escalation vulnerabilities,
 /// where the ability to create a symlink in one directory allows you to
 /// cause the permissions of another file or directory to be modified.
 ///
@@ -3156,6 +3156,25 @@ pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result
     fs_imp::set_permissions(path.as_ref(), perm.0)
 }
 
+/// Set the permissions of a file, unless it is a symlink.
+///
+/// Note that the non-final path elements are allowed to be symlinks.
+///
+/// # Platform-specific behavior
+///
+/// Currently unimplemented on Windows.
+///
+/// On Unix platforms, this results in a [`FilesystemLoop`] error if the last element is a symlink.
+///
+/// This behavior may change in the future.
+///
+/// [`FilesystemLoop`]: crate::io::ErrorKind::FilesystemLoop
+#[doc(alias = "chmod", alias = "SetFileAttributes")]
+#[unstable(feature = "set_permissions_nofollow", issue = "141607")]
+pub fn set_permissions_nofollow<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
+    fs_imp::set_permissions_nofollow(path.as_ref(), perm)
+}
+
 impl DirBuilder {
     /// Creates a new set of options with default mode/security settings for all
     /// platforms and also non-recursive.
diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs
index 574288e579e..9b600cd5575 100644
--- a/library/std/src/io/buffered/bufreader/buffer.rs
+++ b/library/std/src/io/buffered/bufreader/buffer.rs
@@ -122,7 +122,7 @@ impl Buffer {
 
     /// Remove bytes that have already been read from the buffer.
     pub fn backshift(&mut self) {
-        self.buf.copy_within(self.pos.., 0);
+        self.buf.copy_within(self.pos..self.filled, 0);
         self.filled -= self.pos;
         self.pos = 0;
     }
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 15e962924ac..d060ad52897 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -63,10 +63,11 @@ where
     R: Read,
     W: Write,
 {
-    cfg_if::cfg_if! {
-        if #[cfg(any(target_os = "linux", target_os = "android"))] {
+    cfg_select! {
+        any(target_os = "linux", target_os = "android") => {
             crate::sys::kernel_copy::copy_spec(reader, writer)
-        } else {
+        }
+        _ => {
             generic_copy(reader, writer)
         }
     }
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 562fdbf4ff7..dcfa189823f 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -18,7 +18,7 @@ use crate::{error, fmt, result, sys};
 /// This type is broadly used across [`std::io`] for any operation which may
 /// produce an error.
 ///
-/// This typedef is generally used to avoid writing out [`io::Error`] directly and
+/// This type alias is generally used to avoid writing out [`io::Error`] directly and
 /// is otherwise a direct mapping to [`Result`].
 ///
 /// While usual Rust style is to import types directly, aliases of [`Result`]
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index d351ee5e739..ff0e29e04c2 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -2461,7 +2461,7 @@ pub trait BufRead: Read {
     /// delimiter or EOF is found.
     ///
     /// If successful, this function will return the total number of bytes read,
-    /// including the delimiter byte.
+    /// including the delimiter byte if found.
     ///
     /// This is useful for efficiently skipping data such as NUL-terminated strings
     /// in binary file formats without buffering.
@@ -2489,7 +2489,7 @@ pub trait BufRead: Read {
     /// ```
     /// use std::io::{self, BufRead};
     ///
-    /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0");
+    /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0!");
     ///
     /// // read name
     /// let mut name = Vec::new();
@@ -2509,6 +2509,11 @@ pub trait BufRead: Read {
     ///     .expect("reading from cursor won't fail");
     /// assert_eq!(num_bytes, 11);
     /// assert_eq!(animal, b"Crustacean\0");
+    ///
+    /// // reach EOF
+    /// let num_bytes = cursor.skip_until(b'\0')
+    ///     .expect("reading from cursor won't fail");
+    /// assert_eq!(num_bytes, 1);
     /// ```
     #[stable(feature = "bufread_skip_until", since = "1.83.0")]
     fn skip_until(&mut self, byte: u8) -> Result<usize> {
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index f111fcb4a47..ab417b6c72f 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -330,6 +330,7 @@
 #![feature(bstr)]
 #![feature(bstr_internals)]
 #![feature(cast_maybe_uninit)]
+#![feature(cfg_select)]
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
 #![feature(const_cmp)]
@@ -737,6 +738,14 @@ pub use core::{
     unreachable, write, writeln,
 };
 
+// Re-export unstable derive macro defined through core.
+#[unstable(feature = "derive_from", issue = "144889")]
+/// Unstable module containing the unstable `From` derive macro.
+pub mod from {
+    #[unstable(feature = "derive_from", issue = "144889")]
+    pub use core::from::From;
+}
+
 // Include a number of private modules that exist solely to provide
 // the rustdoc documentation for primitive types. Using `include!`
 // because rustdoc only looks for these modules at the crate level.
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 035768a6fab..768fa77a5f8 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -1,14 +1,16 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         target_os = "linux", target_os = "android",
         target_os = "hurd",
         target_os = "dragonfly", target_os = "freebsd",
         target_os = "openbsd", target_os = "netbsd",
         target_os = "solaris", target_os = "illumos",
         target_os = "haiku", target_os = "nto",
-        target_os = "cygwin"))] {
+        target_os = "cygwin",
+    ) => {
         use libc::MSG_NOSIGNAL;
-    } else {
+    }
+    _ => {
         const MSG_NOSIGNAL: core::ffi::c_int = 0x0;
     }
 }
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 76e63a69e45..09429af06e3 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -4,8 +4,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use cfg_if::cfg_if;
-
 use crate::ffi::OsStr;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::path::Path;
@@ -13,17 +11,19 @@ use crate::sealed::Sealed;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 use crate::{io, process, sys};
 
-cfg_if! {
-    if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
+cfg_select! {
+    any(target_os = "vxworks", target_os = "espidf", target_os = "horizon", target_os = "vita") => {
         type UserId = u16;
         type GroupId = u16;
-    } else if #[cfg(target_os = "nto")] {
+    }
+    target_os = "nto" => {
         // Both IDs are signed, see `sys/target_nto.h` of the QNX Neutrino SDP.
         // Only positive values should be used, see e.g.
         // https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/s/setuid.html
         type UserId = i32;
         type GroupId = i32;
-    } else {
+    }
+    _ => {
         type UserId = u32;
         type GroupId = u32;
     }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 3b52804d6be..3899fbf86db 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1191,7 +1191,7 @@ impl PathBuf {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     #[inline]
-    #[rustc_const_unstable(feature = "const_pathbuf_osstring_new", issue = "141520")]
+    #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "CURRENT_RUSTC_VERSION")]
     pub const fn new() -> PathBuf {
         PathBuf { inner: OsString::new() }
     }
@@ -2105,6 +2105,38 @@ impl PartialEq for PathBuf {
     }
 }
 
+#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")]
+impl cmp::PartialEq<str> for PathBuf {
+    #[inline]
+    fn eq(&self, other: &str) -> bool {
+        &*self == other
+    }
+}
+
+#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")]
+impl cmp::PartialEq<PathBuf> for str {
+    #[inline]
+    fn eq(&self, other: &PathBuf) -> bool {
+        other == self
+    }
+}
+
+#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")]
+impl cmp::PartialEq<String> for PathBuf {
+    #[inline]
+    fn eq(&self, other: &String) -> bool {
+        **self == **other
+    }
+}
+
+#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")]
+impl cmp::PartialEq<PathBuf> for String {
+    #[inline]
+    fn eq(&self, other: &PathBuf) -> bool {
+        other == self
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Hash for PathBuf {
     fn hash<H: Hasher>(&self, h: &mut H) {
@@ -3366,6 +3398,39 @@ impl PartialEq for Path {
     }
 }
 
+#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")]
+impl cmp::PartialEq<str> for Path {
+    #[inline]
+    fn eq(&self, other: &str) -> bool {
+        let other: &OsStr = other.as_ref();
+        self == other
+    }
+}
+
+#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")]
+impl cmp::PartialEq<Path> for str {
+    #[inline]
+    fn eq(&self, other: &Path) -> bool {
+        other == self
+    }
+}
+
+#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")]
+impl cmp::PartialEq<String> for Path {
+    #[inline]
+    fn eq(&self, other: &String) -> bool {
+        self == &*other
+    }
+}
+
+#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")]
+impl cmp::PartialEq<Path> for String {
+    #[inline]
+    fn eq(&self, other: &Path) -> bool {
+        other == self
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Hash for Path {
     fn hash<H: Hasher>(&self, h: &mut H) {
diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs
index b6861c78f00..fd1e671d7a3 100644
--- a/library/std/src/sync/nonpoison/mutex.rs
+++ b/library/std/src/sync/nonpoison/mutex.rs
@@ -100,7 +100,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> {
     lock: &'a Mutex<T>,
 }
 
-/// A [`MutexGuard`] is not `Send` to maximize platform portablity.
+/// A [`MutexGuard`] is not `Send` to maximize platform portability.
 ///
 /// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
 /// release mutex locks on the same thread they were acquired.
diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs
index 6205c4fa4ca..720c212c65c 100644
--- a/library/std/src/sync/poison/mutex.rs
+++ b/library/std/src/sync/poison/mutex.rs
@@ -279,7 +279,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> {
     poison: poison::Guard,
 }
 
-/// A [`MutexGuard`] is not `Send` to maximize platform portablity.
+/// A [`MutexGuard`] is not `Send` to maximize platform portability.
 ///
 /// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
 /// release mutex locks on the same thread they were acquired.
diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs
index 727252f03a2..4140718560c 100644
--- a/library/std/src/sync/reentrant_lock.rs
+++ b/library/std/src/sync/reentrant_lock.rs
@@ -1,5 +1,3 @@
-use cfg_if::cfg_if;
-
 use crate::cell::UnsafeCell;
 use crate::fmt;
 use crate::ops::Deref;
@@ -87,8 +85,8 @@ pub struct ReentrantLock<T: ?Sized> {
     data: T,
 }
 
-cfg_if!(
-    if #[cfg(target_has_atomic = "64")] {
+cfg_select!(
+    target_has_atomic = "64" => {
         use crate::sync::atomic::{Atomic, AtomicU64, Ordering::Relaxed};
 
         struct Tid(Atomic<u64>);
@@ -110,7 +108,8 @@ cfg_if!(
                 self.0.store(value, Relaxed);
             }
         }
-    } else {
+    }
+    _ => {
         /// Returns the address of a TLS variable. This is guaranteed to
         /// be unique across all currently alive threads.
         fn tls_addr() -> usize {
diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs
index f3af1f7f599..6d4b09494a3 100644
--- a/library/std/src/sys/alloc/mod.rs
+++ b/library/std/src/sys/alloc/mod.rs
@@ -68,29 +68,37 @@ unsafe fn realloc_fallback(
     }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         target_family = "unix",
         target_os = "wasi",
         target_os = "teeos",
         target_os = "trusty",
-    ))] {
+    ) => {
         mod unix;
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
-    } else if #[cfg(target_family = "wasm")] {
+    }
+    target_family = "wasm" => {
         mod wasm;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
     }
 }
diff --git a/library/std/src/sys/alloc/unix.rs b/library/std/src/sys/alloc/unix.rs
index a7ac4117ec9..3d369b08abc 100644
--- a/library/std/src/sys/alloc/unix.rs
+++ b/library/std/src/sys/alloc/unix.rs
@@ -58,18 +58,16 @@ unsafe impl GlobalAlloc for System {
     }
 }
 
-cfg_if::cfg_if! {
+cfg_select! {
     // We use posix_memalign wherever possible, but some targets have very incomplete POSIX coverage
     // so we need a fallback for those.
-    if #[cfg(any(
-        target_os = "horizon",
-        target_os = "vita",
-    ))] {
+    any(target_os = "horizon", target_os = "vita") => {
         #[inline]
         unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
             unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 }
         }
-    } else {
+    }
+    _ => {
         #[inline]
         #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
         unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
diff --git a/library/std/src/sys/anonymous_pipe/mod.rs b/library/std/src/sys/anonymous_pipe/mod.rs
index aa14c8b650d..b6f464161ee 100644
--- a/library/std/src/sys/anonymous_pipe/mod.rs
+++ b/library/std/src/sys/anonymous_pipe/mod.rs
@@ -1,13 +1,15 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-cfg_if::cfg_if! {
-    if #[cfg(unix)] {
+cfg_select! {
+    unix => {
         mod unix;
         pub use unix::{AnonPipe, pipe};
-    } else if #[cfg(windows)] {
+    }
+    windows => {
         mod windows;
         pub use windows::{AnonPipe, pipe};
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use unsupported::{AnonPipe, pipe};
     }
diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs
index 0011f55dc14..c9627322276 100644
--- a/library/std/src/sys/args/mod.rs
+++ b/library/std/src/sys/args/mod.rs
@@ -12,32 +12,39 @@
 ))]
 mod common;
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))),
         target_os = "hermit",
-    ))] {
+    ) => {
         mod unix;
         pub use unix::*;
-    } else if #[cfg(target_family = "windows")] {
+    }
+    target_family = "windows" => {
         mod windows;
         pub use windows::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use uefi::*;
-    } else if #[cfg(target_os = "wasi")] {
+    }
+    target_os = "wasi" => {
         mod wasi;
         pub use wasi::*;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::*;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
         pub use zkvm::*;
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use unsupported::*;
     }
diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs
index 299ce1a6ff0..1592218ead8 100644
--- a/library/std/src/sys/cmath.rs
+++ b/library/std/src/sys/cmath.rs
@@ -45,69 +45,70 @@ unsafe extern "C" {
     pub safe fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
     pub safe fn erff128(n: f128) -> f128;
     pub safe fn erfcf128(n: f128) -> f128;
-
-    cfg_if::cfg_if! {
-    if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {
-        pub safe fn acosf(n: f32) -> f32;
-        pub safe fn asinf(n: f32) -> f32;
-        pub safe fn atan2f(a: f32, b: f32) -> f32;
-        pub safe fn atanf(n: f32) -> f32;
-        pub safe fn coshf(n: f32) -> f32;
-        pub safe fn sinhf(n: f32) -> f32;
-        pub safe fn tanf(n: f32) -> f32;
-        pub safe fn tanhf(n: f32) -> f32;
-    }}
 }
 
-// On AIX, we don't have lgammaf_r only the f64 version, so we can
-// use the f64 version lgamma_r
-#[cfg(target_os = "aix")]
-pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
-    lgamma_r(n.into(), s) as f32
-}
+cfg_select! {
+    all(target_os = "windows", target_env = "msvc", target_arch = "x86") => {
+        // On 32-bit x86 MSVC these functions aren't defined, so we just define shims
+        // which promote everything to f64, perform the calculation, and then demote
+        // back to f32. While not precisely correct should be "correct enough" for now.
+        #[inline]
+        pub fn acosf(n: f32) -> f32 {
+            f64::acos(n as f64) as f32
+        }
 
-// On 32-bit x86 MSVC these functions aren't defined, so we just define shims
-// which promote everything to f64, perform the calculation, and then demote
-// back to f32. While not precisely correct should be "correct enough" for now.
-cfg_if::cfg_if! {
-if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] {
-    #[inline]
-    pub fn acosf(n: f32) -> f32 {
-        f64::acos(n as f64) as f32
-    }
+        #[inline]
+        pub fn asinf(n: f32) -> f32 {
+            f64::asin(n as f64) as f32
+        }
 
-    #[inline]
-    pub fn asinf(n: f32) -> f32 {
-        f64::asin(n as f64) as f32
-    }
+        #[inline]
+        pub fn atan2f(n: f32, b: f32) -> f32 {
+            f64::atan2(n as f64, b as f64) as f32
+        }
 
-    #[inline]
-    pub fn atan2f(n: f32, b: f32) -> f32 {
-        f64::atan2(n as f64, b as f64) as f32
-    }
+        #[inline]
+        pub fn atanf(n: f32) -> f32 {
+            f64::atan(n as f64) as f32
+        }
 
-    #[inline]
-    pub fn atanf(n: f32) -> f32 {
-        f64::atan(n as f64) as f32
-    }
+        #[inline]
+        pub fn coshf(n: f32) -> f32 {
+            f64::cosh(n as f64) as f32
+        }
 
-    #[inline]
-    pub fn coshf(n: f32) -> f32 {
-        f64::cosh(n as f64) as f32
-    }
+        #[inline]
+        pub fn sinhf(n: f32) -> f32 {
+            f64::sinh(n as f64) as f32
+        }
 
-    #[inline]
-    pub fn sinhf(n: f32) -> f32 {
-        f64::sinh(n as f64) as f32
-    }
+        #[inline]
+        pub fn tanf(n: f32) -> f32 {
+            f64::tan(n as f64) as f32
+        }
 
-    #[inline]
-    pub fn tanf(n: f32) -> f32 {
-        f64::tan(n as f64) as f32
+        #[inline]
+        pub fn tanhf(n: f32) -> f32 {
+            f64::tanh(n as f64) as f32
+        }
     }
-
-    #[inline]
-    pub fn tanhf(n: f32) -> f32 {
-        f64::tanh(n as f64) as f32
+    _ => {
+        unsafe extern "C" {
+            pub safe fn acosf(n: f32) -> f32;
+            pub safe fn asinf(n: f32) -> f32;
+            pub safe fn atan2f(a: f32, b: f32) -> f32;
+            pub safe fn atanf(n: f32) -> f32;
+            pub safe fn coshf(n: f32) -> f32;
+            pub safe fn sinhf(n: f32) -> f32;
+            pub safe fn tanf(n: f32) -> f32;
+            pub safe fn tanhf(n: f32) -> f32;
+        }
     }
-}}
+}
+
+// On AIX, we don't have lgammaf_r only the f64 version, so we can
+// use the f64 version lgamma_r
+#[cfg(target_os = "aix")]
+pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
+    lgamma_r(n.into(), s) as f32
+}
diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs
index d81ff875c83..f211a9fc86b 100644
--- a/library/std/src/sys/env/mod.rs
+++ b/library/std/src/sys/env/mod.rs
@@ -13,35 +13,44 @@
 ))]
 mod common;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_family = "unix")] {
+cfg_select! {
+    target_family = "unix" => {
         mod unix;
         pub use unix::*;
-    } else if #[cfg(target_family = "windows")] {
+    }
+    target_family = "windows" => {
         mod windows;
         pub use windows::*;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
         pub use hermit::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use solid::*;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use uefi::*;
-    } else if #[cfg(target_os = "wasi")] {
+    }
+    target_os = "wasi" => {
         mod wasi;
         pub use wasi::*;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::*;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
         pub use zkvm::*;
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use unsupported::*;
     }
diff --git a/library/std/src/sys/env/wasi.rs b/library/std/src/sys/env/wasi.rs
index 3719f9db51e..1327cbc3263 100644
--- a/library/std/src/sys/env/wasi.rs
+++ b/library/std/src/sys/env/wasi.rs
@@ -7,8 +7,8 @@ use crate::os::wasi::prelude::*;
 use crate::sys::common::small_c_string::run_with_cstr;
 use crate::sys::pal::os::{cvt, libc};
 
-cfg_if::cfg_if! {
-    if #[cfg(target_feature = "atomics")] {
+cfg_select! {
+    target_feature = "atomics" => {
         // Access to the environment must be protected by a lock in multi-threaded scenarios.
         use crate::sync::{PoisonError, RwLock};
         static ENV_LOCK: RwLock<()> = RwLock::new(());
@@ -18,7 +18,8 @@ cfg_if::cfg_if! {
         pub fn env_write_lock() -> impl Drop {
             ENV_LOCK.write().unwrap_or_else(PoisonError::into_inner)
         }
-    } else {
+    }
+    _ => {
         // No need for a lock if we are single-threaded.
         pub fn env_read_lock() -> impl Drop {
             Box::new(())
diff --git a/library/std/src/sys/exit_guard.rs b/library/std/src/sys/exit_guard.rs
index bd70d178244..00b91842e9d 100644
--- a/library/std/src/sys/exit_guard.rs
+++ b/library/std/src/sys/exit_guard.rs
@@ -1,5 +1,5 @@
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "linux")] {
+cfg_select! {
+    target_os = "linux" => {
         /// Mitigation for <https://github.com/rust-lang/rust/issues/126600>
         ///
         /// On glibc, `libc::exit` has been observed to not always be thread-safe.
@@ -56,7 +56,8 @@ cfg_if::cfg_if! {
                 }
             }
         }
-    } else {
+    }
+    _ => {
         /// Mitigation for <https://github.com/rust-lang/rust/issues/126600>
         ///
         /// Mitigation is ***NOT*** implemented on this platform, either because this platform
diff --git a/library/std/src/sys/fd/mod.rs b/library/std/src/sys/fd/mod.rs
index e0f5eab6951..7cb9dd1cba9 100644
--- a/library/std/src/sys/fd/mod.rs
+++ b/library/std/src/sys/fd/mod.rs
@@ -2,18 +2,22 @@
 
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-cfg_if::cfg_if! {
-    if #[cfg(target_family = "unix")] {
+cfg_select! {
+    target_family = "unix" => {
         mod unix;
         pub use unix::*;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
         pub use hermit::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(target_os = "wasi")] {
+    }
+    target_os = "wasi" => {
         mod wasi;
         pub use wasi::*;
     }
+    _ => {}
 }
diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs
index d55e28074fe..dbd782f5018 100644
--- a/library/std/src/sys/fs/mod.rs
+++ b/library/std/src/sys/fs/mod.rs
@@ -5,8 +5,8 @@ use crate::path::{Path, PathBuf};
 
 pub mod common;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_family = "unix")] {
+cfg_select! {
+    target_family = "unix" => {
         mod unix;
         use unix as imp;
         pub use unix::{chown, fchown, lchown, mkfifo};
@@ -16,24 +16,30 @@ cfg_if::cfg_if! {
         #[cfg(any(target_os = "linux", target_os = "android"))]
         pub(crate) use unix::CachedFileMetadata;
         use crate::sys::common::small_c_string::run_path_with_cstr as with_native_path;
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
         use windows as imp;
         pub use windows::{symlink_inner, junction_point};
         use crate::sys::path::with_native_path;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
         use hermit as imp;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         use solid as imp;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         use uefi as imp;
-    } else if #[cfg(target_os = "wasi")] {
+    }
+    target_os = "wasi" => {
         mod wasi;
         use wasi as imp;
-    } else {
+    }
+    _ => {
         mod unsupported;
         use unsupported as imp;
     }
@@ -108,6 +114,21 @@ pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> {
     with_native_path(path, &|path| imp::set_perm(path, perm.clone()))
 }
 
+#[cfg(unix)]
+pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> {
+    use crate::fs::OpenOptions;
+    use crate::os::unix::fs::OpenOptionsExt;
+
+    OpenOptions::new().custom_flags(libc::O_NOFOLLOW).open(path)?.set_permissions(perm)
+}
+
+#[cfg(not(unix))]
+pub fn set_permissions_nofollow(_path: &Path, _perm: crate::fs::Permissions) -> io::Result<()> {
+    crate::unimplemented!(
+        "`set_permissions_nofollow` is currently only implemented on Unix platforms"
+    )
+}
+
 pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
     with_native_path(path, &imp::canonicalize)
 }
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index b310db2dac4..7ee9f3c445a 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -101,10 +101,11 @@ pub struct File(FileDesc);
 // https://github.com/rust-lang/rust/pull/67774
 macro_rules! cfg_has_statx {
     ({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => {
-        cfg_if::cfg_if! {
-            if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
+        cfg_select! {
+            all(target_os = "linux", target_env = "gnu") => {
                 $($then_tt)*
-            } else {
+            }
+            _ => {
                 $($else_tt)*
             }
         }
@@ -1263,6 +1264,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     ))]
     pub fn lock(&self) -> io::Result<()> {
@@ -1275,6 +1277,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     )))]
     pub fn lock(&self) -> io::Result<()> {
@@ -1286,6 +1289,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     ))]
     pub fn lock_shared(&self) -> io::Result<()> {
@@ -1298,6 +1302,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     )))]
     pub fn lock_shared(&self) -> io::Result<()> {
@@ -1309,6 +1314,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     ))]
     pub fn try_lock(&self) -> Result<(), TryLockError> {
@@ -1329,6 +1335,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     )))]
     pub fn try_lock(&self) -> Result<(), TryLockError> {
@@ -1343,6 +1350,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     ))]
     pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
@@ -1363,6 +1371,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     )))]
     pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
@@ -1377,6 +1386,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     ))]
     pub fn unlock(&self) -> io::Result<()> {
@@ -1389,6 +1399,7 @@ impl File {
         target_os = "fuchsia",
         target_os = "linux",
         target_os = "netbsd",
+        target_os = "openbsd",
         target_vendor = "apple",
     )))]
     pub fn unlock(&self) -> io::Result<()> {
@@ -1505,8 +1516,8 @@ impl File {
             )),
             None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
         };
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx"))] {
+        cfg_select! {
+            any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx") => {
                 // Redox doesn't appear to support `UTIME_OMIT`.
                 // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore
                 // the same as for Redox.
@@ -1515,7 +1526,8 @@ impl File {
                     io::ErrorKind::Unsupported,
                     "setting file times not supported",
                 ))
-            } else if #[cfg(target_vendor = "apple")] {
+            }
+            target_vendor = "apple" => {
                 let mut buf = [mem::MaybeUninit::<libc::timespec>::uninit(); 3];
                 let mut num_times = 0;
                 let mut attrlist: libc::attrlist = unsafe { mem::zeroed() };
@@ -1543,7 +1555,8 @@ impl File {
                     0
                 ) })?;
                 Ok(())
-            } else if #[cfg(target_os = "android")] {
+            }
+            target_os = "android" => {
                 let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?];
                 // futimens requires Android API level 19
                 cvt(unsafe {
@@ -1559,7 +1572,8 @@ impl File {
                     }
                 })?;
                 Ok(())
-            } else {
+            }
+            _ => {
                 #[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))]
                 {
                     use crate::sys::{time::__timespec64, weak::weak};
@@ -1677,13 +1691,14 @@ impl fmt::Debug for File {
             let mut buf = vec![0; libc::PATH_MAX as usize];
             let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
             if n == -1 {
-                cfg_if::cfg_if! {
-                    if #[cfg(target_os = "netbsd")] {
+                cfg_select! {
+                    target_os = "netbsd" => {
                         // fallback to procfs as last resort
                         let mut p = PathBuf::from("/proc/self/fd");
                         p.push(&fd.to_string());
                         return run_path_with_cstr(&p, &readlink).ok()
-                    } else {
+                    }
+                    _ => {
                         return None;
                     }
                 }
@@ -1884,15 +1899,16 @@ pub fn symlink(original: &CStr, link: &CStr) -> io::Result<()> {
 }
 
 pub fn link(original: &CStr, link: &CStr) -> io::Result<()> {
-    cfg_if::cfg_if! {
-        if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70"))] {
+    cfg_select! {
+        any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70") => {
             // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves
             // it implementation-defined whether `link` follows symlinks, so rely on the
             // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior.
             // Android has `linkat` on newer versions, but we happen to know `link`
             // always has the correct behavior, so it's here as well.
             cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?;
-        } else {
+        }
+        _ => {
             // Where we can, use `linkat` instead of `link`; see the comment above
             // this one for details on why.
             cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?;
diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs
index ae75f4d97b4..fe8ec1dbb73 100644
--- a/library/std/src/sys/io/mod.rs
+++ b/library/std/src/sys/io/mod.rs
@@ -1,20 +1,24 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
 mod io_slice {
-    cfg_if::cfg_if! {
-        if #[cfg(any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty"))] {
+    cfg_select! {
+        any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty") => {
             mod iovec;
             pub use iovec::*;
-        } else if #[cfg(target_os = "windows")] {
+        }
+        target_os = "windows" => {
             mod windows;
             pub use windows::*;
-        } else if #[cfg(target_os = "wasi")] {
+        }
+        target_os = "wasi" => {
             mod wasi;
             pub use wasi::*;
-        } else if #[cfg(target_os = "uefi")] {
+        }
+        target_os = "uefi" => {
             mod uefi;
             pub use uefi::*;
-        } else {
+        }
+        _ => {
             mod unsupported;
             pub use unsupported::*;
         }
@@ -22,17 +26,20 @@ mod io_slice {
 }
 
 mod is_terminal {
-    cfg_if::cfg_if! {
-        if #[cfg(any(target_family = "unix", target_os = "wasi"))] {
+    cfg_select! {
+        any(target_family = "unix", target_os = "wasi") => {
             mod isatty;
             pub use isatty::*;
-        } else if #[cfg(target_os = "windows")] {
+        }
+        target_os = "windows" => {
             mod windows;
             pub use windows::*;
-        } else if #[cfg(target_os = "hermit")] {
+        }
+        target_os = "hermit" => {
             mod hermit;
             pub use hermit::*;
-        } else {
+        }
+        _ => {
             mod unsupported;
             pub use unsupported::*;
         }
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 8ec0a0e3302..6324c1a232a 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -1,7 +1,7 @@
 #![allow(unsafe_op_in_unsafe_fn)]
 
 /// The configure builtins provides runtime support compiler-builtin features
-/// which require dynamic intialization to work as expected, e.g. aarch64
+/// which require dynamic initialization to work as expected, e.g. aarch64
 /// outline-atomics.
 mod configure_builtins;
 
diff --git a/library/std/src/sys/net/connection/socket.rs b/library/std/src/sys/net/connection/socket.rs
index 7301bde6881..aa83ed65d4c 100644
--- a/library/std/src/sys/net/connection/socket.rs
+++ b/library/std/src/sys/net/connection/socket.rs
@@ -9,29 +9,34 @@ use crate::sys_common::{AsInner, FromInner};
 use crate::time::Duration;
 use crate::{cmp, fmt, mem, ptr};
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "hermit")] {
+cfg_select! {
+    target_os = "hermit" => {
         mod hermit;
         pub use hermit::*;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use solid::*;
-    } else if #[cfg(target_family = "unix")] {
+    }
+    target_family = "unix" => {
         mod unix;
         pub use unix::*;
-    } else if #[cfg(all(target_os = "wasi", target_env = "p2"))] {
+    }
+    all(target_os = "wasi", target_env = "p2") => {
         mod wasip2;
         pub use wasip2::*;
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
         pub use windows::*;
     }
+    _ => {}
 }
 
 use netc as c;
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         target_os = "dragonfly",
         target_os = "freebsd",
         target_os = "openbsd",
@@ -43,39 +48,44 @@ cfg_if::cfg_if! {
         target_os = "nto",
         target_os = "nuttx",
         target_vendor = "apple",
-    ))] {
+    ) => {
         use c::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
         use c::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
-    } else {
+    }
+    _ => {
         use c::IPV6_ADD_MEMBERSHIP;
         use c::IPV6_DROP_MEMBERSHIP;
     }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         target_os = "linux", target_os = "android",
         target_os = "hurd",
         target_os = "dragonfly", target_os = "freebsd",
         target_os = "openbsd", target_os = "netbsd",
         target_os = "solaris", target_os = "illumos",
         target_os = "haiku", target_os = "nto",
-        target_os = "cygwin"))] {
+        target_os = "cygwin",
+    ) => {
         use libc::MSG_NOSIGNAL;
-    } else {
+    }
+    _ => {
         const MSG_NOSIGNAL: c_int = 0x0;
     }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         target_os = "dragonfly", target_os = "freebsd",
         target_os = "openbsd", target_os = "netbsd",
         target_os = "solaris", target_os = "illumos",
-        target_os = "nto"))] {
+        target_os = "nto",
+    ) => {
         use crate::ffi::c_uchar;
         type IpV4MultiCastType = c_uchar;
-    } else {
+    }
+    _ => {
         type IpV4MultiCastType = c_int;
     }
 }
@@ -523,17 +533,19 @@ impl TcpListener {
         let (addr, len) = socket_addr_to_c(addr);
         cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
 
-        cfg_if::cfg_if! {
-            if #[cfg(target_os = "horizon")] {
+        cfg_select! {
+            target_os = "horizon" => {
                 // The 3DS doesn't support a big connection backlog. Sometimes
                 // it allows up to about 37, but other times it doesn't even
                 // accept 32. There may be a global limitation causing this.
                 let backlog = 20;
-            } else if #[cfg(target_os = "haiku")] {
+            }
+            target_os = "haiku" => {
                 // Haiku does not support a queue length > 32
                 // https://github.com/haiku/haiku/blob/979a0bc487864675517fb2fab28f87dc8bf43041/headers/posix/sys/socket.h#L81
                 let backlog = 32;
-            } else {
+            }
+            _ => {
                 // The default for all other platforms
                 let backlog = 128;
             }
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index cc111f3521b..8b5970d1494 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -12,10 +12,11 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::{Duration, Instant};
 use crate::{cmp, mem};
 
-cfg_if::cfg_if! {
-    if #[cfg(target_vendor = "apple")] {
+cfg_select! {
+    target_vendor = "apple" => {
         use libc::SO_LINGER_SEC as SO_LINGER;
-    } else {
+    }
+    _ => {
         use libc::SO_LINGER;
     }
 }
@@ -72,8 +73,8 @@ impl Socket {
 
     pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
         unsafe {
-            cfg_if::cfg_if! {
-                if #[cfg(any(
+            cfg_select! {
+                any(
                     target_os = "android",
                     target_os = "dragonfly",
                     target_os = "freebsd",
@@ -85,7 +86,7 @@ impl Socket {
                     target_os = "cygwin",
                     target_os = "nto",
                     target_os = "solaris",
-                ))] {
+                ) => {
                     // On platforms that support it we pass the SOCK_CLOEXEC
                     // flag to atomically create the socket and set it as
                     // CLOEXEC. On Linux this was added in 2.6.27.
@@ -98,7 +99,8 @@ impl Socket {
                     setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
 
                     Ok(socket)
-                } else {
+                }
+                _ => {
                     let fd = cvt(libc::socket(fam, ty, 0))?;
                     let fd = FileDesc::from_raw_fd(fd);
                     fd.set_cloexec()?;
@@ -120,8 +122,8 @@ impl Socket {
         unsafe {
             let mut fds = [0, 0];
 
-            cfg_if::cfg_if! {
-                if #[cfg(any(
+            cfg_select! {
+                any(
                     target_os = "android",
                     target_os = "dragonfly",
                     target_os = "freebsd",
@@ -132,11 +134,12 @@ impl Socket {
                     target_os = "openbsd",
                     target_os = "cygwin",
                     target_os = "nto",
-                ))] {
+                ) => {
                     // Like above, set cloexec atomically
                     cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
                     Ok((Socket(FileDesc::from_raw_fd(fds[0])), Socket(FileDesc::from_raw_fd(fds[1]))))
-                } else {
+                }
+                _ => {
                     cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
                     let a = FileDesc::from_raw_fd(fds[0]);
                     let b = FileDesc::from_raw_fd(fds[1]);
@@ -250,8 +253,8 @@ impl Socket {
         // atomically set the CLOEXEC flag is to use the `accept4` syscall on
         // platforms that support it. On Linux, this was added in 2.6.28,
         // glibc 2.10 and musl 0.9.5.
-        cfg_if::cfg_if! {
-            if #[cfg(any(
+        cfg_select! {
+            any(
                 target_os = "android",
                 target_os = "dragonfly",
                 target_os = "freebsd",
@@ -261,12 +264,13 @@ impl Socket {
                 target_os = "netbsd",
                 target_os = "openbsd",
                 target_os = "cygwin",
-            ))] {
+            ) => {
                 unsafe {
                     let fd = cvt_r(|| libc::accept4(self.as_raw_fd(), storage, len, libc::SOCK_CLOEXEC))?;
                     Ok(Socket(FileDesc::from_raw_fd(fd)))
                 }
-            } else {
+            }
+            _ => {
                 unsafe {
                     let fd = cvt_r(|| libc::accept(self.as_raw_fd(), storage, len))?;
                     let fd = FileDesc::from_raw_fd(fd);
diff --git a/library/std/src/sys/net/mod.rs b/library/std/src/sys/net/mod.rs
index 646679a1cc8..5df1fe138ab 100644
--- a/library/std/src/sys/net/mod.rs
+++ b/library/std/src/sys/net/mod.rs
@@ -1,36 +1,41 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_family = "unix", not(target_os = "l4re")),
         target_os = "windows",
         target_os = "hermit",
         all(target_os = "wasi", target_env = "p2"),
         target_os = "solid_asp3",
-    ))] {
+    ) => {
         mod connection {
             mod socket;
             pub use socket::*;
         }
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod connection {
             mod sgx;
             pub use sgx::*;
         }
-    } else if #[cfg(all(target_os = "wasi", target_env = "p1"))] {
+    }
+    all(target_os = "wasi", target_env = "p1") => {
         mod connection {
             mod wasip1;
             pub use wasip1::*;
         }
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod connection {
             mod xous;
             pub use xous::*;
         }
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod connection {
             mod uefi;
             pub use uefi::*;
         }
-    } else {
+    }
+    _ => {
         mod connection {
             mod unsupported;
             pub use unsupported::*;
diff --git a/library/std/src/sys/os_str/mod.rs b/library/std/src/sys/os_str/mod.rs
index 345e661586d..65c90d88049 100644
--- a/library/std/src/sys/os_str/mod.rs
+++ b/library/std/src/sys/os_str/mod.rs
@@ -1,13 +1,11 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
-        target_os = "windows",
-        target_os = "uefi",
-    ))] {
+cfg_select! {
+    any(target_os = "windows", target_os = "uefi") => {
         mod wtf8;
         pub use wtf8::{Buf, Slice};
-    } else {
+    }
+    _ => {
         mod bytes;
         pub use bytes::{Buf, Slice};
     }
diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs
index fbefc62ac88..9376f5249f1 100644
--- a/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
@@ -24,60 +24,70 @@
 
 pub mod common;
 
-cfg_if::cfg_if! {
-    if #[cfg(unix)] {
+cfg_select! {
+    unix => {
         mod unix;
         pub use self::unix::*;
-    } else if #[cfg(windows)] {
+    }
+    windows => {
         mod windows;
         pub use self::windows::*;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use self::solid::*;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
         pub use self::hermit::*;
-    } else if #[cfg(target_os = "trusty")] {
+    }
+    target_os = "trusty" => {
         mod trusty;
         pub use self::trusty::*;
-    } else if #[cfg(all(target_os = "wasi", target_env = "p2"))] {
+    }
+    all(target_os = "wasi", target_env = "p2") => {
         mod wasip2;
         pub use self::wasip2::*;
-    } else if #[cfg(target_os = "wasi")] {
+    }
+    target_os = "wasi" => {
         mod wasi;
         pub use self::wasi::*;
-    } else if #[cfg(target_family = "wasm")] {
+    }
+    target_family = "wasm" => {
         mod wasm;
         pub use self::wasm::*;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use self::xous::*;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use self::uefi::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use self::sgx::*;
-    } else if #[cfg(target_os = "teeos")] {
+    }
+    target_os = "teeos" => {
         mod teeos;
         pub use self::teeos::*;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
         pub use self::zkvm::*;
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use self::unsupported::*;
     }
 }
 
-cfg_if::cfg_if! {
+pub const FULL_BACKTRACE_DEFAULT: bool = cfg_select! {
     // Fuchsia components default to full backtrace.
-    if #[cfg(target_os = "fuchsia")] {
-        pub const FULL_BACKTRACE_DEFAULT: bool = true;
-    } else {
-        pub const FULL_BACKTRACE_DEFAULT: bool = false;
-    }
-}
+    target_os = "fuchsia" => true,
+    _ => false,
+};
 
 #[cfg(not(target_os = "uefi"))]
 pub type RawOsError = i32;
diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs
index df5611b2ddd..36ce3f7ef96 100644
--- a/library/std/src/sys/pal/uefi/time.rs
+++ b/library/std/src/sys/pal/uefi/time.rs
@@ -188,7 +188,7 @@ pub(crate) mod system_time_internal {
         Duration::new(epoch, t.nanosecond)
     }
 
-    /// This algorithm is a modifed version of the one described in the post:
+    /// This algorithm is a modified version of the one described in the post:
     /// https://howardhinnant.github.io/date_algorithms.html#clive_from_days
     ///
     /// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
@@ -197,7 +197,7 @@ pub(crate) mod system_time_internal {
         // Check timzone validity
         assert!(timezone <= 1440 && timezone >= -1440);
 
-        // FIXME(#126043): use checked_sub_signed once stablized
+        // FIXME(#126043): use checked_sub_signed once stabilized
         let secs =
             dur.as_secs().checked_add_signed((-timezone as i64) * SECS_IN_MINUTE as i64).unwrap();
 
@@ -296,12 +296,9 @@ pub(crate) mod instant_internal {
     }
 
     pub fn platform_specific() -> Option<Instant> {
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] {
-                timestamp_rdtsc().map(Instant)
-            } else {
-                None
-            }
+        cfg_select! {
+            any(target_arch = "x86_64", target_arch = "x86") => timestamp_rdtsc().map(Instant),
+            _ => None,
         }
     }
 
diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs
index c23278bdf5e..265067d84d5 100644
--- a/library/std/src/sys/pal/unix/futex.rs
+++ b/library/std/src/sys/pal/unix/futex.rs
@@ -46,8 +46,8 @@ pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>)
         }
 
         let r = unsafe {
-            cfg_if::cfg_if! {
-                if #[cfg(target_os = "freebsd")] {
+            cfg_select! {
+                target_os = "freebsd" => {
                     // FreeBSD doesn't have futex(), but it has
                     // _umtx_op(UMTX_OP_WAIT_UINT_PRIVATE), which is nearly
                     // identical. It supports absolute timeouts through a flag
@@ -66,7 +66,8 @@ pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>)
                         crate::ptr::without_provenance_mut(umtx_timeout_size),
                         umtx_timeout_ptr as *mut _,
                     )
-                } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
+                }
+                any(target_os = "linux", target_os = "android") => {
                     // Use FUTEX_WAIT_BITSET rather than FUTEX_WAIT to be able to give an
                     // absolute time rather than a relative time.
                     libc::syscall(
@@ -78,7 +79,8 @@ pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>)
                         null::<u32>(), // This argument is unused for FUTEX_WAIT_BITSET.
                         !0u32,         // A full bitmask, to make it behave like a regular FUTEX_WAIT.
                     )
-                } else {
+                }
+                _ => {
                     compile_error!("unknown target_os");
                 }
             }
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index ba9e14b8009..fede3673eb6 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -366,31 +366,36 @@ pub fn abort_internal() -> ! {
     unsafe { libc::abort() }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "android")] {
+cfg_select! {
+    target_os = "android" => {
         #[link(name = "dl", kind = "static", modifiers = "-bundle",
             cfg(target_feature = "crt-static"))]
         #[link(name = "dl", cfg(not(target_feature = "crt-static")))]
         #[link(name = "log", cfg(not(target_feature = "crt-static")))]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "freebsd")] {
+    }
+    target_os = "freebsd" => {
         #[link(name = "execinfo")]
         #[link(name = "pthread")]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "netbsd")] {
+    }
+    target_os = "netbsd" => {
         #[link(name = "pthread")]
         #[link(name = "rt")]
         unsafe extern "C" {}
-    } else if #[cfg(any(target_os = "dragonfly", target_os = "openbsd", target_os = "cygwin"))] {
+    }
+    any(target_os = "dragonfly", target_os = "openbsd", target_os = "cygwin") => {
         #[link(name = "pthread")]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "solaris")] {
+    }
+    target_os = "solaris" => {
         #[link(name = "socket")]
         #[link(name = "posix4")]
         #[link(name = "pthread")]
         #[link(name = "resolv")]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "illumos")] {
+    }
+    target_os = "illumos" => {
         #[link(name = "socket")]
         #[link(name = "posix4")]
         #[link(name = "pthread")]
@@ -399,24 +404,29 @@ cfg_if::cfg_if! {
         // Use libumem for the (malloc-compatible) allocator
         #[link(name = "umem")]
         unsafe extern "C" {}
-    } else if #[cfg(target_vendor = "apple")] {
+    }
+    target_vendor = "apple" => {
         // Link to `libSystem.dylib`.
         //
         // Don't get confused by the presence of `System.framework`,
         // it is a deprecated wrapper over the dynamic library.
         #[link(name = "System")]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "fuchsia")] {
+    }
+    target_os = "fuchsia" => {
         #[link(name = "zircon")]
         #[link(name = "fdio")]
         unsafe extern "C" {}
-    } else if #[cfg(all(target_os = "linux", target_env = "uclibc"))] {
+    }
+    all(target_os = "linux", target_env = "uclibc") => {
         #[link(name = "dl")]
         unsafe extern "C" {}
-    } else if #[cfg(target_os = "vita")] {
+    }
+    target_os = "vita" => {
         #[link(name = "pthread", kind = "static", modifiers = "-bundle")]
         unsafe extern "C" {}
     }
+    _ => {}
 }
 
 #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))]
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index 0e68313cc3e..1110b775c09 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -17,13 +17,10 @@ use crate::{fmt, io, iter, mem, ptr, slice, str};
 
 const TMPBUF_SZ: usize = 128;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "redox")] {
-        const PATH_SEPARATOR: u8 = b';';
-    } else {
-        const PATH_SEPARATOR: u8 = b':';
-    }
-}
+const PATH_SEPARATOR: u8 = cfg_select! {
+    target_os = "redox" => b';',
+    _ => b':',
+};
 
 unsafe extern "C" {
     #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
@@ -620,14 +617,10 @@ fn darwin_temp_dir() -> PathBuf {
 
 pub fn temp_dir() -> PathBuf {
     crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
-        cfg_if::cfg_if! {
-            if #[cfg(all(target_vendor = "apple", not(miri)))] {
-                darwin_temp_dir()
-            } else if #[cfg(target_os = "android")] {
-                PathBuf::from("/data/local/tmp")
-            } else {
-                PathBuf::from("/tmp")
-            }
+        cfg_select! {
+            all(target_vendor = "apple", not(miri)) => darwin_temp_dir(),
+            target_os = "android" => PathBuf::from("/data/local/tmp"),
+            _ => PathBuf::from("/tmp"),
         }
     })
 }
diff --git a/library/std/src/sys/pal/unix/pipe.rs b/library/std/src/sys/pal/unix/pipe.rs
index 55510153dc8..6b0cd14da4f 100644
--- a/library/std/src/sys/pal/unix/pipe.rs
+++ b/library/std/src/sys/pal/unix/pipe.rs
@@ -18,8 +18,8 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
     // The only known way right now to create atomically set the CLOEXEC flag is
     // to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9
     // and musl 0.9.3, and some other targets also have it.
-    cfg_if::cfg_if! {
-        if #[cfg(any(
+    cfg_select! {
+        any(
             target_os = "dragonfly",
             target_os = "freebsd",
             target_os = "hurd",
@@ -29,12 +29,13 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
             target_os = "openbsd",
             target_os = "cygwin",
             target_os = "redox"
-        ))] {
+        ) => {
             unsafe {
                 cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?;
                 Ok((AnonPipe(FileDesc::from_raw_fd(fds[0])), AnonPipe(FileDesc::from_raw_fd(fds[1]))))
             }
-        } else {
+        }
+        _ => {
             unsafe {
                 cvt(libc::pipe(fds.as_mut_ptr()))?;
 
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 24b65c11fd2..3389b8c0c8a 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -151,12 +151,13 @@ impl Thread {
     ))]
     pub fn set_name(name: &CStr) {
         unsafe {
-            cfg_if::cfg_if! {
-                if #[cfg(any(target_os = "linux", target_os = "cygwin"))] {
+            cfg_select! {
+                any(target_os = "linux", target_os = "cygwin") => {
                     // Linux and Cygwin limits the allowed length of the name.
                     const TASK_COMM_LEN: usize = 16;
                     let name = truncate_cstr::<{ TASK_COMM_LEN }>(name);
-                } else {
+                }
+                _ => {
                     // FreeBSD, DragonFly BSD and NuttX do not enforce length limits.
                 }
             };
@@ -415,9 +416,9 @@ pub(crate) fn current_os_id() -> Option<u64> {
     //
     // The OS thread ID is used rather than `pthread_self` so as to match what will be displayed
     // for process inspection (debuggers, trace, `top`, etc.).
-    cfg_if::cfg_if! {
+    cfg_select! {
         // Most platforms have a function returning a `pid_t` or int, which is an `i32`.
-        if #[cfg(any(target_os = "android", target_os = "linux"))] {
+        any(target_os = "android", target_os = "linux") => {
             use crate::sys::weak::syscall;
 
             // `libc::gettid` is only available on glibc 2.30+, but the syscall is available
@@ -427,28 +428,34 @@ pub(crate) fn current_os_id() -> Option<u64> {
             // SAFETY: FFI call with no preconditions.
             let id: libc::pid_t = unsafe { gettid() };
             Some(id as u64)
-        } else if #[cfg(target_os = "nto")] {
+        }
+        target_os = "nto" => {
             // SAFETY: FFI call with no preconditions.
             let id: libc::pid_t = unsafe { libc::gettid() };
             Some(id as u64)
-        } else if #[cfg(target_os = "openbsd")] {
+        }
+        target_os = "openbsd" => {
             // SAFETY: FFI call with no preconditions.
             let id: libc::pid_t = unsafe { libc::getthrid() };
             Some(id as u64)
-        } else if #[cfg(target_os = "freebsd")] {
+        }
+        target_os = "freebsd" => {
             // SAFETY: FFI call with no preconditions.
             let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
             Some(id as u64)
-        } else if #[cfg(target_os = "netbsd")] {
+        }
+        target_os = "netbsd" => {
             // SAFETY: FFI call with no preconditions.
             let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
             Some(id as u64)
-        } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
+        }
+        any(target_os = "illumos", target_os = "solaris") => {
             // On Illumos and Solaris, the `pthread_t` is the same as the OS thread ID.
             // SAFETY: FFI call with no preconditions.
             let id: libc::pthread_t = unsafe { libc::pthread_self() };
             Some(id as u64)
-        } else if #[cfg(target_vendor = "apple")] {
+        }
+        target_vendor = "apple" => {
             // Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread.
             let mut id = 0u64;
             // SAFETY: `thread_id` is a valid pointer, no other preconditions.
@@ -458,10 +465,9 @@ pub(crate) fn current_os_id() -> Option<u64> {
             } else {
                 None
             }
-        } else {
-            // Other platforms don't have an OS thread ID or don't have a way to access it.
-            None
         }
+        // Other platforms don't have an OS thread ID or don't have a way to access it.
+        _ => None,
     }
 }
 
@@ -483,8 +489,8 @@ fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_W
 }
 
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    cfg_if::cfg_if! {
-        if #[cfg(any(
+    cfg_select! {
+        any(
             target_os = "android",
             target_os = "emscripten",
             target_os = "fuchsia",
@@ -493,7 +499,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
             target_os = "aix",
             target_vendor = "apple",
             target_os = "cygwin",
-        ))] {
+        ) => {
             #[allow(unused_assignments)]
             #[allow(unused_mut)]
             let mut quota = usize::MAX;
@@ -527,12 +533,13 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                     Ok(unsafe { NonZero::new_unchecked(count) })
                 }
             }
-        } else if #[cfg(any(
-                   target_os = "freebsd",
-                   target_os = "dragonfly",
-                   target_os = "openbsd",
-                   target_os = "netbsd",
-               ))] {
+        }
+        any(
+           target_os = "freebsd",
+           target_os = "dragonfly",
+           target_os = "openbsd",
+           target_os = "netbsd",
+        ) => {
             use crate::ptr;
 
             #[cfg(target_os = "freebsd")]
@@ -607,7 +614,8 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
             }
 
             Ok(unsafe { NonZero::new_unchecked(cpus as usize) })
-        } else if #[cfg(target_os = "nto")] {
+        }
+        target_os = "nto" => {
             unsafe {
                 use libc::_syspage_ptr;
                 if _syspage_ptr.is_null() {
@@ -618,13 +626,15 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                         .ok_or(io::Error::UNKNOWN_THREAD_COUNT)
                 }
             }
-        } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] {
+        }
+        any(target_os = "solaris", target_os = "illumos") => {
             let mut cpus = 0u32;
             if unsafe { libc::pset_info(libc::PS_MYID, core::ptr::null_mut(), &mut cpus, core::ptr::null_mut()) } != 0 {
                 return Err(io::Error::UNKNOWN_THREAD_COUNT);
             }
             Ok(unsafe { NonZero::new_unchecked(cpus as usize) })
-        } else if #[cfg(target_os = "haiku")] {
+        }
+        target_os = "haiku" => {
             // system_info cpu_count field gets the static data set at boot time with `smp_set_num_cpus`
             // `get_system_info` calls then `smp_get_num_cpus`
             unsafe {
@@ -637,7 +647,8 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
 
                 Ok(NonZero::new_unchecked(sinfo.cpu_count as usize))
             }
-        } else if #[cfg(target_os = "vxworks")] {
+        }
+        target_os = "vxworks" => {
             // Note: there is also `vxCpuConfiguredGet`, closer to _SC_NPROCESSORS_CONF
             // expectations than the actual cores availability.
             unsafe extern "C" {
@@ -649,7 +660,8 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                 let set = vxCpuEnabledGet();
                 Ok(NonZero::new_unchecked(set.count_ones() as usize))
             }
-        } else {
+        }
+        _ => {
             // FIXME: implement on Redox, l4re
             Err(io::const_error!(io::ErrorKind::Unsupported, "getting the number of hardware threads is not supported on the target platform"))
         }
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index 4755e2ef5da..e062b49bd7a 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -5,8 +5,8 @@ use crate::num::NonZero;
 use crate::time::{Duration, Instant};
 use crate::{io, mem};
 
-cfg_if::cfg_if! {
-    if #[cfg(target_feature = "atomics")] {
+cfg_select! {
+    target_feature = "atomics" => {
         use crate::cmp;
         use crate::ptr;
         use crate::sys::os;
@@ -62,7 +62,8 @@ cfg_if::cfg_if! {
                 debug_assert_eq!(ret, 0);
             }
         }
-    } else {
+    }
+    _ => {
         pub struct Thread(!);
     }
 }
@@ -71,8 +72,8 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
 
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    cfg_if::cfg_if! {
-        if #[cfg(target_feature = "atomics")] {
+    cfg_select! {
+        target_feature = "atomics" => {
             pub unsafe fn new(stack: usize, _name: Option<&str>, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
                 let p = Box::into_raw(Box::new(p));
                 let mut native: libc::pthread_t = unsafe { mem::zeroed() };
@@ -119,7 +120,8 @@ impl Thread {
                     ptr::null_mut()
                 }
             }
-        } else {
+        }
+        _ => {
             pub unsafe fn new(_stack: usize, _name: Option<&str>, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
                 crate::sys::unsupported()
             }
@@ -180,14 +182,15 @@ impl Thread {
     }
 
     pub fn join(self) {
-        cfg_if::cfg_if! {
-            if #[cfg(target_feature = "atomics")] {
+        cfg_select! {
+            target_feature = "atomics" => {
                 let id = mem::ManuallyDrop::new(self).id;
                 let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
                 if ret != 0 {
                     rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
                 }
-            } else {
+            }
+            _ => {
                 self.0
             }
         }
@@ -199,14 +202,13 @@ pub(crate) fn current_os_id() -> Option<u64> {
 }
 
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    cfg_if::cfg_if! {
-        if #[cfg(target_feature = "atomics")] {
+    cfg_select! {
+        target_feature = "atomics" => {
             match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
                 -1 => Err(io::Error::last_os_error()),
                 cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT),
             }
-        } else {
-            crate::sys::unsupported()
         }
+        _ => crate::sys::unsupported(),
     }
 }
diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs
index 37cb46a8f6b..346c9ff88c9 100644
--- a/library/std/src/sys/pal/wasm/mod.rs
+++ b/library/std/src/sys/pal/wasm/mod.rs
@@ -23,13 +23,14 @@ pub mod pipe;
 #[path = "../unsupported/time.rs"]
 pub mod time;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_feature = "atomics")] {
+cfg_select! {
+    target_feature = "atomics" => {
         #[path = "atomics/futex.rs"]
         pub mod futex;
         #[path = "atomics/thread.rs"]
         pub mod thread;
-    } else {
+    }
+    _ => {
         #[path = "../unsupported/thread.rs"]
         pub mod thread;
     }
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index edac5262a4e..25c1a82cc42 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -95,11 +95,8 @@ pub struct MOUNT_POINT_REPARSE_BUFFER {
 }
 
 // Desktop specific functions & types
-cfg_if::cfg_if! {
-if #[cfg(not(target_vendor = "uwp"))] {
-    pub const EXCEPTION_CONTINUE_SEARCH: i32 = 0;
-}
-}
+#[cfg(not(target_vendor = "uwp"))]
+pub const EXCEPTION_CONTINUE_SEARCH: i32 = 0;
 
 // Use raw-dylib to import ProcessPrng as we can't rely on there being an import library.
 #[cfg(not(target_vendor = "win7"))]
@@ -230,12 +227,13 @@ compat_fn_with_fallback! {
     }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(target_vendor = "uwp")] {
+cfg_select! {
+    target_vendor = "uwp" => {
         windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
         windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS);
         windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
         windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
         windows_targets::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
     }
+    _ => {}
 }
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index 8f54e2376eb..10ad4541bed 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -22,10 +22,11 @@ pub mod os;
 pub mod pipe;
 pub mod thread;
 pub mod time;
-cfg_if::cfg_if! {
-    if #[cfg(not(target_vendor = "uwp"))] {
+cfg_select! {
+    not(target_vendor = "uwp") => {
         pub mod stack_overflow;
-    } else {
+    }
+    _ => {
         pub mod stack_overflow_uwp;
         pub use self::stack_overflow_uwp as stack_overflow;
     }
@@ -337,14 +338,17 @@ pub fn dur2timeout(dur: Duration) -> u32 {
 #[cfg(not(miri))] // inline assembly does not work in Miri
 pub fn abort_internal() -> ! {
     unsafe {
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
+        cfg_select! {
+            any(target_arch = "x86", target_arch = "x86_64") => {
                 core::arch::asm!("int $$0x29", in("ecx") c::FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
-            } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
+            }
+            all(target_arch = "arm", target_feature = "thumb-mode") => {
                 core::arch::asm!(".inst 0xDEFB", in("r0") c::FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
-            } else if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] {
+            }
+            any(target_arch = "aarch64", target_arch = "arm64ec") => {
                 core::arch::asm!("brk 0xF003", in("x0") c::FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
-            } else {
+            }
+            _ => {
                 core::intrinsics::abort();
             }
         }
diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs
index a4ff4338cf5..254683bc83f 100644
--- a/library/std/src/sys/path/mod.rs
+++ b/library/std/src/sys/path/mod.rs
@@ -1,22 +1,27 @@
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "windows")] {
+cfg_select! {
+    target_os = "windows" => {
         mod windows;
         mod windows_prefix;
         pub use windows::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod unsupported_backslash;
         pub use unsupported_backslash::*;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use uefi::*;
-    } else if #[cfg(target_os = "cygwin")] {
+    }
+    target_os = "cygwin" => {
         mod cygwin;
         mod windows_prefix;
         pub use cygwin::*;
-    } else {
+    }
+    _ => {
         mod unix;
         pub use unix::*;
     }
diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs
index 75e793f18b8..019d5629d6d 100644
--- a/library/std/src/sys/personality/gcc.rs
+++ b/library/std/src/sys/personality/gcc.rs
@@ -93,12 +93,12 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1
 // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
 // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
 
-cfg_if::cfg_if! {
-    if #[cfg(all(
+cfg_select! {
+    all(
         target_arch = "arm",
         not(target_vendor = "apple"),
         not(target_os = "netbsd"),
-    ))] {
+    ) => {
         /// personality fn called by [ARM EHABI][armeabi-eh]
         ///
         /// 32-bit ARM on iOS/tvOS/watchOS does not use ARM EHABI, it uses
@@ -202,7 +202,8 @@ cfg_if::cfg_if! {
                 }
             }
         }
-    } else {
+    }
+    _ => {
         /// Default personality routine, which is used directly on most targets
         /// and indirectly on Windows x86_64 and AArch64 via SEH.
         unsafe extern "C" fn rust_eh_personality_impl(
@@ -247,11 +248,11 @@ cfg_if::cfg_if! {
             }
         }
 
-        cfg_if::cfg_if! {
-            if #[cfg(any(
-                    all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"),
-                    target_os = "cygwin",
-                ))] {
+        cfg_select! {
+            any(
+                all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"),
+                target_os = "cygwin",
+            ) => {
                 /// personality fn called by [Windows Structured Exception Handling][windows-eh]
                 ///
                 /// On x86_64 and AArch64 MinGW targets, the unwinding mechanism is SEH,
@@ -279,7 +280,8 @@ cfg_if::cfg_if! {
                         )
                     }
                 }
-            } else {
+            }
+            _ => {
                 /// personality fn called by [Itanium C++ ABI Exception Handling][itanium-eh]
                 ///
                 /// The personality routine for most non-Windows targets. This will be called by
diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs
index 2e1d2e53a29..158e44e1764 100644
--- a/library/std/src/sys/personality/mod.rs
+++ b/library/std/src/sys/personality/mod.rs
@@ -13,10 +13,11 @@
 mod dwarf;
 
 #[cfg(not(any(test, doctest)))]
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "emscripten")] {
+cfg_select! {
+    target_os = "emscripten" => {
         mod emcc;
-    } else if #[cfg(any(target_env = "msvc", target_family = "wasm"))] {
+    }
+    any(target_env = "msvc", target_family = "wasm") => {
         // This is required by the compiler to exist (e.g., it's a lang item),
         // but it's never actually called by the compiler because
         // __CxxFrameHandler3 (msvc) / __gxx_wasm_personality_v0 (wasm) is the
@@ -26,16 +27,18 @@ cfg_if::cfg_if! {
         fn rust_eh_personality() {
             core::intrinsics::abort()
         }
-    } else if #[cfg(any(
+    }
+    any(
         all(target_family = "windows", target_env = "gnu"),
         target_os = "psp",
         target_os = "xous",
         target_os = "solid_asp3",
         all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "nuttx")),
         all(target_vendor = "fortanix", target_env = "sgx"),
-    ))] {
+    ) => {
         mod gcc;
-    } else {
+    }
+    _ => {
         // Targets that don't support unwinding.
         // - os=none ("bare metal" targets)
         // - os=uefi
diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs
index 91c7005a328..9ef5496e57a 100644
--- a/library/std/src/sys/process/mod.rs
+++ b/library/std/src/sys/process/mod.rs
@@ -1,14 +1,17 @@
-cfg_if::cfg_if! {
-    if #[cfg(target_family = "unix")] {
+cfg_select! {
+    target_family = "unix" => {
         mod unix;
         use unix as imp;
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
         use windows as imp;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         use uefi as imp;
-    } else {
+    }
+    _ => {
         mod unsupported;
         use unsupported as imp;
     }
diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs
index 6219be60caf..ea45b08e90a 100644
--- a/library/std/src/sys/process/unix/common.rs
+++ b/library/std/src/sys/process/unix/common.rs
@@ -20,12 +20,14 @@ use crate::{fmt, io};
 
 mod cstring_array;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "fuchsia")] {
+cfg_select! {
+    target_os = "fuchsia" => {
         // fuchsia doesn't have /dev/null
-    } else if #[cfg(target_os = "vxworks")] {
+    }
+    target_os = "vxworks" => {
         const DEV_NULL: &CStr = c"/null";
-    } else {
+    }
+    _ => {
         const DEV_NULL: &CStr = c"/dev/null";
     }
 }
@@ -35,8 +37,8 @@ cfg_if::cfg_if! {
 // to support older Android version (independent of libc version).
 // The following implementations are based on
 // https://github.com/aosp-mirror/platform_bionic/blob/ad8dcd6023294b646e5a8288c0ed431b0845da49/libc/include/android/legacy_signal_inlines.h
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "android")] {
+cfg_select! {
+    target_os = "android" => {
         #[allow(dead_code)]
         pub unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
             set.write_bytes(0u8, 1);
@@ -69,7 +71,8 @@ cfg_if::cfg_if! {
             raw[bit / LONG_BIT] |= 1 << (bit % LONG_BIT);
             return 0;
         }
-    } else {
+    }
+    _ => {
         #[allow(unused_imports)]
         pub use libc::{sigemptyset, sigaddset};
     }
diff --git a/library/std/src/sys/process/unix/mod.rs b/library/std/src/sys/process/unix/mod.rs
index ee8fd8b2ca3..b4cf060fba9 100644
--- a/library/std/src/sys/process/unix/mod.rs
+++ b/library/std/src/sys/process/unix/mod.rs
@@ -1,18 +1,21 @@
 #[cfg_attr(any(target_os = "espidf", target_os = "horizon", target_os = "nuttx"), allow(unused))]
 mod common;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "fuchsia")] {
+cfg_select! {
+    target_os = "fuchsia" => {
         mod fuchsia;
         use fuchsia as imp;
-    } else if #[cfg(target_os = "vxworks")] {
+    }
+    target_os = "vxworks" => {
         mod vxworks;
         use vxworks as imp;
-    } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] {
+    }
+    any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx") => {
         mod unsupported;
         use unsupported as imp;
         pub use unsupported::output;
-    } else {
+    }
+    _ => {
         mod unix;
         use unix as imp;
     }
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index 5d13d6da185..11d48878727 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -18,8 +18,8 @@ use crate::sys::cvt;
 use crate::sys::pal::linux::pidfd::PidFd;
 use crate::{fmt, mem, sys};
 
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "nto")] {
+cfg_select! {
+    target_os = "nto" => {
         use crate::thread;
         use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t};
         use crate::time::Duration;
@@ -43,6 +43,7 @@ cfg_if::cfg_if! {
         // Maximum duration of sleeping before giving up and returning an error
         const MAX_FORKSPAWN_SLEEP: Duration = Duration::from_millis(1000);
     }
+    _ => {}
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -465,8 +466,8 @@ impl Command {
             return Ok(None);
         }
 
-        cfg_if::cfg_if! {
-            if #[cfg(target_os = "linux")] {
+        cfg_select! {
+            target_os = "linux" => {
                 use crate::sys::weak::weak;
 
                 weak!(
@@ -526,7 +527,8 @@ impl Command {
                     }
                     core::assert_matches::debug_assert_matches!(support, SPAWN | NO);
                 }
-            } else {
+            }
+            _ => {
                 if self.get_create_pidfd() {
                     unreachable!("only implemented on linux")
                 }
@@ -746,10 +748,11 @@ impl Command {
             }
 
             if self.get_setsid() {
-                cfg_if::cfg_if! {
-                    if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
+                cfg_select! {
+                    all(target_os = "linux", target_env = "gnu") => {
                         flags |= libc::POSIX_SPAWN_SETSID;
-                    } else {
+                    }
+                    _ => {
                         return Ok(None);
                     }
                 }
diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs
index fc85797dcc2..a7fbae86099 100644
--- a/library/std/src/sys/random/mod.rs
+++ b/library/std/src/sys/random/mod.rs
@@ -1,16 +1,19 @@
-cfg_if::cfg_if! {
+cfg_select! {
     // Tier 1
-    if #[cfg(any(target_os = "linux", target_os = "android"))] {
+    any(target_os = "linux", target_os = "android") => {
         mod linux;
         pub use linux::{fill_bytes, hashmap_random_keys};
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
         pub use windows::fill_bytes;
-    } else if #[cfg(target_vendor = "apple")] {
+    }
+    target_vendor = "apple" => {
         mod apple;
         pub use apple::fill_bytes;
     // Others, in alphabetical ordering.
-    } else if #[cfg(any(
+    }
+    any(
         target_os = "dragonfly",
         target_os = "freebsd",
         target_os = "haiku",
@@ -21,69 +24,86 @@ cfg_if::cfg_if! {
         target_os = "solaris",
         target_os = "vita",
         target_os = "nuttx",
-    ))] {
+    ) => {
         mod arc4random;
         pub use arc4random::fill_bytes;
-    } else if #[cfg(target_os = "emscripten")] {
+    }
+    target_os = "emscripten" => {
         mod getentropy;
         pub use getentropy::fill_bytes;
-    } else if #[cfg(target_os = "espidf")] {
+    }
+    target_os = "espidf" => {
         mod espidf;
         pub use espidf::fill_bytes;
-    } else if #[cfg(target_os = "fuchsia")] {
+    }
+    target_os = "fuchsia" => {
         mod fuchsia;
         pub use fuchsia::fill_bytes;
-    } else if #[cfg(target_os = "hermit")] {
+    }
+    target_os = "hermit" => {
         mod hermit;
         pub use hermit::fill_bytes;
-    } else if #[cfg(any(target_os = "horizon", target_os = "cygwin"))] {
+    }
+    any(target_os = "horizon", target_os = "cygwin") => {
         // FIXME(horizon): add arc4random_buf to shim-3ds
         mod getrandom;
         pub use getrandom::fill_bytes;
-    } else if #[cfg(any(
+    }
+    any(
         target_os = "aix",
         target_os = "hurd",
         target_os = "l4re",
         target_os = "nto",
-    ))] {
+    ) => {
         mod unix_legacy;
         pub use unix_legacy::fill_bytes;
-    } else if #[cfg(target_os = "redox")] {
+    }
+    target_os = "redox" => {
         mod redox;
         pub use redox::fill_bytes;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::fill_bytes;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use solid::fill_bytes;
-    } else if #[cfg(target_os = "teeos")] {
+    }
+    target_os = "teeos" => {
         mod teeos;
         pub use teeos::fill_bytes;
-    } else if #[cfg(target_os = "trusty")] {
+    }
+    target_os = "trusty" => {
         mod trusty;
         pub use trusty::fill_bytes;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use uefi::fill_bytes;
-    } else if #[cfg(target_os = "vxworks")] {
+    }
+    target_os = "vxworks" => {
         mod vxworks;
         pub use vxworks::fill_bytes;
-    } else if #[cfg(target_os = "wasi")] {
+    }
+    target_os = "wasi" => {
         mod wasi;
         pub use wasi::fill_bytes;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
         pub use zkvm::fill_bytes;
-    } else if #[cfg(any(
+    }
+    any(
         all(target_family = "wasm", target_os = "unknown"),
         target_os = "xous",
-    ))] {
+    ) => {
         // FIXME: finally remove std support for wasm32-unknown-unknown
         // FIXME: add random data generation to xous
         mod unsupported;
         pub use unsupported::{fill_bytes, hashmap_random_keys};
     }
+    _ => {}
 }
 
 #[cfg(not(any(
diff --git a/library/std/src/sys/random/uefi.rs b/library/std/src/sys/random/uefi.rs
index 4a71d32fffe..697933f197b 100644
--- a/library/std/src/sys/random/uefi.rs
+++ b/library/std/src/sys/random/uefi.rs
@@ -55,12 +55,13 @@ mod rng_protocol {
 /// Port from [getrandom](https://github.com/rust-random/getrandom/blob/master/src/backends/rdrand.rs)
 #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
 mod rdrand {
-    cfg_if::cfg_if! {
-        if #[cfg(target_arch = "x86_64")] {
+    cfg_select! {
+        target_arch = "x86_64" => {
             use crate::arch::x86_64 as arch;
             use arch::_rdrand64_step as rdrand_step;
             type Word = u64;
-        } else if #[cfg(target_arch = "x86")] {
+        }
+        target_arch = "x86" => {
             use crate::arch::x86 as arch;
             use arch::_rdrand32_step as rdrand_step;
             type Word = u32;
diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs
index 336d4c8527d..314f226f07b 100644
--- a/library/std/src/sys/stdio/mod.rs
+++ b/library/std/src/sys/stdio/mod.rs
@@ -1,40 +1,47 @@
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
-        target_family = "unix",
-        target_os = "hermit"
-    ))] {
+cfg_select! {
+    any(target_family = "unix", target_os = "hermit") => {
         mod unix;
         pub use unix::*;
-    } else if #[cfg(target_os = "windows")] {
+    }
+    target_os = "windows" => {
         mod windows;
         pub use windows::*;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use solid::*;
-    } else if #[cfg(target_os = "teeos")] {
+    }
+    target_os = "teeos" => {
         mod teeos;
         pub use teeos::*;
-    } else if #[cfg(target_os = "trusty")] {
+    }
+    target_os = "trusty" => {
         mod trusty;
         pub use trusty::*;
-    } else if #[cfg(target_os = "uefi")] {
+    }
+    target_os = "uefi" => {
         mod uefi;
         pub use uefi::*;
-    } else if #[cfg(target_os = "wasi")] {
+    }
+    target_os = "wasi" => {
         mod wasi;
         pub use wasi::*;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::*;
-    } else if #[cfg(target_os = "zkvm")] {
+    }
+    target_os = "zkvm" => {
         mod zkvm;
         pub use zkvm::*;
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use unsupported::*;
     }
diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs
index d0c998a5597..cb67d273759 100644
--- a/library/std/src/sys/sync/condvar/mod.rs
+++ b/library/std/src/sys/sync/condvar/mod.rs
@@ -1,5 +1,5 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_os = "windows", not(target_vendor="win7")),
         target_os = "linux",
         target_os = "android",
@@ -9,28 +9,34 @@ cfg_if::cfg_if! {
         target_os = "fuchsia",
         all(target_family = "wasm", target_feature = "atomics"),
         target_os = "hermit",
-    ))] {
+    ) => {
         mod futex;
         pub use futex::Condvar;
-    } else if #[cfg(any(
+    }
+    any(
         target_family = "unix",
         target_os = "teeos",
-    ))] {
+    ) => {
         mod pthread;
         pub use pthread::Condvar;
-    } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] {
+    }
+    all(target_os = "windows", target_vendor = "win7") => {
         mod windows7;
         pub use windows7::Condvar;
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::Condvar;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod itron;
         pub use itron::Condvar;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::Condvar;
-    } else {
+    }
+    _ => {
         mod no_threads;
         pub use no_threads::Condvar;
     }
diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs
index 360df3fc4b5..c885b0eabae 100644
--- a/library/std/src/sys/sync/mutex/mod.rs
+++ b/library/std/src/sys/sync/mutex/mod.rs
@@ -1,5 +1,5 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_os = "windows", not(target_vendor = "win7")),
         target_os = "linux",
         target_os = "android",
@@ -8,31 +8,38 @@ cfg_if::cfg_if! {
         target_os = "dragonfly",
         all(target_family = "wasm", target_feature = "atomics"),
         target_os = "hermit",
-    ))] {
+    ) => {
         mod futex;
         pub use futex::Mutex;
-    } else if #[cfg(target_os = "fuchsia")] {
+    }
+    target_os = "fuchsia" => {
         mod fuchsia;
         pub use fuchsia::Mutex;
-    } else if #[cfg(any(
+    }
+    any(
         target_family = "unix",
         target_os = "teeos",
-    ))] {
+    ) => {
         mod pthread;
         pub use pthread::Mutex;
-    } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] {
+    }
+    all(target_os = "windows", target_vendor = "win7") => {
         mod windows7;
         pub use windows7::{Mutex, raw};
-    } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::Mutex;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod itron;
         pub use itron::Mutex;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::Mutex;
-    } else {
+    }
+    _ => {
         mod no_threads;
         pub use no_threads::Mutex;
     }
diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs
index 0e38937b121..8adeb1f259d 100644
--- a/library/std/src/sys/sync/once/mod.rs
+++ b/library/std/src/sys/sync/once/mod.rs
@@ -7,8 +7,8 @@
 // This also gives us the opportunity to optimize the implementation a bit which
 // should help the fast path on call sites.
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_os = "windows", not(target_vendor="win7")),
         target_os = "linux",
         target_os = "android",
@@ -18,19 +18,21 @@ cfg_if::cfg_if! {
         target_os = "dragonfly",
         target_os = "fuchsia",
         target_os = "hermit",
-    ))] {
+    ) => {
         mod futex;
         pub use futex::{Once, OnceState};
-    } else if #[cfg(any(
+    }
+    any(
         windows,
         target_family = "unix",
         all(target_vendor = "fortanix", target_env = "sgx"),
         target_os = "solid_asp3",
         target_os = "xous",
-    ))] {
+    ) => {
         mod queue;
         pub use queue::{Once, OnceState};
-    } else {
+    }
+    _ => {
         mod no_threads;
         pub use no_threads::{Once, OnceState};
     }
diff --git a/library/std/src/sys/sync/rwlock/mod.rs b/library/std/src/sys/sync/rwlock/mod.rs
index 70ba6bf38ef..82f1dd18dee 100644
--- a/library/std/src/sys/sync/rwlock/mod.rs
+++ b/library/std/src/sys/sync/rwlock/mod.rs
@@ -1,5 +1,5 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_os = "windows", not(target_vendor = "win7")),
         target_os = "linux",
         target_os = "android",
@@ -9,24 +9,28 @@ cfg_if::cfg_if! {
         target_os = "fuchsia",
         all(target_family = "wasm", target_feature = "atomics"),
         target_os = "hermit",
-    ))] {
+    ) => {
         mod futex;
         pub use futex::RwLock;
-    } else if #[cfg(any(
+    }
+    any(
         target_family = "unix",
         all(target_os = "windows", target_vendor = "win7"),
         all(target_vendor = "fortanix", target_env = "sgx"),
         target_os = "xous",
-    ))] {
+    ) => {
         mod queue;
         pub use queue::RwLock;
-    } else if #[cfg(target_os = "solid_asp3")] {
+    }
+    target_os = "solid_asp3" => {
         mod solid;
         pub use solid::RwLock;
-    } else if #[cfg(target_os = "teeos")] {
+    }
+    target_os = "teeos" => {
         mod teeos;
         pub use teeos::RwLock;
-    } else {
+    }
+    _ => {
         mod no_threads;
         pub use no_threads::RwLock;
     }
diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs
index f4d8fa0a58c..b9fb27b4eef 100644
--- a/library/std/src/sys/sync/thread_parking/mod.rs
+++ b/library/std/src/sys/sync/thread_parking/mod.rs
@@ -1,5 +1,5 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_os = "windows", not(target_vendor = "win7")),
         target_os = "linux",
         target_os = "android",
@@ -9,30 +9,36 @@ cfg_if::cfg_if! {
         target_os = "dragonfly",
         target_os = "fuchsia",
         target_os = "hermit",
-    ))] {
+    ) => {
         mod futex;
         pub use futex::Parker;
-    } else if #[cfg(any(
+    }
+    any(
         target_os = "netbsd",
         all(target_vendor = "fortanix", target_env = "sgx"),
         target_os = "solid_asp3",
-    ))] {
+    ) => {
         mod id;
         pub use id::Parker;
-    } else if #[cfg(target_vendor = "win7")] {
+    }
+    target_vendor = "win7" => {
         mod windows7;
         pub use windows7::Parker;
-    } else if #[cfg(all(target_vendor = "apple", not(miri)))] {
+    }
+    all(target_vendor = "apple", not(miri)) => {
         // Doesn't work in Miri, see <https://github.com/rust-lang/miri/issues/2589>.
         mod darwin;
         pub use darwin::Parker;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod xous;
         pub use xous::Parker;
-    } else if #[cfg(target_family = "unix")] {
+    }
+    target_family = "unix" => {
         mod pthread;
         pub use pthread::Parker;
-    } else {
+    }
+    _ => {
         mod unsupported;
         pub use unsupported::Parker;
     }
diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs
index 9fafac3aa5b..cff74857c47 100644
--- a/library/std/src/sys/thread_local/mod.rs
+++ b/library/std/src/sys/thread_local/mod.rs
@@ -23,21 +23,23 @@
     issue = "none"
 )]
 
-cfg_if::cfg_if! {
-    if #[cfg(any(
+cfg_select! {
+    any(
         all(target_family = "wasm", not(target_feature = "atomics")),
         target_os = "uefi",
         target_os = "zkvm",
         target_os = "trusty",
-    ))] {
+    ) => {
         mod no_threads;
         pub use no_threads::{EagerStorage, LazyStorage, thread_local_inner};
         pub(crate) use no_threads::{LocalPointer, local_pointer};
-    } else if #[cfg(target_thread_local)] {
+    }
+    target_thread_local => {
         mod native;
         pub use native::{EagerStorage, LazyStorage, thread_local_inner};
         pub(crate) use native::{LocalPointer, local_pointer};
-    } else {
+    }
+    _ => {
         mod os;
         pub use os::{Storage, thread_local_inner};
         pub(crate) use os::{LocalPointer, local_pointer};
@@ -53,8 +55,8 @@ cfg_if::cfg_if! {
 /// single callback that runs all of the destructors in the list.
 #[cfg(all(target_thread_local, not(all(target_family = "wasm", not(target_feature = "atomics")))))]
 pub(crate) mod destructors {
-    cfg_if::cfg_if! {
-        if #[cfg(any(
+    cfg_select! {
+        any(
             target_os = "linux",
             target_os = "android",
             target_os = "fuchsia",
@@ -62,12 +64,13 @@ pub(crate) mod destructors {
             target_os = "hurd",
             target_os = "netbsd",
             target_os = "dragonfly"
-        ))] {
+        ) => {
             mod linux_like;
             mod list;
             pub(super) use linux_like::register;
             pub(super) use list::run;
-        } else {
+        }
+        _ => {
             mod list;
             pub(super) use list::register;
             pub(crate) use list::run;
@@ -79,21 +82,23 @@ pub(crate) mod destructors {
 /// and the [runtime cleanup](crate::rt::thread_cleanup) function. Calling `enable`
 /// should ensure that these functions are called at the right times.
 pub(crate) mod guard {
-    cfg_if::cfg_if! {
-        if #[cfg(all(target_thread_local, target_vendor = "apple"))] {
+    cfg_select! {
+        all(target_thread_local, target_vendor = "apple") => {
             mod apple;
             pub(crate) use apple::enable;
-        } else if #[cfg(target_os = "windows")] {
+        }
+        target_os = "windows" => {
             mod windows;
             pub(crate) use windows::enable;
-        } else if #[cfg(any(
+        }
+        any(
             all(target_family = "wasm", not(
                 all(target_os = "wasi", target_env = "p1", target_feature = "atomics")
             )),
             target_os = "uefi",
             target_os = "zkvm",
             target_os = "trusty",
-        ))] {
+        ) => {
             pub(crate) fn enable() {
                 // FIXME: Right now there is no concept of "thread exit" on
                 // wasm, but this is likely going to show up at some point in
@@ -107,17 +112,20 @@ pub(crate) mod guard {
                 #[allow(unused)]
                 use crate::rt::thread_cleanup;
             }
-        } else if #[cfg(any(
+        }
+        any(
             target_os = "hermit",
             target_os = "xous",
-        ))] {
+        ) => {
             // `std` is the only runtime, so it just calls the destructor functions
             // itself when the time comes.
             pub(crate) fn enable() {}
-        } else if #[cfg(target_os = "solid_asp3")] {
+        }
+        target_os = "solid_asp3" => {
             mod solid;
             pub(crate) use solid::enable;
-        } else {
+        }
+        _ => {
             mod key;
             pub(crate) use key::enable;
         }
@@ -131,8 +139,8 @@ pub(crate) mod guard {
 /// reference an entry in a thread-local table. This then associates each key
 /// with a pointer which we can get and set to store our data.
 pub(crate) mod key {
-    cfg_if::cfg_if! {
-        if #[cfg(any(
+    cfg_select! {
+        any(
             all(
                 not(target_vendor = "apple"),
                 not(target_family = "wasm"),
@@ -141,7 +149,7 @@ pub(crate) mod key {
             all(not(target_thread_local), target_vendor = "apple"),
             target_os = "teeos",
             all(target_os = "wasi", target_env = "p1", target_feature = "atomics"),
-        ))] {
+        ) => {
             mod racy;
             mod unix;
             #[cfg(test)]
@@ -151,12 +159,14 @@ pub(crate) mod key {
             #[cfg(any(not(target_thread_local), test))]
             pub(super) use unix::get;
             use unix::{create, destroy};
-        } else if #[cfg(all(not(target_thread_local), target_os = "windows"))] {
+        }
+        all(not(target_thread_local), target_os = "windows") => {
             #[cfg(test)]
             mod tests;
             mod windows;
             pub(super) use windows::{Key, LazyKey, get, run_dtors, set};
-        } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+        }
+        all(target_vendor = "fortanix", target_env = "sgx") => {
             mod racy;
             mod sgx;
             #[cfg(test)]
@@ -164,7 +174,8 @@ pub(crate) mod key {
             pub(super) use racy::LazyKey;
             pub(super) use sgx::{Key, get, set};
             use sgx::{create, destroy};
-        } else if #[cfg(target_os = "xous")] {
+        }
+        target_os = "xous" => {
             mod racy;
             #[cfg(test)]
             mod tests;
@@ -174,6 +185,7 @@ pub(crate) mod key {
             pub(super) use xous::{Key, get, set};
             use xous::{create, destroy};
         }
+        _ => {}
     }
 }
 
diff --git a/library/std/src/thread/current.rs b/library/std/src/thread/current.rs
index 5c879903526..7da1621da45 100644
--- a/library/std/src/thread/current.rs
+++ b/library/std/src/thread/current.rs
@@ -18,8 +18,8 @@ local_pointer! {
 pub(super) mod id {
     use super::*;
 
-    cfg_if::cfg_if! {
-        if #[cfg(target_thread_local)] {
+    cfg_select! {
+        target_thread_local => {
             use crate::cell::Cell;
 
             #[thread_local]
@@ -34,7 +34,8 @@ pub(super) mod id {
             pub(super) fn set(id: ThreadId) {
                 ID.set(Some(id))
             }
-        } else if #[cfg(target_pointer_width = "16")] {
+        }
+        target_pointer_width = "16" => {
             local_pointer! {
                 static ID0;
                 static ID16;
@@ -59,7 +60,8 @@ pub(super) mod id {
                 ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
                 ID48.set(ptr::without_provenance_mut((val >> 48) as usize));
             }
-        } else if #[cfg(target_pointer_width = "32")] {
+        }
+        target_pointer_width = "32" => {
             local_pointer! {
                 static ID0;
                 static ID32;
@@ -78,7 +80,8 @@ pub(super) mod id {
                 ID0.set(ptr::without_provenance_mut(val as usize));
                 ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
             }
-        } else {
+        }
+        _ => {
             local_pointer! {
                 static ID;
             }
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 292323d0118..b6059c28cec 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1212,8 +1212,8 @@ impl ThreadId {
             panic!("failed to generate unique thread ID: bitspace exhausted")
         }
 
-        cfg_if::cfg_if! {
-            if #[cfg(target_has_atomic = "64")] {
+        cfg_select! {
+            target_has_atomic = "64" => {
                 use crate::sync::atomic::{Atomic, AtomicU64};
 
                 static COUNTER: Atomic<u64> = AtomicU64::new(0);
@@ -1229,7 +1229,8 @@ impl ThreadId {
                         Err(id) => last = id,
                     }
                 }
-            } else {
+            }
+            _ => {
                 use crate::sync::{Mutex, PoisonError};
 
                 static COUNTER: Mutex<u64> = Mutex::new(0);
@@ -1318,8 +1319,8 @@ use thread_name_string::ThreadNameString;
 /// Note however that this also means that the name reported in pre-main functions
 /// will be incorrect, but that's just something we have to live with.
 pub(crate) mod main_thread {
-    cfg_if::cfg_if! {
-        if #[cfg(target_has_atomic = "64")] {
+    cfg_select! {
+        target_has_atomic = "64" => {
             use super::ThreadId;
             use crate::sync::atomic::{Atomic, AtomicU64};
             use crate::sync::atomic::Ordering::Relaxed;
@@ -1335,7 +1336,8 @@ pub(crate) mod main_thread {
             pub(crate) unsafe fn set(id: ThreadId) {
                 MAIN.store(id.as_u64().get(), Relaxed)
             }
-        } else {
+        }
+        _ => {
             use super::ThreadId;
             use crate::mem::MaybeUninit;
             use crate::sync::atomic::{Atomic, AtomicBool};
diff --git a/library/std/tests/env_modify.rs b/library/std/tests/env_modify.rs
index ba84978b35f..fe0ae68806e 100644
--- a/library/std/tests/env_modify.rs
+++ b/library/std/tests/env_modify.rs
@@ -1,5 +1,6 @@
 // These tests are in a separate integration test as they modify the environment,
 // and would otherwise cause some other tests to fail.
+#![feature(cfg_select)]
 
 use std::env::*;
 use std::ffi::{OsStr, OsString};
@@ -110,8 +111,8 @@ fn env_home_dir() {
         }
     }
 
-    cfg_if::cfg_if! {
-        if #[cfg(unix)] {
+    cfg_select! {
+        unix => {
             let oldhome = var_to_os_string(var("HOME"));
 
             unsafe {
@@ -130,7 +131,8 @@ fn env_home_dir() {
             }
 
             if let Some(oldhome) = oldhome { unsafe { set_var("HOME", oldhome); } }
-        } else if #[cfg(windows)] {
+        }
+        windows => {
             let oldhome = var_to_os_string(var("HOME"));
             let olduserprofile = var_to_os_string(var("USERPROFILE"));
 
@@ -159,6 +161,7 @@ fn env_home_dir() {
                 if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); }
             }
         }
+        _ => {}
     }
 }
 
diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs
index 32561dd6ab6..29f220d8a70 100644
--- a/library/std/tests/thread.rs
+++ b/library/std/tests/thread.rs
@@ -19,6 +19,7 @@ fn sleep_very_long() {
 }
 
 #[test]
+#[cfg_attr(target_env = "sgx", ignore = "Time within SGX enclave cannot be trusted")]
 fn sleep_until() {
     let now = Instant::now();
     let period = Duration::from_millis(100);
diff --git a/library/std_detect/Cargo.toml b/library/std_detect/Cargo.toml
index 8d91454726b..2739bb59230 100644
--- a/library/std_detect/Cargo.toml
+++ b/library/std_detect/Cargo.toml
@@ -21,9 +21,8 @@ is-it-maintained-open-issues = { repository = "rust-lang/stdarch" }
 maintenance = { status = "experimental" }
 
 [dependencies]
-cfg-if = "1.0.0"
-core = { path = "../core" }
-alloc = { path = "../alloc" }
+core = { version = "1.0.0", package = 'rustc-std-workspace-core' }
+alloc = { version = "1.0.0", package = 'rustc-std-workspace-alloc' }
 
 [target.'cfg(not(windows))'.dependencies]
 libc = { version = "0.2.0", optional = true, default-features = false }
diff --git a/library/std_detect/src/detect/arch/loongarch.rs b/library/std_detect/src/detect/arch/loongarch.rs
index 68fc600fa8e..d5a442fbbb8 100644
--- a/library/std_detect/src/detect/arch/loongarch.rs
+++ b/library/std_detect/src/detect/arch/loongarch.rs
@@ -8,6 +8,7 @@ features! {
     /// Checks if `loongarch` feature is enabled.
     /// Supported arguments are:
     ///
+    /// * `"32s"`
     /// * `"f"`
     /// * `"d"`
     /// * `"frecipe"`
@@ -22,6 +23,8 @@ features! {
     /// * `"lvz"`
     /// * `"ual"`
     #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")]
+    @FEATURE: #[unstable(feature = "stdarch_loongarch_feature_detection", issue = "117425")] _32s: "32s";
+    /// 32S
     @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] f: "f";
     /// F
     @FEATURE: #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")] d: "d";
diff --git a/library/std_detect/src/detect/arch/mod.rs b/library/std_detect/src/detect/arch/mod.rs
index b0be554ed89..c066b9cc681 100644
--- a/library/std_detect/src/detect/arch/mod.rs
+++ b/library/std_detect/src/detect/arch/mod.rs
@@ -1,7 +1,5 @@
 #![allow(dead_code)]
 
-use cfg_if::cfg_if;
-
 // Export the macros for all supported architectures.
 #[macro_use]
 mod x86;
@@ -24,38 +22,48 @@ mod loongarch;
 #[macro_use]
 mod s390x;
 
-cfg_if! {
-    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
+cfg_select! {
+    any(target_arch = "x86", target_arch = "x86_64") => {
         #[stable(feature = "simd_x86", since = "1.27.0")]
         pub use x86::*;
-    } else if #[cfg(target_arch = "arm")] {
+    }
+    target_arch = "arm" => {
         #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")]
         pub use arm::*;
-    } else if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] {
+    }
+    any(target_arch = "aarch64", target_arch = "arm64ec") => {
         #[stable(feature = "simd_aarch64", since = "1.60.0")]
         pub use aarch64::*;
-    } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
+    }
+    any(target_arch = "riscv32", target_arch = "riscv64") => {
         #[unstable(feature = "stdarch_riscv_feature_detection", issue = "111192")]
         pub use riscv::*;
-    } else if #[cfg(target_arch = "powerpc")] {
+    }
+    target_arch = "powerpc" => {
         #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")]
         pub use powerpc::*;
-    } else if #[cfg(target_arch = "powerpc64")] {
+    }
+    target_arch = "powerpc64" => {
         #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")]
         pub use powerpc64::*;
-    } else if #[cfg(target_arch = "mips")] {
+    }
+    target_arch = "mips" => {
         #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")]
         pub use mips::*;
-    } else if #[cfg(target_arch = "mips64")] {
+    }
+    target_arch = "mips64" => {
         #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")]
         pub use mips64::*;
-    } else if #[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] {
+    }
+    any(target_arch = "loongarch32", target_arch = "loongarch64") => {
         #[stable(feature = "stdarch_loongarch_feature", since = "1.89.0")]
         pub use loongarch::*;
-    } else if #[cfg(target_arch = "s390x")] {
+    }
+    target_arch = "s390x" => {
         #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")]
         pub use s390x::*;
-    } else {
+    }
+    _ => {
         // Unimplemented architecture:
         #[doc(hidden)]
         pub(crate) enum Feature {
diff --git a/library/std_detect/src/detect/arch/riscv.rs b/library/std_detect/src/detect/arch/riscv.rs
index 1d21b1d4855..1e57d09edb1 100644
--- a/library/std_detect/src/detect/arch/riscv.rs
+++ b/library/std_detect/src/detect/arch/riscv.rs
@@ -37,90 +37,121 @@ features! {
     ///
     /// # Unprivileged Specification
     ///
-    /// The supported ratified RISC-V instruction sets are as follows:
+    /// The supported ratified RISC-V instruction sets are as follows (OS
+    /// columns denote runtime feature detection support with or without the
+    /// minimum supported version):
     ///
-    /// * RV32E: `"rv32e"`
-    /// * RV32I: `"rv32i"`
-    /// * RV64I: `"rv64i"`
-    /// * A: `"a"`
-    ///   * Zaamo: `"zaamo"`
-    ///   * Zalrsc: `"zalrsc"`
-    /// * B: `"b"`
-    ///   * Zba: `"zba"`
-    ///   * Zbb: `"zbb"`
-    ///   * Zbs: `"zbs"`
-    /// * C: `"c"`
-    ///   * Zca: `"zca"`
-    ///   * Zcd: `"zcd"` (if D is enabled)
-    ///   * Zcf: `"zcf"` (if F is enabled on RV32)
-    /// * D: `"d"`
-    /// * F: `"f"`
-    /// * M: `"m"`
-    /// * Q: `"q"`
-    /// * V: `"v"`
-    ///   * Zve32x: `"zve32x"`
-    ///   * Zve32f: `"zve32f"`
-    ///   * Zve64x: `"zve64x"`
-    ///   * Zve64f: `"zve64f"`
-    ///   * Zve64d: `"zve64d"`
-    /// * Zicbom: `"zicbom"`
-    /// * Zicboz: `"zicboz"`
-    /// * Zicntr: `"zicntr"`
-    /// * Zicond: `"zicond"`
-    /// * Zicsr: `"zicsr"`
-    /// * Zifencei: `"zifencei"`
-    /// * Zihintntl: `"zihintntl"`
-    /// * Zihintpause: `"zihintpause"`
-    /// * Zihpm: `"zihpm"`
-    /// * Zimop: `"zimop"`
-    /// * Zabha: `"zabha"`
-    /// * Zacas: `"zacas"`
-    /// * Zawrs: `"zawrs"`
-    /// * Zfa: `"zfa"`
-    /// * Zfbfmin: `"zfbfmin"`
-    /// * Zfh: `"zfh"`
-    ///   * Zfhmin: `"zfhmin"`
-    /// * Zfinx: `"zfinx"`
-    /// * Zdinx: `"zdinx"`
-    /// * Zhinx: `"zhinx"`
-    ///   * Zhinxmin: `"zhinxmin"`
-    /// * Zcb: `"zcb"`
-    /// * Zcmop: `"zcmop"`
-    /// * Zbc: `"zbc"`
-    /// * Zbkb: `"zbkb"`
-    /// * Zbkc: `"zbkc"`
-    /// * Zbkx: `"zbkx"`
-    /// * Zk: `"zk"`
-    /// * Zkn: `"zkn"`
-    ///   * Zknd: `"zknd"`
-    ///   * Zkne: `"zkne"`
-    ///   * Zknh: `"zknh"`
-    /// * Zkr: `"zkr"`
-    /// * Zks: `"zks"`
-    ///   * Zksed: `"zksed"`
-    ///   * Zksh: `"zksh"`
-    /// * Zkt: `"zkt"`
-    /// * Zvbb: `"zvbb"`
-    /// * Zvbc: `"zvbc"`
-    /// * Zvfbfmin: `"zvfbfmin"`
-    /// * Zvfbfwma: `"zvfbfwma"`
-    /// * Zvfh: `"zvfh"`
-    ///   * Zvfhmin: `"zvfhmin"`
-    /// * Zvkb: `"zvkb"`
-    /// * Zvkg: `"zvkg"`
-    /// * Zvkn: `"zvkn"`
-    ///   * Zvkned: `"zvkned"`
-    ///   * Zvknha: `"zvknha"`
-    ///   * Zvknhb: `"zvknhb"`
-    /// * Zvknc: `"zvknc"`
-    /// * Zvkng: `"zvkng"`
-    /// * Zvks: `"zvks"`
-    ///   * Zvksed: `"zvksed"`
-    ///   * Zvksh: `"zvksh"`
-    /// * Zvksc: `"zvksc"`
-    /// * Zvksg: `"zvksg"`
-    /// * Zvkt: `"zvkt"`
-    /// * Ztso: `"ztso"`
+    /// | Literal    | Base    | Linux      |
+    /// |:---------- |:------- |:---------- |
+    /// | `"rv32e"`  | RV32E   | No         |
+    /// | `"rv32i"`  | RV32I   | Yes [^ima] |
+    /// | `"rv64i"`  | RV64I   | Yes [^ima] |
+    ///
+    /// | Literal         | Extension   | Linux               |
+    /// |:--------------- |:----------- |:------------------- |
+    /// | `"a"`           | A           | Yes [^ima]          |
+    /// | `"b"`           | B           | 6.5                 |
+    /// | `"c"`           | C           | Yes                 |
+    /// | `"d"`           | D           | Yes                 |
+    /// | `"f"`           | F           | Yes                 |
+    /// | `"m"`           | M           | Yes [^ima]          |
+    /// | `"q"`           | Q           | No                  |
+    /// | `"v"`           | V           | 6.5                 |
+    /// | `"zaamo"`       | Zaamo       | 6.15 [^ima] [^dep]  |
+    /// | `"zabha"`       | Zabha       | 6.16                |
+    /// | `"zacas"`       | Zacas       | 6.8                 |
+    /// | `"zalrsc"`      | Zalrsc      | 6.15 [^ima] [^dep]  |
+    /// | `"zawrs"`       | Zawrs       | 6.11                |
+    /// | `"zba"`         | Zba         | 6.5                 |
+    /// | `"zbb"`         | Zbb         | 6.5                 |
+    /// | `"zbc"`         | Zbc         | 6.8                 |
+    /// | `"zbkb"`        | Zbkb        | 6.8                 |
+    /// | `"zbkc"`        | Zbkc        | 6.8                 |
+    /// | `"zbkx"`        | Zbkx        | 6.8                 |
+    /// | `"zbs"`         | Zbs         | 6.5                 |
+    /// | `"zca"`         | Zca         | 6.11 [^dep]         |
+    /// | `"zcb"`         | Zcb         | 6.11                |
+    /// | `"zcd"`         | Zcd         | 6.11 [^dep]         |
+    /// | `"zcf"`         | Zcf         | 6.11 [^dep]         |
+    /// | `"zcmop"`       | Zcmop       | 6.11                |
+    /// | `"zdinx"`       | Zdinx       | No                  |
+    /// | `"zfa"`         | Zfa         | 6.8                 |
+    /// | `"zfbfmin"`     | Zfbfmin     | 6.15                |
+    /// | `"zfh"`         | Zfh         | 6.8                 |
+    /// | `"zfhmin"`      | Zfhmin      | 6.8                 |
+    /// | `"zfinx"`       | Zfinx       | No                  |
+    /// | `"zhinx"`       | Zhinx       | No                  |
+    /// | `"zhinxmin"`    | Zhinxmin    | No                  |
+    /// | `"zicbom"`      | Zicbom      | 6.15                |
+    /// | `"zicboz"`      | Zicboz      | 6.7                 |
+    /// | `"zicntr"`      | Zicntr      | 6.15 [^ima] [^cntr] |
+    /// | `"zicond"`      | Zicond      | 6.8                 |
+    /// | `"zicsr"`       | Zicsr       | No [^ima] [^dep]    |
+    /// | `"zifencei"`    | Zifencei    | No [^ima]           |
+    /// | `"zihintntl"`   | Zihintntl   | 6.8                 |
+    /// | `"zihintpause"` | Zihintpause | 6.10                |
+    /// | `"zihpm"`       | Zihpm       | 6.15 [^cntr]        |
+    /// | `"zimop"`       | Zimop       | 6.11                |
+    /// | `"zk"`          | Zk          | No [^zkr]           |
+    /// | `"zkn"`         | Zkn         | 6.8                 |
+    /// | `"zknd"`        | Zknd        | 6.8                 |
+    /// | `"zkne"`        | Zkne        | 6.8                 |
+    /// | `"zknh"`        | Zknh        | 6.8                 |
+    /// | `"zkr"`         | Zkr         | No [^zkr]           |
+    /// | `"zks"`         | Zks         | 6.8                 |
+    /// | `"zksed"`       | Zksed       | 6.8                 |
+    /// | `"zksh"`        | Zksh        | 6.8                 |
+    /// | `"zkt"`         | Zkt         | 6.8                 |
+    /// | `"ztso"`        | Ztso        | 6.8                 |
+    /// | `"zvbb"`        | Zvbb        | 6.8                 |
+    /// | `"zvbc"`        | Zvbc        | 6.8                 |
+    /// | `"zve32f"`      | Zve32f      | 6.11 [^dep]         |
+    /// | `"zve32x"`      | Zve32x      | 6.11 [^dep]         |
+    /// | `"zve64d"`      | Zve64d      | 6.11 [^dep]         |
+    /// | `"zve64f"`      | Zve64f      | 6.11 [^dep]         |
+    /// | `"zve64x"`      | Zve64x      | 6.11 [^dep]         |
+    /// | `"zvfbfmin"`    | Zvfbfmin    | 6.15                |
+    /// | `"zvfbfwma"`    | Zvfbfwma    | 6.15                |
+    /// | `"zvfh"`        | Zvfh        | 6.8                 |
+    /// | `"zvfhmin"`     | Zvfhmin     | 6.8                 |
+    /// | `"zvkb"`        | Zvkb        | 6.8                 |
+    /// | `"zvkg"`        | Zvkg        | 6.8                 |
+    /// | `"zvkn"`        | Zvkn        | 6.8                 |
+    /// | `"zvknc"`       | Zvknc       | 6.8                 |
+    /// | `"zvkned"`      | Zvkned      | 6.8                 |
+    /// | `"zvkng"`       | Zvkng       | 6.8                 |
+    /// | `"zvknha"`      | Zvknha      | 6.8                 |
+    /// | `"zvknhb"`      | Zvknhb      | 6.8                 |
+    /// | `"zvks"`        | Zvks        | 6.8                 |
+    /// | `"zvksc"`       | Zvksc       | 6.8                 |
+    /// | `"zvksed"`      | Zvksed      | 6.8                 |
+    /// | `"zvksg"`       | Zvksg       | 6.8                 |
+    /// | `"zvksh"`       | Zvksh       | 6.8                 |
+    /// | `"zvkt"`        | Zvkt        | 6.8                 |
+    ///
+    /// [^ima]: Or enabled when the IMA base behavior is detected on the Linux
+    /// kernel version 6.4 or later (for bases, the only matching one -- either
+    /// `"rv32i"` or `"rv64i"` -- is enabled).
+    ///
+    /// [^cntr]: Even if this extension is available, it does not necessarily
+    /// mean all performance counters are accessible.
+    /// For example, accesses to all performance counters except `time`
+    /// (wall-clock) are blocked by default on the Linux kernel
+    /// version 6.6 or later.
+    /// Also beware that, even if performance counters like `cycle` and
+    /// `instret` are accessible, their value can be unreliable (e.g. returning
+    /// the constant value) under certain circumstances.
+    ///
+    /// [^dep]: Or enabled as a dependency of another extension (a superset)
+    /// even if runtime detection of this feature itself is not supported (as
+    /// long as the runtime detection of the superset is supported).
+    ///
+    /// [^zkr]: Linux does not report existence of this extension even if
+    /// supported by the hardware mainly because the `seed` CSR on the Zkr
+    /// extension (which provides hardware-based randomness) is normally
+    /// inaccessible from the user mode.
+    /// For the Zk extension features except this CSR, check existence of both
+    /// `"zkn"` and `"zkt"` features instead.
     ///
     /// There's also bases and extensions marked as standard instruction set,
     /// but they are in frozen or draft state. These instruction sets are also
diff --git a/library/std_detect/src/detect/arch/x86.rs b/library/std_detect/src/detect/arch/x86.rs
index 28b3e3cfb35..bd749b88f56 100644
--- a/library/std_detect/src/detect/arch/x86.rs
+++ b/library/std_detect/src/detect/arch/x86.rs
@@ -233,6 +233,12 @@ features! {
     /// AMX-TF32 (TensorFloat32 Operations)
     @FEATURE: #[unstable(feature = "x86_amx_intrinsics", issue = "126622")] amx_transpose: "amx-transpose";
     /// AMX-TRANSPOSE (Matrix Transpose Operations)
+    @FEATURE: #[unstable(feature = "apx_target_feature", issue = "139284")] apxf: "apxf";
+    /// APX-F (Advanced Performance Extensions - Foundation)
+    @FEATURE: #[unstable(feature = "avx10_target_feature", issue = "138843")] avx10_1: "avx10.1";
+    /// AVX10.1
+    @FEATURE: #[unstable(feature = "avx10_target_feature", issue = "138843")] avx10_2: "avx10.2";
+    /// AVX10.2
     @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] f16c: "f16c";
     /// F16C (Conversions between IEEE-754 `binary16` and `binary32` formats)
     @FEATURE: #[stable(feature = "simd_x86", since = "1.27.0")] fma: "fma";
diff --git a/library/std_detect/src/detect/cache.rs b/library/std_detect/src/detect/cache.rs
index 1a42e091463..c0c0b7b7f86 100644
--- a/library/std_detect/src/detect/cache.rs
+++ b/library/std_detect/src/detect/cache.rs
@@ -101,8 +101,8 @@ impl Cache {
     }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(feature = "std_detect_env_override")] {
+cfg_select! {
+    feature = "std_detect_env_override" => {
         #[inline]
         fn disable_features(disable: &[u8], value: &mut Initializer) {
             if let Ok(disable) = core::str::from_utf8(disable) {
@@ -116,8 +116,8 @@ cfg_if::cfg_if! {
         fn initialize(mut value: Initializer) -> Initializer {
             use core::ffi::CStr;
             const RUST_STD_DETECT_UNSTABLE: &CStr = c"RUST_STD_DETECT_UNSTABLE";
-            cfg_if::cfg_if! {
-                if #[cfg(windows)] {
+            cfg_select! {
+                windows => {
                     use alloc::vec;
                     #[link(name = "kernel32")]
                     unsafe extern "system" {
@@ -132,7 +132,8 @@ cfg_if::cfg_if! {
                             disable_features(&env[..len as usize], &mut value);
                         }
                     }
-                } else {
+                }
+                _ => {
                     let env = unsafe {
                         libc::getenv(RUST_STD_DETECT_UNSTABLE.as_ptr())
                     };
@@ -146,7 +147,8 @@ cfg_if::cfg_if! {
             do_initialize(value);
             value
         }
-    } else {
+    }
+    _ => {
         #[inline]
         fn initialize(value: Initializer) -> Initializer {
             do_initialize(value);
diff --git a/library/std_detect/src/detect/mod.rs b/library/std_detect/src/detect/mod.rs
index f936a5a1345..2bc6e9a24db 100644
--- a/library/std_detect/src/detect/mod.rs
+++ b/library/std_detect/src/detect/mod.rs
@@ -17,8 +17,6 @@
 //! due to security concerns (x86 is the big exception). These functions are
 //! implemented in the `os/{target_os}.rs` modules.
 
-use cfg_if::cfg_if;
-
 #[macro_use]
 mod macros;
 
@@ -34,8 +32,8 @@ pub(crate) use self::arch::Feature;
 mod bit;
 mod cache;
 
-cfg_if! {
-    if #[cfg(miri)] {
+cfg_select! {
+    miri => {
         // When running under miri all target-features that are not enabled at
         // compile-time are reported as disabled at run-time.
         //
@@ -43,35 +41,42 @@ cfg_if! {
         // this run-time detection logic is never called.
         #[path = "os/other.rs"]
         mod os;
-    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
+    }
+    any(target_arch = "x86", target_arch = "x86_64") => {
         // On x86/x86_64 no OS specific functionality is required.
         #[path = "os/x86.rs"]
         mod os;
-    } else if #[cfg(all(any(target_os = "linux", target_os = "android"), feature = "libc"))] {
+    }
+    all(any(target_os = "linux", target_os = "android"), feature = "libc") => {
         #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
         #[path = "os/riscv.rs"]
         mod riscv;
         #[path = "os/linux/mod.rs"]
         mod os;
-    } else if #[cfg(all(target_os = "freebsd", feature = "libc"))] {
+    }
+    all(target_os = "freebsd", feature = "libc") => {
         #[cfg(target_arch = "aarch64")]
         #[path = "os/aarch64.rs"]
         mod aarch64;
         #[path = "os/freebsd/mod.rs"]
         mod os;
-    } else if #[cfg(all(target_os = "openbsd", target_arch = "aarch64", feature = "libc"))] {
+    }
+    all(target_os = "openbsd", target_arch = "aarch64", feature = "libc") => {
         #[allow(dead_code)] // we don't use code that calls the mrs instruction.
         #[path = "os/aarch64.rs"]
         mod aarch64;
         #[path = "os/openbsd/aarch64.rs"]
         mod os;
-    } else if #[cfg(all(target_os = "windows", any(target_arch = "aarch64", target_arch = "arm64ec")))] {
+    }
+    all(target_os = "windows", any(target_arch = "aarch64", target_arch = "arm64ec")) => {
         #[path = "os/windows/aarch64.rs"]
         mod os;
-    } else if #[cfg(all(target_vendor = "apple", target_arch = "aarch64", feature = "libc"))] {
+    }
+    all(target_vendor = "apple", target_arch = "aarch64", feature = "libc") => {
         #[path = "os/darwin/aarch64.rs"]
         mod os;
-    } else {
+    }
+    _ => {
         #[path = "os/other.rs"]
         mod os;
     }
@@ -89,8 +94,8 @@ fn check_for(x: Feature) -> bool {
 /// is `true` if the feature is supported by the host and `false` otherwise.
 #[unstable(feature = "stdarch_internal", issue = "none")]
 pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
-    cfg_if! {
-        if #[cfg(any(
+    cfg_select! {
+        any(
             target_arch = "x86",
             target_arch = "x86_64",
             target_arch = "arm",
@@ -105,7 +110,7 @@ pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
             target_arch = "loongarch32",
             target_arch = "loongarch64",
             target_arch = "s390x",
-        ))] {
+        ) => {
             (0_u8..Feature::_last as u8).map(|discriminant: u8| {
                 #[allow(bindings_with_variant_name)] // RISC-V has Feature::f
                 let f: Feature = unsafe { core::mem::transmute(discriminant) };
@@ -113,8 +118,7 @@ pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
                 let enabled: bool = check_for(f);
                 (name, enabled)
             })
-        } else {
-            None.into_iter()
         }
+        _ => None.into_iter(),
     }
 }
diff --git a/library/std_detect/src/detect/os/freebsd/mod.rs b/library/std_detect/src/detect/os/freebsd/mod.rs
index ade7fb6269d..7de9250e835 100644
--- a/library/std_detect/src/detect/os/freebsd/mod.rs
+++ b/library/std_detect/src/detect/os/freebsd/mod.rs
@@ -2,17 +2,20 @@
 
 mod auxvec;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_arch = "aarch64")] {
+cfg_select! {
+    target_arch = "aarch64" => {
         mod aarch64;
         pub(crate) use self::aarch64::detect_features;
-    } else if #[cfg(target_arch = "arm")] {
+    }
+    target_arch = "arm" => {
         mod arm;
         pub(crate) use self::arm::detect_features;
-    } else if #[cfg(target_arch = "powerpc64")] {
+    }
+    target_arch = "powerpc64" => {
         mod powerpc;
         pub(crate) use self::powerpc::detect_features;
-    } else {
+    }
+    _ => {
         use crate::detect::cache;
         /// Performs run-time feature detection.
         pub(crate) fn detect_features() -> cache::Initializer {
diff --git a/library/std_detect/src/detect/os/linux/auxvec.rs b/library/std_detect/src/detect/os/linux/auxvec.rs
index 443caaaa186..75e01bdc449 100644
--- a/library/std_detect/src/detect/os/linux/auxvec.rs
+++ b/library/std_detect/src/detect/os/linux/auxvec.rs
@@ -131,15 +131,15 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
 /// `getauxval` function. If the function is not linked, this function return `Err`.
 fn getauxval(key: usize) -> Result<usize, ()> {
     type F = unsafe extern "C" fn(libc::c_ulong) -> libc::c_ulong;
-    cfg_if::cfg_if! {
-        if #[cfg(all(
+    cfg_select! {
+        all(
             feature = "std_detect_dlsym_getauxval",
             not(all(
                 target_os = "linux",
                 any(target_env = "gnu", target_env = "musl", target_env = "ohos"),
             )),
             not(target_os = "android"),
-        ))] {
+        ) => {
             let ffi_getauxval: F = unsafe {
                 let ptr = libc::dlsym(libc::RTLD_DEFAULT, c"getauxval".as_ptr());
                 if ptr.is_null() {
@@ -147,7 +147,8 @@ fn getauxval(key: usize) -> Result<usize, ()> {
                 }
                 core::mem::transmute(ptr)
             };
-        } else {
+        }
+        _ => {
             let ffi_getauxval: F = libc::getauxval;
         }
     }
diff --git a/library/std_detect/src/detect/os/linux/auxvec/tests.rs b/library/std_detect/src/detect/os/linux/auxvec/tests.rs
index 536615fa272..631a3e5e9ef 100644
--- a/library/std_detect/src/detect/os/linux/auxvec/tests.rs
+++ b/library/std_detect/src/detect/os/linux/auxvec/tests.rs
@@ -42,8 +42,8 @@ fn auxv_dump() {
 }
 
 #[cfg(feature = "std_detect_file_io")]
-cfg_if::cfg_if! {
-    if #[cfg(target_arch = "arm")] {
+cfg_select! {
+    target_arch = "arm" => {
         // The tests below can be executed under qemu, where we do not have access to the test
         // files on disk, so we need to embed them with `include_bytes!`.
         #[test]
@@ -62,7 +62,8 @@ cfg_if::cfg_if! {
             assert_eq!(v.hwcap, 126614527);
             assert_eq!(v.hwcap2, 0);
         }
-    } else if #[cfg(target_arch = "aarch64")] {
+    }
+    target_arch = "aarch64" => {
         #[cfg(target_endian = "little")]
         #[test]
         fn linux_artificial_aarch64() {
@@ -81,6 +82,7 @@ cfg_if::cfg_if! {
             assert_eq!(v.hwcap2, 0);
         }
     }
+    _ => {}
 }
 
 #[test]
diff --git a/library/std_detect/src/detect/os/linux/loongarch.rs b/library/std_detect/src/detect/os/linux/loongarch.rs
index e97fda11d08..74415266f8b 100644
--- a/library/std_detect/src/detect/os/linux/loongarch.rs
+++ b/library/std_detect/src/detect/os/linux/loongarch.rs
@@ -17,22 +17,21 @@ pub(crate) fn detect_features() -> cache::Initializer {
     // The values are part of the platform-specific [cpucfg]
     //
     // [cpucfg]: LoongArch Reference Manual Volume 1: Basic Architecture v1.1
+    let cpucfg1: usize;
     let cpucfg2: usize;
-    unsafe {
-        asm!(
-            "cpucfg {}, {}",
-            out(reg) cpucfg2, in(reg) 2,
-            options(pure, nomem, preserves_flags, nostack)
-        );
-    }
     let cpucfg3: usize;
     unsafe {
         asm!(
             "cpucfg {}, {}",
+            "cpucfg {}, {}",
+            "cpucfg {}, {}",
+            out(reg) cpucfg1, in(reg) 1,
+            out(reg) cpucfg2, in(reg) 2,
             out(reg) cpucfg3, in(reg) 3,
             options(pure, nomem, preserves_flags, nostack)
         );
     }
+    enable_feature(&mut value, Feature::_32s, bit::test(cpucfg1, 0) || bit::test(cpucfg1, 1));
     enable_feature(&mut value, Feature::frecipe, bit::test(cpucfg2, 25));
     enable_feature(&mut value, Feature::div32, bit::test(cpucfg2, 26));
     enable_feature(&mut value, Feature::lam_bh, bit::test(cpucfg2, 27));
diff --git a/library/std_detect/src/detect/os/linux/mod.rs b/library/std_detect/src/detect/os/linux/mod.rs
index 5ae2aaeab5b..5273c16c089 100644
--- a/library/std_detect/src/detect/os/linux/mod.rs
+++ b/library/std_detect/src/detect/os/linux/mod.rs
@@ -37,29 +37,36 @@ fn read_file(orig_path: &str) -> Result<Vec<u8>, alloc::string::String> {
     }
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(target_arch = "aarch64")] {
+cfg_select! {
+    target_arch = "aarch64" => {
         mod aarch64;
         pub(crate) use self::aarch64::detect_features;
-    } else if #[cfg(target_arch = "arm")] {
+    }
+    target_arch = "arm" => {
         mod arm;
         pub(crate) use self::arm::detect_features;
-    } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
+    }
+    any(target_arch = "riscv32", target_arch = "riscv64") => {
         mod riscv;
         pub(crate) use self::riscv::detect_features;
-    } else if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] {
+    }
+    any(target_arch = "mips", target_arch = "mips64") => {
         mod mips;
         pub(crate) use self::mips::detect_features;
-    } else if #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] {
+    }
+    any(target_arch = "powerpc", target_arch = "powerpc64") => {
         mod powerpc;
         pub(crate) use self::powerpc::detect_features;
-    } else if #[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))] {
+    }
+    any(target_arch = "loongarch32", target_arch = "loongarch64") => {
         mod loongarch;
         pub(crate) use self::loongarch::detect_features;
-    } else if #[cfg(target_arch = "s390x")] {
+    }
+    target_arch = "s390x" => {
         mod s390x;
         pub(crate) use self::s390x::detect_features;
-    } else {
+    }
+    _ => {
         use crate::detect::cache;
         /// Performs run-time feature detection.
         pub(crate) fn detect_features() -> cache::Initializer {
diff --git a/library/std_detect/src/detect/os/riscv.rs b/library/std_detect/src/detect/os/riscv.rs
index c6acbd3525b..9b9e0cba09d 100644
--- a/library/std_detect/src/detect/os/riscv.rs
+++ b/library/std_detect/src/detect/os/riscv.rs
@@ -119,11 +119,31 @@ pub(crate) fn imply_features(mut value: cache::Initializer) -> cache::Initialize
         imply!(d | zfhmin | zfa => f);
         imply!(zfbfmin => f); // and some of (not all) "Zfh" instructions.
 
-        // Relatively complex implication rules from the "C" extension.
+        // Relatively complex implication rules around the "C" extension.
+        // (from "C" and some others)
         imply!(c => zca);
         imply!(c & d => zcd);
         #[cfg(target_arch = "riscv32")]
         imply!(c & f => zcf);
+        // (to "C"; defined as superset)
+        cfg_select! {
+            target_arch = "riscv32" => {
+                if value.test(Feature::d as u32) {
+                    imply!(zcf & zcd => c);
+                } else if value.test(Feature::f as u32) {
+                    imply!(zcf => c);
+                } else {
+                    imply!(zca => c);
+                }
+            }
+            _ => {
+                if value.test(Feature::d as u32) {
+                    imply!(zcd => c);
+                } else {
+                    imply!(zca => c);
+                }
+            }
+        }
 
         imply!(zicntr | zihpm | f | zfinx | zve32x => zicsr);
 
diff --git a/library/std_detect/src/detect/os/x86.rs b/library/std_detect/src/detect/os/x86.rs
index 20f848ab05c..cf11d833312 100644
--- a/library/std_detect/src/detect/os/x86.rs
+++ b/library/std_detect/src/detect/os/x86.rs
@@ -137,6 +137,32 @@ pub(crate) fn detect_features() -> cache::Initializer {
             enable(ebx, 2, Feature::widekl);
         }
 
+        // This detects ABM on AMD CPUs and LZCNT on Intel CPUs.
+        // On intel CPUs with popcnt, lzcnt implements the
+        // "missing part" of ABM, so we map both to the same
+        // internal feature.
+        //
+        // The `is_x86_feature_detected!("lzcnt")` macro then
+        // internally maps to Feature::abm.
+        enable(extended_proc_info_ecx, 5, Feature::lzcnt);
+
+        // As Hygon Dhyana originates from AMD technology and shares most of the architecture with
+        // AMD's family 17h, but with different CPU Vendor ID("HygonGenuine")/Family series
+        // number(Family 18h).
+        //
+        // For CPUID feature bits, Hygon Dhyana(family 18h) share the same definition with AMD
+        // family 17h.
+        //
+        // Related AMD CPUID specification is https://www.amd.com/system/files/TechDocs/25481.pdf.
+        // Related Hygon kernel patch can be found on
+        // http://lkml.kernel.org/r/5ce86123a7b9dad925ac583d88d2f921040e859b.1538583282.git.puwen@hygon.cn
+        if vendor_id == *b"AuthenticAMD" || vendor_id == *b"HygonGenuine" {
+            // These features are available on AMD arch CPUs:
+            enable(extended_proc_info_ecx, 6, Feature::sse4a);
+            enable(extended_proc_info_ecx, 21, Feature::tbm);
+            enable(extended_proc_info_ecx, 11, Feature::xop);
+        }
+
         // `XSAVE` and `AVX` support:
         let cpu_xsave = bit::test(proc_info_ecx as usize, 26);
         if cpu_xsave {
@@ -161,6 +187,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
                 // * AVX -> `XCR0.AVX[2]`
                 // * AVX-512 -> `XCR0.AVX-512[7:5]`.
                 // * AMX -> `XCR0.AMX[18:17]`
+                // * APX -> `XCR0.APX[19]`
                 //
                 // by setting the corresponding bits of `XCR0` to `1`.
                 //
@@ -173,6 +200,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
                 let os_avx512_support = xcr0 & 0xe0 == 0xe0;
                 // Test `XCR0.AMX[18:17]` with the mask `0b110_0000_0000_0000_0000 == 0x60000`
                 let os_amx_support = xcr0 & 0x60000 == 0x60000;
+                // Test `XCR0.APX[19]` with the mask `0b1000_0000_0000_0000_0000 == 0x80000`
+                let os_apx_support = xcr0 & 0x80000 == 0x80000;
 
                 // Only if the OS and the CPU support saving/restoring the AVX
                 // registers we enable `xsave` support:
@@ -262,33 +291,20 @@ pub(crate) fn detect_features() -> cache::Initializer {
                         enable(amx_feature_flags_eax, 8, Feature::amx_movrs);
                     }
                 }
-            }
-        }
 
-        // This detects ABM on AMD CPUs and LZCNT on Intel CPUs.
-        // On intel CPUs with popcnt, lzcnt implements the
-        // "missing part" of ABM, so we map both to the same
-        // internal feature.
-        //
-        // The `is_x86_feature_detected!("lzcnt")` macro then
-        // internally maps to Feature::abm.
-        enable(extended_proc_info_ecx, 5, Feature::lzcnt);
+                if os_apx_support {
+                    enable(extended_features_edx_leaf_1, 21, Feature::apxf);
+                }
 
-        // As Hygon Dhyana originates from AMD technology and shares most of the architecture with
-        // AMD's family 17h, but with different CPU Vendor ID("HygonGenuine")/Family series
-        // number(Family 18h).
-        //
-        // For CPUID feature bits, Hygon Dhyana(family 18h) share the same definition with AMD
-        // family 17h.
-        //
-        // Related AMD CPUID specification is https://www.amd.com/system/files/TechDocs/25481.pdf.
-        // Related Hygon kernel patch can be found on
-        // http://lkml.kernel.org/r/5ce86123a7b9dad925ac583d88d2f921040e859b.1538583282.git.puwen@hygon.cn
-        if vendor_id == *b"AuthenticAMD" || vendor_id == *b"HygonGenuine" {
-            // These features are available on AMD arch CPUs:
-            enable(extended_proc_info_ecx, 6, Feature::sse4a);
-            enable(extended_proc_info_ecx, 21, Feature::tbm);
-            enable(extended_proc_info_ecx, 11, Feature::xop);
+                let avx10_1 = enable(extended_features_edx_leaf_1, 19, Feature::avx10_1);
+                if avx10_1 {
+                    let CpuidResult { ebx, .. } = unsafe { __cpuid(0x24) };
+                    let avx10_version = ebx & 0xff;
+                    if avx10_version >= 2 {
+                        value.set(Feature::avx10_2 as u32);
+                    }
+                }
+            }
         }
     }
 
diff --git a/library/std_detect/src/lib.rs b/library/std_detect/src/lib.rs
index ab1b77bad5b..73e2f5dd964 100644
--- a/library/std_detect/src/lib.rs
+++ b/library/std_detect/src/lib.rs
@@ -15,7 +15,7 @@
 //! * `s390x`: [`is_s390x_feature_detected`]
 
 #![unstable(feature = "stdarch_internal", issue = "none")]
-#![feature(staged_api, doc_cfg, allow_internal_unstable)]
+#![feature(staged_api, cfg_select, doc_cfg, allow_internal_unstable)]
 #![deny(rust_2018_idioms)]
 #![allow(clippy::shadow_reuse)]
 #![cfg_attr(test, allow(unused_imports))]
diff --git a/library/std_detect/tests/macro_trailing_commas.rs b/library/std_detect/tests/macro_trailing_commas.rs
index 2fee0abdd57..6072ddf5ac4 100644
--- a/library/std_detect/tests/macro_trailing_commas.rs
+++ b/library/std_detect/tests/macro_trailing_commas.rs
@@ -69,6 +69,8 @@ fn aarch64() {
 #[test]
 #[cfg(any(target_arch = "loongarch32", target_arch = "loongarch64"))]
 fn loongarch() {
+    let _ = is_loongarch_feature_detected!("32s");
+    let _ = is_loongarch_feature_detected!("32s",);
     let _ = is_loongarch_feature_detected!("lsx");
     let _ = is_loongarch_feature_detected!("lsx",);
 }
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml
index b9ce676eb3f..f02744a1070 100644
--- a/library/unwind/Cargo.toml
+++ b/library/unwind/Cargo.toml
@@ -14,7 +14,6 @@ bench = false
 doc = false
 
 [dependencies]
-cfg-if = "1.0"
 core = { path = "../rustc-std-workspace-core", package = "rustc-std-workspace-core" }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 5451a38a674..cd3a2f33ffa 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -1,6 +1,7 @@
 #![no_std]
 #![unstable(feature = "panic_unwind", issue = "32837")]
 #![feature(cfg_emscripten_wasm_eh)]
+#![feature(cfg_select)]
 #![feature(link_cfg)]
 #![feature(staged_api)]
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
@@ -15,32 +16,37 @@
 #[cfg(not(all(windows, target_env = "msvc")))]
 extern crate libc as _;
 
-cfg_if::cfg_if! {
-    if #[cfg(target_env = "msvc")] {
+cfg_select! {
+    target_env = "msvc" => {
         // Windows MSVC no extra unwinder support needed
-    } else if #[cfg(any(
+    }
+    any(
         target_os = "l4re",
         target_os = "none",
         target_os = "espidf",
         target_os = "nuttx",
-    ))] {
+    ) => {
         // These "unix" family members do not have unwinder.
-    } else if #[cfg(any(
+    }
+    any(
         unix,
         windows,
         target_os = "psp",
         target_os = "solid_asp3",
         all(target_vendor = "fortanix", target_env = "sgx"),
-    ))] {
+    ) => {
         mod libunwind;
         pub use libunwind::*;
-    } else if #[cfg(target_os = "xous")] {
+    }
+    target_os = "xous" => {
         mod unwinding;
         pub use unwinding::*;
-    } else if #[cfg(target_family = "wasm")] {
+    }
+    target_family = "wasm" => {
         mod wasm;
         pub use wasm::*;
-    } else {
+    }
+    _ => {
         // no unwinder on the system!
         // - os=none ("bare metal" targets)
         // - os=hermit
@@ -52,17 +58,20 @@ cfg_if::cfg_if! {
 }
 
 #[cfg(target_env = "musl")]
-cfg_if::cfg_if! {
-    if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] {
+cfg_select! {
+    all(feature = "llvm-libunwind", feature = "system-llvm-libunwind") => {
         compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
-    } else if #[cfg(feature = "llvm-libunwind")] {
+    }
+    feature = "llvm-libunwind" => {
         #[link(name = "unwind", kind = "static", modifiers = "-bundle")]
         unsafe extern "C" {}
-    } else if #[cfg(feature = "system-llvm-libunwind")] {
+    }
+    feature = "system-llvm-libunwind" => {
         #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
         #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
         unsafe extern "C" {}
-    } else {
+    }
+    _ => {
         #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
         #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
         unsafe extern "C" {}
@@ -72,13 +81,15 @@ cfg_if::cfg_if! {
 // This is the same as musl except that we default to using the system libunwind
 // instead of libgcc.
 #[cfg(target_env = "ohos")]
-cfg_if::cfg_if! {
-    if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] {
+cfg_select! {
+    all(feature = "llvm-libunwind", feature = "system-llvm-libunwind") => {
         compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
-    } else if #[cfg(feature = "llvm-libunwind")] {
+    }
+    feature = "llvm-libunwind" => {
         #[link(name = "unwind", kind = "static", modifiers = "-bundle")]
         unsafe extern "C" {}
-    } else {
+    }
+    _ => {
         #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
         #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
         unsafe extern "C" {}
@@ -86,10 +97,11 @@ cfg_if::cfg_if! {
 }
 
 #[cfg(target_os = "android")]
-cfg_if::cfg_if! {
-    if #[cfg(feature = "llvm-libunwind")] {
+cfg_select! {
+    feature = "llvm-libunwind" => {
         compile_error!("`llvm-libunwind` is not supported for Android targets");
-    } else {
+    }
+    _ => {
         #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
         #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
         unsafe extern "C" {}
@@ -166,11 +178,12 @@ unsafe extern "C" {}
 unsafe extern "C" {}
 
 #[cfg(target_os = "nto")]
-cfg_if::cfg_if! {
-    if #[cfg(target_env = "nto70")] {
+cfg_select! {
+    target_env = "nto70" => {
         #[link(name = "gcc")]
         unsafe extern "C" {}
-    } else {
+    }
+    _ => {
         #[link(name = "gcc_s")]
         unsafe extern "C" {}
     }
diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs
index b350003cbb1..9ac9b54ed4a 100644
--- a/library/unwind/src/libunwind.rs
+++ b/library/unwind/src/libunwind.rs
@@ -122,198 +122,205 @@ unsafe extern "C" {
     pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
 }
 
-cfg_if::cfg_if! {
-if #[cfg(any(target_vendor = "apple", target_os = "netbsd", not(target_arch = "arm")))] {
-    // Not ARM EHABI
-    //
-    // 32-bit ARM on iOS/tvOS/watchOS use either DWARF/Compact unwinding or
-    // "setjmp-longjmp" / SjLj unwinding.
-    pub type _Unwind_Action = c_int;
-
-    pub const _UA_SEARCH_PHASE: c_int = 1;
-    pub const _UA_CLEANUP_PHASE: c_int = 2;
-    pub const _UA_HANDLER_FRAME: c_int = 4;
-    pub const _UA_FORCE_UNWIND: c_int = 8;
-    pub const _UA_END_OF_STACK: c_int = 16;
-
-    #[cfg_attr(
-        all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
-        link(name = "unwind", kind = "static", modifiers = "-bundle")
-    )]
-    unsafe extern "C" {
-        pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
-        pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
-        pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
-        pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word);
-        pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int)
-                                 -> _Unwind_Word;
-        pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
-    }
+cfg_select! {
+    any(target_vendor = "apple", target_os = "netbsd", not(target_arch = "arm")) => {
+        // Not ARM EHABI
+        //
+        // 32-bit ARM on iOS/tvOS/watchOS use either DWARF/Compact unwinding or
+        // "setjmp-longjmp" / SjLj unwinding.
+        pub type _Unwind_Action = c_int;
+
+        pub const _UA_SEARCH_PHASE: c_int = 1;
+        pub const _UA_CLEANUP_PHASE: c_int = 2;
+        pub const _UA_HANDLER_FRAME: c_int = 4;
+        pub const _UA_FORCE_UNWIND: c_int = 8;
+        pub const _UA_END_OF_STACK: c_int = 16;
+
+        #[cfg_attr(
+            all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
+            link(name = "unwind", kind = "static", modifiers = "-bundle")
+        )]
+        unsafe extern "C" {
+            pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
+            pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
+            pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
+            pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word);
+            pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int)
+                                     -> _Unwind_Word;
+            pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
+        }
 
-} else {
-    // ARM EHABI
-    #[repr(C)]
-    #[derive(Copy, Clone, PartialEq)]
-    pub enum _Unwind_State {
-        _US_VIRTUAL_UNWIND_FRAME = 0,
-        _US_UNWIND_FRAME_STARTING = 1,
-        _US_UNWIND_FRAME_RESUME = 2,
-        _US_ACTION_MASK = 3,
-        _US_FORCE_UNWIND = 8,
-        _US_END_OF_STACK = 16,
     }
-    pub use _Unwind_State::*;
+    _ => {
+        // ARM EHABI
+        #[repr(C)]
+        #[derive(Copy, Clone, PartialEq)]
+        pub enum _Unwind_State {
+            _US_VIRTUAL_UNWIND_FRAME = 0,
+            _US_UNWIND_FRAME_STARTING = 1,
+            _US_UNWIND_FRAME_RESUME = 2,
+            _US_ACTION_MASK = 3,
+            _US_FORCE_UNWIND = 8,
+            _US_END_OF_STACK = 16,
+        }
+        pub use _Unwind_State::*;
 
-    #[repr(C)]
-    enum _Unwind_VRS_Result {
-        _UVRSR_OK = 0,
-        _UVRSR_NOT_IMPLEMENTED = 1,
-        _UVRSR_FAILED = 2,
-    }
-    #[repr(C)]
-    enum _Unwind_VRS_RegClass {
-        _UVRSC_CORE = 0,
-        _UVRSC_VFP = 1,
-        _UVRSC_FPA = 2,
-        _UVRSC_WMMXD = 3,
-        _UVRSC_WMMXC = 4,
-    }
-    use _Unwind_VRS_RegClass::*;
-    #[repr(C)]
-    enum _Unwind_VRS_DataRepresentation {
-        _UVRSD_UINT32 = 0,
-        _UVRSD_VFPX = 1,
-        _UVRSD_FPAX = 2,
-        _UVRSD_UINT64 = 3,
-        _UVRSD_FLOAT = 4,
-        _UVRSD_DOUBLE = 5,
-    }
-    use _Unwind_VRS_DataRepresentation::*;
-
-    pub const UNWIND_POINTER_REG: c_int = 12;
-    pub const UNWIND_SP_REG: c_int = 13;
-    pub const UNWIND_IP_REG: c_int = 15;
-
-    #[cfg_attr(
-        all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
-        link(name = "unwind", kind = "static", modifiers = "-bundle")
-    )]
-    unsafe extern "C" {
-        fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
-                           regclass: _Unwind_VRS_RegClass,
-                           regno: _Unwind_Word,
-                           repr: _Unwind_VRS_DataRepresentation,
-                           data: *mut c_void)
-                           -> _Unwind_VRS_Result;
-
-        fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context,
-                           regclass: _Unwind_VRS_RegClass,
-                           regno: _Unwind_Word,
-                           repr: _Unwind_VRS_DataRepresentation,
-                           data: *mut c_void)
-                           -> _Unwind_VRS_Result;
-    }
+        #[repr(C)]
+        enum _Unwind_VRS_Result {
+            _UVRSR_OK = 0,
+            _UVRSR_NOT_IMPLEMENTED = 1,
+            _UVRSR_FAILED = 2,
+        }
+        #[repr(C)]
+        enum _Unwind_VRS_RegClass {
+            _UVRSC_CORE = 0,
+            _UVRSC_VFP = 1,
+            _UVRSC_FPA = 2,
+            _UVRSC_WMMXD = 3,
+            _UVRSC_WMMXC = 4,
+        }
+        use _Unwind_VRS_RegClass::*;
+        #[repr(C)]
+        enum _Unwind_VRS_DataRepresentation {
+            _UVRSD_UINT32 = 0,
+            _UVRSD_VFPX = 1,
+            _UVRSD_FPAX = 2,
+            _UVRSD_UINT64 = 3,
+            _UVRSD_FLOAT = 4,
+            _UVRSD_DOUBLE = 5,
+        }
+        use _Unwind_VRS_DataRepresentation::*;
+
+        pub const UNWIND_POINTER_REG: c_int = 12;
+        pub const UNWIND_SP_REG: c_int = 13;
+        pub const UNWIND_IP_REG: c_int = 15;
+
+        #[cfg_attr(
+            all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
+            link(name = "unwind", kind = "static", modifiers = "-bundle")
+        )]
+        unsafe extern "C" {
+            fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
+                               regclass: _Unwind_VRS_RegClass,
+                               regno: _Unwind_Word,
+                               repr: _Unwind_VRS_DataRepresentation,
+                               data: *mut c_void)
+                               -> _Unwind_VRS_Result;
+
+            fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context,
+                               regclass: _Unwind_VRS_RegClass,
+                               regno: _Unwind_Word,
+                               repr: _Unwind_VRS_DataRepresentation,
+                               data: *mut c_void)
+                               -> _Unwind_VRS_Result;
+        }
 
-    // On Android or ARM/Linux, these are implemented as macros:
+        // On Android or ARM/Linux, these are implemented as macros:
 
-    pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
-        let mut val: _Unwind_Word = core::ptr::null();
-        unsafe { _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
-                        (&raw mut val) as *mut c_void); }
-        val
-    }
+        pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
+            let mut val: _Unwind_Word = core::ptr::null();
+            unsafe { _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
+                            (&raw mut val) as *mut c_void); }
+            val
+        }
 
-    pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
-        let mut value = value;
-        unsafe { _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
-                        (&raw mut value) as *mut c_void); }
-    }
+        pub unsafe fn _Unwind_SetGR(
+            ctx: *mut _Unwind_Context,
+            reg_index: c_int,
+            value: _Unwind_Word
+        ) {
+            let mut value = value;
+            unsafe { _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
+                            (&raw mut value) as *mut c_void); }
+        }
 
-    pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
-                                -> _Unwind_Word {
-        let val = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG) };
-        val.map_addr(|v| v & !1)
-    }
+        pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
+                                    -> _Unwind_Word {
+            let val = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG) };
+            val.map_addr(|v| v & !1)
+        }
 
-    pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
-                                value: _Unwind_Word) {
-        // Propagate thumb bit to instruction pointer
-        let thumb_state = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG).addr() & 1 };
-        let value = value.map_addr(|v| v | thumb_state);
-        unsafe { _Unwind_SetGR(ctx, UNWIND_IP_REG, value); }
-    }
+        pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
+                                    value: _Unwind_Word) {
+            // Propagate thumb bit to instruction pointer
+            let thumb_state = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG).addr() & 1 };
+            let value = value.map_addr(|v| v | thumb_state);
+            unsafe { _Unwind_SetGR(ctx, UNWIND_IP_REG, value); }
+        }
 
-    pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
-                                    ip_before_insn: *mut c_int)
-                                    -> _Unwind_Word {
-        unsafe {
-            *ip_before_insn = 0;
-            _Unwind_GetIP(ctx)
+        pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
+                                        ip_before_insn: *mut c_int)
+                                        -> _Unwind_Word {
+            unsafe {
+                *ip_before_insn = 0;
+                _Unwind_GetIP(ctx)
+            }
         }
-    }
 
-    // This function also doesn't exist on Android or ARM/Linux, so make it a no-op
-    pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
-        pc
+        // This function also doesn't exist on Android or ARM/Linux, so make it a no-op
+        pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
+            pc
+        }
     }
 }
-} // cfg_if!
-
-cfg_if::cfg_if! {
-if #[cfg(all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm"))] {
-    // 32-bit ARM Apple (except for watchOS armv7k specifically) uses SjLj and
-    // does not provide _Unwind_Backtrace()
-    unsafe extern "C-unwind" {
-        pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
-    }
 
-    pub use _Unwind_SjLj_RaiseException as _Unwind_RaiseException;
-} else {
-    #[cfg_attr(
-        all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
-        link(name = "unwind", kind = "static", modifiers = "-bundle")
-    )]
-    unsafe extern "C-unwind" {
-        pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
+cfg_select! {
+    all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm") => {
+        // 32-bit ARM Apple (except for watchOS armv7k specifically) uses SjLj and
+        // does not provide _Unwind_Backtrace()
+        unsafe extern "C-unwind" {
+            pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
+        }
+
+        pub use _Unwind_SjLj_RaiseException as _Unwind_RaiseException;
     }
-    #[cfg_attr(
-        all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
-        link(name = "unwind", kind = "static", modifiers = "-bundle")
-    )]
-    unsafe extern "C" {
-        pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
-                                 trace_argument: *mut c_void)
-                                 -> _Unwind_Reason_Code;
+    _ => {
+        #[cfg_attr(
+            all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
+            link(name = "unwind", kind = "static", modifiers = "-bundle")
+        )]
+        unsafe extern "C-unwind" {
+            pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
+        }
+        #[cfg_attr(
+            all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
+            link(name = "unwind", kind = "static", modifiers = "-bundle")
+        )]
+        unsafe extern "C" {
+            pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
+                                     trace_argument: *mut c_void)
+                                     -> _Unwind_Reason_Code;
+        }
     }
 }
-} // cfg_if!
 
-cfg_if::cfg_if! {
-if #[cfg(any(
+cfg_select! {
+    any(
         all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"),
         target_os = "cygwin",
-    ))] {
-    // We declare these as opaque types. This is fine since you just need to
-    // pass them to _GCC_specific_handler and forget about them.
-    pub enum EXCEPTION_RECORD {}
-    pub type LPVOID = *mut c_void;
-    pub enum CONTEXT {}
-    pub enum DISPATCHER_CONTEXT {}
-    pub type EXCEPTION_DISPOSITION = c_int;
-    type PersonalityFn = unsafe extern "C" fn(version: c_int,
-                                              actions: _Unwind_Action,
-                                              exception_class: _Unwind_Exception_Class,
-                                              exception_object: *mut _Unwind_Exception,
-                                              context: *mut _Unwind_Context)
-                                              -> _Unwind_Reason_Code;
-
-    unsafe extern "C" {
-        pub fn _GCC_specific_handler(exceptionRecord: *mut EXCEPTION_RECORD,
-                                establisherFrame: LPVOID,
-                                contextRecord: *mut CONTEXT,
-                                dispatcherContext: *mut DISPATCHER_CONTEXT,
-                                personality: PersonalityFn)
-                                -> EXCEPTION_DISPOSITION;
+    ) => {
+        // We declare these as opaque types. This is fine since you just need to
+        // pass them to _GCC_specific_handler and forget about them.
+        pub enum EXCEPTION_RECORD {}
+        pub type LPVOID = *mut c_void;
+        pub enum CONTEXT {}
+        pub enum DISPATCHER_CONTEXT {}
+        pub type EXCEPTION_DISPOSITION = c_int;
+        type PersonalityFn = unsafe extern "C" fn(version: c_int,
+                                                  actions: _Unwind_Action,
+                                                  exception_class: _Unwind_Exception_Class,
+                                                  exception_object: *mut _Unwind_Exception,
+                                                  context: *mut _Unwind_Context)
+                                                  -> _Unwind_Reason_Code;
+
+        unsafe extern "C" {
+            pub fn _GCC_specific_handler(exceptionRecord: *mut EXCEPTION_RECORD,
+                                    establisherFrame: LPVOID,
+                                    contextRecord: *mut CONTEXT,
+                                    dispatcherContext: *mut DISPATCHER_CONTEXT,
+                                    personality: PersonalityFn)
+                                    -> EXCEPTION_DISPOSITION;
+        }
     }
+    _ => {}
 }
-} // cfg_if!
diff --git a/library/unwind/src/wasm.rs b/library/unwind/src/wasm.rs
index 2d36a8be004..3341e54759a 100644
--- a/library/unwind/src/wasm.rs
+++ b/library/unwind/src/wasm.rs
@@ -45,18 +45,19 @@ pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwi
     // via integers, with 0 corresponding to C++ exceptions and 1 to C setjmp()/longjmp().
     // Ideally, we'd be able to choose something unique for Rust, but for now,
     // we pretend to be C++ and implement the Itanium exception-handling ABI.
-    cfg_if::cfg_if! {
+    cfg_select! {
         // panic=abort is default for wasm targets. Because an unknown instruction is a load-time
         // error on wasm, instead of a runtime error like on traditional architectures, we never
         // want to codegen a `throw` instruction, as that would break users using runtimes that
         // don't yet support exceptions. The only time this first branch would be selected is if
         // the user explicitly opts in to wasm exceptions, via -Zbuild-std with -Cpanic=unwind.
-        if #[cfg(panic = "unwind")] {
+        panic = "unwind" => {
             // corresponds with llvm::WebAssembly::Tag::CPP_EXCEPTION
             //     in llvm-project/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h
             const CPP_EXCEPTION_TAG: i32 = 0;
             core::arch::wasm::throw::<CPP_EXCEPTION_TAG>(exception.cast())
-        } else {
+        }
+        _ => {
             let _ = exception;
             core::arch::wasm::unreachable()
         }
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 5865df67b66..f15b76fa85c 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -179,6 +179,16 @@ fn main() {
         }
     }
 
+    // Here we pass additional paths that essentially act as a sysroot.
+    // These are used to load rustc crates (e.g. `extern crate rustc_ast;`)
+    // for rustc_private tools, so that we do not have to copy them into the
+    // actual sysroot of the compiler that builds the tool.
+    if let Ok(dirs) = env::var("RUSTC_ADDITIONAL_SYSROOT_PATHS") {
+        for dir in dirs.split(",") {
+            cmd.arg(format!("-L{dir}"));
+        }
+    }
+
     // Force all crates compiled by this compiler to (a) be unstable and (b)
     // allow the `rustc_private` feature to link to other unstable crates
     // also in the sysroot. We also do this for host crates, since those
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index 4a110b733e1..bebae893ee7 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -1,5 +1,8 @@
 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
 
+use std::fs;
+use std::path::{Path, PathBuf};
+
 use crate::core::build_steps::compile::{
     add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
 };
@@ -9,11 +12,11 @@ use crate::core::build_steps::tool::{
     prepare_tool_cargo,
 };
 use crate::core::builder::{
-    self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,
+    self, Alias, Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,
 };
 use crate::core::config::TargetSelection;
 use crate::utils::build_stamp::{self, BuildStamp};
-use crate::{CodegenBackendKind, Compiler, Mode, Subcommand};
+use crate::{CodegenBackendKind, Compiler, Mode, Subcommand, t};
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
@@ -33,7 +36,7 @@ impl Std {
 }
 
 impl Step for Std {
-    type Output = ();
+    type Output = BuildStamp;
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -60,13 +63,14 @@ impl Step for Std {
 
         let crates = std_crates_for_run_make(&run);
         run.builder.ensure(Std {
-            build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Std),
+            build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Std)
+                .build_compiler(),
             target: run.target,
             crates,
         });
     }
 
-    fn run(self, builder: &Builder<'_>) {
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
         let build_compiler = self.build_compiler;
         let target = self.target;
 
@@ -93,18 +97,27 @@ impl Step for Std {
             Kind::Check,
             format_args!("library artifacts{}", crate_description(&self.crates)),
             Mode::Std,
-            self.build_compiler,
+            build_compiler,
             target,
         );
 
-        let stamp = build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check");
-        run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
+        let check_stamp =
+            build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check");
+        run_cargo(
+            builder,
+            cargo,
+            builder.config.free_args.clone(),
+            &check_stamp,
+            vec![],
+            true,
+            false,
+        );
 
         drop(_guard);
 
         // don't check test dependencies if we haven't built libtest
         if !self.crates.iter().any(|krate| krate == "test") {
-            return;
+            return check_stamp;
         }
 
         // Then run cargo again, once we've put the rmeta files for the library
@@ -137,10 +150,11 @@ impl Step for Std {
             Kind::Check,
             "library test/bench/example targets",
             Mode::Std,
-            self.build_compiler,
+            build_compiler,
             target,
         );
         run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
+        check_stamp
     }
 
     fn metadata(&self) -> Option<StepMetadata> {
@@ -148,12 +162,135 @@ impl Step for Std {
     }
 }
 
-/// Checks rustc using `build_compiler` and copies the built
-/// .rmeta files into the sysroot of `build_compiler`.
+/// Represents a proof that rustc was **checked**.
+/// Contains directories with .rmeta files generated by checking rustc for a specific
+/// target.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+struct RmetaSysroot {
+    host_dir: PathBuf,
+    target_dir: PathBuf,
+}
+
+impl RmetaSysroot {
+    /// Copy rmeta artifacts from the given `stamp` into a sysroot located at `directory`.
+    fn from_stamp(
+        builder: &Builder<'_>,
+        stamp: BuildStamp,
+        target: TargetSelection,
+        directory: &Path,
+    ) -> Self {
+        let host_dir = directory.join("host");
+        let target_dir = directory.join(target);
+        let _ = fs::remove_dir_all(directory);
+        t!(fs::create_dir_all(directory));
+        add_to_sysroot(builder, &target_dir, &host_dir, &stamp);
+
+        Self { host_dir, target_dir }
+    }
+
+    /// Configure the given cargo invocation so that the compiled crate will be able to use
+    /// rustc .rmeta artifacts that were previously generated.
+    fn configure_cargo(&self, cargo: &mut Cargo) {
+        cargo.append_to_env(
+            "RUSTC_ADDITIONAL_SYSROOT_PATHS",
+            format!("{},{}", self.host_dir.to_str().unwrap(), self.target_dir.to_str().unwrap()),
+            ",",
+        );
+    }
+}
+
+/// Checks rustc using the given `build_compiler` for the given `target`, and produces
+/// a sysroot in the build directory that stores the generated .rmeta files.
+///
+/// This step exists so that we can store the generated .rmeta artifacts into a separate
+/// directory, instead of copying them into the sysroot of `build_compiler`, which would
+/// "pollute" it (that is especially problematic for the external stage0 rustc).
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+struct PrepareRustcRmetaSysroot {
+    build_compiler: CompilerForCheck,
+    target: TargetSelection,
+}
+
+impl PrepareRustcRmetaSysroot {
+    fn new(build_compiler: CompilerForCheck, target: TargetSelection) -> Self {
+        Self { build_compiler, target }
+    }
+}
+
+impl Step for PrepareRustcRmetaSysroot {
+    type Output = RmetaSysroot;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.never()
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        // Check rustc
+        let stamp = builder.ensure(Rustc::from_build_compiler(
+            self.build_compiler.clone(),
+            self.target,
+            vec![],
+        ));
+
+        let build_compiler = self.build_compiler.build_compiler();
+
+        // Copy the generated rmeta artifacts to a separate directory
+        let dir = builder
+            .out
+            .join(build_compiler.host)
+            .join(format!("stage{}-rustc-rmeta-artifacts", build_compiler.stage + 1));
+        RmetaSysroot::from_stamp(builder, stamp, self.target, &dir)
+    }
+}
+
+/// Checks std using the given `build_compiler` for the given `target`, and produces
+/// a sysroot in the build directory that stores the generated .rmeta files.
+///
+/// This step exists so that we can store the generated .rmeta artifacts into a separate
+/// directory, instead of copying them into the sysroot of `build_compiler`, which would
+/// "pollute" it (that is especially problematic for the external stage0 rustc).
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+struct PrepareStdRmetaSysroot {
+    build_compiler: Compiler,
+    target: TargetSelection,
+}
+
+impl PrepareStdRmetaSysroot {
+    fn new(build_compiler: Compiler, target: TargetSelection) -> Self {
+        Self { build_compiler, target }
+    }
+}
+
+impl Step for PrepareStdRmetaSysroot {
+    type Output = RmetaSysroot;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.never()
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        // Check std
+        let stamp = builder.ensure(Std {
+            build_compiler: self.build_compiler,
+            target: self.target,
+            crates: vec![],
+        });
+
+        // Copy the generated rmeta artifacts to a separate directory
+        let dir = builder
+            .out
+            .join(self.build_compiler.host)
+            .join(format!("stage{}-std-rmeta-artifacts", self.build_compiler.stage));
+
+        RmetaSysroot::from_stamp(builder, stamp, self.target, &dir)
+    }
+}
+
+/// Checks rustc using `build_compiler`.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
     /// Compiler that will check this rustc.
-    pub build_compiler: Compiler,
+    pub build_compiler: CompilerForCheck,
     pub target: TargetSelection,
     /// Whether to build only a subset of crates.
     ///
@@ -166,12 +303,20 @@ pub struct Rustc {
 impl Rustc {
     pub fn new(builder: &Builder<'_>, target: TargetSelection, crates: Vec<String>) -> Self {
         let build_compiler = prepare_compiler_for_check(builder, target, Mode::Rustc);
+        Self::from_build_compiler(build_compiler, target, crates)
+    }
+
+    fn from_build_compiler(
+        build_compiler: CompilerForCheck,
+        target: TargetSelection,
+        crates: Vec<String>,
+    ) -> Self {
         Self { build_compiler, target, crates }
     }
 }
 
 impl Step for Rustc {
-    type Output = ();
+    type Output = BuildStamp;
     const IS_HOST: bool = true;
     const DEFAULT: bool = true;
 
@@ -191,8 +336,8 @@ impl Step for Rustc {
     /// created will also be linked into the sysroot directory.
     ///
     /// If we check a stage 2 compiler, we will have to first build a stage 1 compiler to check it.
-    fn run(self, builder: &Builder<'_>) {
-        let build_compiler = self.build_compiler;
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let build_compiler = self.build_compiler.build_compiler;
         let target = self.target;
 
         let mut cargo = builder::Cargo::new(
@@ -205,6 +350,7 @@ impl Step for Rustc {
         );
 
         rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
+        self.build_compiler.configure_cargo(&mut cargo);
 
         // Explicitly pass -p for all compiler crates -- this will force cargo
         // to also check the tests/benches/examples for these crates, rather
@@ -217,7 +363,7 @@ impl Step for Rustc {
             Kind::Check,
             format_args!("compiler artifacts{}", crate_description(&self.crates)),
             Mode::Rustc,
-            self.build_compiler,
+            self.build_compiler.build_compiler(),
             target,
         );
 
@@ -226,13 +372,12 @@ impl Step for Rustc {
 
         run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
 
-        let libdir = builder.sysroot_target_libdir(build_compiler, target);
-        let hostdir = builder.sysroot_target_libdir(build_compiler, build_compiler.host);
-        add_to_sysroot(builder, &libdir, &hostdir, &stamp);
+        stamp
     }
 
     fn metadata(&self) -> Option<StepMetadata> {
-        let metadata = StepMetadata::check("rustc", self.target).built_by(self.build_compiler);
+        let metadata = StepMetadata::check("rustc", self.target)
+            .built_by(self.build_compiler.build_compiler());
         let metadata = if self.crates.is_empty() {
             metadata
         } else {
@@ -242,45 +387,101 @@ impl Step for Rustc {
     }
 }
 
+/// Represents a compiler that can check something.
+///
+/// If the compiler was created for `Mode::ToolRustc` or `Mode::Codegen`, it will also contain
+/// .rmeta artifacts from rustc that was already checked using `build_compiler`.
+///
+/// All steps that use this struct in a "general way" (i.e. they don't know exactly what kind of
+/// thing is being built) should call `configure_cargo` to ensure that the rmeta artifacts are
+/// properly linked, if present.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct CompilerForCheck {
+    build_compiler: Compiler,
+    rustc_rmeta_sysroot: Option<RmetaSysroot>,
+    std_rmeta_sysroot: Option<RmetaSysroot>,
+}
+
+impl CompilerForCheck {
+    pub fn build_compiler(&self) -> Compiler {
+        self.build_compiler
+    }
+
+    /// If there are any rustc rmeta artifacts available, configure the Cargo invocation
+    /// so that the artifact being built can find them.
+    pub fn configure_cargo(&self, cargo: &mut Cargo) {
+        if let Some(sysroot) = &self.rustc_rmeta_sysroot {
+            sysroot.configure_cargo(cargo);
+        }
+        if let Some(sysroot) = &self.std_rmeta_sysroot {
+            sysroot.configure_cargo(cargo);
+        }
+    }
+}
+
+/// Prepare the standard library for checking something (that requires stdlib) using
+/// `build_compiler`.
+fn prepare_std(
+    builder: &Builder<'_>,
+    build_compiler: Compiler,
+    target: TargetSelection,
+) -> Option<RmetaSysroot> {
+    // We need to build the host stdlib even if we only check, to compile build scripts and proc
+    // macros
+    builder.std(build_compiler, builder.host_target);
+
+    // If we're cross-compiling, we generate the rmeta files for the given target
+    // This check has to be here, because if we generate both .so and .rmeta files, rustc will fail,
+    // as it will have multiple candidates for linking.
+    if builder.host_target != target {
+        Some(builder.ensure(PrepareStdRmetaSysroot::new(build_compiler, target)))
+    } else {
+        None
+    }
+}
+
 /// Prepares a compiler that will check something with the given `mode`.
 pub fn prepare_compiler_for_check(
     builder: &Builder<'_>,
     target: TargetSelection,
     mode: Mode,
-) -> Compiler {
+) -> CompilerForCheck {
     let host = builder.host_target;
 
-    match mode {
+    let mut rustc_rmeta_sysroot = None;
+    let mut std_rmeta_sysroot = None;
+    let build_compiler = match mode {
         Mode::ToolBootstrap => builder.compiler(0, host),
+        // We could also only check std here and use `prepare_std`, but `ToolTarget` is currently
+        // only used for running in-tree Clippy on bootstrap tools, so it does not seem worth it to
+        // optimize it. Therefore, here we build std for the target, instead of just checking it.
         Mode::ToolTarget => get_tool_target_compiler(builder, ToolTargetBuildMode::Build(target)),
         Mode::ToolStd => {
             if builder.config.compile_time_deps {
                 // When --compile-time-deps is passed, we can't use any rustc
                 // other than the bootstrap compiler. Luckily build scripts and
                 // proc macros for tools are unlikely to need nightly.
-                return builder.compiler(0, host);
+                builder.compiler(0, host)
+            } else {
+                // These tools require the local standard library to be checked
+                let build_compiler = builder.compiler(builder.top_stage, host);
+                std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
+                build_compiler
             }
-
-            // These tools require the local standard library to be checked
-            let build_compiler = builder.compiler(builder.top_stage, host);
-
-            // We need to build the host stdlib to check the tool itself.
-            // We need to build the target stdlib so that the tool can link to it.
-            builder.std(build_compiler, host);
-            // We could only check this library in theory, but `check::Std` doesn't copy rmetas
-            // into `build_compiler`'s sysroot to avoid clashes with `.rlibs`, so we build it
-            // instead.
-            builder.std(build_compiler, target);
-            build_compiler
         }
         Mode::ToolRustc | Mode::Codegen => {
             // Check Rustc to produce the required rmeta artifacts for rustc_private, and then
             // return the build compiler that was used to check rustc.
             // We do not need to check examples/tests/etc. of Rustc for rustc_private, so we pass
             // an empty set of crates, which will avoid using `cargo -p`.
-            let check = Rustc::new(builder, target, vec![]);
-            let build_compiler = check.build_compiler;
-            builder.ensure(check);
+            let compiler_for_rustc = prepare_compiler_for_check(builder, target, Mode::Rustc);
+            rustc_rmeta_sysroot = Some(
+                builder.ensure(PrepareRustcRmetaSysroot::new(compiler_for_rustc.clone(), target)),
+            );
+            let build_compiler = compiler_for_rustc.build_compiler();
+
+            // To check a rustc_private tool, we also need to check std that it will link to
+            std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
             build_compiler
         }
         Mode::Rustc => {
@@ -294,15 +495,8 @@ pub fn prepare_compiler_for_check(
             let stage = if host == target { builder.top_stage - 1 } else { builder.top_stage };
             let build_compiler = builder.compiler(stage, host);
 
-            // Build host std for compiling build scripts
-            builder.std(build_compiler, build_compiler.host);
-
-            // Build target std so that the checked rustc can link to it during the check
-            // FIXME: maybe we can a way to only do a check of std here?
-            // But for that we would have to copy the stdlib rmetas to the sysroot of the build
-            // compiler, which conflicts with std rlibs, if we also build std.
-            builder.std(build_compiler, target);
-
+            // To check rustc, we need to check std that it will link to
+            std_rmeta_sysroot = prepare_std(builder, build_compiler, target);
             build_compiler
         }
         Mode::Std => {
@@ -311,13 +505,14 @@ pub fn prepare_compiler_for_check(
             // stage 0 stdlib is used to compile build scripts and proc macros.
             builder.compiler(builder.top_stage, host)
         }
-    }
+    };
+    CompilerForCheck { build_compiler, rustc_rmeta_sysroot, std_rmeta_sysroot }
 }
 
 /// Check the Cranelift codegen backend.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct CraneliftCodegenBackend {
-    build_compiler: Compiler,
+    build_compiler: CompilerForCheck,
     target: TargetSelection,
 }
 
@@ -332,12 +527,14 @@ impl Step for CraneliftCodegenBackend {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        let build_compiler = prepare_compiler_for_check(run.builder, run.target, Mode::Codegen);
-        run.builder.ensure(CraneliftCodegenBackend { build_compiler, target: run.target });
+        run.builder.ensure(CraneliftCodegenBackend {
+            build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Codegen),
+            target: run.target,
+        });
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let build_compiler = self.build_compiler;
+        let build_compiler = self.build_compiler.build_compiler();
         let target = self.target;
 
         let mut cargo = builder::Cargo::new(
@@ -353,12 +550,13 @@ impl Step for CraneliftCodegenBackend {
             .arg("--manifest-path")
             .arg(builder.src.join("compiler/rustc_codegen_cranelift/Cargo.toml"));
         rustc_cargo_env(builder, &mut cargo, target);
+        self.build_compiler.configure_cargo(&mut cargo);
 
         let _guard = builder.msg(
             Kind::Check,
             "rustc_codegen_cranelift",
             Mode::Codegen,
-            self.build_compiler,
+            build_compiler,
             target,
         );
 
@@ -376,7 +574,7 @@ impl Step for CraneliftCodegenBackend {
     fn metadata(&self) -> Option<StepMetadata> {
         Some(
             StepMetadata::check("rustc_codegen_cranelift", self.target)
-                .built_by(self.build_compiler),
+                .built_by(self.build_compiler.build_compiler()),
         )
     }
 }
@@ -384,7 +582,7 @@ impl Step for CraneliftCodegenBackend {
 /// Check the GCC codegen backend.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct GccCodegenBackend {
-    build_compiler: Compiler,
+    build_compiler: CompilerForCheck,
     target: TargetSelection,
 }
 
@@ -399,8 +597,10 @@ impl Step for GccCodegenBackend {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        let build_compiler = prepare_compiler_for_check(run.builder, run.target, Mode::Codegen);
-        run.builder.ensure(GccCodegenBackend { build_compiler, target: run.target });
+        run.builder.ensure(GccCodegenBackend {
+            build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Codegen),
+            target: run.target,
+        });
     }
 
     fn run(self, builder: &Builder<'_>) {
@@ -410,7 +610,7 @@ impl Step for GccCodegenBackend {
             return;
         }
 
-        let build_compiler = self.build_compiler;
+        let build_compiler = self.build_compiler.build_compiler();
         let target = self.target;
 
         let mut cargo = builder::Cargo::new(
@@ -424,14 +624,10 @@ impl Step for GccCodegenBackend {
 
         cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
         rustc_cargo_env(builder, &mut cargo, target);
+        self.build_compiler.configure_cargo(&mut cargo);
 
-        let _guard = builder.msg(
-            Kind::Check,
-            "rustc_codegen_gcc",
-            Mode::Codegen,
-            self.build_compiler,
-            target,
-        );
+        let _guard =
+            builder.msg(Kind::Check, "rustc_codegen_gcc", Mode::Codegen, build_compiler, target);
 
         let stamp = build_stamp::codegen_backend_stamp(
             builder,
@@ -445,7 +641,10 @@ impl Step for GccCodegenBackend {
     }
 
     fn metadata(&self) -> Option<StepMetadata> {
-        Some(StepMetadata::check("rustc_codegen_gcc", self.target).built_by(self.build_compiler))
+        Some(
+            StepMetadata::check("rustc_codegen_gcc", self.target)
+                .built_by(self.build_compiler.build_compiler()),
+        )
     }
 }
 
@@ -467,8 +666,8 @@ macro_rules! tool_check_step {
     ) => {
         #[derive(Debug, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
-            pub build_compiler: Compiler,
-            pub target: TargetSelection,
+            compiler: CompilerForCheck,
+            target: TargetSelection,
         }
 
         impl Step for $name {
@@ -486,7 +685,7 @@ macro_rules! tool_check_step {
                 let builder = run.builder;
                 let mode = $mode(builder);
 
-                let build_compiler = prepare_compiler_for_check(run.builder, target, mode);
+                let compiler = prepare_compiler_for_check(run.builder, target, mode);
 
                 // It doesn't make sense to cross-check bootstrap tools
                 if mode == Mode::ToolBootstrap && target != run.builder.host_target {
@@ -494,11 +693,11 @@ macro_rules! tool_check_step {
                     return;
                 };
 
-                run.builder.ensure($name { target, build_compiler });
+                run.builder.ensure($name { target, compiler });
             }
 
             fn run(self, builder: &Builder<'_>) {
-                let Self { target, build_compiler } = self;
+                let Self { target, compiler } = self;
                 let allow_features = {
                     let mut _value = "";
                     $( _value = $allow_features; )?
@@ -506,11 +705,11 @@ macro_rules! tool_check_step {
                 };
                 let extra_features: &[&str] = &[$($($enable_features),*)?];
                 let mode = $mode(builder);
-                run_tool_check_step(builder, build_compiler, target, $path, mode, allow_features, extra_features);
+                run_tool_check_step(builder, compiler, target, $path, mode, allow_features, extra_features);
             }
 
             fn metadata(&self) -> Option<StepMetadata> {
-                Some(StepMetadata::check(stringify!($name), self.target).built_by(self.build_compiler))
+                Some(StepMetadata::check(stringify!($name), self.target).built_by(self.compiler.build_compiler))
             }
         }
     }
@@ -519,7 +718,7 @@ macro_rules! tool_check_step {
 /// Used by the implementation of `Step::run` in `tool_check_step!`.
 fn run_tool_check_step(
     builder: &Builder<'_>,
-    build_compiler: Compiler,
+    compiler: CompilerForCheck,
     target: TargetSelection,
     path: &str,
     mode: Mode,
@@ -528,6 +727,8 @@ fn run_tool_check_step(
 ) {
     let display_name = path.rsplit('/').next().unwrap();
 
+    let build_compiler = compiler.build_compiler();
+
     let extra_features = extra_features.iter().map(|f| f.to_string()).collect::<Vec<String>>();
     let mut cargo = prepare_tool_cargo(
         builder,
@@ -544,6 +745,7 @@ fn run_tool_check_step(
         &extra_features,
     );
     cargo.allow_features(allow_features);
+    compiler.configure_cargo(&mut cargo);
 
     // FIXME: check bootstrap doesn't currently work when multiple targets are checked
     // FIXME: rust-analyzer does not work with --all-targets
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index 3c4aa0886c2..05f8b240291 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -18,7 +18,7 @@ use build_helper::exit;
 use super::compile::{run_cargo, rustc_cargo, std_cargo};
 use super::tool::{SourceType, prepare_tool_cargo};
 use crate::builder::{Builder, ShouldRun};
-use crate::core::build_steps::check::prepare_compiler_for_check;
+use crate::core::build_steps::check::{CompilerForCheck, prepare_compiler_for_check};
 use crate::core::build_steps::compile::std_crates_for_run_make;
 use crate::core::builder;
 use crate::core::builder::{Alias, Kind, RunConfig, Step, StepMetadata, crate_description};
@@ -231,7 +231,7 @@ impl Step for Std {
 /// in-tree rustc.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
-    build_compiler: Compiler,
+    build_compiler: CompilerForCheck,
     target: TargetSelection,
     config: LintConfig,
     /// Whether to lint only a subset of crates.
@@ -271,7 +271,7 @@ impl Step for Rustc {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let build_compiler = self.build_compiler;
+        let build_compiler = self.build_compiler.build_compiler();
         let target = self.target;
 
         let mut cargo = builder::Cargo::new(
@@ -284,6 +284,7 @@ impl Step for Rustc {
         );
 
         rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
+        self.build_compiler.configure_cargo(&mut cargo);
 
         // Explicitly pass -p for all compiler crates -- this will force cargo
         // to also lint the tests/benches/examples for these crates, rather
@@ -312,13 +313,16 @@ impl Step for Rustc {
     }
 
     fn metadata(&self) -> Option<StepMetadata> {
-        Some(StepMetadata::clippy("rustc", self.target).built_by(self.build_compiler))
+        Some(
+            StepMetadata::clippy("rustc", self.target)
+                .built_by(self.build_compiler.build_compiler()),
+        )
     }
 }
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct CodegenGcc {
-    build_compiler: Compiler,
+    build_compiler: CompilerForCheck,
     target: TargetSelection,
     config: LintConfig,
 }
@@ -347,10 +351,10 @@ impl Step for CodegenGcc {
     }
 
     fn run(self, builder: &Builder<'_>) -> Self::Output {
-        let build_compiler = self.build_compiler;
+        let build_compiler = self.build_compiler.build_compiler();
         let target = self.target;
 
-        let cargo = prepare_tool_cargo(
+        let mut cargo = prepare_tool_cargo(
             builder,
             build_compiler,
             Mode::Codegen,
@@ -360,6 +364,7 @@ impl Step for CodegenGcc {
             SourceType::InTree,
             &[],
         );
+        self.build_compiler.configure_cargo(&mut cargo);
 
         let _guard =
             builder.msg(Kind::Clippy, "rustc_codegen_gcc", Mode::ToolRustc, build_compiler, target);
@@ -379,7 +384,10 @@ impl Step for CodegenGcc {
     }
 
     fn metadata(&self) -> Option<StepMetadata> {
-        Some(StepMetadata::clippy("rustc_codegen_gcc", self.target).built_by(self.build_compiler))
+        Some(
+            StepMetadata::clippy("rustc_codegen_gcc", self.target)
+                .built_by(self.build_compiler.build_compiler()),
+        )
     }
 }
 
@@ -396,7 +404,7 @@ macro_rules! lint_any {
 
         #[derive(Debug, Clone, Hash, PartialEq, Eq)]
         pub struct $name {
-            build_compiler: Compiler,
+            build_compiler: CompilerForCheck,
             target: TargetSelection,
             config: LintConfig,
         }
@@ -419,9 +427,9 @@ macro_rules! lint_any {
             }
 
             fn run(self, builder: &Builder<'_>) -> Self::Output {
-                let build_compiler = self.build_compiler;
+                let build_compiler = self.build_compiler.build_compiler();
                 let target = self.target;
-                let cargo = prepare_tool_cargo(
+                let mut cargo = prepare_tool_cargo(
                     builder,
                     build_compiler,
                     $mode,
@@ -431,6 +439,7 @@ macro_rules! lint_any {
                     SourceType::InTree,
                     &[],
                 );
+                self.build_compiler.configure_cargo(&mut cargo);
 
                 let _guard = builder.msg(
                     Kind::Clippy,
@@ -456,7 +465,7 @@ macro_rules! lint_any {
             }
 
             fn metadata(&self) -> Option<StepMetadata> {
-                Some(StepMetadata::clippy($readable_name, self.target).built_by(self.build_compiler))
+                Some(StepMetadata::clippy($readable_name, self.target).built_by(self.build_compiler.build_compiler()))
             }
         }
         )+
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 997a152a31f..be09cfa41af 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -12,6 +12,7 @@ use std::ffi::OsStr;
 use std::io::BufReader;
 use std::io::prelude::*;
 use std::path::{Path, PathBuf};
+use std::time::SystemTime;
 use std::{env, fs, str};
 
 use serde_derive::Deserialize;
@@ -38,7 +39,7 @@ use crate::{
 };
 
 /// Build a standard library for the given `target` using the given `build_compiler`.
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
     pub target: TargetSelection,
     /// Compiler that builds the standard library.
@@ -933,13 +934,22 @@ fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, conte
     }
 }
 
+/// Represents information about a built rustc.
+#[derive(Clone, Debug)]
+pub struct BuiltRustc {
+    /// The compiler that actually built this *rustc*.
+    /// This can be different from the *build_compiler* passed to the `Rustc` step because of
+    /// uplifting.
+    pub build_compiler: Compiler,
+}
+
 /// Build rustc using the passed `build_compiler`.
 ///
 /// - Makes sure that `build_compiler` has a standard library prepared for its host target,
 ///   so that it can compile build scripts and proc macros when building this `rustc`.
 /// - Makes sure that `build_compiler` has a standard library prepared for `target`,
 ///   so that the built `rustc` can *link to it* and use it at runtime.
-#[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
     /// The target on which rustc will run (its host).
     pub target: TargetSelection,
@@ -960,7 +970,7 @@ impl Rustc {
 }
 
 impl Step for Rustc {
-    type Output = ();
+    type Output = BuiltRustc;
 
     const IS_HOST: bool = true;
     const DEFAULT: bool = false;
@@ -1000,7 +1010,7 @@ impl Step for Rustc {
     /// This will build the compiler for a particular stage of the build using
     /// the `build_compiler` targeting the `target` architecture. The artifacts
     /// created will also be linked into the sysroot directory.
-    fn run(self, builder: &Builder<'_>) {
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
         let build_compiler = self.build_compiler;
         let target = self.target;
 
@@ -1016,7 +1026,7 @@ impl Step for Rustc {
                 &sysroot,
                 builder.config.ci_rustc_dev_contents(),
             );
-            return;
+            return BuiltRustc { build_compiler };
         }
 
         // Build a standard library for `target` using the `build_compiler`.
@@ -1028,9 +1038,9 @@ impl Step for Rustc {
 
             builder.info("WARNING: Using a potentially old librustc. This may not behave well.");
             builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes");
-            builder.ensure(RustcLink::from_rustc(self, build_compiler));
+            builder.ensure(RustcLink::from_rustc(self));
 
-            return;
+            return BuiltRustc { build_compiler };
         }
 
         // The stage of the compiler that we're building
@@ -1038,25 +1048,35 @@ impl Step for Rustc {
 
         // If we are building a stage3+ compiler, and full bootstrap is disabled, and we have a
         // previous rustc available, we will uplift a compiler from a previous stage.
+        // We do not allow cross-compilation uplifting here, because there it can be quite tricky
+        // to figure out which stage actually built the rustc that should be uplifted.
         if build_compiler.stage >= 2
             && !builder.config.full_bootstrap
-            && (target == builder.host_target || builder.hosts.contains(&target))
+            && target == builder.host_target
         {
-            // If we're cross-compiling, the earliest rustc that we could have is stage 2.
-            // If we're not cross-compiling, then we should have rustc stage 1.
-            let stage_to_uplift = if target == builder.host_target { 1 } else { 2 };
-            let rustc_to_uplift = builder.compiler(stage_to_uplift, target);
-            let msg = if rustc_to_uplift.host == target {
-                format!("Uplifting rustc (stage{} -> stage{stage})", rustc_to_uplift.stage,)
-            } else {
-                format!(
-                    "Uplifting rustc (stage{}:{} -> stage{stage}:{target})",
-                    rustc_to_uplift.stage, rustc_to_uplift.host,
-                )
-            };
+            // Here we need to determine the **build compiler** that built the stage that we will
+            // be uplifting. We cannot uplift stage 1, as it has a different ABI than stage 2+,
+            // so we always uplift the stage2 compiler (compiled with stage 1).
+            let uplift_build_compiler = builder.compiler(1, build_compiler.host);
+
+            let msg = format!("Uplifting rustc from stage2 to stage{stage})");
             builder.info(&msg);
-            builder.ensure(RustcLink::from_rustc(self, rustc_to_uplift));
-            return;
+
+            // Here the compiler that built the rlibs (`uplift_build_compiler`) can be different
+            // from the compiler whose sysroot should be modified in this step. So we need to copy
+            // the (previously built) rlibs into the correct sysroot.
+            builder.ensure(RustcLink::from_build_compiler_and_sysroot(
+                // This is the compiler that actually built the rustc rlibs
+                uplift_build_compiler,
+                // We copy the rlibs into the sysroot of `build_compiler`
+                build_compiler,
+                target,
+                self.crates,
+            ));
+
+            // Here we have performed an uplift, so we return the actual build compiler that "built"
+            // this rustc.
+            return BuiltRustc { build_compiler: uplift_build_compiler };
         }
 
         // Build a standard library for the current host target using the `build_compiler`.
@@ -1129,10 +1149,8 @@ impl Step for Rustc {
             strip_debug(builder, target, &target_root_dir.join("rustc-main"));
         }
 
-        builder.ensure(RustcLink::from_rustc(
-            self,
-            builder.compiler(build_compiler.stage, builder.config.host_target),
-        ));
+        builder.ensure(RustcLink::from_rustc(self));
+        BuiltRustc { build_compiler }
     }
 
     fn metadata(&self) -> Option<StepMetadata> {
@@ -1441,31 +1459,51 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
     }
 }
 
-/// `RustcLink` copies all of the rlibs from the rustc build into the previous stage's sysroot.
+/// `RustcLink` copies compiler rlibs from a rustc build into a compiler sysroot.
+/// It works with (potentially up to) three compilers:
+/// - `build_compiler` is a compiler that built rustc rlibs
+/// - `sysroot_compiler` is a compiler into whose sysroot we will copy the rlibs
+///   - In most situations, `build_compiler` == `sysroot_compiler`
+/// - `target_compiler` is the compiler whose rlibs were built. It is not represented explicitly
+///   in this step, rather we just read the rlibs from a rustc build stamp of `build_compiler`.
+///
 /// This is necessary for tools using `rustc_private`, where the previous compiler will build
 /// a tool against the next compiler.
 /// To build a tool against a compiler, the rlibs of that compiler that it links against
 /// must be in the sysroot of the compiler that's doing the compiling.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 struct RustcLink {
-    /// The compiler whose rlibs we are copying around.
-    pub compiler: Compiler,
-    /// This is the compiler into whose sysroot we want to copy the rlibs into.
-    pub previous_stage_compiler: Compiler,
-    pub target: TargetSelection,
+    /// This compiler **built** some rustc, whose rlibs we will copy into a sysroot.
+    build_compiler: Compiler,
+    /// This is the compiler into whose sysroot we want to copy the built rlibs.
+    /// In most cases, it will correspond to `build_compiler`.
+    sysroot_compiler: Compiler,
+    target: TargetSelection,
     /// Not actually used; only present to make sure the cache invalidation is correct.
     crates: Vec<String>,
 }
 
 impl RustcLink {
-    fn from_rustc(rustc: Rustc, host_compiler: Compiler) -> Self {
+    /// Copy rlibs from the build compiler that build this `rustc` into the sysroot of that
+    /// build compiler.
+    fn from_rustc(rustc: Rustc) -> Self {
         Self {
-            compiler: host_compiler,
-            previous_stage_compiler: rustc.build_compiler,
+            build_compiler: rustc.build_compiler,
+            sysroot_compiler: rustc.build_compiler,
             target: rustc.target,
             crates: rustc.crates,
         }
     }
+
+    /// Copy rlibs **built** by `build_compiler` into the sysroot of `sysroot_compiler`.
+    fn from_build_compiler_and_sysroot(
+        build_compiler: Compiler,
+        sysroot_compiler: Compiler,
+        target: TargetSelection,
+        crates: Vec<String>,
+    ) -> Self {
+        Self { build_compiler, sysroot_compiler, target, crates }
+    }
 }
 
 impl Step for RustcLink {
@@ -1477,14 +1515,14 @@ impl Step for RustcLink {
 
     /// Same as `std_link`, only for librustc
     fn run(self, builder: &Builder<'_>) {
-        let compiler = self.compiler;
-        let previous_stage_compiler = self.previous_stage_compiler;
+        let build_compiler = self.build_compiler;
+        let sysroot_compiler = self.sysroot_compiler;
         let target = self.target;
         add_to_sysroot(
             builder,
-            &builder.sysroot_target_libdir(previous_stage_compiler, target),
-            &builder.sysroot_target_libdir(previous_stage_compiler, compiler.host),
-            &build_stamp::librustc_stamp(builder, compiler, target),
+            &builder.sysroot_target_libdir(sysroot_compiler, target),
+            &builder.sysroot_target_libdir(sysroot_compiler, sysroot_compiler.host),
+            &build_stamp::librustc_stamp(builder, build_compiler, target),
         );
     }
 }
@@ -1918,7 +1956,7 @@ impl Step for Sysroot {
 /// linker wrappers (LLD, LLVM bitcode linker, etc.).
 ///
 /// This will assemble a compiler in `build/$target/stage$stage`.
-#[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Assemble {
     /// The compiler which we will produce in this step. Assemble itself will
     /// take care of ensuring that the necessary prerequisites to do so exist,
@@ -2099,7 +2137,10 @@ impl Step for Assemble {
             "target_compiler.host" = ?target_compiler.host,
             "building compiler libraries to link to"
         );
-        builder.ensure(Rustc::new(build_compiler, target_compiler.host));
+
+        // It is possible that an uplift has happened, so we override build_compiler here.
+        let BuiltRustc { build_compiler } =
+            builder.ensure(Rustc::new(build_compiler, target_compiler.host));
 
         let stage = target_compiler.stage;
         let host = target_compiler.host;
@@ -2286,6 +2327,7 @@ impl Step for Assemble {
 ///
 /// For a particular stage this will link the file listed in `stamp` into the
 /// `sysroot_dst` provided.
+#[track_caller]
 pub fn add_to_sysroot(
     builder: &Builder<'_>,
     sysroot_dst: &Path,
@@ -2568,7 +2610,17 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path)
     }
 
     let previous_mtime = t!(t!(path.metadata()).modified());
-    command("strip").arg("--strip-debug").arg(path).run_capture(builder);
+    let stamp = BuildStamp::new(path.parent().unwrap())
+        .with_prefix(path.file_name().unwrap().to_str().unwrap())
+        .with_prefix("strip")
+        .add_stamp(previous_mtime.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos());
+
+    // Running strip can be relatively expensive (~1s on librustc_driver.so), so we don't rerun it
+    // if the file is unchanged.
+    if !stamp.is_up_to_date() {
+        command("strip").arg("--strip-debug").arg(path).run_capture(builder);
+    }
+    t!(stamp.write());
 
     let file = t!(fs::File::open(path));
 
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 414f4464d1e..beb71e70035 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -54,7 +54,7 @@ fn should_build_extended_tool(builder: &Builder<'_>, tool: &str) -> bool {
     builder.config.tools.as_ref().is_none_or(|tools| tools.contains(tool))
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Docs {
     pub host: TargetSelection,
 }
@@ -91,7 +91,7 @@ impl Step for Docs {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct JsonDocs {
     build_compiler: Compiler,
     target: TargetSelection,
@@ -354,7 +354,7 @@ fn get_cc_search_dirs(
     (bin_path, lib_path)
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Mingw {
     pub host: TargetSelection,
 }
@@ -394,7 +394,7 @@ impl Step for Mingw {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Rustc {
     pub compiler: Compiler,
 }
@@ -730,7 +730,7 @@ fn copy_target_libs(
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Std {
     pub compiler: Compiler,
     pub target: TargetSelection,
@@ -785,7 +785,7 @@ impl Step for Std {
 /// `rust.download-rustc`.
 ///
 /// (Don't confuse this with [`RustDev`], without the `c`!)
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct RustcDev {
     pub compiler: Compiler,
     pub target: TargetSelection,
@@ -916,6 +916,12 @@ fn copy_src_dirs(
     exclude_dirs: &[&str],
     dst_dir: &Path,
 ) {
+    // The src directories should be relative to `base`, we depend on them not being absolute
+    // paths below.
+    for src_dir in src_dirs {
+        assert!(Path::new(src_dir).is_relative());
+    }
+
     // Iterating, filtering and copying a large number of directories can be quite slow.
     // Avoid doing it in dry run (and thus also tests).
     if builder.config.dry_run() {
@@ -923,6 +929,7 @@ fn copy_src_dirs(
     }
 
     fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
+        // The paths are relative, e.g. `llvm-project/...`.
         let spath = match path.to_str() {
             Some(path) => path,
             None => return false,
@@ -930,65 +937,53 @@ fn copy_src_dirs(
         if spath.ends_with('~') || spath.ends_with(".pyc") {
             return false;
         }
+        // Normalize slashes
+        let spath = spath.replace("\\", "/");
 
-        const LLVM_PROJECTS: &[&str] = &[
+        static LLVM_PROJECTS: &[&str] = &[
             "llvm-project/clang",
-            "llvm-project\\clang",
             "llvm-project/libunwind",
-            "llvm-project\\libunwind",
             "llvm-project/lld",
-            "llvm-project\\lld",
             "llvm-project/lldb",
-            "llvm-project\\lldb",
             "llvm-project/llvm",
-            "llvm-project\\llvm",
             "llvm-project/compiler-rt",
-            "llvm-project\\compiler-rt",
             "llvm-project/cmake",
-            "llvm-project\\cmake",
             "llvm-project/runtimes",
-            "llvm-project\\runtimes",
             "llvm-project/third-party",
-            "llvm-project\\third-party",
         ];
-        if spath.contains("llvm-project")
-            && !spath.ends_with("llvm-project")
-            && !LLVM_PROJECTS.iter().any(|path| spath.contains(path))
-        {
-            return false;
-        }
+        if spath.starts_with("llvm-project") && spath != "llvm-project" {
+            if !LLVM_PROJECTS.iter().any(|path| spath.starts_with(path)) {
+                return false;
+            }
 
-        // Keep only these third party libraries
-        const LLVM_THIRD_PARTY: &[&str] =
-            &["llvm-project/third-party/siphash", "llvm-project\\third-party\\siphash"];
-        if (spath.starts_with("llvm-project/third-party")
-            || spath.starts_with("llvm-project\\third-party"))
-            && !(spath.ends_with("llvm-project/third-party")
-                || spath.ends_with("llvm-project\\third-party"))
-            && !LLVM_THIRD_PARTY.iter().any(|path| spath.contains(path))
-        {
-            return false;
-        }
+            // Keep siphash third-party dependency
+            if spath.starts_with("llvm-project/third-party")
+                && spath != "llvm-project/third-party"
+                && !spath.starts_with("llvm-project/third-party/siphash")
+            {
+                return false;
+            }
 
-        const LLVM_TEST: &[&str] = &["llvm-project/llvm/test", "llvm-project\\llvm\\test"];
-        if LLVM_TEST.iter().any(|path| spath.contains(path))
-            && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s"))
-        {
-            return false;
+            if spath.starts_with("llvm-project/llvm/test")
+                && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s"))
+            {
+                return false;
+            }
         }
 
         // Cargo tests use some files like `.gitignore` that we would otherwise exclude.
-        const CARGO_TESTS: &[&str] = &["tools/cargo/tests", "tools\\cargo\\tests"];
-        if CARGO_TESTS.iter().any(|path| spath.contains(path)) {
+        if spath.starts_with("tools/cargo/tests") {
             return true;
         }
 
-        let full_path = Path::new(dir).join(path);
-        if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
-            return false;
+        if !exclude_dirs.is_empty() {
+            let full_path = Path::new(dir).join(path);
+            if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
+                return false;
+            }
         }
 
-        let excludes = [
+        static EXCLUDES: &[&str] = &[
             "CVS",
             "RCS",
             "SCCS",
@@ -1011,7 +1006,15 @@ fn copy_src_dirs(
             ".hgrags",
             "_darcs",
         ];
-        !path.iter().map(|s| s.to_str().unwrap()).any(|s| excludes.contains(&s))
+
+        // We want to check if any component of `path` doesn't contain the strings in `EXCLUDES`.
+        // However, since we traverse directories top-down in `Builder::cp_link_filtered`,
+        // it is enough to always check only the last component:
+        // - If the path is a file, we will iterate to it and then check it's filename
+        // - If the path is a dir, if it's dir name contains an excluded string, we will not even
+        //   recurse into it.
+        let last_component = path.iter().next_back().map(|s| s.to_str().unwrap()).unwrap();
+        !EXCLUDES.contains(&last_component)
     }
 
     // Copy the directories using our filter
@@ -1023,7 +1026,7 @@ fn copy_src_dirs(
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Src;
 
 impl Step for Src {
@@ -1084,7 +1087,7 @@ impl Step for Src {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct PlainSourceTarball;
 
 impl Step for PlainSourceTarball {
@@ -1230,7 +1233,7 @@ impl Step for PlainSourceTarball {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Cargo {
     pub build_compiler: Compiler,
     pub target: TargetSelection,
@@ -1284,7 +1287,7 @@ impl Step for Cargo {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct RustAnalyzer {
     pub build_compiler: Compiler,
     pub target: TargetSelection,
@@ -1560,7 +1563,7 @@ impl Step for Rustfmt {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Extended {
     stage: u32,
     host: TargetSelection,
@@ -2401,7 +2404,7 @@ impl Step for LlvmTools {
 
 /// Distributes the `llvm-bitcode-linker` tool so that it can be used by a compiler whose host
 /// is `target`.
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct LlvmBitcodeLinker {
     /// The linker will be compiled by this compiler.
     pub build_compiler: Compiler,
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index f6b27d83120..7fe19c00ef5 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -580,7 +580,7 @@ impl Step for SharedAssets {
 }
 
 /// Document the standard library using `build_compiler`.
-#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Std {
     build_compiler: Compiler,
     target: TargetSelection,
@@ -715,7 +715,7 @@ impl Step for Std {
 /// or remote link.
 const STD_PUBLIC_CRATES: [&str; 5] = ["core", "alloc", "std", "proc_macro", "test"];
 
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub enum DocumentationFormat {
     Html,
     Json,
@@ -1230,7 +1230,7 @@ fn symlink_dir_force(config: &Config, original: &Path, link: &Path) {
 }
 
 /// Builds the Rust compiler book.
-#[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct RustcBook {
     build_compiler: Compiler,
     target: TargetSelection,
@@ -1334,7 +1334,7 @@ impl Step for RustcBook {
 /// Documents the reference.
 /// It has to always be done using a stage 1+ compiler, because it references in-tree
 /// compiler/stdlib concepts.
-#[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Reference {
     build_compiler: Compiler,
     target: TargetSelection,
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 7f1a7d00257..c6288f63847 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -17,7 +17,7 @@ use crate::core::config::flags::get_completion;
 use crate::utils::exec::command;
 use crate::{Mode, t};
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct BuildManifest;
 
 impl Step for BuildManifest {
@@ -56,7 +56,7 @@ impl Step for BuildManifest {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct BumpStage0;
 
 impl Step for BumpStage0 {
@@ -78,7 +78,7 @@ impl Step for BumpStage0 {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct ReplaceVersionPlaceholder;
 
 impl Step for ReplaceVersionPlaceholder {
@@ -169,7 +169,7 @@ impl Step for Miri {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct CollectLicenseMetadata;
 
 impl Step for CollectLicenseMetadata {
@@ -200,7 +200,7 @@ impl Step for CollectLicenseMetadata {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct GenerateCopyright;
 
 impl Step for GenerateCopyright {
@@ -264,7 +264,7 @@ impl Step for GenerateCopyright {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct GenerateWindowsSys;
 
 impl Step for GenerateWindowsSys {
@@ -326,7 +326,7 @@ impl Step for GenerateCompletions {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct UnicodeTableGenerator;
 
 impl Step for UnicodeTableGenerator {
@@ -348,7 +348,7 @@ impl Step for UnicodeTableGenerator {
     }
 }
 
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct FeaturesStatusDump;
 
 impl Step for FeaturesStatusDump {
@@ -408,7 +408,7 @@ impl Step for CyclicStep {
 ///
 /// The coverage-dump tool is an internal detail of coverage tests, so this run
 /// step is only needed when testing coverage-dump manually.
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct CoverageDump;
 
 impl Step for CoverageDump {
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 4006bed4ac5..56e7582a6ff 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1830,10 +1830,27 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         cmd.arg("--host").arg(&*compiler.host.triple);
         cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target));
 
-        if let Some(codegen_backend) = builder.config.default_codegen_backend(compiler.host) {
-            // Tells compiletest which codegen backend is used by default by the compiler.
+        if let Some(codegen_backend) = builder.config.cmd.test_codegen_backend() {
+            if !builder.config.enabled_codegen_backends(compiler.host).contains(codegen_backend) {
+                eprintln!(
+                    "\
+ERROR: No configured backend named `{name}`
+HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?}]`",
+                    name = codegen_backend.name(),
+                );
+                crate::exit!(1);
+            }
+            // Tells compiletest that we want to use this codegen in particular and to override
+            // the default one.
+            cmd.arg("--override-codegen-backend").arg(codegen_backend.name());
+            // Tells compiletest which codegen backend to use.
+            // It is used to e.g. ignore tests that don't support that codegen backend.
+            cmd.arg("--default-codegen-backend").arg(codegen_backend.name());
+        } else {
+            // Tells compiletest which codegen backend to use.
             // It is used to e.g. ignore tests that don't support that codegen backend.
-            cmd.arg("--codegen-backend").arg(codegen_backend.name());
+            cmd.arg("--default-codegen-backend")
+                .arg(builder.config.default_codegen_backend(compiler.host).unwrap().name());
         }
 
         if builder.build.config.llvm_enzyme {
@@ -2732,7 +2749,7 @@ fn prepare_cargo_test(
 /// FIXME(Zalathar): Try to split this into two separate steps: a user-visible
 /// step for testing standard library crates, and an internal step used for both
 /// library crates and compiler crates.
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Crate {
     pub compiler: Compiler,
     pub target: TargetSelection,
@@ -3747,7 +3764,7 @@ impl Step for TestFloatParse {
 /// Runs the tool `src/tools/collect-license-metadata` in `ONLY_CHECK=1` mode,
 /// which verifies that `license-metadata.json` is up-to-date and therefore
 /// running the tool normally would not update anything.
-#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct CollectLicenseMetadata;
 
 impl Step for CollectLicenseMetadata {
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index 3ce21eb151c..72192403412 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -101,6 +101,7 @@ pub struct Cargo {
 impl Cargo {
     /// Calls [`Builder::cargo`] and [`Cargo::configure_linker`] to prepare an invocation of `cargo`
     /// to be run.
+    #[track_caller]
     pub fn new(
         builder: &Builder<'_>,
         compiler: Compiler,
@@ -139,6 +140,7 @@ impl Cargo {
 
     /// Same as [`Cargo::new`] except this one doesn't configure the linker with
     /// [`Cargo::configure_linker`].
+    #[track_caller]
     pub fn new_for_mir_opt_tests(
         builder: &Builder<'_>,
         compiler: Compiler,
@@ -186,6 +188,32 @@ impl Cargo {
         self
     }
 
+    /// Append a value to an env var of the cargo command instance.
+    /// If the variable was unset previously, this is equivalent to [`Cargo::env`].
+    /// If the variable was already set, this will append `delimiter` and then `value` to it.
+    ///
+    /// Note that this only considers the existence of the env. var. configured on this `Cargo`
+    /// instance. It does not look at the environment of this process.
+    pub fn append_to_env(
+        &mut self,
+        key: impl AsRef<OsStr>,
+        value: impl AsRef<OsStr>,
+        delimiter: impl AsRef<OsStr>,
+    ) -> &mut Cargo {
+        assert_ne!(key.as_ref(), "RUSTFLAGS");
+        assert_ne!(key.as_ref(), "RUSTDOCFLAGS");
+
+        let key = key.as_ref();
+        if let Some((_, Some(previous_value))) = self.command.get_envs().find(|(k, _)| *k == key) {
+            let mut combined: OsString = previous_value.to_os_string();
+            combined.push(delimiter.as_ref());
+            combined.push(value.as_ref());
+            self.env(key, combined)
+        } else {
+            self.env(key, value)
+        }
+    }
+
     pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>) {
         builder.add_rustc_lib_path(self.compiler, &mut self.command);
     }
@@ -396,6 +424,7 @@ impl From<Cargo> for BootstrapCommand {
 
 impl Builder<'_> {
     /// Like [`Builder::cargo`], but only passes flags that are valid for all commands.
+    #[track_caller]
     pub fn bare_cargo(
         &self,
         compiler: Compiler,
@@ -480,6 +509,7 @@ impl Builder<'_> {
     /// scoped by `mode`'s output directory, it will pass the `--target` flag for the specified
     /// `target`, and will be executing the Cargo command `cmd`. `cmd` can be `miri-cmd` for
     /// commands to be run with Miri.
+    #[track_caller]
     fn cargo(
         &self,
         compiler: Compiler,
@@ -1296,7 +1326,12 @@ impl Builder<'_> {
 
             if let Some(limit) = limit
                 && (build_compiler_stage == 0
-                    || self.config.default_codegen_backend(target).unwrap_or_default().is_llvm())
+                    || self
+                        .config
+                        .default_codegen_backend(target)
+                        .cloned()
+                        .unwrap_or_default()
+                        .is_llvm())
             {
                 rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));
             }
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index a9398a654e9..a2fe546c60a 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -673,6 +673,83 @@ mod snapshot {
     }
 
     #[test]
+    fn build_compiler_stage_3() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("build")
+                .path("compiler")
+                .stage(3)
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustc 1 <host> -> rustc 2 <host>
+        [build] rustc 2 <host> -> std 2 <host>
+        [build] rustc 2 <host> -> rustc 3 <host>
+        ");
+    }
+
+    #[test]
+    fn build_compiler_stage_3_cross() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("build")
+                .path("compiler")
+                .hosts(&[TEST_TRIPLE_1])
+                .stage(3)
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] llvm <target1>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustc 1 <host> -> rustc 2 <host>
+        [build] rustc 1 <host> -> std 1 <target1>
+        [build] rustc 2 <host> -> std 2 <target1>
+        [build] rustc 2 <host> -> std 2 <host>
+        [build] rustc 2 <host> -> rustc 3 <target1>
+        ");
+    }
+
+    #[test]
+    fn build_compiler_stage_3_full_bootstrap() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("build")
+                .path("compiler")
+                .stage(3)
+                .args(&["--set", "build.full-bootstrap=true"])
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustc 1 <host> -> rustc 2 <host>
+        [build] rustc 2 <host> -> std 2 <host>
+        [build] rustc 2 <host> -> rustc 3 <host>
+        ");
+    }
+
+    #[test]
+    fn build_compiler_stage_3_cross_full_bootstrap() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("build")
+                .path("compiler")
+                .stage(3)
+                .hosts(&[TEST_TRIPLE_1])
+                .args(&["--set", "build.full-bootstrap=true"])
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] llvm <target1>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustc 1 <host> -> rustc 2 <host>
+        [build] rustc 2 <host> -> std 2 <target1>
+        [build] rustc 2 <host> -> std 2 <host>
+        [build] rustc 2 <host> -> rustc 3 <target1>
+        ");
+    }
+
+    #[test]
     fn build_compiler_codegen_backend() {
         let ctx = TestCtx::new();
         insta::assert_snapshot!(
@@ -1514,7 +1591,7 @@ mod snapshot {
         insta::assert_snapshot!(
             ctx.config("check")
                 .path("compiler")
-                .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (73 crates)");
+                .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)");
     }
 
     #[test]
@@ -1540,7 +1617,7 @@ mod snapshot {
             ctx.config("check")
                 .path("compiler")
                 .stage(1)
-                .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (73 crates)");
+                .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)");
     }
 
     #[test]
@@ -1554,7 +1631,7 @@ mod snapshot {
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
-        [check] rustc 1 <host> -> rustc 2 <host> (73 crates)
+        [check] rustc 1 <host> -> rustc 2 <host> (74 crates)
         ");
     }
 
@@ -1569,8 +1646,8 @@ mod snapshot {
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
-        [build] rustc 1 <host> -> std 1 <target1>
-        [check] rustc 1 <host> -> rustc 2 <target1> (73 crates)
+        [check] rustc 1 <host> -> std 1 <target1>
+        [check] rustc 1 <host> -> rustc 2 <target1> (74 crates)
         [check] rustc 1 <host> -> rustc 2 <target1>
         [check] rustc 1 <host> -> Rustdoc 2 <target1>
         [check] rustc 1 <host> -> rustc_codegen_cranelift 2 <target1>
@@ -1666,7 +1743,7 @@ mod snapshot {
             ctx.config("check")
                 .paths(&["library", "compiler"])
                 .args(&args)
-                .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (73 crates)");
+                .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)");
     }
 
     #[test]
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 5eea5436023..d0647537e56 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1755,8 +1755,8 @@ impl Config {
 
     /// Returns the codegen backend that should be configured as the *default* codegen backend
     /// for a rustc compiled by bootstrap.
-    pub fn default_codegen_backend(&self, target: TargetSelection) -> Option<CodegenBackendKind> {
-        self.enabled_codegen_backends(target).first().cloned()
+    pub fn default_codegen_backend(&self, target: TargetSelection) -> Option<&CodegenBackendKind> {
+        self.enabled_codegen_backends(target).first()
     }
 
     pub fn jemalloc(&self, target: TargetSelection) -> bool {
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 17bfb388280..c01b71b9260 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -15,7 +15,7 @@ use crate::core::build_steps::setup::Profile;
 use crate::core::builder::{Builder, Kind};
 use crate::core::config::Config;
 use crate::core::config::target_selection::{TargetSelectionList, target_selection_list};
-use crate::{Build, DocTests};
+use crate::{Build, CodegenBackendKind, DocTests};
 
 #[derive(Copy, Clone, Default, Debug, ValueEnum)]
 pub enum Color {
@@ -419,6 +419,9 @@ pub enum Subcommand {
         #[arg(long)]
         /// don't capture stdout/stderr of tests
         no_capture: bool,
+        #[arg(long)]
+        /// Use a different codegen backend when running tests.
+        test_codegen_backend: Option<CodegenBackendKind>,
     },
     /// Build and run some test suites *in Miri*
     Miri {
@@ -658,6 +661,13 @@ impl Subcommand {
             _ => vec![],
         }
     }
+
+    pub fn test_codegen_backend(&self) -> Option<&CodegenBackendKind> {
+        match self {
+            Subcommand::Test { test_codegen_backend, .. } => test_codegen_backend.as_ref(),
+            _ => None,
+        }
+    }
 }
 
 /// Returns the shell completion for a given shell, if the result differs from the current
diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs
index 285d20917e7..8c5f9037251 100644
--- a/src/bootstrap/src/core/config/mod.rs
+++ b/src/bootstrap/src/core/config/mod.rs
@@ -324,7 +324,7 @@ impl FromStr for LlvmLibunwind {
     }
 }
 
-#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
 pub enum SplitDebuginfo {
     Packed,
     Unpacked,
diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs
index ebd3fe7a8c6..40b63a7f9c7 100644
--- a/src/bootstrap/src/core/config/target_selection.rs
+++ b/src/bootstrap/src/core/config/target_selection.rs
@@ -14,7 +14,7 @@ pub struct TargetSelection {
 }
 
 /// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic
-#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Clone, Default, PartialEq, Eq, Hash, Debug)]
 pub struct TargetSelectionList(pub Vec<TargetSelection>);
 
 pub fn target_selection_list(s: &str) -> Result<TargetSelectionList, String> {
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 706a3cbb210..ec7edbf7531 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -165,6 +165,20 @@ impl CodegenBackendKind {
     }
 }
 
+impl std::str::FromStr for CodegenBackendKind {
+    type Err = &'static str;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s.to_lowercase().as_str() {
+            "" => Err("Invalid empty backend name"),
+            "gcc" => Ok(Self::Gcc),
+            "llvm" => Ok(Self::Llvm),
+            "cranelift" => Ok(Self::Cranelift),
+            _ => Ok(Self::Custom(s.to_string())),
+        }
+    }
+}
+
 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
 pub enum DocTests {
     /// Run normal tests and doc tests (default).
@@ -279,7 +293,7 @@ pub enum DependencyType {
 ///
 /// These entries currently correspond to the various output directories of the
 /// build system, with each mod generating output in a different directory.
-#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
 pub enum Mode {
     /// Build the standard library, placing output in the "stageN-std" directory.
     Std,
@@ -357,7 +371,7 @@ pub enum RemapScheme {
     NonCompiler,
 }
 
-#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
 pub enum CLang {
     C,
     Cxx,
@@ -1743,6 +1757,7 @@ impl Build {
     ///
     /// If `src` is a symlink, `src` will be resolved to the actual path
     /// and copied to `dst` instead of the symlink itself.
+    #[track_caller]
     pub fn resolve_symlink_and_copy(&self, src: &Path, dst: &Path) {
         self.copy_link_internal(src, dst, true);
     }
@@ -1751,6 +1766,7 @@ impl Build {
     /// Attempts to use hard links if possible, falling back to copying.
     /// You can neither rely on this being a copy nor it being a link,
     /// so do not write to dst.
+    #[track_caller]
     pub fn copy_link(&self, src: &Path, dst: &Path, file_type: FileType) {
         self.copy_link_internal(src, dst, false);
 
@@ -1765,6 +1781,7 @@ impl Build {
         }
     }
 
+    #[track_caller]
     fn copy_link_internal(&self, src: &Path, dst: &Path, dereference_symlinks: bool) {
         if self.config.dry_run() {
             return;
@@ -1773,6 +1790,10 @@ impl Build {
         if src == dst {
             return;
         }
+
+        #[cfg(feature = "tracing")]
+        let _span = trace_io!("file-copy-link", ?src, ?dst);
+
         if let Err(e) = fs::remove_file(dst)
             && cfg!(windows)
             && e.kind() != io::ErrorKind::NotFound
@@ -1815,6 +1836,7 @@ impl Build {
     /// Links the `src` directory recursively to `dst`. Both are assumed to exist
     /// when this function is called.
     /// Will attempt to use hard links if possible and fall back to copying.
+    #[track_caller]
     pub fn cp_link_r(&self, src: &Path, dst: &Path) {
         if self.config.dry_run() {
             return;
@@ -1837,12 +1859,14 @@ impl Build {
     /// Will attempt to use hard links if possible and fall back to copying.
     /// Unwanted files or directories can be skipped
     /// by returning `false` from the filter function.
+    #[track_caller]
     pub fn cp_link_filtered(&self, src: &Path, dst: &Path, filter: &dyn Fn(&Path) -> bool) {
         // Immediately recurse with an empty relative path
         self.cp_link_filtered_recurse(src, dst, Path::new(""), filter)
     }
 
     // Inner function does the actual work
+    #[track_caller]
     fn cp_link_filtered_recurse(
         &self,
         src: &Path,
@@ -1862,7 +1886,6 @@ impl Build {
                     self.create_dir(&dst);
                     self.cp_link_filtered_recurse(&path, &dst, &relative, filter);
                 } else {
-                    let _ = fs::remove_file(&dst);
                     self.copy_link(&path, &dst, FileType::Regular);
                 }
             }
@@ -1904,10 +1927,15 @@ impl Build {
         t!(fs::read_to_string(path))
     }
 
+    #[track_caller]
     fn create_dir(&self, dir: &Path) {
         if self.config.dry_run() {
             return;
         }
+
+        #[cfg(feature = "tracing")]
+        let _span = trace_io!("dir-create", ?dir);
+
         t!(fs::create_dir_all(dir))
     }
 
@@ -1915,6 +1943,10 @@ impl Build {
         if self.config.dry_run() {
             return;
         }
+
+        #[cfg(feature = "tracing")]
+        let _span = trace_io!("dir-remove", ?dir);
+
         t!(fs::remove_dir_all(dir))
     }
 
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index b454a8ddefb..4fb5891ed18 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -506,4 +506,14 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "It is no longer possible to `x clippy` with stage 0. All clippy commands have to be on stage 1+.",
     },
+    ChangeInfo {
+        change_id: 145256,
+        severity: ChangeSeverity::Info,
+        summary: "Added `--test-codegen-backend` CLI option for tests",
+    },
+    ChangeInfo {
+        change_id: 145379,
+        severity: ChangeSeverity::Info,
+        summary: "Build/check now supports forwarding `--timings` flag to cargo.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/tracing.rs b/src/bootstrap/src/utils/tracing.rs
index 428ba013c98..472781ffa73 100644
--- a/src/bootstrap/src/utils/tracing.rs
+++ b/src/bootstrap/src/utils/tracing.rs
@@ -49,13 +49,36 @@ macro_rules! error {
 }
 
 #[cfg(feature = "tracing")]
+pub const IO_SPAN_TARGET: &str = "IO";
+
+/// Create a tracing span around an I/O operation, if tracing is enabled.
+/// Note that at least one tracing value field has to be passed to this macro, otherwise it will not
+/// compile.
+#[macro_export]
+macro_rules! trace_io {
+    ($name:expr, $($args:tt)*) => {
+        ::tracing::trace_span!(
+            target: $crate::utils::tracing::IO_SPAN_TARGET,
+            $name,
+            $($args)*,
+            location = $crate::utils::tracing::format_location(*::std::panic::Location::caller())
+        ).entered()
+    }
+}
+
+#[cfg(feature = "tracing")]
+pub fn format_location(location: std::panic::Location<'static>) -> String {
+    format!("{}:{}", location.file(), location.line())
+}
+
+#[cfg(feature = "tracing")]
 const COMMAND_SPAN_TARGET: &str = "COMMAND";
 
 #[cfg(feature = "tracing")]
 pub fn trace_cmd(command: &crate::BootstrapCommand) -> tracing::span::EnteredSpan {
     let fingerprint = command.fingerprint();
     let location = command.get_created_location();
-    let location = format!("{}:{}", location.file(), location.line());
+    let location = format_location(location);
 
     tracing::span!(
         target: COMMAND_SPAN_TARGET,
@@ -84,6 +107,7 @@ mod inner {
     use std::fmt::Debug;
     use std::fs::File;
     use std::io::Write;
+    use std::path::{Path, PathBuf};
     use std::sync::atomic::Ordering;
 
     use chrono::{DateTime, Utc};
@@ -93,8 +117,8 @@ mod inner {
     use tracing_subscriber::registry::{LookupSpan, SpanRef};
     use tracing_subscriber::{EnvFilter, Layer};
 
+    use super::{COMMAND_SPAN_TARGET, IO_SPAN_TARGET};
     use crate::STEP_SPAN_TARGET;
-    use crate::utils::tracing::COMMAND_SPAN_TARGET;
 
     pub fn setup_tracing(env_name: &str) -> TracingGuard {
         let filter = EnvFilter::from_env(env_name);
@@ -291,6 +315,23 @@ mod inner {
                 Ok(())
             }
 
+            // Write fields while treating the "location" field specially, and assuming that it
+            // contains the source file location relevant to the span.
+            let write_with_location = |writer: &mut W| -> std::io::Result<()> {
+                if let Some(values) = field_values {
+                    write_fields(
+                        writer,
+                        values.fields.iter().filter(|(name, _)| *name != "location"),
+                    )?;
+                    let location =
+                        &values.fields.iter().find(|(name, _)| *name == "location").unwrap().1;
+                    let (filename, line) = location.rsplit_once(':').unwrap();
+                    let filename = shorten_filename(filename);
+                    write!(writer, " ({filename}:{line})",)?;
+                }
+                Ok(())
+            };
+
             // We handle steps specially. We instrument them dynamically in `Builder::ensure`,
             // and we want to have custom name for each step span. But tracing doesn't allow setting
             // dynamic span names. So we detect step spans here and override their name.
@@ -311,17 +352,11 @@ mod inner {
                 // Executed command
                 COMMAND_SPAN_TARGET => {
                     write!(writer, "{}", span.name())?;
-                    if let Some(values) = field_values {
-                        write_fields(
-                            writer,
-                            values.fields.iter().filter(|(name, _)| *name != "location"),
-                        )?;
-                        write!(
-                            writer,
-                            " ({})",
-                            values.fields.iter().find(|(name, _)| *name == "location").unwrap().1
-                        )?;
-                    }
+                    write_with_location(writer)?;
+                }
+                IO_SPAN_TARGET => {
+                    write!(writer, "{}", span.name())?;
+                    write_with_location(writer)?;
                 }
                 // Other span
                 _ => {
@@ -342,21 +377,10 @@ mod inner {
         writer: &mut W,
         metadata: &'static tracing::Metadata<'static>,
     ) -> std::io::Result<()> {
-        use std::path::{Path, PathBuf};
-
         if let Some(filename) = metadata.file() {
-            // Keep only the module name and file name to make it shorter
-            let filename: PathBuf = Path::new(filename)
-                .components()
-                // Take last two path components
-                .rev()
-                .take(2)
-                .collect::<Vec<_>>()
-                .into_iter()
-                .rev()
-                .collect();
-
-            write!(writer, " ({}", filename.display())?;
+            let filename = shorten_filename(filename);
+
+            write!(writer, " ({filename}")?;
             if let Some(line) = metadata.line() {
                 write!(writer, ":{line}")?;
             }
@@ -365,6 +389,21 @@ mod inner {
         Ok(())
     }
 
+    /// Keep only the module name and file name to make it shorter
+    fn shorten_filename(filename: &str) -> String {
+        Path::new(filename)
+            .components()
+            // Take last two path components
+            .rev()
+            .take(2)
+            .collect::<Vec<_>>()
+            .into_iter()
+            .rev()
+            .collect::<PathBuf>()
+            .display()
+            .to_string()
+    }
+
     impl<S> Layer<S> for TracingPrinter
     where
         S: Subscriber,
diff --git a/src/build_helper/src/util.rs b/src/build_helper/src/util.rs
index a8355f774e9..1bdbb7515e2 100644
--- a/src/build_helper/src/util.rs
+++ b/src/build_helper/src/util.rs
@@ -3,6 +3,8 @@ use std::io::{BufRead, BufReader};
 use std::path::Path;
 use std::process::Command;
 
+use crate::ci::CiEnv;
+
 /// Invokes `build_helper::util::detail_exit` with `cfg!(test)`
 ///
 /// This is a macro instead of a function so that it uses `cfg(test)` in the *calling* crate, not in build helper.
@@ -20,6 +22,15 @@ pub fn detail_exit(code: i32, is_test: bool) -> ! {
     if is_test {
         panic!("status code: {code}");
     } else {
+        // If we're in CI, print the current bootstrap invocation command, to make it easier to
+        // figure out what exactly has failed.
+        if CiEnv::is_ci() {
+            // Skip the first argument, as it will be some absolute path to the bootstrap binary.
+            let bootstrap_args =
+                std::env::args().skip(1).map(|a| a.to_string()).collect::<Vec<_>>().join(" ");
+            eprintln!("Bootstrap failed while executing `{bootstrap_args}`");
+        }
+
         // otherwise, exit with provided status code
         std::process::exit(code);
     }
diff --git a/src/ci/docker/host-x86_64/tidy/Dockerfile b/src/ci/docker/host-x86_64/tidy/Dockerfile
index ee1ae5410ee..c8558689d3b 100644
--- a/src/ci/docker/host-x86_64/tidy/Dockerfile
+++ b/src/ci/docker/host-x86_64/tidy/Dockerfile
@@ -45,4 +45,4 @@ RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)'
 # NOTE: intentionally uses python2 for x.py so we can test it still works.
 # validate-toolstate only runs in our CI, so it's ok for it to only support python3.
 ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \
-  src/tools/tidy tidyselftest --extra-checks=py,cpp,js
+  src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck
diff --git a/src/ci/docker/host-x86_64/tidy/eslint.version b/src/ci/docker/host-x86_64/tidy/eslint.version
index 1acea15afd6..42890ac0095 100644
--- a/src/ci/docker/host-x86_64/tidy/eslint.version
+++ b/src/ci/docker/host-x86_64/tidy/eslint.version
@@ -1 +1 @@
-8.6.0
\ No newline at end of file
+8.57.1
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index ae13d14c380..8cfcc0c5b15 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -23,10 +23,6 @@ runners:
     <<: *base-job
 
   - &job-macos
-    os: macos-13
-    <<: *base-job
-
-  - &job-macos-m1
     os: macos-14
     <<: *base-job
 
@@ -68,17 +64,6 @@ runners:
     <<: *base-job
 
 envs:
-  env-x86_64-apple-tests: &env-x86_64-apple-tests
-    SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
-    RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
-    # Ensure that host tooling is tested on our minimum supported macOS version.
-    MACOSX_DEPLOYMENT_TARGET: 10.12
-    MACOSX_STD_DEPLOYMENT_TARGET: 10.12
-    SELECT_XCODE: /Applications/Xcode_15.2.app
-    NO_LLVM_ASSERTIONS: 1
-    NO_DEBUG_ASSERTIONS: 1
-    NO_OVERFLOW_CHECKS: 1
-
   production:
     &production
     DEPLOY_BUCKET: rust-lang-ci2
@@ -455,8 +440,19 @@ auto:
 
   - 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
+      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
+        --disable-docs
+        --set rust.jemalloc
+        --set rust.lto=thin
+        --set rust.codegen-units=1
       # Ensure that host tooling is built to support our minimum support macOS version.
       MACOSX_DEPLOYMENT_TARGET: 10.12
       MACOSX_STD_DEPLOYMENT_TARGET: 10.12
@@ -482,17 +478,6 @@ auto:
       NO_LLVM_ASSERTIONS: 1
       NO_DEBUG_ASSERTIONS: 1
       NO_OVERFLOW_CHECKS: 1
-    <<: *job-macos-m1
-
-  - name: x86_64-apple-1
-    env:
-      <<: *env-x86_64-apple-tests
-    <<: *job-macos
-
-  - name: x86_64-apple-2
-    env:
-      SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc
-      <<: *env-x86_64-apple-tests
     <<: *job-macos
 
   - name: dist-aarch64-apple
@@ -517,7 +502,7 @@ auto:
       NO_OVERFLOW_CHECKS: 1
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
-    <<: *job-macos-m1
+    <<: *job-macos
 
   - name: aarch64-apple
     env:
@@ -537,7 +522,7 @@ auto:
       NO_LLVM_ASSERTIONS: 1
       NO_DEBUG_ASSERTIONS: 1
       NO_OVERFLOW_CHECKS: 1
-    <<: *job-macos-m1
+    <<: *job-macos
 
   ######################
   #  Windows Builders  #
diff --git a/src/ci/scripts/free-disk-space-windows-wait.py b/src/ci/scripts/free-disk-space-windows-wait.py
index b8612bb71c2..d510781d534 100644
--- a/src/ci/scripts/free-disk-space-windows-wait.py
+++ b/src/ci/scripts/free-disk-space-windows-wait.py
@@ -61,12 +61,27 @@ def read_pid_from_file() -> int:
         ) from e
 
 
-def main() -> int:
-    pid = read_pid_from_file()
+def wait_for_process(pid: int):
+    timeout_duration_seconds = 5 * 60
+    interval_seconds = 3
+    max_attempts = timeout_duration_seconds / interval_seconds
+    attempts = 0
 
     # Poll until process exits
     while is_process_running(pid):
-        time.sleep(3)
+        if attempts >= max_attempts:
+            print(
+                "::warning::Timeout expired while waiting for the disk cleanup process to finish."
+            )
+            break
+        time.sleep(interval_seconds)
+        attempts += 1
+
+
+def main() -> int:
+    pid = read_pid_from_file()
+
+    wait_for_process(pid)
 
     print_logs()
 
diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md
index fb90c0fdb43..93b11c0690a 100644
--- a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md
+++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md
@@ -81,9 +81,11 @@ There are two orthogonal ways to control which kind of tracing logs you want:
    - If you select a level, all events/spans with an equal or higher priority level will be shown.
 2. You can also control the log **target**, e.g. `bootstrap` or `bootstrap::core::config` or a custom target like `CONFIG_HANDLING` or `STEP`.
     - Custom targets are used to limit what kinds of spans you are interested in, as the `BOOTSTRAP_TRACING=trace` output can be quite verbose. Currently, you can use the following custom targets:
-        - `CONFIG_HANDLING`: show spans related to config handling
-        - `STEP`: show all executed steps. Note that executed commands have `info` event level.
-        - `COMMAND`: show all executed commands. Note that executed commands have `trace` event level.
+        - `CONFIG_HANDLING`: show spans related to config handling.
+        - `STEP`: show all executed steps. Executed commands have `info` event level.
+        - `COMMAND`: show all executed commands. Executed commands have `trace` event level.
+        - `IO`: show performed I/O operations. Executed commands have `trace` event level.
+            - Note that many I/O are currently not being traced.
 
 You can of course combine them (custom target logs are typically gated behind `TRACE` log level additionally):
 
diff --git a/src/doc/rustc-dev-guide/src/sanitizers.md b/src/doc/rustc-dev-guide/src/sanitizers.md
index 29d9056c15d..34c78d4d952 100644
--- a/src/doc/rustc-dev-guide/src/sanitizers.md
+++ b/src/doc/rustc-dev-guide/src/sanitizers.md
@@ -45,7 +45,7 @@ implementation:
    [marked][sanitizer-attribute] with appropriate LLVM attribute:
    `SanitizeAddress`, `SanitizeHWAddress`, `SanitizeMemory`, or
    `SanitizeThread`. By default all functions are instrumented, but this
-   behaviour can be changed with `#[no_sanitize(...)]`.
+   behaviour can be changed with `#[sanitize(xyz = "on|off")]`.
 
 *  The decision whether to perform instrumentation or not is possible only at a
    function granularity. In the cases were those decision differ between
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index 07eafdf4c4c..445b10188e3 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -375,12 +375,12 @@ linking time. It takes one of the following values:
 
 * `y`, `yes`, `on`, `true`, `fat`, or no value: perform "fat" LTO which attempts to
   perform optimizations across all crates within the dependency graph.
-* `n`, `no`, `off`, `false`: disables LTO.
 * `thin`: perform ["thin"
   LTO](http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html).
   This is similar to "fat", but takes substantially less time to run while
   still achieving performance gains similar to "fat".
   For larger projects like the Rust compiler, ThinLTO can even result in better performance than fat LTO.
+* `n`, `no`, `off`, `false`: disables LTO.
 
 If `-C lto` is not specified, then the compiler will attempt to perform "thin
 local LTO" which performs "thin" LTO on the local crate only across its
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 89b43cda9b9..c039517a970 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -36,7 +36,6 @@ target | notes
 `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+)
 [`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI]
-[`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+)
 [`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+)
 [`x86_64-pc-windows-msvc`](platform-support/windows-msvc.md) | 64-bit MSVC (Windows 10+, Windows Server 2016+)
 `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+)
@@ -106,6 +105,7 @@ target | notes
 [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20+, glibc 2.29)
 [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20+, musl 1.2.3)
 [`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2+, glibc 2.17)
+[`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+)
 [`x86_64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | 64-bit x86 MinGW (Windows 10+), LLVM ABI
 [`x86_64-unknown-freebsd`](platform-support/freebsd.md) | 64-bit x86 FreeBSD
 [`x86_64-unknown-illumos`](platform-support/illumos.md) | illumos
diff --git a/src/doc/rustc/src/platform-support/apple-darwin.md b/src/doc/rustc/src/platform-support/apple-darwin.md
index e41aee9bdb2..bdbb3a663f1 100644
--- a/src/doc/rustc/src/platform-support/apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/apple-darwin.md
@@ -4,9 +4,12 @@ Apple macOS targets.
 
 **Tier: 1**
 
-- `x86_64-apple-darwin`: macOS on 64-bit x86.
 - `aarch64-apple-darwin`: macOS on ARM64 (M1-family or later Apple Silicon CPUs).
 
+**Tier: 2**
+
+- `x86_64-apple-darwin`: macOS on 64-bit x86.
+
 ## Target maintainers
 
 [@thomcc](https://github.com/thomcc)
diff --git a/src/doc/rustc/src/platform-support/openharmony.md b/src/doc/rustc/src/platform-support/openharmony.md
index 3acdc3707a8..de3b83d6c2c 100644
--- a/src/doc/rustc/src/platform-support/openharmony.md
+++ b/src/doc/rustc/src/platform-support/openharmony.md
@@ -16,7 +16,7 @@ system.
 ## Target maintainers
 
 [@Amanieu](https://github.com/Amanieu)
-[@lubinglun](https://github.com/lubinglun)
+[@cceerczw](https://github.com/cceerczw)
 
 ## Requirements
 
diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md
index a0acfdf0e4a..28d3dc32a63 100644
--- a/src/doc/rustc/src/target-tier-policy.md
+++ b/src/doc/rustc/src/target-tier-policy.md
@@ -534,10 +534,10 @@ tests, and will reject patches that fail to build or pass the testsuite on a
 target. We hold tier 1 targets to our highest standard of requirements.
 
 A proposed new tier 1 target must be reviewed and approved by the compiler team
-based on these requirements. In addition, the release team must approve the
-viability and value of supporting the target. For a tier 1 target, this will
+based on these requirements. In addition, the infra team must approve the
+viability of supporting the target. For a tier 1 target, this will
 typically take place via a full RFC proposing the target, to be jointly
-reviewed and approved by the compiler team and release team.
+reviewed and approved by the compiler team and infra team.
 
 In addition, the infrastructure team must approve the integration of the target
 into Continuous Integration (CI), and the tier 1 CI-related requirements. This
@@ -617,7 +617,7 @@ including the infrastructure team in the RFC proposing the target.
 A tier 1 target may be demoted if it no longer meets these requirements but
 still meets the requirements for a lower tier. Any proposal for demotion of a
 tier 1 target requires a full RFC process, with approval by the compiler and
-release teams. Any such proposal will be communicated widely to the Rust
+infra teams. Any such proposal will be communicated widely to the Rust
 community, both when initially proposed and before being dropped from a stable
 release. A tier 1 target is highly unlikely to be directly removed without
 first being demoted to tier 2 or tier 3. (The amount of time between such
@@ -628,7 +628,7 @@ planned and scheduled action.)
 
 Raising the baseline expectations of a tier 1 target (such as the minimum CPU
 features or OS version required) requires the approval of the compiler and
-release teams, and should be widely communicated as well, but does not
+infra teams, and should be widely communicated as well, but does not
 necessarily require a full RFC.
 
 ### Tier 1 with host tools
@@ -638,11 +638,11 @@ host (such as `rustc` and `cargo`). This allows the target to be used as a
 development platform, not just a compilation target.
 
 A proposed new tier 1 target with host tools must be reviewed and approved by
-the compiler team based on these requirements. In addition, the release team
-must approve the viability and value of supporting host tools for the target.
+the compiler team based on these requirements. In addition, the infra team
+must approve the viability of supporting host tools for the target.
 For a tier 1 target, this will typically take place via a full RFC proposing
 the target, to be jointly reviewed and approved by the compiler team and
-release team.
+infra team.
 
 In addition, the infrastructure team must approve the integration of the
 target's host tools into Continuous Integration (CI), and the CI-related
@@ -697,7 +697,7 @@ target with host tools may be demoted (including having its host tools dropped,
 or being demoted to tier 2 with host tools) if it no longer meets these
 requirements but still meets the requirements for a lower tier. Any proposal
 for demotion of a tier 1 target (with or without host tools) requires a full
-RFC process, with approval by the compiler and release teams. Any such proposal
+RFC process, with approval by the compiler and infra teams. Any such proposal
 will be communicated widely to the Rust community, both when initially proposed
 and before being dropped from a stable release.
 
diff --git a/src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md b/src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md
new file mode 100644
index 00000000000..040e2d41701
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md
@@ -0,0 +1,19 @@
+# `indirect-branch-cs-prefix`
+
+The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/116852.
+
+------------------------
+
+Option `-Zindirect-branch-cs-prefix` controls whether a `cs` prefix is added to
+`call` and `jmp` to indirect thunks.
+
+It is equivalent to [Clang]'s and [GCC]'s `-mindirect-branch-cs-prefix`. The
+Linux kernel uses it for RETPOLINE builds. For details, see
+[LLVM commit 6f867f910283] ("[X86] Support ``-mindirect-branch-cs-prefix`` for
+call and jmp to indirect thunk") which introduces the feature.
+
+Only x86 and x86_64 are supported.
+
+[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mindirect-branch-cs-prefix
+[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mindirect-branch-cs-prefix
+[LLVM commit 6f867f910283]: https://github.com/llvm/llvm-project/commit/6f867f9102838ebe314c1f3661fdf95700386e5a
diff --git a/src/doc/unstable-book/src/language-features/no-sanitize.md b/src/doc/unstable-book/src/language-features/no-sanitize.md
deleted file mode 100644
index 28c683934d4..00000000000
--- a/src/doc/unstable-book/src/language-features/no-sanitize.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# `no_sanitize`
-
-The tracking issue for this feature is: [#39699]
-
-[#39699]: https://github.com/rust-lang/rust/issues/39699
-
-------------------------
-
-The `no_sanitize` attribute can be used to selectively disable sanitizer
-instrumentation in an annotated function. This might be useful to: avoid
-instrumentation overhead in a performance critical function, or avoid
-instrumenting code that contains constructs unsupported by given sanitizer.
-
-The precise effect of this annotation depends on particular sanitizer in use.
-For example, with `no_sanitize(thread)`, the thread sanitizer will no longer
-instrument non-atomic store / load operations, but it will instrument atomic
-operations to avoid reporting false positives and provide meaning full stack
-traces.
-
-## Examples
-
-``` rust
-#![feature(no_sanitize)]
-
-#[no_sanitize(address)]
-fn foo() {
-  // ...
-}
-```
diff --git a/src/doc/unstable-book/src/language-features/sanitize.md b/src/doc/unstable-book/src/language-features/sanitize.md
new file mode 100644
index 00000000000..fcd099cb36e
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/sanitize.md
@@ -0,0 +1,73 @@
+# `sanitize`
+
+The tracking issue for this feature is: [#39699]
+
+[#39699]: https://github.com/rust-lang/rust/issues/39699
+
+------------------------
+
+The `sanitize` attribute can be used to selectively disable or enable sanitizer
+instrumentation in an annotated function. This might be useful to: avoid
+instrumentation overhead in a performance critical function, or avoid
+instrumenting code that contains constructs unsupported by given sanitizer.
+
+The precise effect of this annotation depends on particular sanitizer in use.
+For example, with `sanitize(thread = "off")`, the thread sanitizer will no
+longer instrument non-atomic store / load operations, but it will instrument
+atomic operations to avoid reporting false positives and provide meaning full
+stack traces.
+
+This attribute was previously named `no_sanitize`.
+
+## Examples
+
+``` rust
+#![feature(sanitize)]
+
+#[sanitize(address = "off")]
+fn foo() {
+  // ...
+}
+```
+
+It is also possible to disable sanitizers for entire modules and enable them
+for single items or functions.
+
+```rust
+#![feature(sanitize)]
+
+#[sanitize(address = "off")]
+mod foo {
+  fn unsanitized() {
+    // ...
+  }
+
+  #[sanitize(address = "on")]
+  fn sanitized() {
+    // ...
+  }
+}
+```
+
+It's also applicable to impl blocks.
+
+```rust
+#![feature(sanitize)]
+
+trait MyTrait {
+  fn foo(&self);
+  fn bar(&self);
+}
+
+#[sanitize(address = "off")]
+impl MyTrait for () {
+  fn foo(&self) {
+    // ...
+  }
+
+  #[sanitize(address = "on")]
+  fn bar(&self) {
+    // ...
+  }
+}
+```
diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish
index 0b9af334214..544f9b97237 100644
--- a/src/etc/completions/x.fish
+++ b/src/etc/completions/x.fish
@@ -305,6 +305,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l extra-checks -d 'comma-sepa
 complete -c x -n "__fish_x_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
 complete -c x -n "__fish_x_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
 complete -c x -n "__fish_x_using_subcommand test" -l run -d 'whether to execute run-* tests' -r
+complete -c x -n "__fish_x_using_subcommand test" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r
 complete -c x -n "__fish_x_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
 complete -c x -n "__fish_x_using_subcommand test" -l build -d 'host target of the stage0 compiler' -r -f
diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1
index 95cee4b6336..b03acf930f7 100644
--- a/src/etc/completions/x.ps1
+++ b/src/etc/completions/x.ps1
@@ -351,6 +351,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
             [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
             [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
+            [CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
             [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 6fba6a45623..08e4cd26ce8 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -305,6 +305,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l extra-checks -d 'comm
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l run -d 'whether to execute run-* tests' -r
+complete -c x.py -n "__fish_x.py_using_subcommand test" -l test-codegen-backend -d 'Use a different codegen backend when running tests' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l build -d 'host target of the stage0 compiler' -r -f
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index 458879a17a7..3d95d88af49 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -351,6 +351,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
             [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
             [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
+            [CompletionResult]::new('--test-codegen-backend', '--test-codegen-backend', [CompletionResultType]::ParameterName, 'Use a different codegen backend when running tests')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
             [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index e003bf7fd0b..8ff0eaf35c8 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -3875,7 +3875,7 @@ _x.py() {
             return 0
             ;;
         x.py__test)
-            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -3905,6 +3905,10 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
+                --test-codegen-backend)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
                 --config)
                     local oldifs
                     if [ -n "${IFS+x}" ]; then
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index b82c2d65e86..9d2d73e582e 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -351,6 +351,7 @@ _arguments "${_arguments_options[@]}" : \
 '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
 '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
 '--run=[whether to execute run-* tests]:auto | always | never:_default' \
+'--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
 '--build=[host target of the stage0 compiler]:BUILD:' \
diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh
index c2cb7710020..c1b73fb7c9e 100644
--- a/src/etc/completions/x.sh
+++ b/src/etc/completions/x.sh
@@ -3875,7 +3875,7 @@ _x() {
             return 0
             ;;
         x__test)
-            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --test-codegen-backend --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
@@ -3905,6 +3905,10 @@ _x() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
+                --test-codegen-backend)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
                 --config)
                     local oldifs
                     if [ -n "${IFS+x}" ]; then
diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh
index 49139e70f7f..29237ef9bf8 100644
--- a/src/etc/completions/x.zsh
+++ b/src/etc/completions/x.zsh
@@ -351,6 +351,7 @@ _arguments "${_arguments_options[@]}" : \
 '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
 '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
 '--run=[whether to execute run-* tests]:auto | always | never:_default' \
+'--test-codegen-backend=[Use a different codegen backend when running tests]:TEST_CODEGEN_BACKEND:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
 '--build=[host target of the stage0 compiler]:BUILD:' \
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 72975cc6206..8d7f7341c2e 100755
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -15,6 +15,7 @@ import os.path
 import re
 import shlex
 from collections import namedtuple
+from pathlib import Path
 
 try:
     from html.parser import HTMLParser
@@ -242,6 +243,11 @@ class CachedFiles(object):
             return self.last_path
 
     def get_absolute_path(self, path):
+        if "*" in path:
+            paths = list(Path(self.root).glob(path))
+            if len(paths) != 1:
+                raise FailedCheck("glob path does not resolve to one file")
+            path = str(paths[0])
         return os.path.join(self.root, path)
 
     def get_file(self, path):
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index fdde8309cf9..5d36ffc2d3a 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -21,6 +21,7 @@ rustdoc-json-types = { path = "../rustdoc-json-types" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.8.1"
+stringdex = { version = "0.0.1-alpha4" }
 tempfile = "3"
 threadpool = "1.8.1"
 tracing = "0.1"
diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs
index 07269d5bdc2..5b497183ae6 100644
--- a/src/librustdoc/build.rs
+++ b/src/librustdoc/build.rs
@@ -10,6 +10,7 @@ fn main() {
         "static/css/normalize.css",
         "static/js/main.js",
         "static/js/search.js",
+        "static/js/stringdex.js",
         "static/js/settings.js",
         "static/js/src-script.js",
         "static/js/storage.js",
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 26b087feb16..46aaa0068de 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1552,10 +1552,10 @@ impl Type {
         matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
     }
 
-    /// Check if two types are "the same" for documentation purposes.
+    /// Check if this type is a subtype of another type for documentation purposes.
     ///
     /// This is different from `Eq`, because it knows that things like
-    /// `Placeholder` are possible matches for everything.
+    /// `Infer` and generics have special subtyping rules.
     ///
     /// This relation is not commutative when generics are involved:
     ///
@@ -1566,8 +1566,8 @@ impl Type {
     /// let cache = Cache::new(false);
     /// let generic = Type::Generic(rustc_span::symbol::sym::Any);
     /// let unit = Type::Primitive(PrimitiveType::Unit);
-    /// assert!(!generic.is_same(&unit, &cache));
-    /// assert!(unit.is_same(&generic, &cache));
+    /// assert!(!generic.is_doc_subtype_of(&unit, &cache));
+    /// assert!(unit.is_doc_subtype_of(&generic, &cache));
     /// ```
     ///
     /// An owned type is also the same as its borrowed variants (this is commutative),
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 80399cf3842..cb6837dd614 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -1,6 +1,5 @@
 use std::mem;
 
-use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::StabilityLevel;
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
@@ -48,7 +47,7 @@ pub(crate) struct Cache {
 
     /// Similar to `paths`, but only holds external paths. This is only used for
     /// generating explicit hyperlinks to other crates.
-    pub(crate) external_paths: FxHashMap<DefId, (Vec<Symbol>, ItemType)>,
+    pub(crate) external_paths: FxIndexMap<DefId, (Vec<Symbol>, ItemType)>,
 
     /// Maps local `DefId`s of exported types to fully qualified paths.
     /// Unlike 'paths', this mapping ignores any renames that occur
@@ -574,7 +573,6 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
         clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id),
         _ => item_def_id,
     };
-    let path = join_path_syms(parent_path);
     let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() {
         item_id.as_def_id()
     } else {
@@ -593,11 +591,11 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
         ty: item.type_(),
         defid: Some(defid),
         name,
-        path,
+        module_path: parent_path.to_vec(),
         desc,
         parent: parent_did,
         parent_idx: None,
-        exact_path: None,
+        exact_module_path: None,
         impl_id,
         search_type,
         aliases,
diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs
index 1dba84aa44c..142a9d7d8af 100644
--- a/src/librustdoc/formats/item_type.rs
+++ b/src/librustdoc/formats/item_type.rs
@@ -4,7 +4,7 @@ use std::fmt;
 
 use rustc_hir::def::{CtorOf, DefKind, MacroKinds};
 use rustc_span::hygiene::MacroKind;
-use serde::{Serialize, Serializer};
+use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
 
 use crate::clean;
 
@@ -68,6 +68,52 @@ impl Serialize for ItemType {
     }
 }
 
+impl<'de> Deserialize<'de> for ItemType {
+    fn deserialize<D>(deserializer: D) -> Result<ItemType, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct ItemTypeVisitor;
+        impl<'de> de::Visitor<'de> for ItemTypeVisitor {
+            type Value = ItemType;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                write!(formatter, "an integer between 0 and 25")
+            }
+            fn visit_u64<E: de::Error>(self, v: u64) -> Result<ItemType, E> {
+                Ok(match v {
+                    0 => ItemType::Keyword,
+                    1 => ItemType::Primitive,
+                    2 => ItemType::Module,
+                    3 => ItemType::ExternCrate,
+                    4 => ItemType::Import,
+                    5 => ItemType::Struct,
+                    6 => ItemType::Enum,
+                    7 => ItemType::Function,
+                    8 => ItemType::TypeAlias,
+                    9 => ItemType::Static,
+                    10 => ItemType::Trait,
+                    11 => ItemType::Impl,
+                    12 => ItemType::TyMethod,
+                    13 => ItemType::Method,
+                    14 => ItemType::StructField,
+                    15 => ItemType::Variant,
+                    16 => ItemType::Macro,
+                    17 => ItemType::AssocType,
+                    18 => ItemType::Constant,
+                    19 => ItemType::AssocConst,
+                    20 => ItemType::Union,
+                    21 => ItemType::ForeignType,
+                    23 => ItemType::ProcAttribute,
+                    24 => ItemType::ProcDerive,
+                    25 => ItemType::TraitAlias,
+                    _ => return Err(E::missing_field("unknown number")),
+                })
+            }
+        }
+        deserializer.deserialize_any(ItemTypeVisitor)
+    }
+}
+
 impl<'a> From<&'a clean::Item> for ItemType {
     fn from(item: &'a clean::Item) -> ItemType {
         let kind = match &item.kind {
@@ -198,6 +244,10 @@ impl ItemType {
     pub(crate) fn is_adt(&self) -> bool {
         matches!(self, ItemType::Struct | ItemType::Union | ItemType::Enum)
     }
+    /// Keep this the same as isFnLikeTy in search.js
+    pub(crate) fn is_fn_like(&self) -> bool {
+        matches!(self, ItemType::Function | ItemType::Method | ItemType::TyMethod)
+    }
 }
 
 impl fmt::Display for ItemType {
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 2782e8e0058..5db742bdebf 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -27,6 +27,7 @@ pub(crate) struct Layout {
 
 pub(crate) struct Page<'a> {
     pub(crate) title: &'a str,
+    pub(crate) short_title: &'a str,
     pub(crate) css_class: &'a str,
     pub(crate) root_path: &'a str,
     pub(crate) static_root_path: Option<&'a str>,
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 5ceb1fc988d..e4fca09d64f 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -204,6 +204,18 @@ impl<'tcx> Context<'tcx> {
         if !is_module {
             title.push_str(it.name.unwrap().as_str());
         }
+        let short_title;
+        let short_title = if is_module {
+            let module_name = self.current.last().unwrap();
+            short_title = if it.is_crate() {
+                format!("Crate {module_name}")
+            } else {
+                format!("Module {module_name}")
+            };
+            &short_title[..]
+        } else {
+            it.name.as_ref().unwrap().as_str()
+        };
         if !it.is_primitive() && !it.is_keyword() {
             if !is_module {
                 title.push_str(" in ");
@@ -240,6 +252,7 @@ impl<'tcx> Context<'tcx> {
                 root_path: &self.root_path(),
                 static_root_path: self.shared.static_root_path.as_deref(),
                 title: &title,
+                short_title,
                 description: &desc,
                 resource_suffix: &self.shared.resource_suffix,
                 rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
@@ -617,6 +630,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         let shared = &self.shared;
         let mut page = layout::Page {
             title: "List of all items in this crate",
+            short_title: "All",
             css_class: "mod sys",
             root_path: "../",
             static_root_path: shared.static_root_path.as_deref(),
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index a46253237db..8d7f0577506 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -130,11 +130,11 @@ pub(crate) struct IndexItem {
     pub(crate) ty: ItemType,
     pub(crate) defid: Option<DefId>,
     pub(crate) name: Symbol,
-    pub(crate) path: String,
+    pub(crate) module_path: Vec<Symbol>,
     pub(crate) desc: String,
     pub(crate) parent: Option<DefId>,
-    pub(crate) parent_idx: Option<isize>,
-    pub(crate) exact_path: Option<String>,
+    pub(crate) parent_idx: Option<usize>,
+    pub(crate) exact_module_path: Option<Vec<Symbol>>,
     pub(crate) impl_id: Option<DefId>,
     pub(crate) search_type: Option<IndexItemFunctionType>,
     pub(crate) aliases: Box<[Symbol]>,
@@ -150,6 +150,19 @@ struct RenderType {
 }
 
 impl RenderType {
+    fn size(&self) -> usize {
+        let mut size = 1;
+        if let Some(generics) = &self.generics {
+            size += generics.iter().map(RenderType::size).sum::<usize>();
+        }
+        if let Some(bindings) = &self.bindings {
+            for (_, constraints) in bindings.iter() {
+                size += 1;
+                size += constraints.iter().map(RenderType::size).sum::<usize>();
+            }
+        }
+        size
+    }
     // Types are rendered as lists of lists, because that's pretty compact.
     // The contents of the lists are always integers in self-terminating hex
     // form, handled by `RenderTypeId::write_to_string`, so no commas are
@@ -191,6 +204,62 @@ impl RenderType {
             write_optional_id(self.id, string);
         }
     }
+    fn read_from_bytes(string: &[u8]) -> (RenderType, usize) {
+        let mut i = 0;
+        if string[i] == b'{' {
+            i += 1;
+            let (id, offset) = RenderTypeId::read_from_bytes(&string[i..]);
+            i += offset;
+            let generics = if string[i] == b'{' {
+                i += 1;
+                let mut generics = Vec::new();
+                while string[i] != b'}' {
+                    let (ty, offset) = RenderType::read_from_bytes(&string[i..]);
+                    i += offset;
+                    generics.push(ty);
+                }
+                assert!(string[i] == b'}');
+                i += 1;
+                Some(generics)
+            } else {
+                None
+            };
+            let bindings = if string[i] == b'{' {
+                i += 1;
+                let mut bindings = Vec::new();
+                while string[i] == b'{' {
+                    i += 1;
+                    let (binding, boffset) = RenderTypeId::read_from_bytes(&string[i..]);
+                    i += boffset;
+                    let mut bconstraints = Vec::new();
+                    assert!(string[i] == b'{');
+                    i += 1;
+                    while string[i] != b'}' {
+                        let (constraint, coffset) = RenderType::read_from_bytes(&string[i..]);
+                        i += coffset;
+                        bconstraints.push(constraint);
+                    }
+                    assert!(string[i] == b'}');
+                    i += 1;
+                    bindings.push((binding.unwrap(), bconstraints));
+                    assert!(string[i] == b'}');
+                    i += 1;
+                }
+                assert!(string[i] == b'}');
+                i += 1;
+                Some(bindings)
+            } else {
+                None
+            };
+            assert!(string[i] == b'}');
+            i += 1;
+            (RenderType { id, generics, bindings }, i)
+        } else {
+            let (id, offset) = RenderTypeId::read_from_bytes(string);
+            i += offset;
+            (RenderType { id, generics: None, bindings: None }, i)
+        }
+    }
 }
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -212,7 +281,20 @@ impl RenderTypeId {
             RenderTypeId::Index(idx) => (*idx).try_into().unwrap(),
             _ => panic!("must convert render types to indexes before serializing"),
         };
-        search_index::encode::write_vlqhex_to_string(id, string);
+        search_index::encode::write_signed_vlqhex_to_string(id, string);
+    }
+    fn read_from_bytes(string: &[u8]) -> (Option<RenderTypeId>, usize) {
+        let Some((value, offset)) = search_index::encode::read_signed_vlqhex_from_string(string)
+        else {
+            return (None, 0);
+        };
+        let value = isize::try_from(value).unwrap();
+        let ty = match value {
+            ..0 => Some(RenderTypeId::Index(value)),
+            0 => None,
+            1.. => Some(RenderTypeId::Index(value - 1)),
+        };
+        (ty, offset)
     }
 }
 
@@ -226,12 +308,64 @@ pub(crate) struct IndexItemFunctionType {
 }
 
 impl IndexItemFunctionType {
-    fn write_to_string<'a>(
-        &'a self,
-        string: &mut String,
-        backref_queue: &mut VecDeque<&'a IndexItemFunctionType>,
-    ) {
-        assert!(backref_queue.len() <= 16);
+    fn size(&self) -> usize {
+        self.inputs.iter().map(RenderType::size).sum::<usize>()
+            + self.output.iter().map(RenderType::size).sum::<usize>()
+            + self
+                .where_clause
+                .iter()
+                .map(|constraints| constraints.iter().map(RenderType::size).sum::<usize>())
+                .sum::<usize>()
+    }
+    fn read_from_string_without_param_names(string: &[u8]) -> (IndexItemFunctionType, usize) {
+        let mut i = 0;
+        if string[i] == b'`' {
+            return (
+                IndexItemFunctionType {
+                    inputs: Vec::new(),
+                    output: Vec::new(),
+                    where_clause: Vec::new(),
+                    param_names: Vec::new(),
+                },
+                1,
+            );
+        }
+        assert_eq!(b'{', string[i]);
+        i += 1;
+        fn read_args_from_string(string: &[u8]) -> (Vec<RenderType>, usize) {
+            let mut i = 0;
+            let mut params = Vec::new();
+            if string[i] == b'{' {
+                // multiple params
+                i += 1;
+                while string[i] != b'}' {
+                    let (ty, offset) = RenderType::read_from_bytes(&string[i..]);
+                    i += offset;
+                    params.push(ty);
+                }
+                i += 1;
+            } else if string[i] != b'}' {
+                let (tyid, offset) = RenderTypeId::read_from_bytes(&string[i..]);
+                params.push(RenderType { id: tyid, generics: None, bindings: None });
+                i += offset;
+            }
+            (params, i)
+        }
+        let (inputs, offset) = read_args_from_string(&string[i..]);
+        i += offset;
+        let (output, offset) = read_args_from_string(&string[i..]);
+        i += offset;
+        let mut where_clause = Vec::new();
+        while string[i] != b'}' {
+            let (constraint, offset) = read_args_from_string(&string[i..]);
+            i += offset;
+            where_clause.push(constraint);
+        }
+        assert_eq!(b'}', string[i], "{} {}", String::from_utf8_lossy(&string), i);
+        i += 1;
+        (IndexItemFunctionType { inputs, output, where_clause, param_names: Vec::new() }, i)
+    }
+    fn write_to_string_without_param_names<'a>(&'a self, string: &mut String) {
         // If we couldn't figure out a type, just write 0,
         // which is encoded as `` ` `` (see RenderTypeId::write_to_string).
         let has_missing = self
@@ -241,18 +375,7 @@ impl IndexItemFunctionType {
             .any(|i| i.id.is_none() && i.generics.is_none());
         if has_missing {
             string.push('`');
-        } else if let Some(idx) = backref_queue.iter().position(|other| *other == self) {
-            // The backref queue has 16 items, so backrefs use
-            // a single hexit, disjoint from the ones used for numbers.
-            string.push(
-                char::try_from('0' as u32 + u32::try_from(idx).unwrap())
-                    .expect("last possible value is '?'"),
-            );
         } else {
-            backref_queue.push_front(self);
-            if backref_queue.len() > 16 {
-                backref_queue.pop_back();
-            }
             string.push('{');
             match &self.inputs[..] {
                 [one] if one.generics.is_none() && one.bindings.is_none() => {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 759f53974f5..407238d66b8 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -35,6 +35,7 @@ use crate::html::format::{
     visibility_print_with_space,
 };
 use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
+use crate::html::render::sidebar::filters;
 use crate::html::render::{document_full, document_item_info};
 use crate::html::url_parts_builder::UrlPartsBuilder;
 
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index e2f86b8a854..41657e290ea 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -1,72 +1,1169 @@
 pub(crate) mod encode;
 
+use std::collections::BTreeSet;
 use std::collections::hash_map::Entry;
-use std::collections::{BTreeMap, VecDeque};
+use std::path::Path;
 
-use encode::{bitmap_to_string, write_vlqhex_to_string};
 use rustc_ast::join_path_syms;
-use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
 use rustc_span::sym;
 use rustc_span::symbol::{Symbol, kw};
-use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
+use serde::de::{self, Deserializer, Error as _};
+use serde::ser::{SerializeSeq, Serializer};
+use serde::{Deserialize, Serialize};
+use stringdex::internals as stringdex_internals;
 use thin_vec::ThinVec;
 use tracing::instrument;
 
 use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
 use crate::clean::{self, utils};
+use crate::error::Error;
 use crate::formats::cache::{Cache, OrphanImplItem};
 use crate::formats::item_type::ItemType;
 use crate::html::markdown::short_markdown_summary;
-use crate::html::render::ordered_json::OrderedJson;
 use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
 
-/// The serialized search description sharded version
-///
-/// The `index` is a JSON-encoded list of names and other information.
-///
-/// The desc has newlined descriptions, split up by size into 128KiB shards.
-/// For example, `(4, "foo\nbar\nbaz\nquux")`.
-///
-/// There is no single, optimal size for these shards, because it depends on
-/// configuration values that we can't predict or control, such as the version
-/// of HTTP used (HTTP/1.1 would work better with larger files, while HTTP/2
-/// and 3 are more agnostic), transport compression (gzip, zstd, etc), whether
-/// the search query is going to produce a large number of results or a small
-/// number, the bandwidth delay product of the network...
-///
-/// Gzipping some standard library descriptions to guess what transport
-/// compression will do, the compressed file sizes can be as small as 4.9KiB
-/// or as large as 18KiB (ignoring the final 1.9KiB shard of leftovers).
-/// A "reasonable" range for files is for them to be bigger than 1KiB,
-/// since that's about the amount of data that can be transferred in a
-/// single TCP packet, and 64KiB, the maximum amount of data that
-/// TCP can transfer in a single round trip without extensions.
-///
-/// [1]: https://en.wikipedia.org/wiki/Maximum_transmission_unit#MTUs_for_common_media
-/// [2]: https://en.wikipedia.org/wiki/Sliding_window_protocol#Basic_concept
-/// [3]: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/description-tcp-features
+#[derive(Clone, Debug, Default, Deserialize, Serialize)]
 pub(crate) struct SerializedSearchIndex {
-    pub(crate) index: OrderedJson,
-    pub(crate) desc: Vec<(usize, String)>,
+    // data from disk
+    names: Vec<String>,
+    path_data: Vec<Option<PathData>>,
+    entry_data: Vec<Option<EntryData>>,
+    descs: Vec<String>,
+    function_data: Vec<Option<FunctionData>>,
+    alias_pointers: Vec<Option<usize>>,
+    // inverted index for concrete types and generics
+    type_data: Vec<Option<TypeData>>,
+    /// inverted index of generics
+    ///
+    /// - The outermost list has one entry per alpha-normalized generic.
+    ///
+    /// - The second layer is sorted by number of types that appear in the
+    ///   type signature. The search engine iterates over these in order from
+    ///   smallest to largest. Functions with less stuff in their type
+    ///   signature are more likely to be what the user wants, because we never
+    ///   show functions that are *missing* parts of the query, so removing..
+    ///
+    /// - The final layer is the list of functions.
+    generic_inverted_index: Vec<Vec<Vec<u32>>>,
+    // generated in-memory backref cache
+    #[serde(skip)]
+    crate_paths_index: FxHashMap<(ItemType, Vec<Symbol>), usize>,
+}
+
+impl SerializedSearchIndex {
+    fn load(doc_root: &Path, resource_suffix: &str) -> Result<SerializedSearchIndex, Error> {
+        let mut names: Vec<String> = Vec::new();
+        let mut path_data: Vec<Option<PathData>> = Vec::new();
+        let mut entry_data: Vec<Option<EntryData>> = Vec::new();
+        let mut descs: Vec<String> = Vec::new();
+        let mut function_data: Vec<Option<FunctionData>> = Vec::new();
+        let mut type_data: Vec<Option<TypeData>> = Vec::new();
+        let mut alias_pointers: Vec<Option<usize>> = Vec::new();
+
+        let mut generic_inverted_index: Vec<Vec<Vec<u32>>> = Vec::new();
+
+        match perform_read_strings(resource_suffix, doc_root, "name", &mut names) {
+            Ok(()) => {
+                perform_read_serde(resource_suffix, doc_root, "path", &mut path_data)?;
+                perform_read_serde(resource_suffix, doc_root, "entry", &mut entry_data)?;
+                perform_read_strings(resource_suffix, doc_root, "desc", &mut descs)?;
+                perform_read_serde(resource_suffix, doc_root, "function", &mut function_data)?;
+                perform_read_serde(resource_suffix, doc_root, "type", &mut type_data)?;
+                perform_read_serde(resource_suffix, doc_root, "alias", &mut alias_pointers)?;
+                perform_read_postings(
+                    resource_suffix,
+                    doc_root,
+                    "generic_inverted_index",
+                    &mut generic_inverted_index,
+                )?;
+            }
+            Err(_) => {
+                names.clear();
+            }
+        }
+        fn perform_read_strings(
+            resource_suffix: &str,
+            doc_root: &Path,
+            column_name: &str,
+            column: &mut Vec<String>,
+        ) -> Result<(), Error> {
+            let root_path = doc_root.join(format!("search.index/root{resource_suffix}.js"));
+            let column_path = doc_root.join(format!("search.index/{column_name}/"));
+            stringdex_internals::read_data_from_disk_column(
+                root_path,
+                column_name.as_bytes(),
+                column_path.clone(),
+                &mut |_id, item| {
+                    column.push(String::from_utf8(item.to_vec())?);
+                    Ok(())
+                },
+            )
+            .map_err(
+                |error: stringdex_internals::ReadDataError<Box<dyn std::error::Error>>| Error {
+                    file: column_path,
+                    error: format!("failed to read column from disk: {error}"),
+                },
+            )
+        }
+        fn perform_read_serde(
+            resource_suffix: &str,
+            doc_root: &Path,
+            column_name: &str,
+            column: &mut Vec<Option<impl for<'de> Deserialize<'de> + 'static>>,
+        ) -> Result<(), Error> {
+            let root_path = doc_root.join(format!("search.index/root{resource_suffix}.js"));
+            let column_path = doc_root.join(format!("search.index/{column_name}/"));
+            stringdex_internals::read_data_from_disk_column(
+                root_path,
+                column_name.as_bytes(),
+                column_path.clone(),
+                &mut |_id, item| {
+                    if item.is_empty() {
+                        column.push(None);
+                    } else {
+                        column.push(Some(serde_json::from_slice(item)?));
+                    }
+                    Ok(())
+                },
+            )
+            .map_err(
+                |error: stringdex_internals::ReadDataError<Box<dyn std::error::Error>>| Error {
+                    file: column_path,
+                    error: format!("failed to read column from disk: {error}"),
+                },
+            )
+        }
+        fn perform_read_postings(
+            resource_suffix: &str,
+            doc_root: &Path,
+            column_name: &str,
+            column: &mut Vec<Vec<Vec<u32>>>,
+        ) -> Result<(), Error> {
+            let root_path = doc_root.join(format!("search.index/root{resource_suffix}.js"));
+            let column_path = doc_root.join(format!("search.index/{column_name}/"));
+            stringdex_internals::read_data_from_disk_column(
+                root_path,
+                column_name.as_bytes(),
+                column_path.clone(),
+                &mut |_id, buf| {
+                    let mut postings = Vec::new();
+                    encode::read_postings_from_string(&mut postings, buf);
+                    column.push(postings);
+                    Ok(())
+                },
+            )
+            .map_err(
+                |error: stringdex_internals::ReadDataError<Box<dyn std::error::Error>>| Error {
+                    file: column_path,
+                    error: format!("failed to read column from disk: {error}"),
+                },
+            )
+        }
+
+        assert_eq!(names.len(), path_data.len());
+        assert_eq!(path_data.len(), entry_data.len());
+        assert_eq!(entry_data.len(), descs.len());
+        assert_eq!(descs.len(), function_data.len());
+        assert_eq!(function_data.len(), type_data.len());
+        assert_eq!(type_data.len(), alias_pointers.len());
+
+        // generic_inverted_index is not the same length as other columns,
+        // because it's actually a completely different set of objects
+
+        let mut crate_paths_index: FxHashMap<(ItemType, Vec<Symbol>), usize> = FxHashMap::default();
+        for (i, (name, path_data)) in names.iter().zip(path_data.iter()).enumerate() {
+            if let Some(path_data) = path_data {
+                let full_path = if path_data.module_path.is_empty() {
+                    vec![Symbol::intern(name)]
+                } else {
+                    let mut full_path = path_data.module_path.to_vec();
+                    full_path.push(Symbol::intern(name));
+                    full_path
+                };
+                crate_paths_index.insert((path_data.ty, full_path), i);
+            }
+        }
+
+        Ok(SerializedSearchIndex {
+            names,
+            path_data,
+            entry_data,
+            descs,
+            function_data,
+            type_data,
+            alias_pointers,
+            generic_inverted_index,
+            crate_paths_index,
+        })
+    }
+    fn push(
+        &mut self,
+        name: String,
+        path_data: Option<PathData>,
+        entry_data: Option<EntryData>,
+        desc: String,
+        function_data: Option<FunctionData>,
+        type_data: Option<TypeData>,
+        alias_pointer: Option<usize>,
+    ) -> usize {
+        let index = self.names.len();
+        assert_eq!(self.names.len(), self.path_data.len());
+        if let Some(path_data) = &path_data
+            && let name = Symbol::intern(&name)
+            && let fqp = if path_data.module_path.is_empty() {
+                vec![name]
+            } else {
+                let mut v = path_data.module_path.clone();
+                v.push(name);
+                v
+            }
+            && let Some(&other_path) = self.crate_paths_index.get(&(path_data.ty, fqp))
+            && self.path_data.get(other_path).map_or(false, Option::is_some)
+        {
+            self.path_data.push(None);
+        } else {
+            self.path_data.push(path_data);
+        }
+        self.names.push(name);
+        assert_eq!(self.entry_data.len(), self.descs.len());
+        self.entry_data.push(entry_data);
+        assert_eq!(self.descs.len(), self.function_data.len());
+        self.descs.push(desc);
+        assert_eq!(self.function_data.len(), self.type_data.len());
+        self.function_data.push(function_data);
+        assert_eq!(self.type_data.len(), self.alias_pointers.len());
+        self.type_data.push(type_data);
+        self.alias_pointers.push(alias_pointer);
+        index
+    }
+    fn push_path(&mut self, name: String, path_data: PathData) -> usize {
+        self.push(name, Some(path_data), None, String::new(), None, None, None)
+    }
+    fn push_type(&mut self, name: String, path_data: PathData, type_data: TypeData) -> usize {
+        self.push(name, Some(path_data), None, String::new(), None, Some(type_data), None)
+    }
+    fn push_alias(&mut self, name: String, alias_pointer: usize) -> usize {
+        self.push(name, None, None, String::new(), None, None, Some(alias_pointer))
+    }
+
+    fn get_id_by_module_path(&mut self, path: &[Symbol]) -> usize {
+        let ty = if path.len() == 1 { ItemType::ExternCrate } else { ItemType::Module };
+        match self.crate_paths_index.entry((ty, path.to_vec())) {
+            Entry::Occupied(index) => *index.get(),
+            Entry::Vacant(slot) => {
+                slot.insert(self.path_data.len());
+                let (name, module_path) = path.split_last().unwrap();
+                self.push_path(
+                    name.as_str().to_string(),
+                    PathData { ty, module_path: module_path.to_vec(), exact_module_path: None },
+                )
+            }
+        }
+    }
+
+    pub(crate) fn union(mut self, other: &SerializedSearchIndex) -> SerializedSearchIndex {
+        let other_entryid_offset = self.names.len();
+        let mut map_other_pathid_to_self_pathid: Vec<usize> = Vec::new();
+        let mut skips = FxHashSet::default();
+        for (other_pathid, other_path_data) in other.path_data.iter().enumerate() {
+            if let Some(other_path_data) = other_path_data {
+                let mut fqp = other_path_data.module_path.clone();
+                let name = Symbol::intern(&other.names[other_pathid]);
+                fqp.push(name);
+                let self_pathid = other_entryid_offset + other_pathid;
+                let self_pathid = match self.crate_paths_index.entry((other_path_data.ty, fqp)) {
+                    Entry::Vacant(slot) => {
+                        slot.insert(self_pathid);
+                        self_pathid
+                    }
+                    Entry::Occupied(existing_entryid) => {
+                        skips.insert(other_pathid);
+                        let self_pathid = *existing_entryid.get();
+                        let new_type_data = match (
+                            self.type_data[self_pathid].take(),
+                            other.type_data[other_pathid].as_ref(),
+                        ) {
+                            (Some(self_type_data), None) => Some(self_type_data),
+                            (None, Some(other_type_data)) => Some(TypeData {
+                                search_unbox: other_type_data.search_unbox,
+                                inverted_function_signature_index: other_type_data
+                                    .inverted_function_signature_index
+                                    .iter()
+                                    .cloned()
+                                    .map(|mut list: Vec<u32>| {
+                                        for fnid in &mut list {
+                                            assert!(
+                                                other.function_data
+                                                    [usize::try_from(*fnid).unwrap()]
+                                                .is_some(),
+                                            );
+                                            // this is valid because we call `self.push()` once, exactly, for every entry,
+                                            // even if we're just pushing a tombstone
+                                            *fnid += u32::try_from(other_entryid_offset).unwrap();
+                                        }
+                                        list
+                                    })
+                                    .collect(),
+                            }),
+                            (Some(mut self_type_data), Some(other_type_data)) => {
+                                for (size, other_list) in other_type_data
+                                    .inverted_function_signature_index
+                                    .iter()
+                                    .enumerate()
+                                {
+                                    while self_type_data.inverted_function_signature_index.len()
+                                        <= size
+                                    {
+                                        self_type_data
+                                            .inverted_function_signature_index
+                                            .push(Vec::new());
+                                    }
+                                    self_type_data.inverted_function_signature_index[size].extend(
+                                        other_list.iter().copied().map(|fnid| {
+                                            assert!(
+                                                other.function_data[usize::try_from(fnid).unwrap()]
+                                                    .is_some(),
+                                            );
+                                            // this is valid because we call `self.push()` once, exactly, for every entry,
+                                            // even if we're just pushing a tombstone
+                                            fnid + u32::try_from(other_entryid_offset).unwrap()
+                                        }),
+                                    )
+                                }
+                                Some(self_type_data)
+                            }
+                            (None, None) => None,
+                        };
+                        self.type_data[self_pathid] = new_type_data;
+                        self_pathid
+                    }
+                };
+                map_other_pathid_to_self_pathid.push(self_pathid);
+            } else {
+                // if this gets used, we want it to crash
+                // this should be impossible as a valid index, since some of the
+                // memory must be used for stuff other than the list
+                map_other_pathid_to_self_pathid.push(!0);
+            }
+        }
+        for other_entryid in 0..other.names.len() {
+            if skips.contains(&other_entryid) {
+                // we push tombstone entries to keep the IDs lined up
+                self.push(String::new(), None, None, String::new(), None, None, None);
+            } else {
+                self.push(
+                    other.names[other_entryid].clone(),
+                    other.path_data[other_entryid].clone(),
+                    other.entry_data[other_entryid].as_ref().map(|other_entry_data| EntryData {
+                        parent: other_entry_data
+                            .parent
+                            .map(|parent| map_other_pathid_to_self_pathid[parent])
+                            .clone(),
+                        module_path: other_entry_data
+                            .module_path
+                            .map(|path| map_other_pathid_to_self_pathid[path])
+                            .clone(),
+                        exact_module_path: other_entry_data
+                            .exact_module_path
+                            .map(|exact_path| map_other_pathid_to_self_pathid[exact_path])
+                            .clone(),
+                        krate: map_other_pathid_to_self_pathid[other_entry_data.krate],
+                        ..other_entry_data.clone()
+                    }),
+                    other.descs[other_entryid].clone(),
+                    other.function_data[other_entryid].as_ref().map(|function_data| FunctionData {
+                        function_signature: {
+                            let (mut func, _offset) =
+                                IndexItemFunctionType::read_from_string_without_param_names(
+                                    function_data.function_signature.as_bytes(),
+                                );
+                            fn map_fn_sig_item(
+                                map_other_pathid_to_self_pathid: &mut Vec<usize>,
+                                ty: &mut RenderType,
+                            ) {
+                                match ty.id {
+                                    None => {}
+                                    Some(RenderTypeId::Index(generic)) if generic < 0 => {}
+                                    Some(RenderTypeId::Index(id)) => {
+                                        let id = usize::try_from(id).unwrap();
+                                        let id = map_other_pathid_to_self_pathid[id];
+                                        assert!(id != !0);
+                                        ty.id =
+                                            Some(RenderTypeId::Index(isize::try_from(id).unwrap()));
+                                    }
+                                    _ => unreachable!(),
+                                }
+                                if let Some(generics) = &mut ty.generics {
+                                    for generic in generics {
+                                        map_fn_sig_item(map_other_pathid_to_self_pathid, generic);
+                                    }
+                                }
+                                if let Some(bindings) = &mut ty.bindings {
+                                    for (param, constraints) in bindings {
+                                        *param = match *param {
+                                            param @ RenderTypeId::Index(generic) if generic < 0 => {
+                                                param
+                                            }
+                                            RenderTypeId::Index(id) => {
+                                                let id = usize::try_from(id).unwrap();
+                                                let id = map_other_pathid_to_self_pathid[id];
+                                                assert!(id != !0);
+                                                RenderTypeId::Index(isize::try_from(id).unwrap())
+                                            }
+                                            _ => unreachable!(),
+                                        };
+                                        for constraint in constraints {
+                                            map_fn_sig_item(
+                                                map_other_pathid_to_self_pathid,
+                                                constraint,
+                                            );
+                                        }
+                                    }
+                                }
+                            }
+                            for input in &mut func.inputs {
+                                map_fn_sig_item(&mut map_other_pathid_to_self_pathid, input);
+                            }
+                            for output in &mut func.output {
+                                map_fn_sig_item(&mut map_other_pathid_to_self_pathid, output);
+                            }
+                            for clause in &mut func.where_clause {
+                                for entry in clause {
+                                    map_fn_sig_item(&mut map_other_pathid_to_self_pathid, entry);
+                                }
+                            }
+                            let mut result =
+                                String::with_capacity(function_data.function_signature.len());
+                            func.write_to_string_without_param_names(&mut result);
+                            result
+                        },
+                        param_names: function_data.param_names.clone(),
+                    }),
+                    other.type_data[other_entryid].as_ref().map(|type_data| TypeData {
+                        inverted_function_signature_index: type_data
+                            .inverted_function_signature_index
+                            .iter()
+                            .cloned()
+                            .map(|mut list| {
+                                for fnid in &mut list {
+                                    assert!(
+                                        other.function_data[usize::try_from(*fnid).unwrap()]
+                                            .is_some(),
+                                    );
+                                    // this is valid because we call `self.push()` once, exactly, for every entry,
+                                    // even if we're just pushing a tombstone
+                                    *fnid += u32::try_from(other_entryid_offset).unwrap();
+                                }
+                                list
+                            })
+                            .collect(),
+                        search_unbox: type_data.search_unbox,
+                    }),
+                    other.alias_pointers[other_entryid]
+                        .map(|alias_pointer| alias_pointer + other_entryid_offset),
+                );
+            }
+        }
+        for (i, other_generic_inverted_index) in other.generic_inverted_index.iter().enumerate() {
+            for (size, other_list) in other_generic_inverted_index.iter().enumerate() {
+                let self_generic_inverted_index = match self.generic_inverted_index.get_mut(i) {
+                    Some(self_generic_inverted_index) => self_generic_inverted_index,
+                    None => {
+                        self.generic_inverted_index.push(Vec::new());
+                        self.generic_inverted_index.last_mut().unwrap()
+                    }
+                };
+                while self_generic_inverted_index.len() <= size {
+                    self_generic_inverted_index.push(Vec::new());
+                }
+                self_generic_inverted_index[size].extend(
+                    other_list
+                        .iter()
+                        .copied()
+                        .map(|fnid| fnid + u32::try_from(other_entryid_offset).unwrap()),
+                );
+            }
+        }
+        self
+    }
+
+    pub(crate) fn sort(self) -> SerializedSearchIndex {
+        let mut idlist: Vec<usize> = (0..self.names.len()).collect();
+        // nameless entries are tombstones, and will be removed after sorting
+        // sort shorter names first, so that we can present them in order out of search.js
+        idlist.sort_by_key(|&id| {
+            (
+                self.names[id].is_empty(),
+                self.names[id].len(),
+                &self.names[id],
+                self.entry_data[id].as_ref().map_or("", |entry| self.names[entry.krate].as_str()),
+                self.path_data[id].as_ref().map_or(&[][..], |entry| &entry.module_path[..]),
+            )
+        });
+        let map = FxHashMap::from_iter(
+            idlist.iter().enumerate().map(|(new_id, &old_id)| (old_id, new_id)),
+        );
+        let mut new = SerializedSearchIndex::default();
+        for &id in &idlist {
+            if self.names[id].is_empty() {
+                break;
+            }
+            new.push(
+                self.names[id].clone(),
+                self.path_data[id].clone(),
+                self.entry_data[id].as_ref().map(
+                    |EntryData {
+                         krate,
+                         ty,
+                         module_path,
+                         exact_module_path,
+                         parent,
+                         deprecated,
+                         associated_item_disambiguator,
+                     }| EntryData {
+                        krate: *map.get(krate).unwrap(),
+                        ty: *ty,
+                        module_path: module_path.and_then(|path_id| map.get(&path_id).copied()),
+                        exact_module_path: exact_module_path
+                            .and_then(|path_id| map.get(&path_id).copied()),
+                        parent: parent.and_then(|path_id| map.get(&path_id).copied()),
+                        deprecated: *deprecated,
+                        associated_item_disambiguator: associated_item_disambiguator.clone(),
+                    },
+                ),
+                self.descs[id].clone(),
+                self.function_data[id].as_ref().map(
+                    |FunctionData { function_signature, param_names }| FunctionData {
+                        function_signature: {
+                            let (mut func, _offset) =
+                                IndexItemFunctionType::read_from_string_without_param_names(
+                                    function_signature.as_bytes(),
+                                );
+                            fn map_fn_sig_item(map: &FxHashMap<usize, usize>, ty: &mut RenderType) {
+                                match ty.id {
+                                    None => {}
+                                    Some(RenderTypeId::Index(generic)) if generic < 0 => {}
+                                    Some(RenderTypeId::Index(id)) => {
+                                        let id = usize::try_from(id).unwrap();
+                                        let id = *map.get(&id).unwrap();
+                                        assert!(id != !0);
+                                        ty.id =
+                                            Some(RenderTypeId::Index(isize::try_from(id).unwrap()));
+                                    }
+                                    _ => unreachable!(),
+                                }
+                                if let Some(generics) = &mut ty.generics {
+                                    for generic in generics {
+                                        map_fn_sig_item(map, generic);
+                                    }
+                                }
+                                if let Some(bindings) = &mut ty.bindings {
+                                    for (param, constraints) in bindings {
+                                        *param = match *param {
+                                            param @ RenderTypeId::Index(generic) if generic < 0 => {
+                                                param
+                                            }
+                                            RenderTypeId::Index(id) => {
+                                                let id = usize::try_from(id).unwrap();
+                                                let id = *map.get(&id).unwrap();
+                                                assert!(id != !0);
+                                                RenderTypeId::Index(isize::try_from(id).unwrap())
+                                            }
+                                            _ => unreachable!(),
+                                        };
+                                        for constraint in constraints {
+                                            map_fn_sig_item(map, constraint);
+                                        }
+                                    }
+                                }
+                            }
+                            for input in &mut func.inputs {
+                                map_fn_sig_item(&map, input);
+                            }
+                            for output in &mut func.output {
+                                map_fn_sig_item(&map, output);
+                            }
+                            for clause in &mut func.where_clause {
+                                for entry in clause {
+                                    map_fn_sig_item(&map, entry);
+                                }
+                            }
+                            let mut result = String::with_capacity(function_signature.len());
+                            func.write_to_string_without_param_names(&mut result);
+                            result
+                        },
+                        param_names: param_names.clone(),
+                    },
+                ),
+                self.type_data[id].as_ref().map(
+                    |TypeData { search_unbox, inverted_function_signature_index }| {
+                        let inverted_function_signature_index: Vec<Vec<u32>> =
+                            inverted_function_signature_index
+                                .iter()
+                                .cloned()
+                                .map(|mut list| {
+                                    for id in &mut list {
+                                        *id = u32::try_from(
+                                            *map.get(&usize::try_from(*id).unwrap()).unwrap(),
+                                        )
+                                        .unwrap();
+                                    }
+                                    list.sort();
+                                    list
+                                })
+                                .collect();
+                        TypeData { search_unbox: *search_unbox, inverted_function_signature_index }
+                    },
+                ),
+                self.alias_pointers[id].and_then(|alias| map.get(&alias).copied()),
+            );
+        }
+        new.generic_inverted_index = self
+            .generic_inverted_index
+            .into_iter()
+            .map(|mut postings| {
+                for list in postings.iter_mut() {
+                    let mut new_list: Vec<u32> = list
+                        .iter()
+                        .copied()
+                        .filter_map(|id| u32::try_from(*map.get(&usize::try_from(id).ok()?)?).ok())
+                        .collect();
+                    new_list.sort();
+                    *list = new_list;
+                }
+                postings
+            })
+            .collect();
+        new
+    }
+
+    pub(crate) fn write_to(self, doc_root: &Path, resource_suffix: &str) -> Result<(), Error> {
+        let SerializedSearchIndex {
+            names,
+            path_data,
+            entry_data,
+            descs,
+            function_data,
+            type_data,
+            alias_pointers,
+            generic_inverted_index,
+            crate_paths_index: _,
+        } = self;
+        let mut serialized_root = Vec::new();
+        serialized_root.extend_from_slice(br#"rr_('{"normalizedName":{"I":""#);
+        let normalized_names = names
+            .iter()
+            .map(|name| {
+                if name.contains("_") {
+                    name.replace("_", "").to_ascii_lowercase()
+                } else {
+                    name.to_ascii_lowercase()
+                }
+            })
+            .collect::<Vec<String>>();
+        let names_search_tree = stringdex_internals::tree::encode_search_tree_ukkonen(
+            normalized_names.iter().map(|name| name.as_bytes()),
+        );
+        let dir_path = doc_root.join(format!("search.index/"));
+        let _ = std::fs::remove_dir_all(&dir_path); // if already missing, no problem
+        stringdex_internals::write_tree_to_disk(
+            &names_search_tree,
+            &dir_path,
+            &mut serialized_root,
+        )
+        .map_err(|error| Error {
+            file: dir_path,
+            error: format!("failed to write name tree to disk: {error}"),
+        })?;
+        std::mem::drop(names_search_tree);
+        serialized_root.extend_from_slice(br#"","#);
+        serialized_root.extend_from_slice(&perform_write_strings(
+            doc_root,
+            "normalizedName",
+            normalized_names.into_iter(),
+        )?);
+        serialized_root.extend_from_slice(br#"},"crateNames":{"#);
+        let mut crates: Vec<&[u8]> = entry_data
+            .iter()
+            .filter_map(|entry_data| Some(names[entry_data.as_ref()?.krate].as_bytes()))
+            .collect();
+        crates.sort();
+        crates.dedup();
+        serialized_root.extend_from_slice(&perform_write_strings(
+            doc_root,
+            "crateNames",
+            crates.into_iter(),
+        )?);
+        serialized_root.extend_from_slice(br#"},"name":{"#);
+        serialized_root.extend_from_slice(&perform_write_strings(doc_root, "name", names.iter())?);
+        serialized_root.extend_from_slice(br#"},"path":{"#);
+        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "path", path_data)?);
+        serialized_root.extend_from_slice(br#"},"entry":{"#);
+        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "entry", entry_data)?);
+        serialized_root.extend_from_slice(br#"},"desc":{"#);
+        serialized_root.extend_from_slice(&perform_write_strings(
+            doc_root,
+            "desc",
+            descs.into_iter(),
+        )?);
+        serialized_root.extend_from_slice(br#"},"function":{"#);
+        serialized_root.extend_from_slice(&perform_write_serde(
+            doc_root,
+            "function",
+            function_data,
+        )?);
+        serialized_root.extend_from_slice(br#"},"type":{"#);
+        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "type", type_data)?);
+        serialized_root.extend_from_slice(br#"},"alias":{"#);
+        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "alias", alias_pointers)?);
+        serialized_root.extend_from_slice(br#"},"generic_inverted_index":{"#);
+        serialized_root.extend_from_slice(&perform_write_postings(
+            doc_root,
+            "generic_inverted_index",
+            generic_inverted_index,
+        )?);
+        serialized_root.extend_from_slice(br#"}}')"#);
+        fn perform_write_strings(
+            doc_root: &Path,
+            dirname: &str,
+            mut column: impl Iterator<Item = impl AsRef<[u8]> + Clone> + ExactSizeIterator,
+        ) -> Result<Vec<u8>, Error> {
+            let dir_path = doc_root.join(format!("search.index/{dirname}"));
+            stringdex_internals::write_data_to_disk(&mut column, &dir_path).map_err(|error| Error {
+                file: dir_path,
+                error: format!("failed to write column to disk: {error}"),
+            })
+        }
+        fn perform_write_serde(
+            doc_root: &Path,
+            dirname: &str,
+            column: Vec<Option<impl Serialize>>,
+        ) -> Result<Vec<u8>, Error> {
+            perform_write_strings(
+                doc_root,
+                dirname,
+                column.into_iter().map(|value| {
+                    if let Some(value) = value {
+                        serde_json::to_vec(&value).unwrap()
+                    } else {
+                        Vec::new()
+                    }
+                }),
+            )
+        }
+        fn perform_write_postings(
+            doc_root: &Path,
+            dirname: &str,
+            column: Vec<Vec<Vec<u32>>>,
+        ) -> Result<Vec<u8>, Error> {
+            perform_write_strings(
+                doc_root,
+                dirname,
+                column.into_iter().map(|postings| {
+                    let mut buf = Vec::new();
+                    encode::write_postings_to_string(&postings, &mut buf);
+                    buf
+                }),
+            )
+        }
+        std::fs::write(
+            doc_root.join(format!("search.index/root{resource_suffix}.js")),
+            serialized_root,
+        )
+        .map_err(|error| Error {
+            file: doc_root.join(format!("search.index/root{resource_suffix}.js")),
+            error: format!("failed to write root to disk: {error}"),
+        })?;
+        Ok(())
+    }
+}
+
+#[derive(Clone, Debug)]
+struct EntryData {
+    krate: usize,
+    ty: ItemType,
+    module_path: Option<usize>,
+    exact_module_path: Option<usize>,
+    parent: Option<usize>,
+    deprecated: bool,
+    associated_item_disambiguator: Option<String>,
+}
+
+impl Serialize for EntryData {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        let mut seq = serializer.serialize_seq(None)?;
+        seq.serialize_element(&self.krate)?;
+        seq.serialize_element(&self.ty)?;
+        seq.serialize_element(&self.module_path.map(|id| id + 1).unwrap_or(0))?;
+        seq.serialize_element(&self.exact_module_path.map(|id| id + 1).unwrap_or(0))?;
+        seq.serialize_element(&self.parent.map(|id| id + 1).unwrap_or(0))?;
+        seq.serialize_element(&if self.deprecated { 1 } else { 0 })?;
+        if let Some(disambig) = &self.associated_item_disambiguator {
+            seq.serialize_element(&disambig)?;
+        }
+        seq.end()
+    }
+}
+
+impl<'de> Deserialize<'de> for EntryData {
+    fn deserialize<D>(deserializer: D) -> Result<EntryData, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct EntryDataVisitor;
+        impl<'de> de::Visitor<'de> for EntryDataVisitor {
+            type Value = EntryData;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                write!(formatter, "path data")
+            }
+            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<EntryData, A::Error> {
+                let krate: usize =
+                    v.next_element()?.ok_or_else(|| A::Error::missing_field("krate"))?;
+                let ty: ItemType =
+                    v.next_element()?.ok_or_else(|| A::Error::missing_field("ty"))?;
+                let module_path: SerializedOptional32 =
+                    v.next_element()?.ok_or_else(|| A::Error::missing_field("module_path"))?;
+                let exact_module_path: SerializedOptional32 = v
+                    .next_element()?
+                    .ok_or_else(|| A::Error::missing_field("exact_module_path"))?;
+                let parent: SerializedOptional32 =
+                    v.next_element()?.ok_or_else(|| A::Error::missing_field("parent"))?;
+                let deprecated: u32 = v.next_element()?.unwrap_or(0);
+                let associated_item_disambiguator: Option<String> = v.next_element()?;
+                Ok(EntryData {
+                    krate,
+                    ty,
+                    module_path: Option::<i32>::from(module_path).map(|path| path as usize),
+                    exact_module_path: Option::<i32>::from(exact_module_path)
+                        .map(|path| path as usize),
+                    parent: Option::<i32>::from(parent).map(|path| path as usize),
+                    deprecated: deprecated != 0,
+                    associated_item_disambiguator,
+                })
+            }
+        }
+        deserializer.deserialize_any(EntryDataVisitor)
+    }
+}
+
+#[derive(Clone, Debug)]
+struct PathData {
+    ty: ItemType,
+    module_path: Vec<Symbol>,
+    exact_module_path: Option<Vec<Symbol>>,
 }
 
-const DESC_INDEX_SHARD_LEN: usize = 128 * 1024;
+impl Serialize for PathData {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        let mut seq = serializer.serialize_seq(None)?;
+        seq.serialize_element(&self.ty)?;
+        seq.serialize_element(&if self.module_path.is_empty() {
+            String::new()
+        } else {
+            join_path_syms(&self.module_path)
+        })?;
+        if let Some(ref path) = self.exact_module_path {
+            seq.serialize_element(&if path.is_empty() {
+                String::new()
+            } else {
+                join_path_syms(path)
+            })?;
+        }
+        seq.end()
+    }
+}
+
+impl<'de> Deserialize<'de> for PathData {
+    fn deserialize<D>(deserializer: D) -> Result<PathData, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct PathDataVisitor;
+        impl<'de> de::Visitor<'de> for PathDataVisitor {
+            type Value = PathData;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                write!(formatter, "path data")
+            }
+            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<PathData, A::Error> {
+                let ty: ItemType =
+                    v.next_element()?.ok_or_else(|| A::Error::missing_field("ty"))?;
+                let module_path: String =
+                    v.next_element()?.ok_or_else(|| A::Error::missing_field("module_path"))?;
+                let exact_module_path: Option<String> =
+                    v.next_element()?.and_then(SerializedOptionalString::into);
+                Ok(PathData {
+                    ty,
+                    module_path: if module_path.is_empty() {
+                        vec![]
+                    } else {
+                        module_path.split("::").map(Symbol::intern).collect()
+                    },
+                    exact_module_path: exact_module_path.map(|path| {
+                        if path.is_empty() {
+                            vec![]
+                        } else {
+                            path.split("::").map(Symbol::intern).collect()
+                        }
+                    }),
+                })
+            }
+        }
+        deserializer.deserialize_any(PathDataVisitor)
+    }
+}
+
+#[derive(Clone, Debug)]
+struct TypeData {
+    /// If set to "true", the generics can be matched without having to
+    /// mention the type itself. The truth table, assuming `Unboxable`
+    /// has `search_unbox = true` and `Inner` has `search_unbox = false`
+    ///
+    /// | **query**          | `Unboxable<Inner>` | `Inner` | `Inner<Unboxable>` |
+    /// |--------------------|--------------------|---------|--------------------|
+    /// | `Inner`            | yes                | yes     | yes                |
+    /// | `Unboxable`        | yes                | no      | no                 |
+    /// | `Unboxable<Inner>` | yes                | no      | no                 |
+    /// | `Inner<Unboxable>` | no                 | no      | yes                |
+    search_unbox: bool,
+    /// List of functions that mention this type in their type signature.
+    ///
+    /// - The outermost list has one entry per alpha-normalized generic.
+    ///
+    /// - The second layer is sorted by number of types that appear in the
+    ///   type signature. The search engine iterates over these in order from
+    ///   smallest to largest. Functions with less stuff in their type
+    ///   signature are more likely to be what the user wants, because we never
+    ///   show functions that are *missing* parts of the query, so removing..
+    ///
+    /// - The final layer is the list of functions.
+    inverted_function_signature_index: Vec<Vec<u32>>,
+}
+
+impl Serialize for TypeData {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        if self.search_unbox || !self.inverted_function_signature_index.is_empty() {
+            let mut seq = serializer.serialize_seq(None)?;
+            if !self.inverted_function_signature_index.is_empty() {
+                let mut buf = Vec::new();
+                encode::write_postings_to_string(&self.inverted_function_signature_index, &mut buf);
+                let mut serialized_result = Vec::new();
+                stringdex_internals::encode::write_base64_to_bytes(&buf, &mut serialized_result);
+                seq.serialize_element(&String::from_utf8(serialized_result).unwrap())?;
+            }
+            if self.search_unbox {
+                seq.serialize_element(&1)?;
+            }
+            seq.end()
+        } else {
+            None::<()>.serialize(serializer)
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for TypeData {
+    fn deserialize<D>(deserializer: D) -> Result<TypeData, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct TypeDataVisitor;
+        impl<'de> de::Visitor<'de> for TypeDataVisitor {
+            type Value = TypeData;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                write!(formatter, "type data")
+            }
+            fn visit_none<E>(self) -> Result<TypeData, E> {
+                Ok(TypeData { inverted_function_signature_index: vec![], search_unbox: false })
+            }
+            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<TypeData, A::Error> {
+                let inverted_function_signature_index: String =
+                    v.next_element()?.unwrap_or(String::new());
+                let search_unbox: u32 = v.next_element()?.unwrap_or(0);
+                let mut idx: Vec<u8> = Vec::new();
+                stringdex_internals::decode::read_base64_from_bytes(
+                    inverted_function_signature_index.as_bytes(),
+                    &mut idx,
+                )
+                .unwrap();
+                let mut inverted_function_signature_index = Vec::new();
+                encode::read_postings_from_string(&mut inverted_function_signature_index, &idx);
+                Ok(TypeData { inverted_function_signature_index, search_unbox: search_unbox == 1 })
+            }
+        }
+        deserializer.deserialize_any(TypeDataVisitor)
+    }
+}
+
+enum SerializedOptionalString {
+    None,
+    Some(String),
+}
+
+impl From<SerializedOptionalString> for Option<String> {
+    fn from(me: SerializedOptionalString) -> Option<String> {
+        match me {
+            SerializedOptionalString::Some(string) => Some(string),
+            SerializedOptionalString::None => None,
+        }
+    }
+}
+
+impl Serialize for SerializedOptionalString {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        match self {
+            SerializedOptionalString::Some(string) => string.serialize(serializer),
+            SerializedOptionalString::None => 0.serialize(serializer),
+        }
+    }
+}
+impl<'de> Deserialize<'de> for SerializedOptionalString {
+    fn deserialize<D>(deserializer: D) -> Result<SerializedOptionalString, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct SerializedOptionalStringVisitor;
+        impl<'de> de::Visitor<'de> for SerializedOptionalStringVisitor {
+            type Value = SerializedOptionalString;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                write!(formatter, "0 or string")
+            }
+            fn visit_u64<E: de::Error>(self, v: u64) -> Result<SerializedOptionalString, E> {
+                if v != 0 {
+                    return Err(E::missing_field("not 0"));
+                }
+                Ok(SerializedOptionalString::None)
+            }
+            fn visit_string<E: de::Error>(self, v: String) -> Result<SerializedOptionalString, E> {
+                Ok(SerializedOptionalString::Some(v))
+            }
+            fn visit_str<E: de::Error>(self, v: &str) -> Result<SerializedOptionalString, E> {
+                Ok(SerializedOptionalString::Some(v.to_string()))
+            }
+        }
+        deserializer.deserialize_any(SerializedOptionalStringVisitor)
+    }
+}
+
+enum SerializedOptional32 {
+    None,
+    Some(i32),
+}
+
+impl From<SerializedOptional32> for Option<i32> {
+    fn from(me: SerializedOptional32) -> Option<i32> {
+        match me {
+            SerializedOptional32::Some(number) => Some(number),
+            SerializedOptional32::None => None,
+        }
+    }
+}
+
+impl Serialize for SerializedOptional32 {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        match self {
+            &SerializedOptional32::Some(number) if number < 0 => number.serialize(serializer),
+            &SerializedOptional32::Some(number) => (number + 1).serialize(serializer),
+            &SerializedOptional32::None => 0.serialize(serializer),
+        }
+    }
+}
+impl<'de> Deserialize<'de> for SerializedOptional32 {
+    fn deserialize<D>(deserializer: D) -> Result<SerializedOptional32, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct SerializedOptional32Visitor;
+        impl<'de> de::Visitor<'de> for SerializedOptional32Visitor {
+            type Value = SerializedOptional32;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                write!(formatter, "integer")
+            }
+            fn visit_i64<E: de::Error>(self, v: i64) -> Result<SerializedOptional32, E> {
+                Ok(match v {
+                    0 => SerializedOptional32::None,
+                    v if v < 0 => SerializedOptional32::Some(v as i32),
+                    v => SerializedOptional32::Some(v as i32 - 1),
+                })
+            }
+            fn visit_u64<E: de::Error>(self, v: u64) -> Result<SerializedOptional32, E> {
+                Ok(match v {
+                    0 => SerializedOptional32::None,
+                    v => SerializedOptional32::Some(v as i32 - 1),
+                })
+            }
+        }
+        deserializer.deserialize_any(SerializedOptional32Visitor)
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct FunctionData {
+    function_signature: String,
+    param_names: Vec<String>,
+}
+
+impl Serialize for FunctionData {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        let mut seq = serializer.serialize_seq(None)?;
+        seq.serialize_element(&self.function_signature)?;
+        seq.serialize_element(&self.param_names)?;
+        seq.end()
+    }
+}
+
+impl<'de> Deserialize<'de> for FunctionData {
+    fn deserialize<D>(deserializer: D) -> Result<FunctionData, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct FunctionDataVisitor;
+        impl<'de> de::Visitor<'de> for FunctionDataVisitor {
+            type Value = FunctionData;
+            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                write!(formatter, "fn data")
+            }
+            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<FunctionData, A::Error> {
+                let function_signature: String = v
+                    .next_element()?
+                    .ok_or_else(|| A::Error::missing_field("function_signature"))?;
+                let param_names: Vec<String> =
+                    v.next_element()?.ok_or_else(|| A::Error::missing_field("param_names"))?;
+                Ok(FunctionData { function_signature, param_names })
+            }
+        }
+        deserializer.deserialize_any(FunctionDataVisitor)
+    }
+}
 
 /// Builds the search index from the collected metadata
 pub(crate) fn build_index(
     krate: &clean::Crate,
     cache: &mut Cache,
     tcx: TyCtxt<'_>,
-) -> SerializedSearchIndex {
-    // Maps from ID to position in the `crate_paths` array.
-    let mut itemid_to_pathid = FxHashMap::default();
-    let mut primitives = FxHashMap::default();
-    let mut associated_types = FxHashMap::default();
-
-    // item type, display path, re-exported internal path
-    let mut crate_paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)> = vec![];
+    doc_root: &Path,
+    resource_suffix: &str,
+) -> Result<SerializedSearchIndex, Error> {
+    let mut search_index = std::mem::take(&mut cache.search_index);
 
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
@@ -74,15 +1171,15 @@ pub(crate) fn build_index(
     {
         if let Some((fqp, _)) = cache.paths.get(&parent) {
             let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache));
-            cache.search_index.push(IndexItem {
+            search_index.push(IndexItem {
                 ty: item.type_(),
                 defid: item.item_id.as_def_id(),
                 name: item.name.unwrap(),
-                path: join_path_syms(&fqp[..fqp.len() - 1]),
+                module_path: fqp[..fqp.len() - 1].to_vec(),
                 desc,
                 parent: Some(parent),
                 parent_idx: None,
-                exact_path: None,
+                exact_module_path: None,
                 impl_id,
                 search_type: get_function_type_for_search(
                     item,
@@ -97,85 +1194,299 @@ pub(crate) fn build_index(
         }
     }
 
+    // Sort search index items. This improves the compressibility of the search index.
+    search_index.sort_unstable_by(|k1, k2| {
+        // `sort_unstable_by_key` produces lifetime errors
+        // HACK(rustdoc): should not be sorting `CrateNum` or `DefIndex`, this will soon go away, too
+        let k1 =
+            (&k1.module_path, k1.name.as_str(), &k1.ty, k1.parent.map(|id| (id.index, id.krate)));
+        let k2 =
+            (&k2.module_path, k2.name.as_str(), &k2.ty, k2.parent.map(|id| (id.index, id.krate)));
+        Ord::cmp(&k1, &k2)
+    });
+
+    // Now, convert to an on-disk search index format
+    //
+    // if there's already a search index, load it into memory and add the new entries to it
+    // otherwise, do nothing
+    let mut serialized_index = SerializedSearchIndex::load(doc_root, resource_suffix)?;
+
+    // The crate always goes first in this list
+    let crate_name = krate.name(tcx);
     let crate_doc =
         short_markdown_summary(&krate.module.doc_value(), &krate.module.link_names(cache));
+    let crate_idx = {
+        let crate_path = (ItemType::ExternCrate, vec![crate_name]);
+        match serialized_index.crate_paths_index.entry(crate_path) {
+            Entry::Occupied(index) => {
+                let index = *index.get();
+                serialized_index.descs[index] = crate_doc;
+                for type_data in serialized_index.type_data.iter_mut() {
+                    if let Some(TypeData { inverted_function_signature_index, .. }) = type_data {
+                        for list in &mut inverted_function_signature_index[..] {
+                            list.retain(|fnid| {
+                                serialized_index.entry_data[usize::try_from(*fnid).unwrap()]
+                                    .as_ref()
+                                    .unwrap()
+                                    .krate
+                                    != index
+                            });
+                        }
+                    }
+                }
+                for i in (index + 1)..serialized_index.entry_data.len() {
+                    // if this crate has been built before, replace its stuff with new
+                    if let Some(EntryData { krate, .. }) = serialized_index.entry_data[i]
+                        && krate == index
+                    {
+                        serialized_index.entry_data[i] = None;
+                        serialized_index.descs[i] = String::new();
+                        serialized_index.function_data[i] = None;
+                        if serialized_index.path_data[i].is_none() {
+                            serialized_index.names[i] = String::new();
+                        }
+                    }
+                    if let Some(alias_pointer) = serialized_index.alias_pointers[i]
+                        && serialized_index.entry_data[alias_pointer].is_none()
+                    {
+                        serialized_index.alias_pointers[i] = None;
+                        if serialized_index.path_data[i].is_none()
+                            && serialized_index.entry_data[i].is_none()
+                        {
+                            serialized_index.names[i] = String::new();
+                        }
+                    }
+                }
+                index
+            }
+            Entry::Vacant(slot) => {
+                let krate = serialized_index.names.len();
+                slot.insert(krate);
+                serialized_index.push(
+                    crate_name.as_str().to_string(),
+                    Some(PathData {
+                        ty: ItemType::ExternCrate,
+                        module_path: vec![],
+                        exact_module_path: None,
+                    }),
+                    Some(EntryData {
+                        krate,
+                        ty: ItemType::ExternCrate,
+                        module_path: None,
+                        exact_module_path: None,
+                        parent: None,
+                        deprecated: false,
+                        associated_item_disambiguator: None,
+                    }),
+                    crate_doc,
+                    None,
+                    None,
+                    None,
+                );
+                krate
+            }
+        }
+    };
+
+    // First, populate associated item parents
+    let crate_items: Vec<&mut IndexItem> = search_index
+        .iter_mut()
+        .map(|item| {
+            item.parent_idx = item.parent.and_then(|defid| {
+                cache.paths.get(&defid).map(|&(ref fqp, ty)| {
+                    let pathid = serialized_index.names.len();
+                    match serialized_index.crate_paths_index.entry((ty, fqp.clone())) {
+                        Entry::Occupied(entry) => *entry.get(),
+                        Entry::Vacant(entry) => {
+                            entry.insert(pathid);
+                            let (name, path) = fqp.split_last().unwrap();
+                            serialized_index.push_path(
+                                name.as_str().to_string(),
+                                PathData {
+                                    ty,
+                                    module_path: path.to_vec(),
+                                    exact_module_path: if let Some(exact_path) =
+                                        cache.exact_paths.get(&defid)
+                                        && let Some((name2, exact_path)) = exact_path.split_last()
+                                        && name == name2
+                                    {
+                                        Some(exact_path.to_vec())
+                                    } else {
+                                        None
+                                    },
+                                },
+                            );
+                            usize::try_from(pathid).unwrap()
+                        }
+                    }
+                })
+            });
+
+            if let Some(defid) = item.defid
+                && item.parent_idx.is_none()
+            {
+                // If this is a re-export, retain the original path.
+                // Associated items don't use this.
+                // Their parent carries the exact fqp instead.
+                let exact_fqp = cache
+                    .exact_paths
+                    .get(&defid)
+                    .or_else(|| cache.external_paths.get(&defid).map(|(fqp, _)| fqp));
+                item.exact_module_path = exact_fqp.and_then(|fqp| {
+                    // Re-exports only count if the name is exactly the same.
+                    // This is a size optimization, since it means we only need
+                    // to store the name once (and the path is re-used for everything
+                    // exported from this same module). It's also likely to Do
+                    // What I Mean, since if a re-export changes the name, it might
+                    // also be a change in semantic meaning.
+                    if fqp.last() != Some(&item.name) {
+                        return None;
+                    }
+                    let path =
+                        if item.ty == ItemType::Macro && tcx.has_attr(defid, sym::macro_export) {
+                            // `#[macro_export]` always exports to the crate root.
+                            vec![tcx.crate_name(defid.krate)]
+                        } else {
+                            if fqp.len() < 2 {
+                                return None;
+                            }
+                            fqp[..fqp.len() - 1].to_vec()
+                        };
+                    if path == item.module_path {
+                        return None;
+                    }
+                    Some(path)
+                });
+            } else if let Some(parent_idx) = item.parent_idx {
+                let i = usize::try_from(parent_idx).unwrap();
+                item.module_path =
+                    serialized_index.path_data[i].as_ref().unwrap().module_path.clone();
+                item.exact_module_path =
+                    serialized_index.path_data[i].as_ref().unwrap().exact_module_path.clone();
+            }
 
-    #[derive(Eq, Ord, PartialEq, PartialOrd)]
-    struct SerSymbolAsStr(Symbol);
+            &mut *item
+        })
+        .collect();
 
-    impl Serialize for SerSymbolAsStr {
-        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-        where
-            S: Serializer,
+    // Now, find anywhere that the same name is used for two different items
+    // these need a disambiguator hash for lints
+    let mut associated_item_duplicates = FxHashMap::<(usize, ItemType, Symbol), usize>::default();
+    for item in crate_items.iter().map(|x| &*x) {
+        if item.impl_id.is_some()
+            && let Some(parent_idx) = item.parent_idx
         {
-            self.0.as_str().serialize(serializer)
+            let count =
+                associated_item_duplicates.entry((parent_idx, item.ty, item.name)).or_insert(0);
+            *count += 1;
         }
     }
 
-    type AliasMap = BTreeMap<SerSymbolAsStr, Vec<usize>>;
-    // Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
-    // we need the alias element to have an array of items.
-    let mut aliases: AliasMap = BTreeMap::new();
+    // now populate the actual entries, type data, and function data
+    for item in crate_items {
+        assert_eq!(
+            item.parent.is_some(),
+            item.parent_idx.is_some(),
+            "`{}` is missing idx",
+            item.name
+        );
 
-    // Sort search index items. This improves the compressibility of the search index.
-    cache.search_index.sort_unstable_by(|k1, k2| {
-        // `sort_unstable_by_key` produces lifetime errors
-        // HACK(rustdoc): should not be sorting `CrateNum` or `DefIndex`, this will soon go away, too
-        let k1 = (&k1.path, k1.name.as_str(), &k1.ty, k1.parent.map(|id| (id.index, id.krate)));
-        let k2 = (&k2.path, k2.name.as_str(), &k2.ty, k2.parent.map(|id| (id.index, id.krate)));
-        Ord::cmp(&k1, &k2)
-    });
+        let module_path = Some(serialized_index.get_id_by_module_path(&item.module_path));
+        let exact_module_path = item
+            .exact_module_path
+            .as_ref()
+            .map(|path| serialized_index.get_id_by_module_path(path));
+
+        let new_entry_id = serialized_index.push(
+            item.name.as_str().to_string(),
+            None,
+            Some(EntryData {
+                ty: item.ty,
+                parent: item.parent_idx,
+                module_path,
+                exact_module_path,
+                deprecated: item.deprecation.is_some(),
+                associated_item_disambiguator: if let Some(impl_id) = item.impl_id
+                    && let Some(parent_idx) = item.parent_idx
+                    && associated_item_duplicates
+                        .get(&(parent_idx, item.ty, item.name))
+                        .copied()
+                        .unwrap_or(0)
+                        > 1
+                {
+                    Some(render::get_id_for_impl(tcx, ItemId::DefId(impl_id)))
+                } else {
+                    None
+                },
+                krate: crate_idx,
+            }),
+            item.desc.to_string(),
+            None, // filled in after all the types have been indexed
+            None,
+            None,
+        );
 
-    // Set up alias indexes.
-    for (i, item) in cache.search_index.iter().enumerate() {
+        // Aliases
+        // -------
         for alias in &item.aliases[..] {
-            aliases.entry(SerSymbolAsStr(*alias)).or_default().push(i);
+            serialized_index.push_alias(alias.as_str().to_string(), new_entry_id);
         }
-    }
-
-    // Reduce `DefId` in paths into smaller sequential numbers,
-    // and prune the paths that do not appear in the index.
-    let mut lastpath = "";
-    let mut lastpathid = 0isize;
 
-    // First, on function signatures
-    let mut search_index = std::mem::take(&mut cache.search_index);
-    for item in search_index.iter_mut() {
-        fn insert_into_map<F: std::hash::Hash + Eq>(
-            map: &mut FxHashMap<F, isize>,
-            itemid: F,
-            lastpathid: &mut isize,
-            crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
-            item_type: ItemType,
+        // Function signature reverse index
+        // --------------------------------
+        fn insert_into_map(
+            ty: ItemType,
             path: &[Symbol],
             exact_path: Option<&[Symbol]>,
             search_unbox: bool,
+            serialized_index: &mut SerializedSearchIndex,
+            used_in_function_signature: &mut BTreeSet<isize>,
         ) -> RenderTypeId {
-            match map.entry(itemid) {
-                Entry::Occupied(entry) => RenderTypeId::Index(*entry.get()),
+            let pathid = serialized_index.names.len();
+            let pathid = match serialized_index.crate_paths_index.entry((ty, path.to_vec())) {
+                Entry::Occupied(entry) => {
+                    let id = *entry.get();
+                    if serialized_index.type_data[id].as_mut().is_none() {
+                        serialized_index.type_data[id] = Some(TypeData {
+                            search_unbox,
+                            inverted_function_signature_index: Vec::new(),
+                        });
+                    } else if search_unbox {
+                        serialized_index.type_data[id].as_mut().unwrap().search_unbox = true;
+                    }
+                    id
+                }
                 Entry::Vacant(entry) => {
-                    let pathid = *lastpathid;
                     entry.insert(pathid);
-                    *lastpathid += 1;
-                    crate_paths.push((
-                        item_type,
-                        path.to_vec(),
-                        exact_path.map(|path| path.to_vec()),
-                        search_unbox,
-                    ));
-                    RenderTypeId::Index(pathid)
+                    let (name, path) = path.split_last().unwrap();
+                    serialized_index.push_type(
+                        name.to_string(),
+                        PathData {
+                            ty,
+                            module_path: path.to_vec(),
+                            exact_module_path: if let Some(exact_path) = exact_path
+                                && let Some((name2, exact_path)) = exact_path.split_last()
+                                && name == name2
+                            {
+                                Some(exact_path.to_vec())
+                            } else {
+                                None
+                            },
+                        },
+                        TypeData { search_unbox, inverted_function_signature_index: Vec::new() },
+                    );
+                    pathid
                 }
-            }
+            };
+            used_in_function_signature.insert(isize::try_from(pathid).unwrap());
+            RenderTypeId::Index(isize::try_from(pathid).unwrap())
         }
 
         fn convert_render_type_id(
             id: RenderTypeId,
             cache: &mut Cache,
-            itemid_to_pathid: &mut FxHashMap<ItemId, isize>,
-            primitives: &mut FxHashMap<Symbol, isize>,
-            associated_types: &mut FxHashMap<Symbol, isize>,
-            lastpathid: &mut isize,
-            crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
+            serialized_index: &mut SerializedSearchIndex,
+            used_in_function_signature: &mut BTreeSet<isize>,
             tcx: TyCtxt<'_>,
         ) -> Option<RenderTypeId> {
             use crate::clean::PrimitiveType;
@@ -192,39 +1503,55 @@ pub(crate) fn build_index(
             };
             match id {
                 RenderTypeId::Mut => Some(insert_into_map(
-                    primitives,
-                    kw::Mut,
-                    lastpathid,
-                    crate_paths,
                     ItemType::Keyword,
                     &[kw::Mut],
                     None,
                     search_unbox,
+                    serialized_index,
+                    used_in_function_signature,
                 )),
                 RenderTypeId::DefId(defid) => {
                     if let Some(&(ref fqp, item_type)) =
                         paths.get(&defid).or_else(|| external_paths.get(&defid))
                     {
-                        let exact_fqp = exact_paths
-                            .get(&defid)
-                            .or_else(|| external_paths.get(&defid).map(|(fqp, _)| fqp))
-                            // Re-exports only count if the name is exactly the same.
-                            // This is a size optimization, since it means we only need
-                            // to store the name once (and the path is re-used for everything
-                            // exported from this same module). It's also likely to Do
-                            // What I Mean, since if a re-export changes the name, it might
-                            // also be a change in semantic meaning.
-                            .filter(|this_fqp| this_fqp.last() == fqp.last());
-                        Some(insert_into_map(
-                            itemid_to_pathid,
-                            ItemId::DefId(defid),
-                            lastpathid,
-                            crate_paths,
-                            item_type,
-                            fqp,
-                            exact_fqp.map(|x| &x[..]).filter(|exact_fqp| exact_fqp != fqp),
-                            search_unbox,
-                        ))
+                        if tcx.lang_items().fn_mut_trait() == Some(defid)
+                            || tcx.lang_items().fn_once_trait() == Some(defid)
+                            || tcx.lang_items().fn_trait() == Some(defid)
+                        {
+                            let name = *fqp.last().unwrap();
+                            // Make absolutely sure we use this single, correct path,
+                            // because search.js needs to match. If we don't do this,
+                            // there are three different paths that these traits may
+                            // appear to come from.
+                            Some(insert_into_map(
+                                item_type,
+                                &[sym::core, sym::ops, name],
+                                Some(&[sym::core, sym::ops, name]),
+                                search_unbox,
+                                serialized_index,
+                                used_in_function_signature,
+                            ))
+                        } else {
+                            let exact_fqp = exact_paths
+                                .get(&defid)
+                                .or_else(|| external_paths.get(&defid).map(|(fqp, _)| fqp))
+                                .map(|v| &v[..])
+                                // Re-exports only count if the name is exactly the same.
+                                // This is a size optimization, since it means we only need
+                                // to store the name once (and the path is re-used for everything
+                                // exported from this same module). It's also likely to Do
+                                // What I Mean, since if a re-export changes the name, it might
+                                // also be a change in semantic meaning.
+                                .filter(|this_fqp| this_fqp.last() == fqp.last());
+                            Some(insert_into_map(
+                                item_type,
+                                fqp,
+                                exact_fqp,
+                                search_unbox,
+                                serialized_index,
+                                used_in_function_signature,
+                            ))
+                        }
                     } else {
                         None
                     }
@@ -232,26 +1559,25 @@ pub(crate) fn build_index(
                 RenderTypeId::Primitive(primitive) => {
                     let sym = primitive.as_sym();
                     Some(insert_into_map(
-                        primitives,
-                        sym,
-                        lastpathid,
-                        crate_paths,
                         ItemType::Primitive,
                         &[sym],
                         None,
                         search_unbox,
+                        serialized_index,
+                        used_in_function_signature,
                     ))
                 }
-                RenderTypeId::Index(_) => Some(id),
+                RenderTypeId::Index(index) => {
+                    used_in_function_signature.insert(index);
+                    Some(id)
+                }
                 RenderTypeId::AssociatedType(sym) => Some(insert_into_map(
-                    associated_types,
-                    sym,
-                    lastpathid,
-                    crate_paths,
                     ItemType::AssocType,
                     &[sym],
                     None,
                     search_unbox,
+                    serialized_index,
+                    used_in_function_signature,
                 )),
             }
         }
@@ -259,11 +1585,8 @@ pub(crate) fn build_index(
         fn convert_render_type(
             ty: &mut RenderType,
             cache: &mut Cache,
-            itemid_to_pathid: &mut FxHashMap<ItemId, isize>,
-            primitives: &mut FxHashMap<Symbol, isize>,
-            associated_types: &mut FxHashMap<Symbol, isize>,
-            lastpathid: &mut isize,
-            crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
+            serialized_index: &mut SerializedSearchIndex,
+            used_in_function_signature: &mut BTreeSet<isize>,
             tcx: TyCtxt<'_>,
         ) {
             if let Some(generics) = &mut ty.generics {
@@ -271,11 +1594,8 @@ pub(crate) fn build_index(
                     convert_render_type(
                         item,
                         cache,
-                        itemid_to_pathid,
-                        primitives,
-                        associated_types,
-                        lastpathid,
-                        crate_paths,
+                        serialized_index,
+                        used_in_function_signature,
                         tcx,
                     );
                 }
@@ -285,11 +1605,8 @@ pub(crate) fn build_index(
                     let converted_associated_type = convert_render_type_id(
                         *associated_type,
                         cache,
-                        itemid_to_pathid,
-                        primitives,
-                        associated_types,
-                        lastpathid,
-                        crate_paths,
+                        serialized_index,
+                        used_in_function_signature,
                         tcx,
                     );
                     let Some(converted_associated_type) = converted_associated_type else {
@@ -300,11 +1617,8 @@ pub(crate) fn build_index(
                         convert_render_type(
                             constraint,
                             cache,
-                            itemid_to_pathid,
-                            primitives,
-                            associated_types,
-                            lastpathid,
-                            crate_paths,
+                            serialized_index,
+                            used_in_function_signature,
                             tcx,
                         );
                     }
@@ -318,24 +1632,74 @@ pub(crate) fn build_index(
             ty.id = convert_render_type_id(
                 id,
                 cache,
-                itemid_to_pathid,
-                primitives,
-                associated_types,
-                lastpathid,
-                crate_paths,
+                serialized_index,
+                used_in_function_signature,
                 tcx,
             );
+            use crate::clean::PrimitiveType;
+            // These cases are added to the inverted index, but not actually included
+            // in the signature. There's a matching set of cases in the
+            // `unifyFunctionTypeIsMatchCandidate` function, for the slow path.
+            match id {
+                // typeNameIdOfArrayOrSlice
+                RenderTypeId::Primitive(PrimitiveType::Array | PrimitiveType::Slice) => {
+                    insert_into_map(
+                        ItemType::Primitive,
+                        &[Symbol::intern("[]")],
+                        None,
+                        false,
+                        serialized_index,
+                        used_in_function_signature,
+                    );
+                }
+                RenderTypeId::Primitive(PrimitiveType::Tuple | PrimitiveType::Unit) => {
+                    // typeNameIdOfArrayOrSlice
+                    insert_into_map(
+                        ItemType::Primitive,
+                        &[Symbol::intern("()")],
+                        None,
+                        false,
+                        serialized_index,
+                        used_in_function_signature,
+                    );
+                }
+                // typeNameIdOfHof
+                RenderTypeId::Primitive(PrimitiveType::Fn) => {
+                    insert_into_map(
+                        ItemType::Primitive,
+                        &[Symbol::intern("->")],
+                        None,
+                        false,
+                        serialized_index,
+                        used_in_function_signature,
+                    );
+                }
+                RenderTypeId::DefId(did)
+                    if tcx.lang_items().fn_mut_trait() == Some(did)
+                        || tcx.lang_items().fn_once_trait() == Some(did)
+                        || tcx.lang_items().fn_trait() == Some(did) =>
+                {
+                    insert_into_map(
+                        ItemType::Primitive,
+                        &[Symbol::intern("->")],
+                        None,
+                        false,
+                        serialized_index,
+                        used_in_function_signature,
+                    );
+                }
+                // not special
+                _ => {}
+            }
         }
         if let Some(search_type) = &mut item.search_type {
+            let mut used_in_function_signature = BTreeSet::new();
             for item in &mut search_type.inputs {
                 convert_render_type(
                     item,
                     cache,
-                    &mut itemid_to_pathid,
-                    &mut primitives,
-                    &mut associated_types,
-                    &mut lastpathid,
-                    &mut crate_paths,
+                    &mut serialized_index,
+                    &mut used_in_function_signature,
                     tcx,
                 );
             }
@@ -343,11 +1707,8 @@ pub(crate) fn build_index(
                 convert_render_type(
                     item,
                     cache,
-                    &mut itemid_to_pathid,
-                    &mut primitives,
-                    &mut associated_types,
-                    &mut lastpathid,
-                    &mut crate_paths,
+                    &mut serialized_index,
+                    &mut used_in_function_signature,
                     tcx,
                 );
             }
@@ -356,464 +1717,56 @@ pub(crate) fn build_index(
                     convert_render_type(
                         trait_,
                         cache,
-                        &mut itemid_to_pathid,
-                        &mut primitives,
-                        &mut associated_types,
-                        &mut lastpathid,
-                        &mut crate_paths,
+                        &mut serialized_index,
+                        &mut used_in_function_signature,
                         tcx,
                     );
                 }
             }
-        }
-    }
-
-    let Cache { ref paths, ref exact_paths, ref external_paths, .. } = *cache;
-
-    // Then, on parent modules
-    let crate_items: Vec<&IndexItem> = search_index
-        .iter_mut()
-        .map(|item| {
-            item.parent_idx =
-                item.parent.and_then(|defid| match itemid_to_pathid.entry(ItemId::DefId(defid)) {
-                    Entry::Occupied(entry) => Some(*entry.get()),
-                    Entry::Vacant(entry) => {
-                        let pathid = lastpathid;
-                        entry.insert(pathid);
-                        lastpathid += 1;
-
-                        if let Some(&(ref fqp, short)) = paths.get(&defid) {
-                            let exact_fqp = exact_paths
-                                .get(&defid)
-                                .or_else(|| external_paths.get(&defid).map(|(fqp, _)| fqp))
-                                .filter(|exact_fqp| {
-                                    exact_fqp.last() == Some(&item.name) && *exact_fqp != fqp
-                                });
-                            crate_paths.push((
-                                short,
-                                fqp.clone(),
-                                exact_fqp.cloned(),
-                                utils::has_doc_flag(tcx, defid, sym::search_unbox),
-                            ));
-                            Some(pathid)
-                        } else {
-                            None
-                        }
-                    }
-                });
-
-            if let Some(defid) = item.defid
-                && item.parent_idx.is_none()
-            {
-                // If this is a re-export, retain the original path.
-                // Associated items don't use this.
-                // Their parent carries the exact fqp instead.
-                let exact_fqp = exact_paths
-                    .get(&defid)
-                    .or_else(|| external_paths.get(&defid).map(|(fqp, _)| fqp));
-                item.exact_path = exact_fqp.and_then(|fqp| {
-                    // Re-exports only count if the name is exactly the same.
-                    // This is a size optimization, since it means we only need
-                    // to store the name once (and the path is re-used for everything
-                    // exported from this same module). It's also likely to Do
-                    // What I Mean, since if a re-export changes the name, it might
-                    // also be a change in semantic meaning.
-                    if fqp.last() != Some(&item.name) {
-                        return None;
-                    }
-                    let path =
-                        if item.ty == ItemType::Macro && tcx.has_attr(defid, sym::macro_export) {
-                            // `#[macro_export]` always exports to the crate root.
-                            tcx.crate_name(defid.krate).to_string()
-                        } else {
-                            if fqp.len() < 2 {
-                                return None;
-                            }
-                            join_path_syms(&fqp[..fqp.len() - 1])
-                        };
-                    if path == item.path {
-                        return None;
-                    }
-                    Some(path)
-                });
-            } else if let Some(parent_idx) = item.parent_idx {
-                let i = <isize as TryInto<usize>>::try_into(parent_idx).unwrap();
-                item.path = {
-                    let p = &crate_paths[i].1;
-                    join_path_syms(&p[..p.len() - 1])
-                };
-                item.exact_path =
-                    crate_paths[i].2.as_ref().map(|xp| join_path_syms(&xp[..xp.len() - 1]));
-            }
-
-            // Omit the parent path if it is same to that of the prior item.
-            if lastpath == item.path {
-                item.path.clear();
-            } else {
-                lastpath = &item.path;
-            }
-
-            &*item
-        })
-        .collect();
-
-    // Find associated items that need disambiguators
-    let mut associated_item_duplicates = FxHashMap::<(isize, ItemType, Symbol), usize>::default();
-
-    for &item in &crate_items {
-        if item.impl_id.is_some()
-            && let Some(parent_idx) = item.parent_idx
-        {
-            let count =
-                associated_item_duplicates.entry((parent_idx, item.ty, item.name)).or_insert(0);
-            *count += 1;
-        }
-    }
-
-    let associated_item_disambiguators = crate_items
-        .iter()
-        .enumerate()
-        .filter_map(|(index, item)| {
-            let impl_id = ItemId::DefId(item.impl_id?);
-            let parent_idx = item.parent_idx?;
-            let count = *associated_item_duplicates.get(&(parent_idx, item.ty, item.name))?;
-            if count > 1 { Some((index, render::get_id_for_impl(tcx, impl_id))) } else { None }
-        })
-        .collect::<Vec<_>>();
-
-    struct CrateData<'a> {
-        items: Vec<&'a IndexItem>,
-        paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
-        // The String is alias name and the vec is the list of the elements with this alias.
-        //
-        // To be noted: the `usize` elements are indexes to `items`.
-        aliases: &'a AliasMap,
-        // Used when a type has more than one impl with an associated item with the same name.
-        associated_item_disambiguators: &'a Vec<(usize, String)>,
-        // A list of shard lengths encoded as vlqhex. See the comment in write_vlqhex_to_string
-        // for information on the format.
-        desc_index: String,
-        // A list of items with no description. This is eventually turned into a bitmap.
-        empty_desc: Vec<u32>,
-    }
-
-    struct Paths {
-        ty: ItemType,
-        name: Symbol,
-        path: Option<usize>,
-        exact_path: Option<usize>,
-        search_unbox: bool,
-    }
-
-    impl Serialize for Paths {
-        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-        where
-            S: Serializer,
-        {
-            let mut seq = serializer.serialize_seq(None)?;
-            seq.serialize_element(&self.ty)?;
-            seq.serialize_element(self.name.as_str())?;
-            if let Some(ref path) = self.path {
-                seq.serialize_element(path)?;
-            }
-            if let Some(ref path) = self.exact_path {
-                assert!(self.path.is_some());
-                seq.serialize_element(path)?;
-            }
-            if self.search_unbox {
-                if self.path.is_none() {
-                    seq.serialize_element(&None::<u8>)?;
-                }
-                if self.exact_path.is_none() {
-                    seq.serialize_element(&None::<u8>)?;
-                }
-                seq.serialize_element(&1)?;
-            }
-            seq.end()
-        }
-    }
-
-    impl Serialize for CrateData<'_> {
-        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-        where
-            S: Serializer,
-        {
-            let mut extra_paths = FxHashMap::default();
-            // We need to keep the order of insertion, hence why we use an `IndexMap`. Then we will
-            // insert these "extra paths" (which are paths of items from external crates) into the
-            // `full_paths` list at the end.
-            let mut revert_extra_paths = FxIndexMap::default();
-            let mut mod_paths = FxHashMap::default();
-            for (index, item) in self.items.iter().enumerate() {
-                if item.path.is_empty() {
-                    continue;
-                }
-                mod_paths.insert(&item.path, index);
-            }
-            let mut paths = Vec::with_capacity(self.paths.len());
-            for &(ty, ref path, ref exact, search_unbox) in &self.paths {
-                if path.len() < 2 {
-                    paths.push(Paths {
-                        ty,
-                        name: path[0],
-                        path: None,
-                        exact_path: None,
-                        search_unbox,
-                    });
-                    continue;
-                }
-                let full_path = join_path_syms(&path[..path.len() - 1]);
-                let full_exact_path = exact
-                    .as_ref()
-                    .filter(|exact| exact.last() == path.last() && exact.len() >= 2)
-                    .map(|exact| join_path_syms(&exact[..exact.len() - 1]));
-                let exact_path = extra_paths.len() + self.items.len();
-                let exact_path = full_exact_path.as_ref().map(|full_exact_path| match extra_paths
-                    .entry(full_exact_path.clone())
-                {
-                    Entry::Occupied(entry) => *entry.get(),
-                    Entry::Vacant(entry) => {
-                        if let Some(index) = mod_paths.get(&full_exact_path) {
-                            return *index;
-                        }
-                        entry.insert(exact_path);
-                        if !revert_extra_paths.contains_key(&exact_path) {
-                            revert_extra_paths.insert(exact_path, full_exact_path.clone());
-                        }
-                        exact_path
-                    }
-                });
-                if let Some(index) = mod_paths.get(&full_path) {
-                    paths.push(Paths {
-                        ty,
-                        name: *path.last().unwrap(),
-                        path: Some(*index),
-                        exact_path,
-                        search_unbox,
-                    });
-                    continue;
-                }
-                // It means it comes from an external crate so the item and its path will be
-                // stored into another array.
+            let search_type_size = search_type.size() +
+                // Artificially give struct fields a size of 8 instead of their real
+                // size of 2. This is because search.js sorts them to the end, so
+                // by pushing them down, we prevent them from blocking real 2-arity functions.
                 //
-                // `index` is put after the last `mod_paths`
-                let index = extra_paths.len() + self.items.len();
-                match extra_paths.entry(full_path.clone()) {
-                    Entry::Occupied(entry) => {
-                        paths.push(Paths {
-                            ty,
-                            name: *path.last().unwrap(),
-                            path: Some(*entry.get()),
-                            exact_path,
-                            search_unbox,
-                        });
-                    }
-                    Entry::Vacant(entry) => {
-                        entry.insert(index);
-                        if !revert_extra_paths.contains_key(&index) {
-                            revert_extra_paths.insert(index, full_path);
-                        }
-                        paths.push(Paths {
-                            ty,
-                            name: *path.last().unwrap(),
-                            path: Some(index),
-                            exact_path,
-                            search_unbox,
-                        });
-                    }
-                }
-            }
-
-            // Direct exports use adjacent arrays for the current crate's items,
-            // but re-exported exact paths don't.
-            let mut re_exports = Vec::new();
-            for (item_index, item) in self.items.iter().enumerate() {
-                if let Some(exact_path) = item.exact_path.as_ref() {
-                    if let Some(path_index) = mod_paths.get(&exact_path) {
-                        re_exports.push((item_index, *path_index));
-                    } else {
-                        let path_index = extra_paths.len() + self.items.len();
-                        let path_index = match extra_paths.entry(exact_path.clone()) {
-                            Entry::Occupied(entry) => *entry.get(),
-                            Entry::Vacant(entry) => {
-                                entry.insert(path_index);
-                                if !revert_extra_paths.contains_key(&path_index) {
-                                    revert_extra_paths.insert(path_index, exact_path.clone());
-                                }
-                                path_index
-                            }
-                        };
-                        re_exports.push((item_index, path_index));
-                    }
-                }
-            }
-
-            let mut names = Vec::with_capacity(self.items.len());
-            let mut types = String::with_capacity(self.items.len());
-            let mut full_paths = Vec::with_capacity(self.items.len());
-            let mut parents = String::with_capacity(self.items.len());
-            let mut parents_backref_queue = VecDeque::new();
-            let mut functions = String::with_capacity(self.items.len());
-            let mut deprecated = Vec::with_capacity(self.items.len());
-
-            let mut type_backref_queue = VecDeque::new();
-
-            let mut last_name = None;
-            for (index, item) in self.items.iter().enumerate() {
-                let n = item.ty as u8;
-                let c = char::from(n + b'A');
-                assert!(c <= 'z', "item types must fit within ASCII printables");
-                types.push(c);
-
-                assert_eq!(
-                    item.parent.is_some(),
-                    item.parent_idx.is_some(),
-                    "`{}` is missing idx",
-                    item.name
-                );
-                assert!(
-                    parents_backref_queue.len() <= 16,
-                    "the string encoding only supports 16 slots of lookback"
-                );
-                let parent: i32 = item.parent_idx.map(|x| x + 1).unwrap_or(0).try_into().unwrap();
-                if let Some(idx) = parents_backref_queue.iter().position(|p: &i32| *p == parent) {
-                    parents.push(
-                        char::try_from('0' as u32 + u32::try_from(idx).unwrap())
-                            .expect("last possible value is '?'"),
-                    );
-                } else if parent == 0 {
-                    write_vlqhex_to_string(parent, &mut parents);
-                } else {
-                    parents_backref_queue.push_front(parent);
-                    write_vlqhex_to_string(parent, &mut parents);
-                    if parents_backref_queue.len() > 16 {
-                        parents_backref_queue.pop_back();
-                    }
-                }
-
-                if Some(item.name.as_str()) == last_name {
-                    names.push("");
+                // The number 8 is arbitrary. We want it big, but not enormous,
+                // because the postings list has to fill in an empty array for each
+                // unoccupied size.
+                if item.ty.is_fn_like() { 0 } else { 16 };
+            serialized_index.function_data[new_entry_id] = Some(FunctionData {
+                function_signature: {
+                    let mut function_signature = String::new();
+                    search_type.write_to_string_without_param_names(&mut function_signature);
+                    function_signature
+                },
+                param_names: search_type
+                    .param_names
+                    .iter()
+                    .map(|sym| sym.map(|sym| sym.to_string()).unwrap_or(String::new()))
+                    .collect::<Vec<String>>(),
+            });
+            for index in used_in_function_signature {
+                let postings = if index >= 0 {
+                    assert!(serialized_index.path_data[index as usize].is_some());
+                    &mut serialized_index.type_data[index as usize]
+                        .as_mut()
+                        .unwrap()
+                        .inverted_function_signature_index
                 } else {
-                    names.push(item.name.as_str());
-                    last_name = Some(item.name.as_str());
-                }
-
-                if !item.path.is_empty() {
-                    full_paths.push((index, &item.path));
-                }
-
-                match &item.search_type {
-                    Some(ty) => ty.write_to_string(&mut functions, &mut type_backref_queue),
-                    None => functions.push('`'),
-                }
-
-                if item.deprecation.is_some() {
-                    // bitmasks always use 1-indexing for items, with 0 as the crate itself
-                    deprecated.push(u32::try_from(index + 1).unwrap());
-                }
-            }
-
-            for (index, path) in &revert_extra_paths {
-                full_paths.push((*index, path));
-            }
-
-            let param_names: Vec<(usize, String)> = {
-                let mut prev = Vec::new();
-                let mut result = Vec::new();
-                for (index, item) in self.items.iter().enumerate() {
-                    if let Some(ty) = &item.search_type
-                        && let my = ty
-                            .param_names
-                            .iter()
-                            .filter_map(|sym| sym.map(|sym| sym.to_string()))
-                            .collect::<Vec<_>>()
-                        && my != prev
-                    {
-                        result.push((index, my.join(",")));
-                        prev = my;
+                    let generic_id = usize::try_from(-index).unwrap() - 1;
+                    for _ in serialized_index.generic_inverted_index.len()..=generic_id {
+                        serialized_index.generic_inverted_index.push(Vec::new());
                     }
+                    &mut serialized_index.generic_inverted_index[generic_id]
+                };
+                while postings.len() <= search_type_size {
+                    postings.push(Vec::new());
                 }
-                result
-            };
-
-            let has_aliases = !self.aliases.is_empty();
-            let mut crate_data =
-                serializer.serialize_struct("CrateData", if has_aliases { 13 } else { 12 })?;
-            crate_data.serialize_field("t", &types)?;
-            crate_data.serialize_field("n", &names)?;
-            crate_data.serialize_field("q", &full_paths)?;
-            crate_data.serialize_field("i", &parents)?;
-            crate_data.serialize_field("f", &functions)?;
-            crate_data.serialize_field("D", &self.desc_index)?;
-            crate_data.serialize_field("p", &paths)?;
-            crate_data.serialize_field("r", &re_exports)?;
-            crate_data.serialize_field("b", &self.associated_item_disambiguators)?;
-            crate_data.serialize_field("c", &bitmap_to_string(&deprecated))?;
-            crate_data.serialize_field("e", &bitmap_to_string(&self.empty_desc))?;
-            crate_data.serialize_field("P", &param_names)?;
-            if has_aliases {
-                crate_data.serialize_field("a", &self.aliases)?;
+                postings[search_type_size].push(new_entry_id as u32);
             }
-            crate_data.end()
         }
     }
 
-    let (empty_desc, desc) = {
-        let mut empty_desc = Vec::new();
-        let mut result = Vec::new();
-        let mut set = String::new();
-        let mut len: usize = 0;
-        let mut item_index: u32 = 0;
-        for desc in std::iter::once(&crate_doc).chain(crate_items.iter().map(|item| &item.desc)) {
-            if desc.is_empty() {
-                empty_desc.push(item_index);
-                item_index += 1;
-                continue;
-            }
-            if set.len() >= DESC_INDEX_SHARD_LEN {
-                result.push((len, std::mem::take(&mut set)));
-                len = 0;
-            } else if len != 0 {
-                set.push('\n');
-            }
-            set.push_str(desc);
-            len += 1;
-            item_index += 1;
-        }
-        result.push((len, std::mem::take(&mut set)));
-        (empty_desc, result)
-    };
-
-    let desc_index = {
-        let mut desc_index = String::with_capacity(desc.len() * 4);
-        for &(len, _) in desc.iter() {
-            write_vlqhex_to_string(len.try_into().unwrap(), &mut desc_index);
-        }
-        desc_index
-    };
-
-    assert_eq!(
-        crate_items.len() + 1,
-        desc.iter().map(|(len, _)| *len).sum::<usize>() + empty_desc.len()
-    );
-
-    // The index, which is actually used to search, is JSON
-    // It uses `JSON.parse(..)` to actually load, since JSON
-    // parses faster than the full JavaScript syntax.
-    let crate_name = krate.name(tcx);
-    let data = CrateData {
-        items: crate_items,
-        paths: crate_paths,
-        aliases: &aliases,
-        associated_item_disambiguators: &associated_item_disambiguators,
-        desc_index,
-        empty_desc,
-    };
-    let index = OrderedJson::array_unsorted([
-        OrderedJson::serialize(crate_name.as_str()).unwrap(),
-        OrderedJson::serialize(data).unwrap(),
-    ]);
-    SerializedSearchIndex { index, desc }
+    Ok(serialized_index.sort())
 }
 
 pub(crate) fn get_function_type_for_search(
diff --git a/src/librustdoc/html/render/search_index/encode.rs b/src/librustdoc/html/render/search_index/encode.rs
index de2f54558ff..d15e13a2d37 100644
--- a/src/librustdoc/html/render/search_index/encode.rs
+++ b/src/librustdoc/html/render/search_index/encode.rs
@@ -1,6 +1,4 @@
-use base64::prelude::*;
-
-pub(crate) fn write_vlqhex_to_string(n: i32, string: &mut String) {
+pub(crate) fn write_signed_vlqhex_to_string(n: i32, string: &mut String) {
     let (sign, magnitude): (bool, u32) =
         if n >= 0 { (false, n.try_into().unwrap()) } else { (true, (-n).try_into().unwrap()) };
     // zig-zag encoding
@@ -37,206 +35,66 @@ pub(crate) fn write_vlqhex_to_string(n: i32, string: &mut String) {
     }
 }
 
-// Used during bitmap encoding
-enum Container {
-    /// number of ones, bits
-    Bits(Box<[u64; 1024]>),
-    /// list of entries
-    Array(Vec<u16>),
-    /// list of (start, len-1)
-    Run(Vec<(u16, u16)>),
-}
-impl Container {
-    fn popcount(&self) -> u32 {
-        match self {
-            Container::Bits(bits) => bits.iter().copied().map(|x| x.count_ones()).sum(),
-            Container::Array(array) => {
-                array.len().try_into().expect("array can't be bigger than 2**32")
-            }
-            Container::Run(runs) => {
-                runs.iter().copied().map(|(_, lenm1)| u32::from(lenm1) + 1).sum()
-            }
+pub fn read_signed_vlqhex_from_string(string: &[u8]) -> Option<(i32, usize)> {
+    let mut n = 0i32;
+    let mut i = 0;
+    while let Some(&c) = string.get(i) {
+        i += 1;
+        n = (n << 4) | i32::from(c & 0xF);
+        if c >= 96 {
+            // zig-zag encoding
+            let (sign, magnitude) = (n & 1, n >> 1);
+            let value = if sign == 0 { 1 } else { -1 } * magnitude;
+            return Some((value, i));
         }
     }
-    fn push(&mut self, value: u16) {
-        match self {
-            Container::Bits(bits) => bits[value as usize >> 6] |= 1 << (value & 0x3F),
-            Container::Array(array) => {
-                array.push(value);
-                if array.len() >= 4096 {
-                    let array = std::mem::take(array);
-                    *self = Container::Bits(Box::new([0; 1024]));
-                    for value in array {
-                        self.push(value);
-                    }
-                }
-            }
-            Container::Run(runs) => {
-                if let Some(r) = runs.last_mut()
-                    && r.0 + r.1 + 1 == value
-                {
-                    r.1 += 1;
-                } else {
-                    runs.push((value, 0));
-                }
-            }
+    None
+}
+
+pub fn write_postings_to_string(postings: &[Vec<u32>], buf: &mut Vec<u8>) {
+    for list in postings {
+        if list.is_empty() {
+            buf.push(0);
+            continue;
         }
-    }
-    fn try_make_run(&mut self) -> bool {
-        match self {
-            Container::Bits(bits) => {
-                let mut r: u64 = 0;
-                for (i, chunk) in bits.iter().copied().enumerate() {
-                    let next_chunk =
-                        i.checked_add(1).and_then(|i| bits.get(i)).copied().unwrap_or(0);
-                    r += !chunk & u64::from((chunk << 1).count_ones());
-                    r += !next_chunk & u64::from((chunk >> 63).count_ones());
-                }
-                if (2 + 4 * r) >= 8192 {
-                    return false;
-                }
-                let bits = std::mem::replace(bits, Box::new([0; 1024]));
-                *self = Container::Run(Vec::new());
-                for (i, bits) in bits.iter().copied().enumerate() {
-                    if bits == 0 {
-                        continue;
-                    }
-                    for j in 0..64 {
-                        let value = (u16::try_from(i).unwrap() << 6) | j;
-                        if bits & (1 << j) != 0 {
-                            self.push(value);
-                        }
-                    }
-                }
-                true
+        let len_before = buf.len();
+        stringdex::internals::encode::write_bitmap_to_bytes(&list, &mut *buf).unwrap();
+        let len_after = buf.len();
+        if len_after - len_before > 1 + (4 * list.len()) && list.len() < 0x3a {
+            buf.truncate(len_before);
+            buf.push(list.len() as u8);
+            for &item in list {
+                buf.push(item as u8);
+                buf.push((item >> 8) as u8);
+                buf.push((item >> 16) as u8);
+                buf.push((item >> 24) as u8);
             }
-            Container::Array(array) if array.len() <= 5 => false,
-            Container::Array(array) => {
-                let mut r = 0;
-                let mut prev = None;
-                for value in array.iter().copied() {
-                    if value.checked_sub(1) != prev {
-                        r += 1;
-                    }
-                    prev = Some(value);
-                }
-                if 2 + 4 * r >= 2 * array.len() + 2 {
-                    return false;
-                }
-                let array = std::mem::take(array);
-                *self = Container::Run(Vec::new());
-                for value in array {
-                    self.push(value);
-                }
-                true
-            }
-            Container::Run(_) => true,
         }
     }
 }
 
-// checked against roaring-rs in
-// https://gitlab.com/notriddle/roaring-test
-pub(crate) fn write_bitmap_to_bytes(
-    domain: &[u32],
-    mut out: impl std::io::Write,
-) -> std::io::Result<()> {
-    // https://arxiv.org/pdf/1603.06549.pdf
-    let mut keys = Vec::<u16>::new();
-    let mut containers = Vec::<Container>::new();
-    let mut key: u16;
-    let mut domain_iter = domain.iter().copied().peekable();
-    let mut has_run = false;
-    while let Some(entry) = domain_iter.next() {
-        key = (entry >> 16).try_into().expect("shifted off the top 16 bits, so it should fit");
-        let value: u16 = (entry & 0x00_00_FF_FF).try_into().expect("AND 16 bits, so it should fit");
-        let mut container = Container::Array(vec![value]);
-        while let Some(entry) = domain_iter.peek().copied() {
-            let entry_key: u16 =
-                (entry >> 16).try_into().expect("shifted off the top 16 bits, so it should fit");
-            if entry_key != key {
-                break;
+pub fn read_postings_from_string(postings: &mut Vec<Vec<u32>>, mut buf: &[u8]) {
+    use stringdex::internals::decode::RoaringBitmap;
+    while let Some(&c) = buf.get(0) {
+        if c < 0x3a {
+            buf = &buf[1..];
+            let mut slot = Vec::new();
+            for _ in 0..c {
+                slot.push(
+                    (buf[0] as u32)
+                        | ((buf[1] as u32) << 8)
+                        | ((buf[2] as u32) << 16)
+                        | ((buf[3] as u32) << 24),
+                );
+                buf = &buf[4..];
             }
-            domain_iter.next().expect("peeking just succeeded");
-            container
-                .push((entry & 0x00_00_FF_FF).try_into().expect("AND 16 bits, so it should fit"));
-        }
-        keys.push(key);
-        has_run = container.try_make_run() || has_run;
-        containers.push(container);
-    }
-    // https://github.com/RoaringBitmap/RoaringFormatSpec
-    const SERIAL_COOKIE_NO_RUNCONTAINER: u32 = 12346;
-    const SERIAL_COOKIE: u32 = 12347;
-    const NO_OFFSET_THRESHOLD: u32 = 4;
-    let size: u32 = containers.len().try_into().unwrap();
-    let start_offset = if has_run {
-        out.write_all(&u32::to_le_bytes(SERIAL_COOKIE | ((size - 1) << 16)))?;
-        for set in containers.chunks(8) {
-            let mut b = 0;
-            for (i, container) in set.iter().enumerate() {
-                if matches!(container, &Container::Run(..)) {
-                    b |= 1 << i;
-                }
-            }
-            out.write_all(&[b])?;
-        }
-        if size < NO_OFFSET_THRESHOLD {
-            4 + 4 * size + size.div_ceil(8)
+            postings.push(slot);
         } else {
-            4 + 8 * size + size.div_ceil(8)
-        }
-    } else {
-        out.write_all(&u32::to_le_bytes(SERIAL_COOKIE_NO_RUNCONTAINER))?;
-        out.write_all(&u32::to_le_bytes(containers.len().try_into().unwrap()))?;
-        4 + 4 + 4 * size + 4 * size
-    };
-    for (&key, container) in keys.iter().zip(&containers) {
-        // descriptive header
-        let key: u32 = key.into();
-        let count: u32 = container.popcount() - 1;
-        out.write_all(&u32::to_le_bytes((count << 16) | key))?;
-    }
-    if !has_run || size >= NO_OFFSET_THRESHOLD {
-        // offset header
-        let mut starting_offset = start_offset;
-        for container in &containers {
-            out.write_all(&u32::to_le_bytes(starting_offset))?;
-            starting_offset += match container {
-                Container::Bits(_) => 8192u32,
-                Container::Array(array) => u32::try_from(array.len()).unwrap() * 2,
-                Container::Run(runs) => 2 + u32::try_from(runs.len()).unwrap() * 4,
-            };
+            let (bitmap, consumed_bytes_len) =
+                RoaringBitmap::from_bytes(buf).unwrap_or_else(|| (RoaringBitmap::default(), 0));
+            assert_ne!(consumed_bytes_len, 0);
+            postings.push(bitmap.to_vec());
+            buf = &buf[consumed_bytes_len..];
         }
     }
-    for container in &containers {
-        match container {
-            Container::Bits(bits) => {
-                for chunk in bits.iter() {
-                    out.write_all(&u64::to_le_bytes(*chunk))?;
-                }
-            }
-            Container::Array(array) => {
-                for value in array.iter() {
-                    out.write_all(&u16::to_le_bytes(*value))?;
-                }
-            }
-            Container::Run(runs) => {
-                out.write_all(&u16::to_le_bytes(runs.len().try_into().unwrap()))?;
-                for (start, lenm1) in runs.iter().copied() {
-                    out.write_all(&u16::to_le_bytes(start))?;
-                    out.write_all(&u16::to_le_bytes(lenm1))?;
-                }
-            }
-        }
-    }
-    Ok(())
-}
-
-pub(crate) fn bitmap_to_string(domain: &[u32]) -> String {
-    let mut buf = Vec::new();
-    let mut strbuf = String::new();
-    write_bitmap_to_bytes(domain, &mut buf).unwrap();
-    BASE64_STANDARD.encode_string(&buf, &mut strbuf);
-    strbuf
 }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 1f691392b17..e37a5246a76 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -65,17 +65,17 @@ pub(crate) fn write_shared(
     // Write shared runs within a flock; disable thread dispatching of IO temporarily.
     let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file);
 
-    let SerializedSearchIndex { index, desc } = build_index(krate, &mut cx.shared.cache, tcx);
-    write_search_desc(cx, krate, &desc)?; // does not need to be merged
+    let search_index =
+        build_index(krate, &mut cx.shared.cache, tcx, &cx.dst, &cx.shared.resource_suffix)?;
 
     let crate_name = krate.name(cx.tcx());
     let crate_name = crate_name.as_str(); // rand
     let crate_name_json = OrderedJson::serialize(crate_name).unwrap(); // "rand"
     let external_crates = hack_get_external_crate_names(&cx.dst, &cx.shared.resource_suffix)?;
     let info = CrateInfo {
-        version: CrateInfoVersion::V1,
+        version: CrateInfoVersion::V2,
         src_files_js: SourcesPart::get(cx, &crate_name_json)?,
-        search_index_js: SearchIndexPart::get(index, &cx.shared.resource_suffix)?,
+        search_index,
         all_crates: AllCratesPart::get(crate_name_json.clone(), &cx.shared.resource_suffix)?,
         crates_index: CratesIndexPart::get(crate_name, &external_crates)?,
         trait_impl: TraitAliasPart::get(cx, &crate_name_json)?,
@@ -141,7 +141,7 @@ pub(crate) fn write_not_crate_specific(
     resource_suffix: &str,
     include_sources: bool,
 ) -> Result<(), Error> {
-    write_rendered_cross_crate_info(crates, dst, opt, include_sources)?;
+    write_rendered_cross_crate_info(crates, dst, opt, include_sources, resource_suffix)?;
     write_static_files(dst, opt, style_files, css_file_extension, resource_suffix)?;
     Ok(())
 }
@@ -151,13 +151,18 @@ fn write_rendered_cross_crate_info(
     dst: &Path,
     opt: &RenderOptions,
     include_sources: bool,
+    resource_suffix: &str,
 ) -> Result<(), Error> {
     let m = &opt.should_merge;
     if opt.should_emit_crate() {
         if include_sources {
             write_rendered_cci::<SourcesPart, _>(SourcesPart::blank, dst, crates, m)?;
         }
-        write_rendered_cci::<SearchIndexPart, _>(SearchIndexPart::blank, dst, crates, m)?;
+        crates
+            .iter()
+            .fold(SerializedSearchIndex::default(), |a, b| a.union(&b.search_index))
+            .sort()
+            .write_to(dst, resource_suffix)?;
         write_rendered_cci::<AllCratesPart, _>(AllCratesPart::blank, dst, crates, m)?;
     }
     write_rendered_cci::<TraitAliasPart, _>(TraitAliasPart::blank, dst, crates, m)?;
@@ -215,38 +220,12 @@ fn write_static_files(
     Ok(())
 }
 
-/// Write the search description shards to disk
-fn write_search_desc(
-    cx: &mut Context<'_>,
-    krate: &Crate,
-    search_desc: &[(usize, String)],
-) -> Result<(), Error> {
-    let crate_name = krate.name(cx.tcx()).to_string();
-    let encoded_crate_name = OrderedJson::serialize(&crate_name).unwrap();
-    let path = PathBuf::from_iter([&cx.dst, Path::new("search.desc"), Path::new(&crate_name)]);
-    if path.exists() {
-        try_err!(fs::remove_dir_all(&path), &path);
-    }
-    for (i, (_, part)) in search_desc.iter().enumerate() {
-        let filename = static_files::suffix_path(
-            &format!("{crate_name}-desc-{i}-.js"),
-            &cx.shared.resource_suffix,
-        );
-        let path = path.join(filename);
-        let part = OrderedJson::serialize(part).unwrap();
-        let part = format!("searchState.loadedDescShard({encoded_crate_name}, {i}, {part})");
-        create_parents(&path)?;
-        try_err!(fs::write(&path, part), &path);
-    }
-    Ok(())
-}
-
 /// Contains pre-rendered contents to insert into the CCI template
 #[derive(Serialize, Deserialize, Clone, Debug)]
 pub(crate) struct CrateInfo {
     version: CrateInfoVersion,
     src_files_js: PartsAndLocations<SourcesPart>,
-    search_index_js: PartsAndLocations<SearchIndexPart>,
+    search_index: SerializedSearchIndex,
     all_crates: PartsAndLocations<AllCratesPart>,
     crates_index: PartsAndLocations<CratesIndexPart>,
     trait_impl: PartsAndLocations<TraitAliasPart>,
@@ -277,7 +256,7 @@ impl CrateInfo {
 /// to provide better diagnostics about including an invalid file.
 #[derive(Serialize, Deserialize, Clone, Debug)]
 enum CrateInfoVersion {
-    V1,
+    V2,
 }
 
 /// Paths (relative to the doc root) and their pre-merge contents
@@ -332,36 +311,6 @@ trait CciPart: Sized + fmt::Display + DeserializeOwned + 'static {
 }
 
 #[derive(Serialize, Deserialize, Clone, Default, Debug)]
-struct SearchIndex;
-type SearchIndexPart = Part<SearchIndex, EscapedJson>;
-impl CciPart for SearchIndexPart {
-    type FileFormat = sorted_template::Js;
-    fn from_crate_info(crate_info: &CrateInfo) -> &PartsAndLocations<Self> {
-        &crate_info.search_index_js
-    }
-}
-
-impl SearchIndexPart {
-    fn blank() -> SortedTemplate<<Self as CciPart>::FileFormat> {
-        SortedTemplate::from_before_after(
-            r"var searchIndex = new Map(JSON.parse('[",
-            r"]'));
-if (typeof exports !== 'undefined') exports.searchIndex = searchIndex;
-else if (window.initSearch) window.initSearch(searchIndex);",
-        )
-    }
-
-    fn get(
-        search_index: OrderedJson,
-        resource_suffix: &str,
-    ) -> Result<PartsAndLocations<Self>, Error> {
-        let path = suffix_path("search-index.js", resource_suffix);
-        let search_index = EscapedJson::from(search_index);
-        Ok(PartsAndLocations::with(path, search_index))
-    }
-}
-
-#[derive(Serialize, Deserialize, Clone, Default, Debug)]
 struct AllCrates;
 type AllCratesPart = Part<AllCrates, OrderedJson>;
 impl CciPart for AllCratesPart {
@@ -426,6 +375,7 @@ impl CratesIndexPart {
     fn blank(cx: &Context<'_>) -> SortedTemplate<<Self as CciPart>::FileFormat> {
         let page = layout::Page {
             title: "Index of crates",
+            short_title: "Crates",
             css_class: "mod sys",
             root_path: "./",
             static_root_path: cx.shared.static_root_path.as_deref(),
diff --git a/src/librustdoc/html/render/write_shared/tests.rs b/src/librustdoc/html/render/write_shared/tests.rs
index 6f185e85345..1989a1f87aa 100644
--- a/src/librustdoc/html/render/write_shared/tests.rs
+++ b/src/librustdoc/html/render/write_shared/tests.rs
@@ -30,14 +30,6 @@ fn sources_template() {
 }
 
 #[test]
-fn sources_parts() {
-    let parts =
-        SearchIndexPart::get(OrderedJson::serialize(["foo", "bar"]).unwrap(), "suffix").unwrap();
-    assert_eq!(&parts.parts[0].0, Path::new("search-indexsuffix.js"));
-    assert_eq!(&parts.parts[0].1.to_string(), r#"["foo","bar"]"#);
-}
-
-#[test]
 fn all_crates_template() {
     let mut template = AllCratesPart::blank();
     assert_eq!(but_last_line(&template.to_string()), r"window.ALL_CRATES = [];");
@@ -55,31 +47,6 @@ fn all_crates_parts() {
 }
 
 #[test]
-fn search_index_template() {
-    let mut template = SearchIndexPart::blank();
-    assert_eq!(
-        but_last_line(&template.to_string()),
-        r"var searchIndex = new Map(JSON.parse('[]'));
-if (typeof exports !== 'undefined') exports.searchIndex = searchIndex;
-else if (window.initSearch) window.initSearch(searchIndex);"
-    );
-    template.append(EscapedJson::from(OrderedJson::serialize([1, 2]).unwrap()).to_string());
-    assert_eq!(
-        but_last_line(&template.to_string()),
-        r"var searchIndex = new Map(JSON.parse('[[1,2]]'));
-if (typeof exports !== 'undefined') exports.searchIndex = searchIndex;
-else if (window.initSearch) window.initSearch(searchIndex);"
-    );
-    template.append(EscapedJson::from(OrderedJson::serialize([4, 3]).unwrap()).to_string());
-    assert_eq!(
-        but_last_line(&template.to_string()),
-        r"var searchIndex = new Map(JSON.parse('[[1,2],[4,3]]'));
-if (typeof exports !== 'undefined') exports.searchIndex = searchIndex;
-else if (window.initSearch) window.initSearch(searchIndex);"
-    );
-}
-
-#[test]
 fn crates_index_part() {
     let external_crates = ["bar".to_string(), "baz".to_string()];
     let mut parts = CratesIndexPart::get("foo", &external_crates).unwrap();
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index c34b3154269..9c5518a780e 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -230,6 +230,7 @@ impl SourceCollector<'_, '_> {
         );
         let page = layout::Page {
             title: &title,
+            short_title: &src_fname.to_string_lossy(),
             css_class: "src",
             root_path: &root_path,
             static_root_path: shared.static_root_path.as_deref(),
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index c48863b4681..dc27d7943d9 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -258,6 +258,17 @@ h1, h2, h3, h4 {
 	padding-bottom: 6px;
 	margin-bottom: 15px;
 }
+.search-results-main-heading {
+	grid-template-areas:
+		"main-heading-breadcrumbs main-heading-placeholder"
+		"main-heading-breadcrumbs main-heading-toolbar    "
+		"main-heading-h1          main-heading-toolbar    ";
+}
+.search-results-main-heading nav.sub {
+	grid-area: main-heading-h1;
+	align-items: end;
+	margin: 4px 0 8px 0;
+}
 .rustdoc-breadcrumbs {
 	grid-area: main-heading-breadcrumbs;
 	line-height: 1.25;
@@ -265,6 +276,16 @@ h1, h2, h3, h4 {
 	position: relative;
 	z-index: 1;
 }
+.search-switcher {
+	grid-area: main-heading-breadcrumbs;
+	line-height: 1.5;
+	display: flex;
+	color: var(--main-color);
+	align-items: baseline;
+	white-space: nowrap;
+	padding-top: 8px;
+	min-height: 34px;
+}
 .rustdoc-breadcrumbs a {
 	padding: 5px 0 7px;
 }
@@ -305,7 +326,7 @@ h4.code-header {
 #crate-search,
 h1, h2, h3, h4, h5, h6,
 .sidebar,
-.mobile-topbar,
+rustdoc-topbar,
 .search-input,
 .search-results .result-name,
 .item-table dt > a,
@@ -317,6 +338,7 @@ rustdoc-toolbar,
 summary.hideme,
 .scraped-example-list,
 .rustdoc-breadcrumbs,
+.search-switcher,
 /* This selector is for the items listed in the "all items" page. */
 ul.all-items {
 	font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
@@ -329,7 +351,7 @@ a.anchor,
 .rust a,
 .sidebar h2 a,
 .sidebar h3 a,
-.mobile-topbar h2 a,
+rustdoc-topbar h2 a,
 h1 a,
 .search-results a,
 .search-results li,
@@ -616,7 +638,7 @@ img {
 	color: var(--sidebar-resizer-active);
 }
 
-.sidebar, .mobile-topbar, .sidebar-menu-toggle,
+.sidebar, rustdoc-topbar, .sidebar-menu-toggle,
 #src-sidebar {
 	background-color: var(--sidebar-background-color);
 }
@@ -857,7 +879,7 @@ ul.block, .block li, .block ul {
 	margin-bottom: 1rem;
 }
 
-.mobile-topbar {
+rustdoc-topbar {
 	display: none;
 }
 
@@ -1098,16 +1120,15 @@ div.where {
 nav.sub {
 	flex-grow: 1;
 	flex-flow: row nowrap;
-	margin: 4px 0 0 0;
 	display: flex;
-	align-items: center;
+	align-items: start;
+	margin-top: 4px;
 }
 .search-form {
 	position: relative;
 	display: flex;
 	height: 34px;
 	flex-grow: 1;
-	margin-bottom: 4px;
 }
 .src nav.sub {
 	margin: 0 0 -10px 0;
@@ -1208,27 +1229,14 @@ table,
 	margin-left: 0;
 }
 
-.search-results-title {
-	margin-top: 0;
-	white-space: nowrap;
-	/* flex layout allows shrinking the <select> appropriately if it becomes too large */
-	display: flex;
-	/* make things look like in a line, despite the fact that we're using a layout
-	with boxes (i.e. from the flex layout) */
-	align-items: baseline;
-}
-.search-results-title + .sub-heading {
-	color: var(--main-color);
-	display: flex;
-	align-items: baseline;
-	white-space: nowrap;
-}
 #crate-search-div {
 	/* ensures that 100% in properties of #crate-search-div:after
 	are relative to the size of this div */
 	position: relative;
 	/* allows this div (and with it the <select>-element "#crate-search") to be shrunk */
 	min-width: 0;
+	/* keep label text for switcher from moving down when this appears */
+	margin-top: -1px;
 }
 #crate-search {
 	padding: 0 23px 0 4px;
@@ -1294,6 +1302,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	flex-grow: 1;
 	background-color: var(--button-background-color);
 	color: var(--search-color);
+	max-width: 100%;
 }
 .search-input:focus {
 	border-color: var(--search-input-focused-border-color);
@@ -1459,14 +1468,14 @@ so that we can apply CSS-filters to change the arrow color in themes */
 }
 
 #settings.popover {
-	--popover-arrow-offset: 202px;
+	--popover-arrow-offset: 196px;
 	top: calc(100% - 16px);
 }
 
 /* use larger max-width for help popover, but not for help.html */
 #help.popover {
 	max-width: 600px;
-	--popover-arrow-offset: 118px;
+	--popover-arrow-offset: 115px;
 	top: calc(100% - 16px);
 }
 
@@ -1929,10 +1938,12 @@ a.tooltip:hover::after {
 	color: inherit;
 }
 #search-tabs button:not(.selected) {
+	--search-tab-button-background: var(--search-tab-button-not-selected-background);
 	background-color: var(--search-tab-button-not-selected-background);
 	border-top-color: var(--search-tab-button-not-selected-border-top-color);
 }
 #search-tabs button:hover, #search-tabs button.selected {
+	--search-tab-button-background: var(--search-tab-button-selected-background);
 	background-color: var(--search-tab-button-selected-background);
 	border-top-color: var(--search-tab-button-selected-border-top-color);
 }
@@ -1941,6 +1952,73 @@ a.tooltip:hover::after {
 	font-size: 1rem;
 	font-variant-numeric: tabular-nums;
 	color: var(--search-tab-title-count-color);
+	position: relative;
+}
+
+#search-tabs .count.loading {
+	color: transparent;
+}
+
+.search-form.loading {
+	--search-tab-button-background: var(--button-background-color);
+}
+
+#search-tabs .count.loading::before,
+.search-form.loading::before
+{
+	width: 16px;
+	height: 16px;
+	border-radius: 16px;
+	background: radial-gradient(
+		var(--search-tab-button-background) 0 50%,
+		transparent 50% 100%
+	), conic-gradient(
+		var(--code-highlight-kw-color) 0deg 30deg,
+		var(--code-highlight-prelude-color) 30deg 60deg,
+		var(--code-highlight-number-color) 90deg 120deg,
+		var(--code-highlight-lifetime-color ) 120deg 150deg,
+		var(--code-highlight-comment-color) 150deg 180deg,
+		var(--code-highlight-self-color) 180deg 210deg,
+		var(--code-highlight-attribute-color) 210deg 240deg,
+		var(--code-highlight-literal-color) 210deg 240deg,
+		var(--code-highlight-macro-color) 240deg 270deg,
+		var(--code-highlight-question-mark-color) 270deg 300deg,
+		var(--code-highlight-prelude-val-color) 300deg 330deg,
+		var(--code-highlight-doc-comment-color) 330deg 360deg
+	);
+	content: "";
+	position: absolute;
+	left: 2px;
+	top: 2px;
+	animation: rotating 1.25s linear infinite;
+}
+#search-tabs .count.loading::after,
+.search-form.loading::after
+{
+	width: 18px;
+	height: 18px;
+	border-radius: 18px;
+	background: conic-gradient(
+		var(--search-tab-button-background) 0deg 180deg,
+		transparent 270deg 360deg
+	);
+	content: "";
+	position: absolute;
+	left: 1px;
+	top: 1px;
+	animation: rotating 0.66s linear infinite;
+}
+
+.search-form.loading::before {
+	left: auto;
+	right: 9px;
+	top: 8px;
+}
+
+.search-form.loading::after {
+	left: auto;
+	right: 8px;
+	top: 8px;
 }
 
 #search .error code {
@@ -1974,7 +2052,7 @@ a.tooltip:hover::after {
 	border-bottom: 1px solid var(--border-color);
 }
 
-#settings-menu, #help-button, button#toggle-all-docs {
+#search-button, .settings-menu, .help-menu, button#toggle-all-docs {
 	margin-left: var(--button-left-margin);
 	display: flex;
 	line-height: 1.25;
@@ -1989,69 +2067,100 @@ a.tooltip:hover::after {
 	display: flex;
 	margin-right: 4px;
 	position: fixed;
+	margin-top: 25px;
+	left: 6px;
 	height: 34px;
 	width: 34px;
+	z-index: calc(var(--desktop-sidebar-z-index) + 1);
 }
 .hide-sidebar #sidebar-button {
 	left: 6px;
 	background-color: var(--main-background-color);
-	z-index: 1;
 }
 .src #sidebar-button {
+	margin-top: 0;
+	top: 8px;
 	left: 8px;
-	z-index: calc(var(--desktop-sidebar-z-index) + 1);
+	border-color: var(--border-color);
 }
 .hide-sidebar .src #sidebar-button {
 	position: static;
 }
-#settings-menu > a, #help-button > a, #sidebar-button > a, button#toggle-all-docs {
+#search-button > a,
+.settings-menu > a,
+.help-menu > a,
+#sidebar-button > a,
+button#toggle-all-docs {
 	display: flex;
 	align-items: center;
 	justify-content: center;
 	flex-direction: column;
 }
-#settings-menu > a, #help-button > a, button#toggle-all-docs {
+#search-button > a,
+.settings-menu > a,
+.help-menu > a,
+button#toggle-all-docs {
 	border: 1px solid transparent;
 	border-radius: var(--button-border-radius);
 	color: var(--main-color);
 }
-#settings-menu > a, #help-button > a, button#toggle-all-docs {
+#search-button > a, .settings-menu > a, .help-menu > a, button#toggle-all-docs {
 	width: 80px;
 	border-radius: var(--toolbar-button-border-radius);
 }
-#settings-menu > a, #help-button > a {
+#search-button > a, .settings-menu > a, .help-menu > a {
 	min-width: 0;
 }
 #sidebar-button > a {
-	background-color: var(--sidebar-background-color);
+	border: solid 1px transparent;
+	border-radius: var(--button-border-radius);
+	background-color: var(--button-background-color);
 	width: 33px;
 }
-#sidebar-button > a:hover, #sidebar-button > a:focus-visible {
-	background-color: var(--main-background-color);
+.src #sidebar-button > a {
+	background-color: var(--sidebar-background-color);
+	border-color: var(--border-color);
 }
 
-#settings-menu > a:hover, #settings-menu > a:focus-visible,
-#help-button > a:hover, #help-button > a:focus-visible,
+#search-button > a:hover, #search-button > a:focus-visible,
+.settings-menu > a:hover, .settings-menu > a:focus-visible,
+.help-menu > a:hover, #help-menu > a:focus-visible,
+#sidebar-button > a:hover, #sidebar-button > a:focus-visible,
+#copy-path:hover, #copy-path:focus-visible,
 button#toggle-all-docs:hover, button#toggle-all-docs:focus-visible {
 	border-color: var(--settings-button-border-focus);
 	text-decoration: none;
 }
 
-#settings-menu > a::before {
+#search-button > a::before {
+	/* Magnifying glass */
+	content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
+		width="18" height="18" viewBox="0 0 16 16">\
+	    <circle r="5" cy="7" cx="7" style="fill:none;stroke:black;stroke-width:3"/><path \
+	    d="M14.5,14.5 12,12" style="fill:none;stroke:black;stroke-width:3;stroke-linecap:round">\
+	    </path><desc>Search</desc>\
+	    </svg>');
+	width: 18px;
+	height: 18px;
+	filter: var(--settings-menu-filter);
+}
+
+.settings-menu > a::before {
 	/* Wheel <https://www.svgrepo.com/svg/384069/settings-cog-gear> */
 	content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
 	enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
-	<path d="M10.25,6c0-0.1243286-0.0261841-0.241333-0.0366211-0.362915l1.6077881-1.5545654l\
-	-1.25-2.1650391  c0,0-1.2674561,0.3625488-2.1323853,0.6099854c-0.2034912-0.1431885-0.421875\
-	-0.2639771-0.6494751-0.3701782L7.25,0h-2.5 c0,0-0.3214111,1.2857666-0.5393066,2.1572876\
-	C3.9830933,2.2634888,3.7647095,2.3842773,3.5612183,2.5274658L1.428833,1.9174805 \
-	l-1.25,2.1650391c0,0,0.9641113,0.9321899,1.6077881,1.5545654C1.7761841,5.758667,\
-	1.75,5.8756714,1.75,6  s0.0261841,0.241333,0.0366211,0.362915L0.178833,7.9174805l1.25,\
-	2.1650391l2.1323853-0.6099854  c0.2034912,0.1432495,0.421875,0.2639771,0.6494751,0.3701782\
-	L4.75,12h2.5l0.5393066-2.1572876  c0.2276001-0.1062012,0.4459839-0.2269287,0.6494751\
-	-0.3701782l2.1323853,0.6099854l1.25-2.1650391L10.2133789,6.362915  C10.2238159,6.241333,\
-	10.25,6.1243286,10.25,6z M6,7.5C5.1715698,7.5,4.5,6.8284302,4.5,6S5.1715698,4.5,6,4.5S7.5\
-	,5.1715698,7.5,6  S6.8284302,7.5,6,7.5z" fill="black"/></svg>');
+	<path d="m4.75 0s-0.32117 1.286-0.53906 2.1576c-0.2276 0.1062-0.44625 \
+	0.2266-0.64974 0.36979l-2.1328-0.60938-1.25 2.1641s0.9644 0.93231 1.6081 1.5547c-0.010437 \
+	0.12158-0.036458 0.23895-0.036458 0.36328s0.026021 0.2417 0.036458 0.36328l-1.6081 \
+	1.5547 1.25 2.1641 2.1328-0.60937c0.20349 0.14325 0.42214 0.26359 0.64974 0.36979l0.53906 \
+	2.1576h2.5l0.53906-2.1576c0.2276-0.1062 0.44625-0.22654 0.64974-0.36979l2.1328 0.60937 \
+	1.25-2.1641-1.6081-1.5547c0.010437-0.12158 0.036458-0.23895 \
+	0.036458-0.36328s-0.02602-0.2417-0.03646-0.36328l1.6081-1.5547-1.25-2.1641s-1.2679 \
+	0.36194-2.1328 0.60938c-0.20349-0.14319-0.42214-0.26359-0.64974-0.36979l-0.53906-2.1576\
+	zm1.25 2.5495c1.9058-2.877e-4 3.4508 1.5447 3.4505 3.4505 2.877e-4 1.9058-1.5447 3.4508-3.4505 \
+	3.4505-1.9058 2.877e-4 -3.4508-1.5447-3.4505-3.4505-2.877e-4 -1.9058 1.5447-3.4508 \
+	3.4505-3.4505z" fill="black"/>\
+	<circle cx="6" cy="6" r="1.75" fill="none" stroke="black" stroke-width="1"/></svg>');
 	width: 18px;
 	height: 18px;
 	filter: var(--settings-menu-filter);
@@ -2067,36 +2176,51 @@ button#toggle-all-docs::before {
 	filter: var(--settings-menu-filter);
 }
 
-button#toggle-all-docs.will-expand::before {
-	/* Custom arrow icon */
-	content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
-	enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
-	<path d="M2,5l4,-4l4,4M2,7l4,4l4,-4" stroke="black" fill="none" stroke-width="2px"/></svg>');
-}
-
-#help-button > a::before {
-	/* Question mark with circle */
-	content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
-	enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg" fill="none">\
-	<circle r="5.25" cx="6" cy="6" stroke-width="1.25" stroke="black"/>\
-	<text x="6" y="7" style="font:8px sans-serif;font-weight:1000" text-anchor="middle" \
-		dominant-baseline="middle" fill="black">?</text></svg>');
+.help-menu > a::before {
+	/* Question mark with "circle" */
+	content: url('data:image/svg+xml,\
+		<svg width="18" height="18" enable-background="new 0 0 12 12" fill="none" \
+		version="1.1" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"> \
+		<path d="m6.007 0.6931c2.515 0 5.074 1.908 5.074 5.335 0 3.55-2.567 5.278-5.088 \
+		5.278-2.477 0-5.001-1.742-5.001-5.3 0-3.38 2.527-5.314 5.014-5.314z" stroke="black" \
+		stroke-width="1.5"/>\
+		<path d="m5.999 7.932c0.3111 0 0.7062 0.2915 0.7062 0.7257 0 0.5458-0.3951 \
+		0.8099-0.7081 0.8099-0.2973 0-0.7023-0.266-0.7023-0.7668 0-0.4695 0.3834-0.7688 \
+		0.7042-0.7688z" fill="black"/>\
+		<path d="m4.281 3.946c0.0312-0.03057 0.06298-0.06029 0.09528-0.08916 0.4833-0.432 1.084-0.6722 \
+		1.634-0.6722 1.141 0 1.508 1.043 1.221 1.621-0.2753 0.5542-1.061 0.5065-1.273 \
+		1.595-0.05728 0.2939 0.0134 0.9812 0.0134 1.205" fill="none" stroke="black" \
+		stroke-width="1.25"/>\
+		</svg>');
 	width: 18px;
 	height: 18px;
 	filter: var(--settings-menu-filter);
 }
 
+/* design hack to cope with "Help" being far shorter than "Settings" etc */
+.help-menu > a {
+	width: 74px;
+}
+.help-menu > a > .label {
+	padding-right: 1px;
+}
+#toggle-all-docs:not(.will-expand) > .label {
+	padding-left: 1px;
+}
+
+#search-button > a::before,
 button#toggle-all-docs::before,
-#help-button > a::before,
-#settings-menu > a::before {
+.help-menu > a::before,
+.settings-menu > a::before {
 	filter: var(--settings-menu-filter);
 	margin: 8px;
 }
 
 @media not (pointer: coarse) {
+	#search-button > a:hover::before,
 	button#toggle-all-docs:hover::before,
-	#help-button > a:hover::before,
-	#settings-menu > a:hover::before {
+	.help-menu > a:hover::before,
+	.settings-menu > a:hover::before {
 		filter: var(--settings-menu-hover-filter);
 	}
 }
@@ -2122,9 +2246,9 @@ rustdoc-toolbar span.label {
 	/* sidebar resizer image */
 	content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" \
 		fill="none" stroke="black">\
-		<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
-		<circle cx="4.375" cy="4.375" r="1" stroke-width=".75"/>\
-		<path d="m7.6121 3v16 M5.375 7.625h-2 m2 3h-2 m2 3h-2" stroke-width="1.25"/></svg>');
+		<rect x="1" y="2" width="20" height="18" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
+		<circle cx="4.375" cy="5.375" r="1" stroke-width=".75"/>\
+		<path d="m7.6121 4v14 M5.375 8.625h-2 m2 3h-2 m2 3h-2" stroke-width="1.25"/></svg>');
 	width: 22px;
 	height: 22px;
 }
@@ -2137,7 +2261,8 @@ rustdoc-toolbar span.label {
 	margin-left: 10px;
 	padding: 0;
 	padding-left: 2px;
-	border: 0;
+	border: solid 1px transparent;
+	border-radius: var(--button-border-radius);
 	font-size: 0;
 }
 #copy-path::before {
@@ -2159,7 +2284,7 @@ rustdoc-toolbar span.label {
 		transform: rotate(360deg);
 	}
 }
-#settings-menu.rotate > a img {
+.settings-menu.rotate > a img {
 	animation: rotating 2s linear infinite;
 }
 
@@ -2402,6 +2527,9 @@ However, it's not needed with smaller screen width because the doc/code block is
 	opacity: 0.75;
 	filter: var(--mobile-sidebar-menu-filter);
 }
+.src #sidebar-button > a:hover {
+	background: var(--main-background-color);
+}
 .sidebar-menu-toggle:hover::before,
 .sidebar-menu-toggle:active::before,
 .sidebar-menu-toggle:focus::before {
@@ -2410,8 +2538,8 @@ However, it's not needed with smaller screen width because the doc/code block is
 
 /* Media Queries */
 
-/* Make sure all the buttons line wrap at the same time */
 @media (max-width: 850px) {
+	/* Make sure all the buttons line wrap at the same time */
 	#search-tabs .count {
 		display: block;
 	}
@@ -2421,6 +2549,81 @@ However, it's not needed with smaller screen width because the doc/code block is
 	.side-by-side > div {
 		width: auto;
 	}
+
+	/* Text label takes up too much space at this size. */
+	.main-heading {
+		grid-template-areas:
+			"main-heading-breadcrumbs main-heading-toolbar"
+			"main-heading-h1 main-heading-toolbar"
+			"main-heading-sub-heading main-heading-toolbar";
+	}
+	.search-results-main-heading {
+		display: grid;
+		grid-template-areas:
+			"main-heading-breadcrumbs main-heading-toolbar"
+			"main-heading-breadcrumbs main-heading-toolbar"
+			"main-heading-h1 main-heading-toolbar";
+	}
+	rustdoc-toolbar {
+		margin-top: -10px;
+		display: grid;
+		grid-template-areas:
+			"x settings help"
+			"search summary summary";
+		grid-template-rows: 35px 1fr;
+	}
+	.search-results-main-heading rustdoc-toolbar {
+		display: grid;
+		grid-template-areas:
+			"settings help"
+			"search search";
+	}
+	.search-results-main-heading #toggle-all-docs {
+		display: none;
+	}
+	rustdoc-toolbar .settings-menu span.label,
+	rustdoc-toolbar .help-menu span.label
+	{
+		display: none;
+	}
+	rustdoc-toolbar .settings-menu {
+		grid-area: settings;
+	}
+	rustdoc-toolbar .help-menu {
+		grid-area: help;
+	}
+	rustdoc-toolbar .settings-menu {
+		grid-area: settings;
+	}
+	rustdoc-toolbar #search-button {
+		grid-area: search;
+	}
+	rustdoc-toolbar #toggle-all-docs {
+		grid-area: summary;
+	}
+	rustdoc-toolbar .settings-menu,
+	rustdoc-toolbar .help-menu {
+		height: 35px;
+	}
+	rustdoc-toolbar .settings-menu > a,
+	rustdoc-toolbar .help-menu > a {
+		border-radius: 2px;
+		text-align: center;
+		width: 34px;
+		padding: 5px 0;
+	}
+	rustdoc-toolbar .settings-menu > a:before,
+	rustdoc-toolbar .help-menu > a:before {
+		margin: 0 4px;
+	}
+	#settings.popover {
+		top: 16px;
+		--popover-arrow-offset: 58px;
+	}
+	#help.popover {
+		top: 16px;
+		--popover-arrow-offset: 16px;
+	}
 }
 
 /*
@@ -2435,7 +2638,7 @@ in src-script.js and main.js
 
 	/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
 	   or visiting a URL with a fragment like `#method.new`, we don't want the item to be obscured
-	   by the topbar. Anything with an `id` gets scroll-margin-top equal to .mobile-topbar's size.
+	   by the topbar. Anything with an `id` gets scroll-margin-top equal to rustdoc-topbar's size.
 	*/
 	*[id] {
 		scroll-margin-top: 45px;
@@ -2451,18 +2654,32 @@ in src-script.js and main.js
 		visibility: hidden;
 	}
 
-	/* Text label takes up too much space at this size. */
-	rustdoc-toolbar span.label {
+
+	/* Pull settings and help up into the top bar. */
+	rustdoc-topbar span.label,
+	html:not(.hide-sidebar) .rustdoc:not(.src) rustdoc-toolbar .settings-menu > a,
+	html:not(.hide-sidebar) .rustdoc:not(.src) rustdoc-toolbar .help-menu > a
+	{
 		display: none;
 	}
-	#settings-menu > a, #help-button > a, button#toggle-all-docs {
+	rustdoc-topbar .settings-menu > a,
+	rustdoc-topbar .help-menu > a {
 		width: 33px;
+		line-height: 0;
+	}
+	rustdoc-topbar .settings-menu > a:hover,
+	rustdoc-topbar .help-menu > a:hover {
+		border: none;
+		background: var(--main-background-color);
+		border-radius: 0;
 	}
 	#settings.popover {
-		--popover-arrow-offset: 86px;
+		top: 32px;
+		--popover-arrow-offset: 48px;
 	}
 	#help.popover {
-		--popover-arrow-offset: 48px;
+		top: 32px;
+		--popover-arrow-offset: 12px;
 	}
 
 	.rustdoc {
@@ -2471,13 +2688,13 @@ in src-script.js and main.js
 		display: block;
 	}
 
-	main {
+	html:not(.hide-sidebar) main {
 		padding-left: 15px;
 		padding-top: 0px;
 	}
 
 	/* Hide the logo and item name from the sidebar. Those are displayed
-	   in the mobile-topbar instead. */
+	   in the rustdoc-topbar instead. */
 	.sidebar .logo-container,
 	.sidebar .location,
 	.sidebar-resizer {
@@ -2510,6 +2727,9 @@ in src-script.js and main.js
 		height: 100vh;
 		border: 0;
 	}
+	html .src main {
+		padding: 18px 0;
+	}
 	.src .search-form {
 		margin-left: 40px;
 	}
@@ -2529,9 +2749,9 @@ in src-script.js and main.js
 		left: 0;
 	}
 
-	.mobile-topbar h2 {
+	rustdoc-topbar > h2 {
 		padding-bottom: 0;
-		margin: auto 0.5em auto auto;
+		margin: auto;
 		overflow: hidden;
 		/* Rare exception to specifying font sizes in rem. Since the topbar
 		   height is specified in pixels, this also has to be specified in
@@ -2540,32 +2760,34 @@ in src-script.js and main.js
 		font-size: 24px;
 		white-space: nowrap;
 		text-overflow: ellipsis;
+		text-align: center;
 	}
 
-	.mobile-topbar .logo-container > img {
+	rustdoc-topbar .logo-container > img {
 		max-width: 35px;
 		max-height: 35px;
 		margin: 5px 0 5px 20px;
 	}
 
-	.mobile-topbar {
+	rustdoc-topbar {
 		display: flex;
 		flex-direction: row;
 		position: sticky;
 		z-index: 10;
-		font-size: 2rem;
 		height: 45px;
 		width: 100%;
 		left: 0;
 		top: 0;
 	}
 
-	.hide-sidebar .mobile-topbar {
+	.hide-sidebar rustdoc-topbar {
 		display: none;
 	}
 
 	.sidebar-menu-toggle {
-		width: 45px;
+		/* prevent flexbox shrinking */
+		width: 41px;
+		min-width: 41px;
 		border: none;
 		line-height: 0;
 	}
@@ -2591,9 +2813,13 @@ in src-script.js and main.js
 	#sidebar-button > a::before {
 		content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
 			viewBox="0 0 22 22" fill="none" stroke="black">\
-			<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
-			<circle cx="4.375" cy="4.375" r="1" stroke-width=".75"/>\
-			<path d="m3 7.375h16m0-3h-4" stroke-width="1.25"/></svg>');
+			<rect x="1" y="2" width="20" height="18" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
+			<g fill="black" stroke="none">\
+			<circle cx="4.375" cy="5.375" r="1" stroke-width=".75"/>\
+			<circle cx="17.375" cy="5.375" r="1" stroke-width=".75"/>\
+			<circle cx="14.375" cy="5.375" r="1" stroke-width=".75"/>\
+			</g>\
+			<path d="m3 8.375h16" stroke-width="1.25"/></svg>');
 		width: 22px;
 		height: 22px;
 	}
@@ -3283,7 +3509,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	border-bottom: 1px solid rgba(242, 151, 24, 0.3);
 }
 
-:root[data-theme="ayu"] #settings-menu > a img,
+:root[data-theme="ayu"] .settings-menu > a img,
 :root[data-theme="ayu"] #sidebar-button > a::before {
 	filter: invert(100);
 }
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 8e3d07b3a1c..20fc6b75d37 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -54,23 +54,6 @@ function showMain() {
 window.rootPath = getVar("root-path");
 window.currentCrate = getVar("current-crate");
 
-function setMobileTopbar() {
-    // FIXME: It would be nicer to generate this text content directly in HTML,
-    // but with the current code it's hard to get the right information in the right place.
-    const mobileTopbar = document.querySelector(".mobile-topbar");
-    const locationTitle = document.querySelector(".sidebar h2.location");
-    if (mobileTopbar) {
-        const mobileTitle = document.createElement("h2");
-        mobileTitle.className = "location";
-        if (hasClass(document.querySelector(".rustdoc"), "crate")) {
-            mobileTitle.innerHTML = `Crate <a href="#">${window.currentCrate}</a>`;
-        } else if (locationTitle) {
-            mobileTitle.innerHTML = locationTitle.innerHTML;
-        }
-        mobileTopbar.appendChild(mobileTitle);
-    }
-}
-
 /**
  * Gets the human-readable string for the virtual-key code of the
  * given KeyboardEvent, ev.
@@ -84,6 +67,7 @@ function setMobileTopbar() {
  * So I guess you could say things are getting pretty interoperable.
  *
  * @param {KeyboardEvent} ev
+ * @returns {string}
  */
 function getVirtualKey(ev) {
     if ("key" in ev && typeof ev.key !== "undefined") {
@@ -98,18 +82,8 @@ function getVirtualKey(ev) {
 }
 
 const MAIN_ID = "main-content";
-const SETTINGS_BUTTON_ID = "settings-menu";
 const ALTERNATIVE_DISPLAY_ID = "alternative-display";
 const NOT_DISPLAYED_ID = "not-displayed";
-const HELP_BUTTON_ID = "help-button";
-
-function getSettingsButton() {
-    return document.getElementById(SETTINGS_BUTTON_ID);
-}
-
-function getHelpButton() {
-    return document.getElementById(HELP_BUTTON_ID);
-}
 
 // Returns the current URL without any query parameter or hash.
 function getNakedUrl() {
@@ -174,7 +148,7 @@ function getNotDisplayedElem() {
  * contains the displayed element (there can be only one at the same time!). So basically, we switch
  * elements between the two `<section>` elements.
  *
- * @param {HTMLElement|null} elemToDisplay
+ * @param {Element|null} elemToDisplay
  */
 function switchDisplayedElement(elemToDisplay) {
     const el = getAlternativeDisplayElem();
@@ -239,14 +213,14 @@ function preLoadCss(cssUrl) {
         document.head.append(script);
     }
 
-    const settingsButton = getSettingsButton();
-    if (settingsButton) {
-        settingsButton.onclick = event => {
+    onEachLazy(document.querySelectorAll(".settings-menu"), settingsMenu => {
+        /** @param {MouseEvent} event */
+        settingsMenu.querySelector("a").onclick = event => {
             if (event.ctrlKey || event.altKey || event.metaKey) {
                 return;
             }
             window.hideAllModals(false);
-            addClass(getSettingsButton(), "rotate");
+            addClass(settingsMenu, "rotate");
             event.preventDefault();
             // Sending request for the CSS and the JS files at the same time so it will
             // hopefully be loaded when the JS will generate the settings content.
@@ -268,15 +242,42 @@ function preLoadCss(cssUrl) {
                 }
             }, 0);
         };
-    }
+    });
 
     window.searchState = {
         rustdocToolbar: document.querySelector("rustdoc-toolbar"),
         loadingText: "Loading search results...",
-        // This will always be an HTMLInputElement, but tsc can't see that
-        // @ts-expect-error
-        input: document.getElementsByClassName("search-input")[0],
-        outputElement: () => {
+        inputElement: () => {
+            let el = document.getElementsByClassName("search-input")[0];
+            if (!el) {
+                const out = nonnull(nonnull(window.searchState.outputElement()).parentElement);
+                const hdr = document.createElement("div");
+                hdr.className = "main-heading search-results-main-heading";
+                const params = window.searchState.getQueryStringParams();
+                const autofocusParam = params.search === "" ? "autofocus" : "";
+                hdr.innerHTML = `<nav class="sub">
+                    <form class="search-form loading">
+                        <span></span> <!-- This empty span is a hacky fix for Safari: see #93184 -->
+                        <input
+                            ${autofocusParam}
+                            class="search-input"
+                            name="search"
+                            aria-label="Run search in the documentation"
+                            autocomplete="off"
+                            spellcheck="false"
+                            placeholder="Type ‘S’ or ‘/’ to search, ‘?’ for more options…"
+                            type="search">
+                    </form>
+                </nav><div class="search-switcher"></div>`;
+                out.insertBefore(hdr, window.searchState.outputElement());
+                el = document.getElementsByClassName("search-input")[0];
+            }
+            if (el instanceof HTMLInputElement) {
+                return el;
+            }
+            return null;
+        },
+        containerElement: () => {
             let el = document.getElementById("search");
             if (!el) {
                 el = document.createElement("section");
@@ -285,6 +286,19 @@ function preLoadCss(cssUrl) {
             }
             return el;
         },
+        outputElement: () => {
+            const container = window.searchState.containerElement();
+            if (!container) {
+                return null;
+            }
+            let el = container.querySelector(".search-out");
+            if (!el) {
+                el = document.createElement("div");
+                el.className = "search-out";
+                container.appendChild(el);
+            }
+            return el;
+        },
         title: document.title,
         titleBeforeSearch: document.title,
         timeout: null,
@@ -303,25 +317,52 @@ function preLoadCss(cssUrl) {
             }
         },
         isDisplayed: () => {
-            const outputElement = window.searchState.outputElement();
-            return !!outputElement &&
-                !!outputElement.parentElement &&
-                outputElement.parentElement.id === ALTERNATIVE_DISPLAY_ID;
+            const container = window.searchState.containerElement();
+            if (!container) {
+                return false;
+            }
+            return !!container.parentElement && container.parentElement.id ===
+                ALTERNATIVE_DISPLAY_ID;
         },
         // Sets the focus on the search bar at the top of the page
         focus: () => {
-            window.searchState.input && window.searchState.input.focus();
+            const inputElement = window.searchState.inputElement();
+            window.searchState.showResults();
+            if (inputElement) {
+                inputElement.focus();
+                // Avoid glitch if something focuses the search button after clicking.
+                requestAnimationFrame(() => inputElement.focus());
+            }
         },
         // Removes the focus from the search bar.
         defocus: () => {
-            window.searchState.input && window.searchState.input.blur();
+            nonnull(window.searchState.inputElement()).blur();
         },
-        showResults: search => {
-            if (search === null || typeof search === "undefined") {
-                search = window.searchState.outputElement();
+        toggle: () => {
+            if (window.searchState.isDisplayed()) {
+                window.searchState.defocus();
+                window.searchState.hideResults();
+            } else {
+                window.searchState.focus();
             }
-            switchDisplayedElement(search);
+        },
+        showResults: () => {
             document.title = window.searchState.title;
+            if (window.searchState.isDisplayed()) {
+                return;
+            }
+            const search = window.searchState.containerElement();
+            switchDisplayedElement(search);
+            const btn = document.querySelector("#search-button a");
+            if (browserSupportsHistoryApi() && btn instanceof HTMLAnchorElement &&
+                window.searchState.getQueryStringParams().search === undefined
+            ) {
+                history.pushState(null, "", btn.href);
+            }
+            const btnLabel = document.querySelector("#search-button a span.label");
+            if (btnLabel) {
+                btnLabel.innerHTML = "Exit";
+            }
         },
         removeQueryParameters: () => {
             // We change the document title.
@@ -334,6 +375,10 @@ function preLoadCss(cssUrl) {
             switchDisplayedElement(null);
             // We also remove the query parameter from the URL.
             window.searchState.removeQueryParameters();
+            const btnLabel = document.querySelector("#search-button a span.label");
+            if (btnLabel) {
+                btnLabel.innerHTML = "Search";
+            }
         },
         getQueryStringParams: () => {
             /** @type {Object.<any, string>} */
@@ -348,11 +393,11 @@ function preLoadCss(cssUrl) {
             return params;
         },
         setup: () => {
-            const search_input = window.searchState.input;
+            let searchLoaded = false;
+            const search_input = window.searchState.inputElement();
             if (!search_input) {
                 return;
             }
-            let searchLoaded = false;
             // If you're browsing the nightly docs, the page might need to be refreshed for the
             // search to work because the hash of the JS scripts might have changed.
             function sendSearchForm() {
@@ -363,21 +408,102 @@ function preLoadCss(cssUrl) {
                 if (!searchLoaded) {
                     searchLoaded = true;
                     // @ts-expect-error
-                    loadScript(getVar("static-root-path") + getVar("search-js"), sendSearchForm);
-                    loadScript(resourcePath("search-index", ".js"), sendSearchForm);
+                    window.rr_ = data => {
+                        // @ts-expect-error
+                        window.searchIndex = data;
+                    };
+                    if (!window.StringdexOnload) {
+                        window.StringdexOnload = [];
+                    }
+                    window.StringdexOnload.push(() => {
+                        loadScript(
+                            // @ts-expect-error
+                            getVar("static-root-path") + getVar("search-js"),
+                            sendSearchForm,
+                        );
+                    });
+                    // @ts-expect-error
+                    loadScript(getVar("static-root-path") + getVar("stringdex-js"), sendSearchForm);
+                    loadScript(resourcePath("search.index/root", ".js"), sendSearchForm);
                 }
             }
 
             search_input.addEventListener("focus", () => {
-                window.searchState.origPlaceholder = search_input.placeholder;
-                search_input.placeholder = "Type your search here.";
                 loadSearch();
             });
 
-            if (search_input.value !== "") {
-                loadSearch();
+            const btn = document.getElementById("search-button");
+            if (btn) {
+                btn.onclick = event => {
+                    if (event.ctrlKey || event.altKey || event.metaKey) {
+                        return;
+                    }
+                    event.preventDefault();
+                    window.searchState.toggle();
+                    loadSearch();
+                };
+            }
+
+            // Push and pop states are used to add search results to the browser
+            // history.
+            if (browserSupportsHistoryApi()) {
+                // Store the previous <title> so we can revert back to it later.
+                const previousTitle = document.title;
+
+                window.addEventListener("popstate", e => {
+                    const params = window.searchState.getQueryStringParams();
+                    // Revert to the previous title manually since the History
+                    // API ignores the title parameter.
+                    document.title = previousTitle;
+                    // Synchronize search bar with query string state and
+                    // perform the search. This will empty the bar if there's
+                    // nothing there, which lets you really go back to a
+                    // previous state with nothing in the bar.
+                    const inputElement = window.searchState.inputElement();
+                    if (params.search !== undefined && inputElement !== null) {
+                        loadSearch();
+                        inputElement.value = params.search;
+                        // Some browsers fire "onpopstate" for every page load
+                        // (Chrome), while others fire the event only when actually
+                        // popping a state (Firefox), which is why search() is
+                        // called both here and at the end of the startSearch()
+                        // function.
+                        e.preventDefault();
+                        window.searchState.showResults();
+                        if (params.search === "") {
+                            window.searchState.focus();
+                        }
+                    } else {
+                        // When browsing back from search results the main page
+                        // visibility must be reset.
+                        window.searchState.hideResults();
+                    }
+                });
             }
 
+            // This is required in firefox to avoid this problem: Navigating to a search result
+            // with the keyboard, hitting enter, and then hitting back would take you back to
+            // the doc page, rather than the search that should overlay it.
+            // This was an interaction between the back-forward cache and our handlers
+            // that try to sync state between the URL and the search input. To work around it,
+            // do a small amount of re-init on page show.
+            window.onpageshow = () => {
+                const inputElement = window.searchState.inputElement();
+                const qSearch = window.searchState.getQueryStringParams().search;
+                if (qSearch !== undefined && inputElement !== null) {
+                    if (inputElement.value === "") {
+                        inputElement.value = qSearch;
+                    }
+                    window.searchState.showResults();
+                    if (qSearch === "") {
+                        loadSearch();
+                        window.searchState.focus();
+                    }
+                } else {
+                    window.searchState.hideResults();
+                }
+            };
+
             const params = window.searchState.getQueryStringParams();
             if (params.search !== undefined) {
                 window.searchState.setLoadingSearch();
@@ -386,13 +512,9 @@ function preLoadCss(cssUrl) {
         },
         setLoadingSearch: () => {
             const search = window.searchState.outputElement();
-            if (!search) {
-                return;
-            }
-            search.innerHTML = "<h3 class=\"search-loading\">" +
-                window.searchState.loadingText +
-                "</h3>";
-            window.searchState.showResults(search);
+            nonnull(search).innerHTML = "<h3 class=\"search-loading\">" +
+                window.searchState.loadingText + "</h3>";
+            window.searchState.showResults();
         },
         descShards: new Map(),
         loadDesc: async function({descShard, descIndex}) {
@@ -1500,15 +1622,13 @@ function preLoadCss(cssUrl) {
 
     // @ts-expect-error
     function helpBlurHandler(event) {
-        // @ts-expect-error
-        if (!getHelpButton().contains(document.activeElement) &&
-            // @ts-expect-error
-            !getHelpButton().contains(event.relatedTarget) &&
-            // @ts-expect-error
-            !getSettingsButton().contains(document.activeElement) &&
-            // @ts-expect-error
-            !getSettingsButton().contains(event.relatedTarget)
-        ) {
+        const isInPopover = onEachLazy(
+            document.querySelectorAll(".settings-menu, .help-menu"),
+            menu => {
+                return menu.contains(document.activeElement) || menu.contains(event.relatedTarget);
+            },
+        );
+        if (!isInPopover) {
             window.hidePopoverMenus();
         }
     }
@@ -1529,7 +1649,7 @@ function preLoadCss(cssUrl) {
             ["&#9166;", "Go to active search result"],
             ["+", "Expand all sections"],
             ["-", "Collapse all sections"],
-            // for the sake of brevity, we don't say "inherint impl blocks",
+            // for the sake of brevity, we don't say "inherit impl blocks",
             // although that would be more correct,
             // since trait impl blocks are collapsed by -
             ["_", "Collapse all sections, including impl blocks"],
@@ -1571,10 +1691,9 @@ function preLoadCss(cssUrl) {
 
         const container = document.createElement("div");
         if (!isHelpPage) {
-            container.className = "popover";
+            container.className = "popover content";
         }
         container.id = "help";
-        container.style.display = "none";
 
         const side_by_side = document.createElement("div");
         side_by_side.className = "side-by-side";
@@ -1590,17 +1709,16 @@ function preLoadCss(cssUrl) {
             help_section.appendChild(container);
             // @ts-expect-error
             document.getElementById("main-content").appendChild(help_section);
-            container.style.display = "block";
         } else {
-            const help_button = getHelpButton();
-            // @ts-expect-error
-            help_button.appendChild(container);
-
-            container.onblur = helpBlurHandler;
-            // @ts-expect-error
-            help_button.onblur = helpBlurHandler;
-            // @ts-expect-error
-            help_button.children[0].onblur = helpBlurHandler;
+            onEachLazy(document.getElementsByClassName("help-menu"), menu => {
+                if (menu.offsetWidth !== 0) {
+                    menu.appendChild(container);
+                    container.onblur = helpBlurHandler;
+                    menu.onblur = helpBlurHandler;
+                    menu.children[0].onblur = helpBlurHandler;
+                    return true;
+                }
+            });
         }
 
         return container;
@@ -1621,80 +1739,57 @@ function preLoadCss(cssUrl) {
      * Hide all the popover menus.
      */
     window.hidePopoverMenus = () => {
-        onEachLazy(document.querySelectorAll("rustdoc-toolbar .popover"), elem => {
+        onEachLazy(document.querySelectorAll(".settings-menu .popover"), elem => {
             elem.style.display = "none";
         });
-        const button = getHelpButton();
-        if (button) {
-            removeClass(button, "help-open");
-        }
+        onEachLazy(document.querySelectorAll(".help-menu .popover"), elem => {
+            elem.parentElement.removeChild(elem);
+        });
     };
 
     /**
-     * Returns the help menu element (not the button).
-     *
-     * @param {boolean} buildNeeded - If this argument is `false`, the help menu element won't be
-     *                                built if it doesn't exist.
-     *
-     * @return {HTMLElement}
-     */
-    function getHelpMenu(buildNeeded) {
-        // @ts-expect-error
-        let menu = getHelpButton().querySelector(".popover");
-        if (!menu && buildNeeded) {
-            menu = buildHelpMenu();
-        }
-        // @ts-expect-error
-        return menu;
-    }
-
-    /**
      * Show the help popup menu.
      */
     function showHelp() {
+        window.hideAllModals(false);
         // Prevent `blur` events from being dispatched as a result of closing
         // other modals.
-        const button = getHelpButton();
-        addClass(button, "help-open");
-        // @ts-expect-error
-        button.querySelector("a").focus();
-        const menu = getHelpMenu(true);
-        if (menu.style.display === "none") {
-            // @ts-expect-error
-            window.hideAllModals();
-            menu.style.display = "";
-        }
+        onEachLazy(document.querySelectorAll(".help-menu a"), menu => {
+            if (menu.offsetWidth !== 0) {
+                menu.focus();
+                return true;
+            }
+        });
+        buildHelpMenu();
     }
 
-    const helpLink = document.querySelector(`#${HELP_BUTTON_ID} > a`);
     if (isHelpPage) {
         buildHelpMenu();
-    } else if (helpLink) {
-        helpLink.addEventListener("click", event => {
-            // By default, have help button open docs in a popover.
-            // If user clicks with a moderator, though, use default browser behavior,
-            // probably opening in a new window or tab.
-            if (!helpLink.contains(helpLink) ||
-                // @ts-expect-error
-                event.ctrlKey ||
-                // @ts-expect-error
-                event.altKey ||
-                // @ts-expect-error
-                event.metaKey) {
-                return;
-            }
-            event.preventDefault();
-            const menu = getHelpMenu(true);
-            const shouldShowHelp = menu.style.display === "none";
-            if (shouldShowHelp) {
-                showHelp();
-            } else {
-                window.hidePopoverMenus();
-            }
+    } else {
+        onEachLazy(document.querySelectorAll(".help-menu > a"), helpLink => {
+            helpLink.addEventListener(
+                "click",
+                /** @param {MouseEvent} event */
+                event => {
+                    // By default, have help button open docs in a popover.
+                    // If user clicks with a moderator, though, use default browser behavior,
+                    // probably opening in a new window or tab.
+                    if (event.ctrlKey ||
+                        event.altKey ||
+                        event.metaKey) {
+                        return;
+                    }
+                    event.preventDefault();
+                    if (document.getElementById("help")) {
+                        window.hidePopoverMenus();
+                    } else {
+                        showHelp();
+                    }
+                },
+            );
         });
     }
 
-    setMobileTopbar();
     addSidebarItems();
     addSidebarCrates();
     onHashChange(null);
@@ -1746,7 +1841,15 @@ function preLoadCss(cssUrl) {
     // On larger, "desktop-sized" viewports (though that includes many
     // tablets), it's fixed-position, appears in the left side margin,
     // and it can be activated by resizing the sidebar into nothing.
-    const sidebarButton = document.getElementById("sidebar-button");
+    let sidebarButton = document.getElementById("sidebar-button");
+    const body = document.querySelector(".main-heading");
+    if (!sidebarButton && body) {
+        sidebarButton = document.createElement("div");
+        sidebarButton.id = "sidebar-button";
+        const path = `${window.rootPath}${window.currentCrate}/all.html`;
+        sidebarButton.innerHTML = `<a href="${path}" title="show sidebar"></a>`;
+        body.insertBefore(sidebarButton, body.firstChild);
+    }
     if (sidebarButton) {
         sidebarButton.addEventListener("click", e => {
             removeClass(document.documentElement, "hide-sidebar");
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
index 3d30a7adb98..28852125fe1 100644
--- a/src/librustdoc/html/static/js/rustdoc.d.ts
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -2,6 +2,8 @@
 // not put into the JavaScript we include as part of the documentation. It is used for
 // type checking. See README.md in this directory for more info.
 
+import { RoaringBitmap } from "./stringdex";
+
 /* eslint-disable */
 declare global {
     /** Search engine data used by main.js and search.js */
@@ -10,6 +12,17 @@ declare global {
     declare function nonnull(x: T|null, msg: string|undefined);
     /** Defined and documented in `storage.js` */
     declare function nonundef(x: T|undefined, msg: string|undefined);
+    interface PromiseConstructor {
+        /**
+         * Polyfill
+         * @template T
+         */
+        withResolvers: function(): {
+            "promise": Promise<T>,
+            "resolve": (function(T): void),
+            "reject": (function(any): void)
+        };
+    }
     interface Window {
         /** Make the current theme easy to find */
         currentTheme: HTMLLinkElement|null;
@@ -95,29 +108,28 @@ declare namespace rustdoc {
     interface SearchState {
         rustdocToolbar: HTMLElement|null;
         loadingText: string;
-        input: HTMLInputElement|null;
+        inputElement: function(): HTMLInputElement|null;
+        containerElement: function(): Element|null;
         title: string;
         titleBeforeSearch: string;
-        timeout: number|null;
+        timeout: ReturnType<typeof setTimeout>|null;
         currentTab: number;
-        focusedByTab: [number|null, number|null, number|null];
+        focusedByTab: [Element|null, Element|null, Element|null];
         clearInputTimeout: function;
-        outputElement(): HTMLElement|null;
-        focus();
-        defocus();
-        // note: an optional param is not the same as
-        // a nullable/undef-able param.
-        showResults(elem?: HTMLElement|null);
-        removeQueryParameters();
-        hideResults();
-        getQueryStringParams(): Object.<any, string>;
-        origPlaceholder: string;
+        outputElement: function(): Element|null;
+        focus: function();
+        defocus: function();
+        toggle: function();
+        showResults: function();
+        removeQueryParameters: function();
+        hideResults: function();
+        getQueryStringParams: function(): Object.<any, string>;
         setup: function();
         setLoadingSearch();
         descShards: Map<string, SearchDescShard[]>;
         loadDesc: function({descShard: SearchDescShard, descIndex: number}): Promise<string|null>;
-        loadedDescShard(string, number, string);
-        isDisplayed(): boolean,
+        loadedDescShard: function(string, number, string);
+        isDisplayed: function(): boolean;
     }
 
     interface SearchDescShard {
@@ -131,12 +143,13 @@ declare namespace rustdoc {
      * A single parsed "atom" in a search query. For example,
      * 
      *     std::fmt::Formatter, Write -> Result<()>
-     *     ┏━━━━━━━━━━━━━━━━━━  ┌────    ┏━━━━━┅┅┅┅┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
-     *     ┃                    │        ┗ QueryElement {        ┊
-     *     ┃                    │              name: Result      ┊
-     *     ┃                    │              generics: [       ┊
-     *     ┃                    │                   QueryElement ┘
-     *     ┃                    │                   name: ()
+     *     ┏━━━━━━━━━━━━━━━━━━  ┌────    ┏━━━━━┅┅┅┅┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
+     *     ┃                    │        ┗ QueryElement {          ┊
+     *     ┃                    │              name: Result        ┊
+     *     ┃                    │              generics: [         ┊
+     *     ┃                    │                   QueryElement { ┘
+     *     ┃                    │                       name: ()
+     *     ┃                    │                   }
      *     ┃                    │              ]
      *     ┃                    │          }
      *     ┃                    └ QueryElement {
@@ -156,14 +169,14 @@ declare namespace rustdoc {
         normalizedPathLast: string,
         generics: Array<QueryElement>,
         bindings: Map<number, Array<QueryElement>>,
-        typeFilter: number|null,
+        typeFilter: number,
     }
 
     /**
      * Same as QueryElement, but bindings and typeFilter support strings
      */
     interface ParserQueryElement {
-        name: string|null,
+        name: string,
         id: number|null,
         fullPath: Array<string>,
         pathWithoutLast: Array<string>,
@@ -172,7 +185,7 @@ declare namespace rustdoc {
         generics: Array<ParserQueryElement>,
         bindings: Map<string, Array<ParserQueryElement>>,
         bindingName: {name: string|null, generics: ParserQueryElement[]}|null,
-        typeFilter: number|string|null,
+        typeFilter: string|null,
     }
 
     /**
@@ -215,35 +228,74 @@ declare namespace rustdoc {
     /**
      * An entry in the search index database.
      */
+    interface EntryData {
+        krate: number,
+        ty: ItemType,
+        modulePath: number?,
+        exactModulePath: number?,
+        parent: number?,
+        deprecated: boolean,
+        associatedItemDisambiguator: string?,
+    }
+
+    /**
+     * A path in the search index database
+     */
+    interface PathData {
+        ty: ItemType,
+        modulePath: string,
+        exactModulePath: string?,
+    }
+
+    /**
+     * A function signature in the search index database
+     *
+     * Note that some non-function items (eg. constants, struct fields) have a function signature so they can appear in type-based search.
+     */
+    interface FunctionData {
+        functionSignature: FunctionSearchType|null,
+        paramNames: string[],
+        elemCount: number,
+    }
+
+    /**
+     * A function signature in the search index database
+     */
+    interface TypeData {
+        searchUnbox: boolean,
+        invertedFunctionSignatureIndex: RoaringBitmap[],
+    }
+
+    /**
+     * A search entry of some sort.
+     */
     interface Row {
-        crate: string,
-        descShard: SearchDescShard,
         id: number,
-        // This is the name of the item. For doc aliases, if you want the name of the aliased
-        // item, take a look at `Row.original.name`.
+        crate: string,
+        ty: ItemType,
         name: string,
         normalizedName: string,
-        word: string,
-        paramNames: string[],
-        parent: ({ty: number, name: string, path: string, exactPath: string}|null|undefined),
-        path: string,
-        ty: number,
-        type: FunctionSearchType | null,
-        descIndex: number,
-        bitIndex: number,
-        implDisambiguator: String | null,
-        is_alias?: boolean,
-        original?: Row,
+        modulePath: string,
+        exactModulePath: string,
+        entry: EntryData?,
+        path: PathData?,
+        type: FunctionData?,
+        deprecated: boolean,
+        parent: { path: PathData, name: string}?,
     }
 
+    type ItemType = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
+        11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
+        21 | 22 | 23 | 24 | 25 | 26;
+
     /**
      * The viewmodel for the search engine results page.
      */
     interface ResultsTable {
-        in_args: Array<ResultObject>,
-        returned: Array<ResultObject>,
-        others: Array<ResultObject>,
-        query: ParsedQuery,
+        in_args: AsyncGenerator<ResultObject>,
+        returned: AsyncGenerator<ResultObject>,
+        others: AsyncGenerator<ResultObject>,
+        query: ParsedQuery<rustdoc.ParserQueryElement>,
     }
 
     type Results = { max_dist?: number } & Map<number, ResultObject>
@@ -252,25 +304,41 @@ declare namespace rustdoc {
      * An annotated `Row`, used in the viewmodel.
      */
     interface ResultObject {
-        desc: string,
+        desc: Promise<string|null>,
         displayPath: string,
         fullPath: string,
         href: string,
         id: number,
         dist: number,
         path_dist: number,
-        name: string,
-        normalizedName: string,
-        word: string,
         index: number,
-        parent: (Object|undefined),
-        path: string,
-        ty: number,
+        parent: ({
+            path: string,
+            exactPath: string,
+            name: string,
+            ty: number,
+        }|undefined),
         type?: FunctionSearchType,
         paramNames?: string[],
         displayTypeSignature: Promise<rustdoc.DisplayTypeSignature> | null,
         item: Row,
-        dontValidate?: boolean,
+        is_alias: boolean,
+        alias?: string,
+    }
+
+    /**
+     * An annotated `Row`, used in the viewmodel.
+     */
+    interface PlainResultObject {
+        id: number,
+        dist: number,
+        path_dist: number,
+        index: number,
+        elems: rustdoc.QueryElement[],
+        returned: rustdoc.QueryElement[],
+        is_alias: boolean,
+        alias?: string,
+        original?: rustdoc.Rlow,
     }
 
     /**
@@ -364,7 +432,19 @@ declare namespace rustdoc {
      * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
      * because `null` is four bytes while `0` is one byte.
      */
-    type RawFunctionType = number | [number, Array<RawFunctionType>];
+    type RawFunctionType = number | [number, Array<RawFunctionType>] | [number, Array<RawFunctionType>, Array<[RawFunctionType, RawFunctionType[]]>];
+
+    /**
+     * Utility typedef for deserializing compact JSON.
+     *
+     * R is the required part, O is the optional part, which goes afterward.
+     * For example, `ArrayWithOptionals<[A, B], [C, D]>` matches
+     * `[A, B] | [A, B, C] | [A, B, C, D]`.
+     */
+    type ArrayWithOptionals<R extends any[], O extends any[]> =
+        O extends [infer First, ...infer Rest] ?
+            R | ArrayWithOptionals<[...R, First], Rest> :
+            R;
 
     /**
      * The type signature entry in the decoded search index.
@@ -382,8 +462,8 @@ declare namespace rustdoc {
      */
     interface FunctionType {
         id: null|number,
-        ty: number|null,
-        name?: string,
+        ty: ItemType,
+        name: string|null,
         path: string|null,
         exactPath: string|null,
         unboxFlag: boolean,
@@ -403,70 +483,6 @@ declare namespace rustdoc {
         bindings: Map<number, FingerprintableType[]>;
     };
 
-    /**
-     * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f`
-     * are arrays with the same length. `q`, `a`, and `c` use a sparse
-     * representation for compactness.
-     *
-     * `n[i]` contains the name of an item.
-     *
-     * `t[i]` contains the type of that item
-     * (as a string of characters that represent an offset in `itemTypes`).
-     *
-     * `d[i]` contains the description of that item.
-     *
-     * `q` contains the full paths of the items. For compactness, it is a set of
-     * (index, path) pairs used to create a map. If a given index `i` is
-     * not present, this indicates "same as the last index present".
-     *
-     * `i[i]` contains an item's parent, usually a module. For compactness,
-     * it is a set of indexes into the `p` array.
-     *
-     * `f` contains function signatures, or `0` if the item isn't a function.
-     * More information on how they're encoded can be found in rustc-dev-guide
-     *
-     * Functions are themselves encoded as arrays. The first item is a list of
-     * types representing the function's inputs, and the second list item is a list
-     * of types representing the function's output. Tuples are flattened.
-     * Types are also represented as arrays; the first item is an index into the `p`
-     * array, while the second is a list of types representing any generic parameters.
-     *
-     * b[i] contains an item's impl disambiguator. This is only present if an item
-     * is defined in an impl block and, the impl block's type has more than one associated
-     * item with the same name.
-     *
-     * `a` defines aliases with an Array of pairs: [name, offset], where `offset`
-     * points into the n/t/d/q/i/f arrays.
-     *
-     * `doc` contains the description of the crate.
-     *
-     * `p` is a list of path/type pairs. It is used for parents and function parameters.
-     * The first item is the type, the second is the name, the third is the visible path (if any) and
-     * the fourth is the canonical path used for deduplication (if any).
-     *
-     * `r` is the canonical path used for deduplication of re-exported items.
-     * It is not used for associated items like methods (that's the fourth element
-     * of `p`) but is used for modules items like free functions.
-     *
-     * `c` is an array of item indices that are deprecated.
-     */
-    type RawSearchIndexCrate = {
-    doc: string,
-    a: { [key: string]: number[] },
-    n: Array<string>,
-    t: string,
-    D: string,
-    e: string,
-    q: Array<[number, string]>,
-    i: string,
-    f: string,
-    p: Array<[number, string] | [number, string, number] | [number, string, number, number] | [number, string, number, number, string]>,
-    b: Array<[number, String]>,
-    c: string,
-    r: Array<[number, number]>,
-    P: Array<[number, string]>,
-    };
-
     type VlqData = VlqData[] | number;
 
     /**
@@ -498,4 +514,13 @@ declare namespace rustdoc {
         options?: string[],
         default: string | boolean,
     }
+
+    /**
+     * Single element in the data-locs field of a scraped example.
+     * First field is the start and end char index,
+     * other fields seem to be unused.
+     *
+     * Generated by `render_call_locations` in `render/mod.rs`.
+     */
+    type ScrapedLoc = [[number, number], string, string]
 }
diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js
index d641405c875..eeab591bcd8 100644
--- a/src/librustdoc/html/static/js/scrape-examples.js
+++ b/src/librustdoc/html/static/js/scrape-examples.js
@@ -1,7 +1,4 @@
-/* global addClass, hasClass, removeClass, onEachLazy */
-
-// Eventually fix this.
-// @ts-nocheck
+ /* global addClass, hasClass, removeClass, onEachLazy, nonnull */
 
 "use strict";
 
@@ -14,8 +11,16 @@
     const DEFAULT_MAX_LINES = 5;
     const HIDDEN_MAX_LINES = 10;
 
-    // Scroll code block to the given code location
+    /**
+     * Scroll code block to the given code location
+     * @param {HTMLElement} elt
+     * @param {[number, number]} loc
+     * @param {boolean} isHidden
+     */
     function scrollToLoc(elt, loc, isHidden) {
+        /** @type {HTMLElement[]} */
+        // blocked on https://github.com/microsoft/TypeScript/issues/29037
+        // @ts-expect-error
         const lines = elt.querySelectorAll("[data-nosnippet]");
         let scrollOffset;
 
@@ -35,10 +40,15 @@
             scrollOffset = offsetMid - halfHeight;
         }
 
-        lines[0].parentElement.scrollTo(0, scrollOffset);
-        elt.querySelector(".rust").scrollTo(0, scrollOffset);
+        nonnull(lines[0].parentElement).scrollTo(0, scrollOffset);
+        nonnull(elt.querySelector(".rust")).scrollTo(0, scrollOffset);
     }
 
+    /**
+     * @param {HTMLElement} parent
+     * @param {string} className
+     * @param {string} content
+     */
     function createScrapeButton(parent, className, content) {
         const button = document.createElement("button");
         button.className = className;
@@ -50,20 +60,24 @@
     window.updateScrapedExample = (example, buttonHolder) => {
         let locIndex = 0;
         const highlights = Array.prototype.slice.call(example.querySelectorAll(".highlight"));
-        const link = example.querySelector(".scraped-example-title a");
+
+        /** @type {HTMLAnchorElement} */
+        const link = nonnull(example.querySelector(".scraped-example-title a"));
         let expandButton = null;
 
         if (!example.classList.contains("expanded")) {
             expandButton = createScrapeButton(buttonHolder, "expand", "Show all");
         }
-        const isHidden = example.parentElement.classList.contains("more-scraped-examples");
+        const isHidden = nonnull(example.parentElement).classList.contains("more-scraped-examples");
 
+        // @ts-expect-error
         const locs = example.locs;
         if (locs.length > 1) {
             const next = createScrapeButton(buttonHolder, "next", "Next usage");
             const prev = createScrapeButton(buttonHolder, "prev", "Previous usage");
 
             // Toggle through list of examples in a given file
+            /** @type {function(function(): void): void} */
             const onChangeLoc = changeIndex => {
                 removeClass(highlights[locIndex], "focus");
                 changeIndex();
@@ -106,10 +120,19 @@
         }
     };
 
+    /**
+     * Initialize the `locs` field
+     *
+     * @param {HTMLElement & {locs?: rustdoc.ScrapedLoc[]}} example
+     * @param {boolean} isHidden
+     */
     function setupLoc(example, isHidden) {
-        example.locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
+        const locs_str = nonnull(example.attributes.getNamedItem("data-locs")).textContent;
+        const locs =
+              JSON.parse(nonnull(nonnull(locs_str)));
+        example.locs = locs;
         // Start with the first example in view
-        scrollToLoc(example, example.locs[0][0], isHidden);
+        scrollToLoc(example, locs[0][0], isHidden);
     }
 
     const firstExamples = document.querySelectorAll(".scraped-example-list > .scraped-example");
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 505652c0f4a..d55208150b8 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1,9 +1,16 @@
 // ignore-tidy-filelength
-/* global addClass, getNakedUrl, getSettingValue, getVar */
-/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */
+/* global addClass, getNakedUrl, getVar, nonnull, getSettingValue */
+/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi */
 
 "use strict";
 
+/**
+ * @param {stringdex.Stringdex} Stringdex
+ * @param {typeof stringdex.RoaringBitmap} RoaringBitmap
+ * @param {stringdex.Hooks} hooks
+ */
+const initSearch = async function(Stringdex, RoaringBitmap, hooks) {
+
 // polyfill
 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSpliced
 if (!Array.prototype.toSpliced) {
@@ -20,31 +27,65 @@ if (!Array.prototype.toSpliced) {
  *
  * @template T
  * @param {Iterable<T>} arr
- * @param {function(T): any} func
+ * @param {function(T): Promise<any>} func
  * @param {function(T): boolean} funcBtwn
  */
-function onEachBtwn(arr, func, funcBtwn) {
+async function onEachBtwnAsync(arr, func, funcBtwn) {
     let skipped = true;
     for (const value of arr) {
         if (!skipped) {
             funcBtwn(value);
         }
-        skipped = func(value);
+        skipped = await func(value);
     }
 }
 
 /**
- * Convert any `undefined` to `null`.
- *
- * @template T
- * @param {T|undefined} x
- * @returns {T|null}
+ * Allow the browser to redraw.
+ * @returns {Promise<void>}
  */
-function undef2null(x) {
-    if (x !== undefined) {
-        return x;
-    }
-    return null;
+const yieldToBrowser = typeof window !== "undefined" && window.requestIdleCallback ?
+    function() {
+        return new Promise((resolve, _reject) => {
+            window.requestIdleCallback(resolve);
+        });
+    } :
+    function() {
+        return new Promise((resolve, _reject) => {
+            setTimeout(resolve, 0);
+        });
+    };
+
+/**
+ * Promise-based timer wrapper.
+ * @param {number} ms
+ * @returns {Promise<void>}
+ */
+const timeout = function(ms) {
+    return new Promise((resolve, _reject) => {
+        setTimeout(resolve, ms);
+    });
+};
+
+if (!Promise.withResolvers) {
+    /**
+     * Polyfill
+     * @template T
+     * @returns {{
+            "promise": Promise<T>,
+            "resolve": (function(T): void),
+            "reject": (function(any): void)
+        }}
+     */
+    Promise.withResolvers = () => {
+        let resolve, reject;
+        const promise = new Promise((res, rej) => {
+          resolve = res;
+          reject = rej;
+        });
+        // @ts-expect-error
+        return {promise, resolve, reject};
+    };
 }
 
 // ==================== Core search logic begin ====================
@@ -81,13 +122,22 @@ const itemTypes = [
 ];
 
 // used for special search precedence
-const TY_PRIMITIVE = itemTypes.indexOf("primitive");
-const TY_GENERIC = itemTypes.indexOf("generic");
-const TY_IMPORT = itemTypes.indexOf("import");
-const TY_TRAIT = itemTypes.indexOf("trait");
-const TY_FN = itemTypes.indexOf("fn");
-const TY_METHOD = itemTypes.indexOf("method");
-const TY_TYMETHOD = itemTypes.indexOf("tymethod");
+/** @type {rustdoc.ItemType} */
+const TY_PRIMITIVE = 1;
+/** @type {rustdoc.ItemType} */
+const TY_GENERIC = 26;
+/** @type {rustdoc.ItemType} */
+const TY_IMPORT = 4;
+/** @type {rustdoc.ItemType} */
+const TY_TRAIT = 10;
+/** @type {rustdoc.ItemType} */
+const TY_FN = 7;
+/** @type {rustdoc.ItemType} */
+const TY_METHOD = 13;
+/** @type {rustdoc.ItemType} */
+const TY_TYMETHOD = 12;
+/** @type {rustdoc.ItemType} */
+const TY_ASSOCTYPE = 17;
 const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../";
 
 // Hard limit on how deep to recurse into generics when doing type-driven search.
@@ -242,7 +292,9 @@ function isEndCharacter(c) {
 }
 
 /**
- * @param {number} ty
+ * Same thing as ItemType::is_fn_like in item_type.rs
+ *
+ * @param {rustdoc.ItemType} ty
  * @returns
  */
 function isFnLikeTy(ty) {
@@ -1023,6 +1075,7 @@ class VlqHexDecoder {
         this.string = string;
         this.cons = cons;
         this.offset = 0;
+        this.elemCount = 0;
         /** @type {T[]} */
         this.backrefQueue = [];
     }
@@ -1060,6 +1113,7 @@ class VlqHexDecoder {
         n = (n << 4) | (c & 0xF);
         const [sign, value] = [n & 1, n >> 1];
         this.offset += 1;
+        this.elemCount += 1;
         return sign ? -value : value;
     }
     /**
@@ -1086,1247 +1140,138 @@ class VlqHexDecoder {
         return result;
     }
 }
-class RoaringBitmap {
-    /** @param {string} str */
-    constructor(str) {
-        // https://github.com/RoaringBitmap/RoaringFormatSpec
-        //
-        // Roaring bitmaps are used for flags that can be kept in their
-        // compressed form, even when loaded into memory. This decoder
-        // turns the containers into objects, but uses byte array
-        // slices of the original format for the data payload.
-        const strdecoded = atob(str);
-        const u8array = new Uint8Array(strdecoded.length);
-        for (let j = 0; j < strdecoded.length; ++j) {
-            u8array[j] = strdecoded.charCodeAt(j);
-        }
-        const has_runs = u8array[0] === 0x3b;
-        const size = has_runs ?
-            ((u8array[2] | (u8array[3] << 8)) + 1) :
-            ((u8array[4] | (u8array[5] << 8) | (u8array[6] << 16) | (u8array[7] << 24)));
-        let i = has_runs ? 4 : 8;
-        let is_run;
-        if (has_runs) {
-            const is_run_len = Math.floor((size + 7) / 8);
-            is_run = u8array.slice(i, i + is_run_len);
-            i += is_run_len;
-        } else {
-            is_run = new Uint8Array();
-        }
-        this.keys = [];
-        this.cardinalities = [];
-        for (let j = 0; j < size; ++j) {
-            this.keys.push(u8array[i] | (u8array[i + 1] << 8));
-            i += 2;
-            this.cardinalities.push((u8array[i] | (u8array[i + 1] << 8)) + 1);
-            i += 2;
-        }
-        this.containers = [];
-        let offsets = null;
-        if (!has_runs || this.keys.length >= 4) {
-            offsets = [];
-            for (let j = 0; j < size; ++j) {
-                offsets.push(u8array[i] | (u8array[i + 1] << 8) | (u8array[i + 2] << 16) |
-                    (u8array[i + 3] << 24));
-                i += 4;
-            }
-        }
-        for (let j = 0; j < size; ++j) {
-            if (offsets && offsets[j] !== i) {
-                // eslint-disable-next-line no-console
-                console.log(this.containers);
-                throw new Error(`corrupt bitmap ${j}: ${i} / ${offsets[j]}`);
-            }
-            if (is_run[j >> 3] & (1 << (j & 0x7))) {
-                const runcount = (u8array[i] | (u8array[i + 1] << 8));
-                i += 2;
-                this.containers.push(new RoaringBitmapRun(
-                    runcount,
-                    u8array.slice(i, i + (runcount * 4)),
-                ));
-                i += runcount * 4;
-            } else if (this.cardinalities[j] >= 4096) {
-                this.containers.push(new RoaringBitmapBits(u8array.slice(i, i + 8192)));
-                i += 8192;
-            } else {
-                const end = this.cardinalities[j] * 2;
-                this.containers.push(new RoaringBitmapArray(
-                    this.cardinalities[j],
-                    u8array.slice(i, i + end),
-                ));
-                i += end;
-            }
-        }
-    }
-    /** @param {number} keyvalue */
-    contains(keyvalue) {
-        const key = keyvalue >> 16;
-        const value = keyvalue & 0xFFFF;
-        // Binary search algorithm copied from
-        // https://en.wikipedia.org/wiki/Binary_search#Procedure
-        //
-        // Format is required by specification to be sorted.
-        // Because keys are 16 bits and unique, length can't be
-        // bigger than 2**16, and because we have 32 bits of safe int,
-        // left + right can't overflow.
-        let left = 0;
-        let right = this.keys.length - 1;
-        while (left <= right) {
-            const mid = Math.floor((left + right) / 2);
-            const x = this.keys[mid];
-            if (x < key) {
-                left = mid + 1;
-            } else if (x > key) {
-                right = mid - 1;
-            } else {
-                return this.containers[mid].contains(value);
-            }
-        }
-        return false;
-    }
-}
 
-class RoaringBitmapRun {
-    /**
-     * @param {number} runcount
-     * @param {Uint8Array} array
-     */
-    constructor(runcount, array) {
-        this.runcount = runcount;
-        this.array = array;
-    }
-    /** @param {number} value */
-    contains(value) {
-        // Binary search algorithm copied from
-        // https://en.wikipedia.org/wiki/Binary_search#Procedure
-        //
-        // Since runcount is stored as 16 bits, left + right
-        // can't overflow.
-        let left = 0;
-        let right = this.runcount - 1;
-        while (left <= right) {
-            const mid = Math.floor((left + right) / 2);
-            const i = mid * 4;
-            const start = this.array[i] | (this.array[i + 1] << 8);
-            const lenm1 = this.array[i + 2] | (this.array[i + 3] << 8);
-            if ((start + lenm1) < value) {
-                left = mid + 1;
-            } else if (start > value) {
-                right = mid - 1;
-            } else {
-                return true;
-            }
-        }
-        return false;
-    }
-}
-class RoaringBitmapArray {
-    /**
-     * @param {number} cardinality
-     * @param {Uint8Array} array
-     */
-    constructor(cardinality, array) {
-        this.cardinality = cardinality;
-        this.array = array;
-    }
-    /** @param {number} value */
-    contains(value) {
-        // Binary search algorithm copied from
-        // https://en.wikipedia.org/wiki/Binary_search#Procedure
-        //
-        // Since cardinality can't be higher than 4096, left + right
-        // cannot overflow.
-        let left = 0;
-        let right = this.cardinality - 1;
-        while (left <= right) {
-            const mid = Math.floor((left + right) / 2);
-            const i = mid * 2;
-            const x = this.array[i] | (this.array[i + 1] << 8);
-            if (x < value) {
-                left = mid + 1;
-            } else if (x > value) {
-                right = mid - 1;
-            } else {
-                return true;
-            }
-        }
-        return false;
-    }
-}
-class RoaringBitmapBits {
-    /**
-     * @param {Uint8Array} array
-     */
-    constructor(array) {
-        this.array = array;
-    }
-    /** @param {number} value */
-    contains(value) {
-        return !!(this.array[value >> 3] & (1 << (value & 7)));
-    }
-}
+/** @type {Array<string>} */
+const EMPTY_STRING_ARRAY = [];
+
+/** @type {Array<rustdoc.FunctionType>} */
+const EMPTY_GENERICS_ARRAY = [];
+
+/** @type {Array<[number, rustdoc.FunctionType[]]>} */
+const EMPTY_BINDINGS_ARRAY = [];
+
+/** @type {Map<number, Array<any>>} */
+const EMPTY_BINDINGS_MAP = new Map();
 
 /**
- * A prefix tree, used for name-based search.
- *
- * This data structure is used to drive prefix matches,
- * such as matching the query "link" to `LinkedList`,
- * and Lev-distance matches, such as matching the
- * query "hahsmap" to `HashMap`. Substring matches,
- * such as "list" to `LinkedList`, are done with a
- * tailTable that deep-links into this trie.
- *
- * children
- * : A [sparse array] of subtrees. The array index
- *   is a charCode.
- *
- *   [sparse array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/
- *     Indexed_collections#sparse_arrays
- *
- * matches
- * : A list of search index IDs for this node.
- *
- * @type {{
- *     children: NameTrie[],
- *     matches: number[],
- * }}
+ * @param {string|null} typename
+ * @returns {number}
  */
-class NameTrie {
-    constructor() {
-        this.children = [];
-        this.matches = [];
+function itemTypeFromName(typename) {
+    if (typename === null) {
+        return NO_TYPE_FILTER;
     }
-    /**
-     * @param {string} name
-     * @param {number} id
-     * @param {Map<string, NameTrie[]>} tailTable
-     */
-    insert(name, id, tailTable) {
-        this.insertSubstring(name, 0, id, tailTable);
-    }
-    /**
-     * @param {string} name
-     * @param {number} substart
-     * @param {number} id
-     * @param {Map<string, NameTrie[]>} tailTable
-     */
-    insertSubstring(name, substart, id, tailTable) {
-        const l = name.length;
-        if (substart === l) {
-            this.matches.push(id);
-        } else {
-            const sb = name.charCodeAt(substart);
-            let child;
-            if (this.children[sb] !== undefined) {
-                child = this.children[sb];
-            } else {
-                child = new NameTrie();
-                this.children[sb] = child;
-                /** @type {NameTrie[]} */
-                let sste;
-                if (substart >= 2) {
-                    const tail = name.substring(substart - 2, substart + 1);
-                    const entry = tailTable.get(tail);
-                    if (entry !== undefined) {
-                        sste = entry;
-                    } else {
-                        sste = [];
-                        tailTable.set(tail, sste);
-                    }
-                    sste.push(child);
-                }
-            }
-            child.insertSubstring(name, substart + 1, id, tailTable);
-        }
-    }
-    /**
-     * @param {string} name
-     * @param {Map<string, NameTrie[]>} tailTable
-     */
-    search(name, tailTable) {
-        const results = new Set();
-        this.searchSubstringPrefix(name, 0, results);
-        if (results.size < MAX_RESULTS && name.length >= 3) {
-            const levParams = name.length >= 6 ?
-                new Lev2TParametricDescription(name.length) :
-                new Lev1TParametricDescription(name.length);
-            this.searchLev(name, 0, levParams, results);
-            const tail = name.substring(0, 3);
-            const list = tailTable.get(tail);
-            if (list !== undefined) {
-                for (const entry of list) {
-                    entry.searchSubstringPrefix(name, 3, results);
-                }
-            }
-        }
-        return [...results];
-    }
-    /**
-     * @param {string} name
-     * @param {number} substart
-     * @param {Set<number>} results
-     */
-    searchSubstringPrefix(name, substart, results) {
-        const l = name.length;
-        if (substart === l) {
-            for (const match of this.matches) {
-                results.add(match);
-            }
-            // breadth-first traversal orders prefix matches by length
-            /** @type {NameTrie[]} */
-            let unprocessedChildren = [];
-            for (const child of this.children) {
-                if (child) {
-                    unprocessedChildren.push(child);
-                }
-            }
-            /** @type {NameTrie[]} */
-            let nextSet = [];
-            while (unprocessedChildren.length !== 0) {
-                /** @type {NameTrie} */
-                // @ts-expect-error
-                const next = unprocessedChildren.pop();
-                for (const child of next.children) {
-                    if (child) {
-                        nextSet.push(child);
-                    }
-                }
-                for (const match of next.matches) {
-                    results.add(match);
-                }
-                if (unprocessedChildren.length === 0) {
-                    const tmp = unprocessedChildren;
-                    unprocessedChildren = nextSet;
-                    nextSet = tmp;
-                }
-            }
-        } else {
-            const sb = name.charCodeAt(substart);
-            if (this.children[sb] !== undefined) {
-                this.children[sb].searchSubstringPrefix(name, substart + 1, results);
-            }
-        }
-    }
-    /**
-     * @param {string} name
-     * @param {number} substart
-     * @param {Lev2TParametricDescription|Lev1TParametricDescription} levParams
-     * @param {Set<number>} results
-     */
-    searchLev(name, substart, levParams, results) {
-        const stack = [[this, 0]];
-        const n = levParams.n;
-        while (stack.length !== 0) {
-            // It's not empty
-            //@ts-expect-error
-            const [trie, levState] = stack.pop();
-            for (const [charCode, child] of trie.children.entries()) {
-                if (!child) {
-                    continue;
-                }
-                const levPos = levParams.getPosition(levState);
-                const vector = levParams.getVector(
-                    name,
-                    charCode,
-                    levPos,
-                    Math.min(name.length, levPos + (2 * n) + 1),
-                );
-                const newLevState = levParams.transition(
-                    levState,
-                    levPos,
-                    vector,
-                );
-                if (newLevState >= 0) {
-                    stack.push([child, newLevState]);
-                    if (levParams.isAccept(newLevState)) {
-                        for (const match of child.matches) {
-                            results.add(match);
-                        }
-                    }
-                }
-            }
-        }
+    const index = itemTypes.findIndex(i => i === typename);
+    if (index < 0) {
+        throw ["Unknown type filter ", typename];
     }
+    return index;
 }
 
 class DocSearch {
     /**
-     * @param {Map<string, rustdoc.RawSearchIndexCrate>} rawSearchIndex
      * @param {string} rootPath
-     * @param {rustdoc.SearchState} searchState
+     * @param {stringdex.Database} database
      */
-    constructor(rawSearchIndex, rootPath, searchState) {
-        /**
-         * @type {Map<String, RoaringBitmap>}
-         */
-        this.searchIndexDeprecated = new Map();
-        /**
-         * @type {Map<String, RoaringBitmap>}
-         */
-        this.searchIndexEmptyDesc = new Map();
-        /**
-         *  @type {Uint32Array}
-         */
-        this.functionTypeFingerprint = new Uint32Array(0);
-        /**
-         * Map from normalized type names to integers. Used to make type search
-         * more efficient.
-         *
-         * @type {Map<string, {id: number, assocOnly: boolean}>}
-         */
-        this.typeNameIdMap = new Map();
-        /**
-         * Map from type ID to associated type name. Used for display,
-         * not for search.
-         *
-         * @type {Map<number, string>}
-         */
-        this.assocTypeIdNameMap = new Map();
-        this.ALIASES = new Map();
-        this.FOUND_ALIASES = new Set();
+    constructor(rootPath, database) {
         this.rootPath = rootPath;
-        this.searchState = searchState;
+        this.database = database;
 
-        /**
-         * Special type name IDs for searching by array.
-         * @type {number}
-         */
-        this.typeNameIdOfArray = this.buildTypeMapIndex("array");
-        /**
-         * Special type name IDs for searching by slice.
-         * @type {number}
-         */
-        this.typeNameIdOfSlice = this.buildTypeMapIndex("slice");
-        /**
-         * Special type name IDs for searching by both array and slice (`[]` syntax).
-         * @type {number}
-         */
-        this.typeNameIdOfArrayOrSlice = this.buildTypeMapIndex("[]");
-        /**
-         * Special type name IDs for searching by tuple.
-         * @type {number}
-         */
-        this.typeNameIdOfTuple = this.buildTypeMapIndex("tuple");
-        /**
-         * Special type name IDs for searching by unit.
-         * @type {number}
-         */
-        this.typeNameIdOfUnit = this.buildTypeMapIndex("unit");
-        /**
-         * Special type name IDs for searching by both tuple and unit (`()` syntax).
-         * @type {number}
-         */
-        this.typeNameIdOfTupleOrUnit = this.buildTypeMapIndex("()");
-        /**
-         * Special type name IDs for searching `fn`.
-         * @type {number}
-         */
-        this.typeNameIdOfFn = this.buildTypeMapIndex("fn");
-        /**
-         * Special type name IDs for searching `fnmut`.
-         * @type {number}
-         */
-        this.typeNameIdOfFnMut = this.buildTypeMapIndex("fnmut");
-        /**
-         * Special type name IDs for searching `fnonce`.
-         * @type {number}
-         */
-        this.typeNameIdOfFnOnce = this.buildTypeMapIndex("fnonce");
-        /**
-         * Special type name IDs for searching higher order functions (`->` syntax).
-         * @type {number}
-         */
-        this.typeNameIdOfHof = this.buildTypeMapIndex("->");
-        /**
-         * Special type name IDs the output assoc type.
-         * @type {number}
-         */
-        this.typeNameIdOfOutput = this.buildTypeMapIndex("output", true);
-        /**
-         * Special type name IDs for searching by reference.
-         * @type {number}
-         */
-        this.typeNameIdOfReference = this.buildTypeMapIndex("reference");
+        this.typeNameIdOfOutput = -1;
+        this.typeNameIdOfArray = -1;
+        this.typeNameIdOfSlice = -1;
+        this.typeNameIdOfArrayOrSlice = -1;
+        this.typeNameIdOfTuple = -1;
+        this.typeNameIdOfUnit = -1;
+        this.typeNameIdOfTupleOrUnit = -1;
+        this.typeNameIdOfReference = -1;
+        this.typeNameIdOfHof = -1;
 
-        /**
-         * Empty, immutable map used in item search types with no bindings.
-         *
-         * @type {Map<number, Array<any>>}
-         */
-        this.EMPTY_BINDINGS_MAP = new Map();
+        this.utf8decoder = new TextDecoder();
 
-        /**
-         * Empty, immutable map used in item search types with no bindings.
-         *
-         * @type {Array<any>}
-         */
-        this.EMPTY_GENERICS_ARRAY = [];
-
-        /**
-         * Object pool for function types with no bindings or generics.
-         * This is reset after loading the index.
-         *
-         * @type {Map<number|null, rustdoc.FunctionType>}
-         */
+        /** @type {Map<number|null, rustdoc.FunctionType>} */
         this.TYPES_POOL = new Map();
-
-        /**
-         * A trie for finding items by name.
-         * This is used for edit distance and prefix finding.
-         *
-         * @type {NameTrie}
-         */
-        this.nameTrie = new NameTrie();
-
-        /**
-         * Find items by 3-substring. This is a map from three-char
-         * prefixes into lists of subtries.
-         */
-        this.tailTable = new Map();
-
-        /**
-         *  @type {Array<rustdoc.Row>}
-         */
-        this.searchIndex = this.buildIndex(rawSearchIndex);
     }
 
     /**
-     * Add an item to the type Name->ID map, or, if one already exists, use it.
-     * Returns the number. If name is "" or null, return null (pure generic).
-     *
-     * This is effectively string interning, so that function matching can be
-     * done more quickly. Two types with the same name but different item kinds
-     * get the same ID.
-     *
-     * @template T extends string
-     * @overload
-     * @param {T} name
-     * @param {boolean=} isAssocType - True if this is an assoc type
-     * @returns {T extends "" ? null : number}
-     *
-     * @param {string} name
-     * @param {boolean=} isAssocType
-     * @returns {number | null}
-     *
+     * Load search index. If you do not call this function, `execQuery`
+     * will never fulfill.
      */
-    buildTypeMapIndex(name, isAssocType) {
-        if (name === "" || name === null) {
-            return null;
-        }
-
-        const obj = this.typeNameIdMap.get(name);
-        if (obj !== undefined) {
-            obj.assocOnly = !!(isAssocType && obj.assocOnly);
-            return obj.id;
-        } else {
-            const id = this.typeNameIdMap.size;
-            this.typeNameIdMap.set(name, { id, assocOnly: !!isAssocType });
-            return id;
-        }
-    }
-
-    /**
-     * Convert a list of RawFunctionType / ID to object-based FunctionType.
-     *
-     * Crates often have lots of functions in them, and it's common to have a large number of
-     * functions that operate on a small set of data types, so the search index compresses them
-     * by encoding function parameter and return types as indexes into an array of names.
-     *
-     * Even when a general-purpose compression algorithm is used, this is still a win.
-     * I checked. https://github.com/rust-lang/rust/pull/98475#issue-1284395985
-     *
-     * The format for individual function types is encoded in
-     * librustdoc/html/render/mod.rs: impl Serialize for RenderType
-     *
-     * @param {null|Array<rustdoc.RawFunctionType>} types
-     * @param {Array<{
-     *     name: string,
-    *     ty: number,
-    *     path: string|null,
-    *     exactPath: string|null,
-    *     unboxFlag: boolean
-    * }>} paths
-    * @param {Array<{
-    *     name: string,
-    *     ty: number,
-    *     path: string|null,
-    *     exactPath: string|null,
-    *     unboxFlag: boolean,
-    * }>} lowercasePaths
-     *
-     * @return {Array<rustdoc.FunctionType>}
-     */
-    buildItemSearchTypeAll(types, paths, lowercasePaths) {
-        return types && types.length > 0 ?
-            types.map(type => this.buildItemSearchType(type, paths, lowercasePaths)) :
-            this.EMPTY_GENERICS_ARRAY;
-    }
-
-    /**
-     * Converts a single type.
-     *
-     * @param {rustdoc.RawFunctionType} type
-     * @param {Array<{
-     *     name: string,
-     *     ty: number,
-     *     path: string|null,
-     *     exactPath: string|null,
-     *     unboxFlag: boolean
-     * }>} paths
-     * @param {Array<{
-     *     name: string,
-     *     ty: number,
-     *     path: string|null,
-     *     exactPath: string|null,
-     *     unboxFlag: boolean,
-     * }>} lowercasePaths
-     * @param {boolean=} isAssocType
-     */
-    buildItemSearchType(type, paths, lowercasePaths, isAssocType) {
-        const PATH_INDEX_DATA = 0;
-        const GENERICS_DATA = 1;
-        const BINDINGS_DATA = 2;
-        let pathIndex, generics, bindings;
-        if (typeof type === "number") {
-            pathIndex = type;
-            generics = this.EMPTY_GENERICS_ARRAY;
-            bindings = this.EMPTY_BINDINGS_MAP;
-        } else {
-            pathIndex = type[PATH_INDEX_DATA];
-            generics = this.buildItemSearchTypeAll(
-                type[GENERICS_DATA],
-                paths,
-                lowercasePaths,
-            );
-            // @ts-expect-error
-            if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) {
-                // @ts-expect-error
-                bindings = new Map(type[BINDINGS_DATA].map(binding => {
-                    const [assocType, constraints] = binding;
-                    // Associated type constructors are represented sloppily in rustdoc's
-                    // type search, to make the engine simpler.
-                    //
-                    // MyType<Output<T>=Result<T>> is equivalent to MyType<Output<Result<T>>=T>
-                    // and both are, essentially
-                    // MyType<Output=(T, Result<T>)>, except the tuple isn't actually there.
-                    // It's more like the value of a type binding is naturally an array,
-                    // which rustdoc calls "constraints".
-                    //
-                    // As a result, the key should never have generics on it.
-                    return [
-                        this.buildItemSearchType(assocType, paths, lowercasePaths, true).id,
-                        this.buildItemSearchTypeAll(constraints, paths, lowercasePaths),
-                    ];
-                }));
-            } else {
-                bindings = this.EMPTY_BINDINGS_MAP;
-            }
+    async buildIndex() {
+        const nn = this.database.getIndex("normalizedName");
+        if (!nn) {
+            return;
         }
+        // Each of these identifiers are used specially by
+        // type-driven search.
+        const [
+            // output is the special associated type that goes
+            // after the arrow: the type checker desugars
+            // the path `Fn(a) -> b` into `Fn<Output=b, (a)>`
+            output,
+            // fn, fnmut, and fnonce all match `->`
+            fn,
+            fnMut,
+            fnOnce,
+            hof,
+            // array and slice both match `[]`
+            array,
+            slice,
+            arrayOrSlice,
+            // tuple and unit both match `()`
+            tuple,
+            unit,
+            tupleOrUnit,
+            // reference matches `&`
+            reference,
+            // never matches `!`
+            never,
+        ] = await Promise.all([
+            nn.search("output"),
+            nn.search("fn"),
+            nn.search("fnmut"),
+            nn.search("fnonce"),
+            nn.search("->"),
+            nn.search("array"),
+            nn.search("slice"),
+            nn.search("[]"),
+            nn.search("tuple"),
+            nn.search("unit"),
+            nn.search("()"),
+            nn.search("reference"),
+            nn.search("never"),
+        ]);
         /**
-         * @type {rustdoc.FunctionType}
-         */
-        let result;
-        if (pathIndex < 0) {
-            // types less than 0 are generic parameters
-            // the actual names of generic parameters aren't stored, since they aren't API
-            result = {
-                id: pathIndex,
-                name: "",
-                ty: TY_GENERIC,
-                path: null,
-                exactPath: null,
-                generics,
-                bindings,
-                unboxFlag: true,
-            };
-        } else if (pathIndex === 0) {
-            // `0` is used as a sentinel because it's fewer bytes than `null`
-            result = {
-                id: null,
-                name: "",
-                ty: null,
-                path: null,
-                exactPath: null,
-                generics,
-                bindings,
-                unboxFlag: true,
-            };
-        } else {
-            const item = lowercasePaths[pathIndex - 1];
-            const id = this.buildTypeMapIndex(item.name, isAssocType);
-            if (isAssocType && id !== null) {
-                this.assocTypeIdNameMap.set(id, paths[pathIndex - 1].name);
-            }
-            result = {
-                id,
-                name: paths[pathIndex - 1].name,
-                ty: item.ty,
-                path: item.path,
-                exactPath: item.exactPath,
-                generics,
-                bindings,
-                unboxFlag: item.unboxFlag,
-            };
-        }
-        const cr = this.TYPES_POOL.get(result.id);
-        if (cr) {
-            // Shallow equality check. Since this function is used
-            // to construct every type object, this should be mostly
-            // equivalent to a deep equality check, except if there's
-            // a conflict, we don't keep the old one around, so it's
-            // not a fully precise implementation of hashcons.
-            if (cr.generics.length === result.generics.length &&
-                cr.generics !== result.generics &&
-                cr.generics.every((x, i) => result.generics[i] === x)
-            ) {
-                result.generics = cr.generics;
-            }
-            if (cr.bindings.size === result.bindings.size && cr.bindings !== result.bindings) {
-                let ok = true;
-                for (const [k, v] of cr.bindings.entries()) {
-                    // @ts-expect-error
-                    const v2 = result.bindings.get(v);
-                    if (!v2) {
-                        ok = false;
-                        break;
+         * @param {stringdex.Trie|null|undefined} trie
+         * @param {rustdoc.ItemType} ty
+         * @param {string} modulePath
+         * @returns {Promise<number>}
+         * */
+        const first = async(trie, ty, modulePath) => {
+            if (trie) {
+                for (const id of trie.matches().entries()) {
+                    const pathData = await this.getPathData(id);
+                    if (pathData && pathData.ty === ty && pathData.modulePath === modulePath) {
+                        return id;
                     }
-                    if (v !== v2 && v.length === v2.length && v.every((x, i) => v2[i] === x)) {
-                        result.bindings.set(k, v);
-                    } else if (v !== v2) {
-                        ok = false;
-                        break;
-                    }
-                }
-                if (ok) {
-                    result.bindings = cr.bindings;
                 }
             }
-            if (cr.ty === result.ty && cr.path === result.path
-                && cr.bindings === result.bindings && cr.generics === result.generics
-                && cr.ty === result.ty && cr.name === result.name
-                && cr.unboxFlag === result.unboxFlag
-            ) {
-                return cr;
-            }
-        }
-        this.TYPES_POOL.set(result.id, result);
-        return result;
-    }
-
-    /**
-     * Type fingerprints allow fast, approximate matching of types.
-     *
-     * This algo creates a compact representation of the type set using a Bloom filter.
-     * This fingerprint is used three ways:
-     *
-     * - It accelerates the matching algorithm by checking the function fingerprint against the
-     *   query fingerprint. If any bits are set in the query but not in the function, it can't
-     *   match.
-     *
-     * - The fourth section has the number of items in the set.
-     *   This is the distance function, used for filtering and for sorting.
-     *
-     * [^1]: Distance is the relatively naive metric of counting the number of distinct items in
-     * the function that are not present in the query.
-     *
-     * @param {rustdoc.FingerprintableType} type - a single type
-     * @param {Uint32Array} output - write the fingerprint to this data structure: uses 128 bits
-     */
-    buildFunctionTypeFingerprint(type, output) {
-        let input = type.id;
-        // All forms of `[]`/`()`/`->` get collapsed down to one thing in the bloom filter.
-        // Differentiating between arrays and slices, if the user asks for it, is
-        // still done in the matching algorithm.
-        if (input === this.typeNameIdOfArray || input === this.typeNameIdOfSlice) {
-            input = this.typeNameIdOfArrayOrSlice;
-        }
-        if (input === this.typeNameIdOfTuple || input === this.typeNameIdOfUnit) {
-            input = this.typeNameIdOfTupleOrUnit;
-        }
-        if (input === this.typeNameIdOfFn || input === this.typeNameIdOfFnMut ||
-            input === this.typeNameIdOfFnOnce) {
-            input = this.typeNameIdOfHof;
-        }
-        /**
-         * http://burtleburtle.net/bob/hash/integer.html
-         * ~~ is toInt32. It's used before adding, so
-         * the number stays in safe integer range.
-         * @param {number} k
-         */
-        const hashint1 = k => {
-            k = (~~k + 0x7ed55d16) + (k << 12);
-            k = (k ^ 0xc761c23c) ^ (k >>> 19);
-            k = (~~k + 0x165667b1) + (k << 5);
-            k = (~~k + 0xd3a2646c) ^ (k << 9);
-            k = (~~k + 0xfd7046c5) + (k << 3);
-            return (k ^ 0xb55a4f09) ^ (k >>> 16);
-        };
-        /** @param {number} k */
-        const hashint2 = k => {
-            k = ~k + (k << 15);
-            k ^= k >>> 12;
-            k += k << 2;
-            k ^= k >>> 4;
-            k = Math.imul(k, 2057);
-            return k ^ (k >> 16);
-        };
-        if (input !== null) {
-            const h0a = hashint1(input);
-            const h0b = hashint2(input);
-            // Less Hashing, Same Performance: Building a Better Bloom Filter
-            // doi=10.1.1.72.2442
-            const h1a = ~~(h0a + Math.imul(h0b, 2));
-            const h1b = ~~(h0a + Math.imul(h0b, 3));
-            const h2a = ~~(h0a + Math.imul(h0b, 4));
-            const h2b = ~~(h0a + Math.imul(h0b, 5));
-            output[0] |= (1 << (h0a % 32)) | (1 << (h1b % 32));
-            output[1] |= (1 << (h1a % 32)) | (1 << (h2b % 32));
-            output[2] |= (1 << (h2a % 32)) | (1 << (h0b % 32));
-            // output[3] is the total number of items in the type signature
-            output[3] += 1;
-        }
-        for (const g of type.generics) {
-            this.buildFunctionTypeFingerprint(g, output);
-        }
-        /**
-         * @type {{
-         *   id: number|null,
-         *   ty: number,
-         *   generics: rustdoc.FingerprintableType[],
-         *   bindings: Map<number, rustdoc.FingerprintableType[]>
-         * }}
-         */
-        const fb = {
-            id: null,
-            ty: 0,
-            generics: this.EMPTY_GENERICS_ARRAY,
-            bindings: this.EMPTY_BINDINGS_MAP,
-        };
-        for (const [k, v] of type.bindings.entries()) {
-            fb.id = k;
-            fb.generics = v;
-            this.buildFunctionTypeFingerprint(fb, output);
-        }
-    }
-
-    /**
-     * Convert raw search index into in-memory search index.
-     *
-     * @param {Map<string, rustdoc.RawSearchIndexCrate>} rawSearchIndex
-     * @returns {rustdoc.Row[]}
-     */
-    buildIndex(rawSearchIndex) {
-        /**
-         * Convert from RawFunctionSearchType to FunctionSearchType.
-         *
-         * Crates often have lots of functions in them, and function signatures are sometimes
-         * complex, so rustdoc uses a pretty tight encoding for them. This function converts it
-         * to a simpler, object-based encoding so that the actual search code is more readable
-         * and easier to debug.
-         *
-         * The raw function search type format is generated using serde in
-         * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string
-         *
-         * @param {Array<{
-         *     name: string,
-         *     ty: number,
-         *     path: string|null,
-         *     exactPath: string|null,
-         *     unboxFlag: boolean
-         * }>} paths
-         * @param {Array<{
-         *     name: string,
-         *     ty: number,
-         *     path: string|null,
-         *     exactPath: string|null,
-         *     unboxFlag: boolean
-         * }>} lowercasePaths
-         *
-         * @return {function(rustdoc.RawFunctionSearchType): null|rustdoc.FunctionSearchType}
-         */
-        const buildFunctionSearchTypeCallback = (paths, lowercasePaths) => {
-            /**
-             * @param {rustdoc.RawFunctionSearchType} functionSearchType
-             */
-            const cb = functionSearchType => {
-                if (functionSearchType === 0) {
-                    return null;
-                }
-                const INPUTS_DATA = 0;
-                const OUTPUT_DATA = 1;
-                /** @type {rustdoc.FunctionType[]} */
-                let inputs;
-                /** @type {rustdoc.FunctionType[]} */
-                let output;
-                if (typeof functionSearchType[INPUTS_DATA] === "number") {
-                    inputs = [
-                        this.buildItemSearchType(
-                            functionSearchType[INPUTS_DATA],
-                            paths,
-                            lowercasePaths,
-                        ),
-                    ];
-                } else {
-                    inputs = this.buildItemSearchTypeAll(
-                        functionSearchType[INPUTS_DATA],
-                        paths,
-                        lowercasePaths,
-                    );
-                }
-                if (functionSearchType.length > 1) {
-                    if (typeof functionSearchType[OUTPUT_DATA] === "number") {
-                        output = [
-                            this.buildItemSearchType(
-                                functionSearchType[OUTPUT_DATA],
-                                paths,
-                                lowercasePaths,
-                            ),
-                        ];
-                    } else {
-                        output = this.buildItemSearchTypeAll(
-                            // @ts-expect-error
-                            functionSearchType[OUTPUT_DATA],
-                            paths,
-                            lowercasePaths,
-                        );
-                    }
-                } else {
-                    output = [];
-                }
-                const where_clause = [];
-                const l = functionSearchType.length;
-                for (let i = 2; i < l; ++i) {
-                    where_clause.push(typeof functionSearchType[i] === "number"
-                        // @ts-expect-error
-                        ? [this.buildItemSearchType(functionSearchType[i], paths, lowercasePaths)]
-                        : this.buildItemSearchTypeAll(
-                            // @ts-expect-error
-                            functionSearchType[i],
-                            paths,
-                            lowercasePaths,
-                        ));
-                }
-                return {
-                    inputs, output, where_clause,
-                };
-            };
-            return cb;
+            return -1;
         };
-
-        /** @type {rustdoc.Row[]} */
-        const searchIndex = [];
-        let currentIndex = 0;
-        let id = 0;
-
-        // Function type fingerprints are 128-bit bloom filters that are used to
-        // estimate the distance between function and query.
-        // This loop counts the number of items to allocate a fingerprint for.
-        for (const crate of rawSearchIndex.values()) {
-            // Each item gets an entry in the fingerprint array, and the crate
-            // does, too
-            id += crate.t.length + 1;
-        }
-        this.functionTypeFingerprint = new Uint32Array((id + 1) * 4);
-        // This loop actually generates the search item indexes, including
-        // normalized names, type signature objects and fingerprints, and aliases.
-        id = 0;
-
-        /** @type {Array<[string, { [key: string]: Array<number> },  number]>} */
-        const allAliases = [];
-        for (const [crate, crateCorpus] of rawSearchIndex) {
-            // a string representing the lengths of each description shard
-            // a string representing the list of function types
-            const itemDescShardDecoder = new VlqHexDecoder(crateCorpus.D, noop => {
-                /** @type {number} */
-                // @ts-expect-error
-                const n = noop;
-                return n;
-            });
-            let descShard = {
-                crate,
-                shard: 0,
-                start: 0,
-                len: itemDescShardDecoder.next(),
-                promise: null,
-                resolve: null,
-            };
-            const descShardList = [descShard];
-
-            // Deprecated items and items with no description
-            this.searchIndexDeprecated.set(crate, new RoaringBitmap(crateCorpus.c));
-            this.searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e));
-            let descIndex = 0;
-
-            /**
-             * List of generic function type parameter names.
-             * Used for display, not for searching.
-             * @type {string[]}
-             */
-            let lastParamNames = [];
-
-            // This object should have exactly the same set of fields as the "row"
-            // object defined below. Your JavaScript runtime will thank you.
-            // https://mathiasbynens.be/notes/shapes-ics
-            let normalizedName = crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, "");
-            const crateRow = {
-                crate,
-                ty: 3, // == ExternCrate
-                name: crate,
-                path: "",
-                descShard,
-                descIndex,
-                exactPath: "",
-                desc: crateCorpus.doc,
-                parent: undefined,
-                type: null,
-                paramNames: lastParamNames,
-                id,
-                word: crate,
-                normalizedName,
-                bitIndex: 0,
-                implDisambiguator: null,
-            };
-            this.nameTrie.insert(normalizedName, id, this.tailTable);
-            id += 1;
-            searchIndex.push(crateRow);
-            currentIndex += 1;
-            // it's not undefined
-            // @ts-expect-error
-            if (!this.searchIndexEmptyDesc.get(crate).contains(0)) {
-                descIndex += 1;
-            }
-
-            // see `RawSearchIndexCrate` in `rustdoc.d.ts` for a more
-            // up to date description of these fields
-            const itemTypes = crateCorpus.t;
-            // an array of (String) item names
-            const itemNames = crateCorpus.n;
-            // an array of [(Number) item index,
-            //              (String) full path]
-            // an item whose index is not present will fall back to the previous present path
-            // i.e. if indices 4 and 11 are present, but 5-10 and 12-13 are not present,
-            // 5-10 will fall back to the path for 4 and 12-13 will fall back to the path for 11
-            const itemPaths = new Map(crateCorpus.q);
-            // An array of [(Number) item index, (Number) path index]
-            // Used to de-duplicate inlined and re-exported stuff
-            const itemReexports = new Map(crateCorpus.r);
-            // an array of (Number) the parent path index + 1 to `paths`, or 0 if none
-            const itemParentIdxDecoder = new VlqHexDecoder(crateCorpus.i, noop => noop);
-            // a map Number, string for impl disambiguators
-            const implDisambiguator = new Map(crateCorpus.b);
-            const rawPaths = crateCorpus.p;
-            const aliases = crateCorpus.a;
-            // an array of [(Number) item index,
-            //              (String) comma-separated list of function generic param names]
-            // an item whose index is not present will fall back to the previous present path
-            const itemParamNames = new Map(crateCorpus.P);
-
-            /**
-             * @type {Array<{
-             *     name: string,
-             *     ty: number,
-             *     path: string|null,
-             *     exactPath: string|null,
-             *     unboxFlag: boolean
-             * }>}
-             */
-            const lowercasePaths = [];
-            /**
-             * @type {Array<{
-             *     name: string,
-             *     ty: number,
-             *     path: string|null,
-             *     exactPath: string|null,
-             *     unboxFlag: boolean
-             * }>}
-             */
-            const paths = [];
-
-            // a string representing the list of function types
-            const itemFunctionDecoder = new VlqHexDecoder(
-                crateCorpus.f,
-                // @ts-expect-error
-                buildFunctionSearchTypeCallback(paths, lowercasePaths),
-            );
-
-            // convert `rawPaths` entries into object form
-            // generate normalizedPaths for function search mode
-            let len = rawPaths.length;
-            let lastPath = undef2null(itemPaths.get(0));
-            for (let i = 0; i < len; ++i) {
-                const elem = rawPaths[i];
-                const ty = elem[0];
-                const name = elem[1];
-                /**
-                 * @param {2|3} idx
-                 * @param {string|null} if_null
-                 * @param {string|null} if_not_found
-                 * @returns {string|null}
-                 */
-                const elemPath = (idx, if_null, if_not_found) => {
-                    if (elem.length > idx && elem[idx] !== undefined) {
-                        const p = itemPaths.get(elem[idx]);
-                        if (p !== undefined) {
-                            return p;
-                        }
-                        return if_not_found;
-                    }
-                    return if_null;
-                };
-                const path = elemPath(2, lastPath, null);
-                const exactPath = elemPath(3, path, path);
-                const unboxFlag = elem.length > 4 && !!elem[4];
-
-                lowercasePaths.push({ ty, name: name.toLowerCase(), path, exactPath, unboxFlag });
-                paths[i] = { ty, name, path, exactPath, unboxFlag };
-            }
-
-            // Convert `item*` into an object form, and construct word indices.
-            //
-            // Before any analysis is performed, let's gather the search terms to
-            // search against apart from the rest of the data. This is a quick
-            // operation that is cached for the life of the page state so that
-            // all other search operations have access to this cached data for
-            // faster analysis operations
-            lastPath = "";
-            len = itemTypes.length;
-            let lastName = "";
-            let lastWord = "";
-            for (let i = 0; i < len; ++i) {
-                const bitIndex = i + 1;
-                if (descIndex >= descShard.len &&
-                    // @ts-expect-error
-                    !this.searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
-                    descShard = {
-                        crate,
-                        shard: descShard.shard + 1,
-                        start: descShard.start + descShard.len,
-                        len: itemDescShardDecoder.next(),
-                        promise: null,
-                        resolve: null,
-                    };
-                    descIndex = 0;
-                    descShardList.push(descShard);
-                }
-                const name = itemNames[i] === "" ? lastName : itemNames[i];
-                const word = itemNames[i] === "" ? lastWord : itemNames[i].toLowerCase();
-                const pathU = itemPaths.get(i);
-                const path = pathU !== undefined ? pathU : lastPath;
-                const paramNameString = itemParamNames.get(i);
-                const paramNames = paramNameString !== undefined ?
-                    paramNameString.split(",") :
-                    lastParamNames;
-                const type = itemFunctionDecoder.next();
-                if (type !== null) {
-                    if (type) {
-                        const fp = this.functionTypeFingerprint.subarray(id * 4, (id + 1) * 4);
-                        for (const t of type.inputs) {
-                            this.buildFunctionTypeFingerprint(t, fp);
-                        }
-                        for (const t of type.output) {
-                            this.buildFunctionTypeFingerprint(t, fp);
-                        }
-                        for (const w of type.where_clause) {
-                            for (const t of w) {
-                                this.buildFunctionTypeFingerprint(t, fp);
-                            }
-                        }
-                    }
-                }
-                // This object should have exactly the same set of fields as the "crateRow"
-                // object defined above.
-                const itemParentIdx = itemParentIdxDecoder.next();
-                normalizedName = word.indexOf("_") === -1 ? word : word.replace(/_/g, "");
-                /** @type {rustdoc.Row} */
-                const row = {
-                    crate,
-                    ty: itemTypes.charCodeAt(i) - 65, // 65 = "A"
-                    name,
-                    path,
-                    descShard,
-                    descIndex,
-                    exactPath: itemReexports.has(i) ?
-                        // @ts-expect-error
-                        itemPaths.get(itemReexports.get(i)) : path,
-                    // @ts-expect-error
-                    parent: itemParentIdx > 0 ? paths[itemParentIdx - 1] : undefined,
-                    type,
-                    paramNames,
-                    id,
-                    word,
-                    normalizedName,
-                    bitIndex,
-                    implDisambiguator: undef2null(implDisambiguator.get(i)),
-                };
-                this.nameTrie.insert(normalizedName, id, this.tailTable);
-                id += 1;
-                searchIndex.push(row);
-                lastPath = row.path;
-                lastParamNames = row.paramNames;
-                // @ts-expect-error
-                if (!this.searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
-                    descIndex += 1;
-                }
-                lastName = name;
-                lastWord = word;
-            }
-
-            if (aliases) {
-                // We need to add the aliases in `searchIndex` after we finished filling it
-                // to not mess up indexes.
-                allAliases.push([crate, aliases, currentIndex]);
-            }
-            currentIndex += itemTypes.length;
-            this.searchState.descShards.set(crate, descShardList);
-        }
-
-        for (const [crate, aliases, index] of allAliases) {
-            for (const [alias_name, alias_refs] of Object.entries(aliases)) {
-                if (!this.ALIASES.has(crate)) {
-                    this.ALIASES.set(crate, new Map());
-                }
-                const word = alias_name.toLowerCase();
-                const crate_alias_map = this.ALIASES.get(crate);
-                if (!crate_alias_map.has(word)) {
-                    crate_alias_map.set(word, []);
-                }
-                const aliases_map = crate_alias_map.get(word);
-
-                const normalizedName = word.indexOf("_") === -1 ? word : word.replace(/_/g, "");
-                for (const alias of alias_refs) {
-                    const originalIndex = alias + index;
-                    const original = searchIndex[originalIndex];
-                    /** @type {rustdoc.Row} */
-                    const row = {
-                        crate,
-                        name: alias_name,
-                        normalizedName,
-                        is_alias: true,
-                        ty: original.ty,
-                        type: original.type,
-                        paramNames: [],
-                        word,
-                        id,
-                        parent: undefined,
-                        original,
-                        path: "",
-                        implDisambiguator: original.implDisambiguator,
-                        // Needed to load the description of the original item.
-                        // @ts-ignore
-                        descShard: original.descShard,
-                        descIndex: original.descIndex,
-                        bitIndex: original.bitIndex,
-                    };
-                    aliases_map.push(row);
-                    this.nameTrie.insert(normalizedName, id, this.tailTable);
-                    id += 1;
-                    searchIndex.push(row);
-                }
-            }
-        }
-        // Drop the (rather large) hash table used for reusing function items
-        this.TYPES_POOL = new Map();
-        return searchIndex;
+        this.typeNameIdOfOutput = await first(output, TY_ASSOCTYPE, "");
+        this.typeNameIdOfFnPtr = await first(fn, TY_PRIMITIVE, "");
+        this.typeNameIdOfFn = await first(fn, TY_TRAIT, "core::ops");
+        this.typeNameIdOfFnMut = await first(fnMut, TY_TRAIT, "core::ops");
+        this.typeNameIdOfFnOnce = await first(fnOnce, TY_TRAIT, "core::ops");
+        this.typeNameIdOfArray = await first(array, TY_PRIMITIVE, "");
+        this.typeNameIdOfSlice = await first(slice, TY_PRIMITIVE, "");
+        this.typeNameIdOfArrayOrSlice = await first(arrayOrSlice, TY_PRIMITIVE, "");
+        this.typeNameIdOfTuple = await first(tuple, TY_PRIMITIVE, "");
+        this.typeNameIdOfUnit = await first(unit, TY_PRIMITIVE, "");
+        this.typeNameIdOfTupleOrUnit = await first(tupleOrUnit, TY_PRIMITIVE, "");
+        this.typeNameIdOfReference = await first(reference, TY_PRIMITIVE, "");
+        this.typeNameIdOfHof = await first(hof, TY_PRIMITIVE, "");
+        this.typeNameIdOfNever = await first(never, TY_PRIMITIVE, "");
     }
 
     /**
@@ -2343,41 +1288,6 @@ class DocSearch {
      */
     static parseQuery(userQuery) {
         /**
-         * @param {string} typename
-         * @returns {number}
-         */
-        function itemTypeFromName(typename) {
-            const index = itemTypes.findIndex(i => i === typename);
-            if (index < 0) {
-                throw ["Unknown type filter ", typename];
-            }
-            return index;
-        }
-
-        /**
-         * @param {rustdoc.ParserQueryElement} elem
-         */
-        function convertTypeFilterOnElem(elem) {
-            if (typeof elem.typeFilter === "string") {
-                let typeFilter = elem.typeFilter;
-                if (typeFilter === "const") {
-                    typeFilter = "constant";
-                }
-                elem.typeFilter = itemTypeFromName(typeFilter);
-            } else {
-                elem.typeFilter = NO_TYPE_FILTER;
-            }
-            for (const elem2 of elem.generics) {
-                convertTypeFilterOnElem(elem2);
-            }
-            for (const constraints of elem.bindings.values()) {
-                for (const constraint of constraints) {
-                    convertTypeFilterOnElem(constraint);
-                }
-            }
-        }
-
-        /**
          * Takes the user search input and returns an empty `ParsedQuery`.
          *
          * @param {string} userQuery
@@ -2437,8 +1347,7 @@ class DocSearch {
                     continue;
                 }
                 if (!foundStopChar) {
-                    /** @type String[] */
-                    let extra = [];
+                    let extra = EMPTY_STRING_ARRAY;
                     if (isLastElemGeneric(query.elems, parserState)) {
                         extra = [" after ", ">"];
                     } else if (prevIs(parserState, "\"")) {
@@ -2515,11 +1424,33 @@ class DocSearch {
 
         try {
             parseInput(query, parserState);
+
+            // Scan for invalid type filters, so that we can report the error
+            // outside the search loop.
+            /** @param {rustdoc.ParserQueryElement} elem */
+            const checkTypeFilter = elem => {
+                const ty = itemTypeFromName(elem.typeFilter);
+                if (ty === TY_GENERIC && elem.generics.length !== 0) {
+                    throw [
+                        "Generic type parameter ",
+                        elem.name,
+                        " does not accept generic parameters",
+                    ];
+                }
+                for (const generic of elem.generics) {
+                    checkTypeFilter(generic);
+                }
+                for (const constraints of elem.bindings.values()) {
+                    for (const constraint of constraints) {
+                        checkTypeFilter(constraint);
+                    }
+                }
+            };
             for (const elem of query.elems) {
-                convertTypeFilterOnElem(elem);
+                checkTypeFilter(elem);
             }
             for (const elem of query.returned) {
-                convertTypeFilterOnElem(elem);
+                checkTypeFilter(elem);
             }
         } catch (err) {
             query = newParsedQuery(userQuery);
@@ -2543,208 +1474,573 @@ class DocSearch {
     }
 
     /**
-     * Executes the parsed query and builds a {ResultsTable}.
-     *
-     * @param  {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} origParsedQuery
-     *     - The parsed user query
-     * @param  {Object} filterCrates - Crate to search in if defined
-     * @param  {string} currentCrate - Current crate, to rank results from this crate higher
-     *
-     * @return {Promise<rustdoc.ResultsTable>}
+     * @param {number} id
+     * @returns {Promise<string|null>}
      */
-    async execQuery(origParsedQuery, filterCrates, currentCrate) {
-        /** @type {rustdoc.Results} */
-        const results_others = new Map(),
-            /** @type {rustdoc.Results} */
-            results_in_args = new Map(),
-            /** @type {rustdoc.Results} */
-            results_returned = new Map();
-
-        /** @type {rustdoc.ParsedQuery<rustdoc.QueryElement>} */
-        // @ts-expect-error
-        const parsedQuery = origParsedQuery;
+    async getName(id) {
+        const ni = this.database.getData("name");
+        if (!ni) {
+            return null;
+        }
+        const name = await ni.at(id);
+        return name === undefined || name === null ? null : this.utf8decoder.decode(name);
+    }
 
-        const queryLen =
-            parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
-            parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
-        const maxEditDistance = Math.floor(queryLen / 3);
-        // We reinitialize the `FOUND_ALIASES` map.
-        this.FOUND_ALIASES.clear();
+    /**
+     * @param {number} id
+     * @returns {Promise<string|null>}
+     */
+    async getDesc(id) {
+        const di = this.database.getData("desc");
+        if (!di) {
+            return null;
+        }
+        const desc = await di.at(id);
+        return desc === undefined || desc === null ? null : this.utf8decoder.decode(desc);
+    }
 
+    /**
+     * @param {number} id
+     * @returns {Promise<number|null>}
+     */
+    async getAliasTarget(id) {
+        const ai = this.database.getData("alias");
+        if (!ai) {
+            return null;
+        }
+        const bytes = await ai.at(id);
+        if (bytes === undefined || bytes === null || bytes.length === 0) {
+            return null;
+        } else {
+            /** @type {string} */
+            const encoded = this.utf8decoder.decode(bytes);
+            /** @type {number|null} */
+            const decoded = JSON.parse(encoded);
+            return decoded;
+        }
+    }
+
+    /**
+     * @param {number} id
+     * @returns {Promise<rustdoc.EntryData|null>}
+     */
+    async getEntryData(id) {
+        const ei = this.database.getData("entry");
+        if (!ei) {
+            return null;
+        }
+        const encoded = this.utf8decoder.decode(await ei.at(id));
+        if (encoded === "" || encoded === undefined || encoded === null) {
+            return null;
+        }
         /**
-         * @type {Map<string, number>}
+         * krate,
+         * ty,
+         * module_path,
+         * exact_module_path,
+         * parent,
+         * deprecated,
+         * associated_item_disambiguator
+         * @type {rustdoc.ArrayWithOptionals<[
+         *     number,
+         *     rustdoc.ItemType,
+         *     number,
+         *     number,
+         *     number,
+         *     number,
+         * ], [string]>}
          */
-        const genericSymbols = new Map();
+        const raw = JSON.parse(encoded);
+        return {
+            krate: raw[0],
+            ty: raw[1],
+            modulePath: raw[2] === 0 ? null : raw[2] - 1,
+            exactModulePath: raw[3] === 0 ? null : raw[3] - 1,
+            parent: raw[4] === 0 ? null : raw[4] - 1,
+            deprecated: raw[5] === 1 ? true : false,
+            associatedItemDisambiguator: raw.length === 6 ? null : raw[6],
+        };
+    }
 
+    /**
+     * @param {number} id
+     * @returns {Promise<rustdoc.PathData|null>}
+     */
+    async getPathData(id) {
+        const pi = this.database.getData("path");
+        if (!pi) {
+            return null;
+        }
+        const encoded = this.utf8decoder.decode(await pi.at(id));
+        if (encoded === "" || encoded === undefined || encoded === null) {
+            return null;
+        }
         /**
-         * Convert names to ids in parsed query elements.
-         * This is not used for the "In Names" tab, but is used for the
-         * "In Params", "In Returns", and "In Function Signature" tabs.
-         *
-         * If there is no matching item, but a close-enough match, this
-         * function also that correction.
-         *
-         * See `buildTypeMapIndex` for more information.
-         *
-         * @param {rustdoc.QueryElement} elem
-         * @param {boolean=} isAssocType
+         * ty, module_path, exact_module_path, search_unbox, inverted_function_signature_index
+         * @type {rustdoc.ArrayWithOptionals<[rustdoc.ItemType, string], [string|0, 0|1, string]>}
          */
-        const convertNameToId = (elem, isAssocType) => {
-            const loweredName = elem.pathLast.toLowerCase();
-            if (this.typeNameIdMap.has(loweredName) &&
-                // @ts-expect-error
-                (isAssocType || !this.typeNameIdMap.get(loweredName).assocOnly)) {
-                // @ts-expect-error
-                elem.id = this.typeNameIdMap.get(loweredName).id;
-            } else if (!parsedQuery.literalSearch) {
-                let match = null;
-                let matchDist = maxEditDistance + 1;
-                let matchName = "";
-                for (const [name, { id, assocOnly }] of this.typeNameIdMap) {
-                    const dist = Math.min(
-                        editDistance(name, loweredName, maxEditDistance),
-                        editDistance(name, elem.normalizedPathLast, maxEditDistance),
-                    );
-                    if (dist <= matchDist && dist <= maxEditDistance &&
-                        (isAssocType || !assocOnly)) {
-                        if (dist === matchDist && matchName > name) {
-                            continue;
-                        }
-                        match = id;
-                        matchDist = dist;
-                        matchName = name;
-                    }
-                }
-                if (match !== null) {
-                    parsedQuery.correction = matchName;
-                }
-                elem.id = match;
+        const raw = JSON.parse(encoded);
+        return {
+            ty: raw[0],
+            modulePath: raw[1],
+            exactModulePath: raw[2] === 0 || raw[2] === undefined ? raw[1] : raw[2],
+        };
+    }
+
+    /**
+     * @param {number} id
+     * @returns {Promise<rustdoc.FunctionData|null>}
+     */
+    async getFunctionData(id) {
+        const fi = this.database.getData("function");
+        if (!fi) {
+            return null;
+        }
+        const encoded = this.utf8decoder.decode(await fi.at(id));
+        if (encoded === "" || encoded === undefined || encoded === null) {
+            return null;
+        }
+        /**
+         * function_signature, param_names
+         * @type {[string, string[]]}
+         */
+        const raw = JSON.parse(encoded);
+
+        const parser = new VlqHexDecoder(raw[0], async functionSearchType => {
+            if (typeof functionSearchType === "number") {
+                return null;
             }
-            if ((elem.id === null && parsedQuery.totalElems > 1 && elem.typeFilter === -1
-                && elem.generics.length === 0 && elem.bindings.size === 0)
-                || elem.typeFilter === TY_GENERIC) {
-                const id = genericSymbols.get(elem.normalizedPathLast);
-                if (id !== undefined) {
-                    elem.id = id;
+            const INPUTS_DATA = 0;
+            const OUTPUT_DATA = 1;
+            /** @type {Promise<rustdoc.FunctionType[]>} */
+            let inputs_;
+            /** @type {Promise<rustdoc.FunctionType[]>} */
+            let output_;
+            if (typeof functionSearchType[INPUTS_DATA] === "number") {
+                inputs_ = Promise.all([
+                    this.buildItemSearchType(functionSearchType[INPUTS_DATA]),
+                ]);
+            } else {
+                // @ts-ignore
+                inputs_ = this.buildItemSearchTypeAll(functionSearchType[INPUTS_DATA]);
+            }
+            if (functionSearchType.length > 1) {
+                if (typeof functionSearchType[OUTPUT_DATA] === "number") {
+                    output_ = Promise.all([
+                        this.buildItemSearchType(functionSearchType[OUTPUT_DATA]),
+                    ]);
                 } else {
-                    elem.id = -(genericSymbols.size + 1);
-                    genericSymbols.set(elem.normalizedPathLast, elem.id);
-                }
-                if (elem.typeFilter === -1 && elem.normalizedPathLast.length >= 3) {
-                    // Silly heuristic to catch if the user probably meant
-                    // to not write a generic parameter. We don't use it,
-                    // just bring it up.
-                    const maxPartDistance = Math.floor(elem.normalizedPathLast.length / 3);
-                    let matchDist = maxPartDistance + 1;
-                    let matchName = "";
-                    for (const name of this.typeNameIdMap.keys()) {
-                        const dist = editDistance(
-                            name,
-                            elem.normalizedPathLast,
-                            maxPartDistance,
-                        );
-                        if (dist <= matchDist && dist <= maxPartDistance) {
-                            if (dist === matchDist && matchName > name) {
-                                continue;
-                            }
-                            matchDist = dist;
-                            matchName = name;
-                        }
-                    }
-                    if (matchName !== "") {
-                        parsedQuery.proposeCorrectionFrom = elem.name;
-                        parsedQuery.proposeCorrectionTo = matchName;
-                    }
+                    // @ts-expect-error
+                    output_ = this.buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA]);
                 }
-                elem.typeFilter = TY_GENERIC;
-            }
-            if (elem.generics.length > 0 && elem.typeFilter === TY_GENERIC) {
-                // Rust does not have HKT
-                parsedQuery.error = [
-                    "Generic type parameter ",
-                    elem.name,
-                    " does not accept generic parameters",
-                ];
-            }
-            for (const elem2 of elem.generics) {
-                convertNameToId(elem2);
+            } else {
+                output_ = Promise.resolve(EMPTY_GENERICS_ARRAY);
             }
-            elem.bindings = new Map(Array.from(elem.bindings.entries())
-                .map(entry => {
-                    const [name, constraints] = entry;
+            /** @type {Promise<rustdoc.FunctionType[]>[]} */
+            const where_clause_ = [];
+            const l = functionSearchType.length;
+            for (let i = 2; i < l; ++i) {
+                where_clause_.push(typeof functionSearchType[i] === "number"
                     // @ts-expect-error
-                    if (!this.typeNameIdMap.has(name)) {
-                        parsedQuery.error = [
-                            "Type parameter ",
-                            // @ts-expect-error
-                            name,
-                            " does not exist",
-                        ];
-                        return [0, []];
-                    }
-                    for (const elem2 of constraints) {
-                        convertNameToId(elem2, false);
-                    }
-
+                    ? Promise.all([this.buildItemSearchType(functionSearchType[i])])
                     // @ts-expect-error
-                    return [this.typeNameIdMap.get(name).id, constraints];
-                }),
-            );
+                    : this.buildItemSearchTypeAll(functionSearchType[i]),
+                );
+            }
+            const [inputs, output, where_clause] = await Promise.all([
+                inputs_,
+                output_,
+                Promise.all(where_clause_),
+            ]);
+            return {
+                inputs, output, where_clause,
+            };
+        });
+
+        return {
+            functionSignature: await parser.next(),
+            paramNames: raw[1],
+            elemCount: parser.elemCount,
         };
+    }
 
-        for (const elem of parsedQuery.elems) {
-            convertNameToId(elem, false);
-            this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
+    /**
+     * @param {number} id
+     * @returns {Promise<rustdoc.TypeData|null>}
+     */
+    async getTypeData(id) {
+        const ti = this.database.getData("type");
+        if (!ti) {
+            return null;
         }
-        for (const elem of parsedQuery.returned) {
-            convertNameToId(elem, false);
-            this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
+        const encoded = this.utf8decoder.decode(await ti.at(id));
+        if (encoded === "" || encoded === undefined || encoded === null) {
+            return null;
         }
+        /**
+         * function_signature, param_names
+         * @type {[string, number] | [number] | [string] | [] | null}
+         */
+        const raw = JSON.parse(encoded);
 
+        if (!raw || raw.length === 0) {
+            return null;
+        }
+
+        let searchUnbox = false;
+        const invertedFunctionSignatureIndex = [];
+
+        if (typeof raw[0] === "string") {
+            if (raw[1]) {
+                searchUnbox = true;
+            }
+            // the inverted function signature index is a list of bitmaps,
+            // by number of types that appear in the function
+            let i = 0;
+            const pb = makeUint8ArrayFromBase64(raw[0]);
+            const l = pb.length;
+            while (i < l) {
+                if (pb[i] === 0) {
+                    invertedFunctionSignatureIndex.push(RoaringBitmap.empty());
+                    i += 1;
+                } else {
+                    const bitmap = new RoaringBitmap(pb, i);
+                    i += bitmap.consumed_len_bytes;
+                    invertedFunctionSignatureIndex.push(bitmap);
+                }
+            }
+        } else if (raw[0]) {
+            searchUnbox = true;
+        }
+
+        return { searchUnbox, invertedFunctionSignatureIndex };
+    }
+
+    /**
+     * @returns {Promise<string[]>}
+     */
+    async getCrateNameList() {
+        const crateNames = this.database.getData("crateNames");
+        if (!crateNames) {
+            return [];
+        }
+        const l = crateNames.length;
+        const names = [];
+        for (let i = 0; i < l; ++i) {
+            names.push(crateNames.at(i).then(name => {
+                if (name === undefined) {
+                    return "";
+                }
+                return this.utf8decoder.decode(name);
+            }));
+        }
+        return Promise.all(names);
+    }
+
+    /**
+     * @param {number} id non-negative generic index
+     * @returns {Promise<stringdex.RoaringBitmap[]>}
+     */
+    async getGenericInvertedIndex(id) {
+        const gii = this.database.getData("generic_inverted_index");
+        if (!gii) {
+            return [];
+        }
+        const pb = await gii.at(id);
+        if (pb === undefined || pb === null || pb.length === 0) {
+            return [];
+        }
+
+        const invertedFunctionSignatureIndex = [];
+        // the inverted function signature index is a list of bitmaps,
+        // by number of types that appear in the function
+        let i = 0;
+        const l = pb.length;
+        while (i < l) {
+            if (pb[i] === 0) {
+                invertedFunctionSignatureIndex.push(RoaringBitmap.empty());
+                i += 1;
+            } else {
+                const bitmap = new RoaringBitmap(pb, i);
+                i += bitmap.consumed_len_bytes;
+                invertedFunctionSignatureIndex.push(bitmap);
+            }
+        }
+        return invertedFunctionSignatureIndex;
+    }
+
+    /**
+     * @param {number} id
+     * @returns {Promise<rustdoc.Row?>}
+     */
+    async getRow(id) {
+        const [name_, entry, path, type] = await Promise.all([
+            this.getName(id),
+            this.getEntryData(id),
+            this.getPathData(id),
+            this.getFunctionData(id),
+        ]);
+        if (!entry && !path) {
+            return null;
+        }
+        const [
+            moduleName,
+            modulePathData,
+            exactModuleName,
+            exactModulePathData,
+        ] = await Promise.all([
+            entry && entry.modulePath !== null ? this.getName(entry.modulePath) : null,
+            entry && entry.modulePath !== null ? this.getPathData(entry.modulePath) : null,
+            entry && entry.exactModulePath !== null ?
+                this.getName(entry.exactModulePath) :
+                null,
+            entry && entry.exactModulePath !== null ?
+                this.getPathData(entry.exactModulePath) :
+                null,
+        ]);
+        const name = name_ === null ? "" : name_;
+        const normalizedName = (name.indexOf("_") === -1 ?
+            name :
+            name.replace(/_/g, "")).toLowerCase();
+        const modulePath = modulePathData === null || moduleName === null ? "" :
+            (modulePathData.modulePath === "" ?
+                moduleName :
+                `${modulePathData.modulePath}::${moduleName}`);
+        const [parentName, parentPath] = entry !== null && entry.parent !== null ?
+            await Promise.all([this.getName(entry.parent), this.getPathData(entry.parent)]) :
+            [null, null];
+        return {
+            id,
+            crate: entry ? nonnull(await this.getName(entry.krate)) : "",
+            ty: entry ? entry.ty : nonnull(path).ty,
+            name,
+            normalizedName,
+            modulePath,
+            exactModulePath: exactModulePathData === null || exactModuleName === null ? modulePath :
+                (exactModulePathData.exactModulePath === "" ?
+                    exactModuleName :
+                    `${exactModulePathData.exactModulePath}::${exactModuleName}`),
+            entry,
+            path,
+            type,
+            deprecated: entry ? entry.deprecated : false,
+            parent: parentName !== null && parentPath !== null ?
+                { name: parentName, path: parentPath } :
+                null,
+        };
+    }
+
+    /**
+     * Convert a list of RawFunctionType / ID to object-based FunctionType.
+     *
+     * Crates often have lots of functions in them, and it's common to have a large number of
+     * functions that operate on a small set of data types, so the search index compresses them
+     * by encoding function parameter and return types as indexes into an array of names.
+     *
+     * Even when a general-purpose compression algorithm is used, this is still a win.
+     * I checked. https://github.com/rust-lang/rust/pull/98475#issue-1284395985
+     *
+     * The format for individual function types is encoded in
+     * librustdoc/html/render/mod.rs: impl Serialize for RenderType
+     *
+     * @param {null|Array<rustdoc.RawFunctionType>} types
+     *
+     * @return {Promise<Array<rustdoc.FunctionType>>}
+     */
+    async buildItemSearchTypeAll(types) {
+        return types && types.length > 0 ?
+            await Promise.all(types.map(type => this.buildItemSearchType(type))) :
+            EMPTY_GENERICS_ARRAY;
+    }
 
+    /**
+     * Converts a single type.
+     *
+     * @param {rustdoc.RawFunctionType} type
+     * @return {Promise<rustdoc.FunctionType>}
+     */
+    async buildItemSearchType(type) {
+        const PATH_INDEX_DATA = 0;
+        const GENERICS_DATA = 1;
+        const BINDINGS_DATA = 2;
+        let id, generics;
         /**
-         * Creates the query results.
-         *
-         * @param {Array<rustdoc.ResultObject>} results_in_args
-         * @param {Array<rustdoc.ResultObject>} results_returned
-         * @param {Array<rustdoc.ResultObject>} results_others
-         * @param {rustdoc.ParsedQuery<rustdoc.QueryElement>} parsedQuery
-         *
-         * @return {rustdoc.ResultsTable}
+         * @type {Map<number, rustdoc.FunctionType[]>}
          */
-        function createQueryResults(
-            results_in_args,
-            results_returned,
-            results_others,
-            parsedQuery) {
-            return {
-                "in_args": results_in_args,
-                "returned": results_returned,
-                "others": results_others,
-                "query": parsedQuery,
+        let bindings;
+        if (typeof type === "number") {
+            id = type;
+            generics = EMPTY_GENERICS_ARRAY;
+            bindings = EMPTY_BINDINGS_MAP;
+        } else {
+            id = type[PATH_INDEX_DATA];
+            generics = await this.buildItemSearchTypeAll(type[GENERICS_DATA]);
+            if (type[BINDINGS_DATA] && type[BINDINGS_DATA].length > 0) {
+                bindings = new Map((await Promise.all(type[BINDINGS_DATA].map(
+                    /**
+                     * @param {[rustdoc.RawFunctionType, rustdoc.RawFunctionType[]]} binding
+                     * @returns {Promise<[number, rustdoc.FunctionType[]][]>}
+                    */
+                    async binding => {
+                        const [assocType, constraints] = binding;
+                        // Associated type constructors are represented sloppily in rustdoc's
+                        // type search, to make the engine simpler.
+                        //
+                        // MyType<Output<T>=Result<T>> is equivalent to MyType<Output<Result<T>>=T>
+                        // and both are, essentially
+                        // MyType<Output=(T, Result<T>)>, except the tuple isn't actually there.
+                        // It's more like the value of a type binding is naturally an array,
+                        // which rustdoc calls "constraints".
+                        //
+                        // As a result, the key should never have generics on it.
+                        const [k, v] = await Promise.all([
+                            this.buildItemSearchType(assocType).then(t => t.id),
+                            this.buildItemSearchTypeAll(constraints),
+                        ]);
+                        return k === null ? EMPTY_BINDINGS_ARRAY : [[k, v]];
+                    },
+                ))).flat());
+            } else {
+                bindings = EMPTY_BINDINGS_MAP;
+            }
+        }
+        /**
+         * @type {rustdoc.FunctionType}
+         */
+        let result;
+        if (id < 0) {
+            // types less than 0 are generic parameters
+            // the actual names of generic parameters aren't stored, since they aren't API
+            result = {
+                id,
+                name: "",
+                ty: TY_GENERIC,
+                path: null,
+                exactPath: null,
+                generics,
+                bindings,
+                unboxFlag: true,
+            };
+        } else if (id === 0) {
+            // `0` is used as a sentinel because it's fewer bytes than `null`
+            result = {
+                id: null,
+                name: "",
+                ty: TY_GENERIC,
+                path: null,
+                exactPath: null,
+                generics,
+                bindings,
+                unboxFlag: true,
+            };
+        } else {
+            const [name, path, type] = await Promise.all([
+                this.getName(id - 1),
+                this.getPathData(id - 1),
+                this.getTypeData(id - 1),
+            ]);
+            if (path === undefined || path === null || type === undefined || type === null) {
+                return {
+                    id: null,
+                    name: "",
+                    ty: TY_GENERIC,
+                    path: null,
+                    exactPath: null,
+                    generics,
+                    bindings,
+                    unboxFlag: true,
+                };
+            }
+            result = {
+                id: id - 1,
+                name,
+                ty: path.ty,
+                path: path.modulePath,
+                exactPath: path.exactModulePath === null ? path.modulePath : path.exactModulePath,
+                generics,
+                bindings,
+                unboxFlag: type.searchUnbox,
             };
         }
+        const cr = this.TYPES_POOL.get(result.id);
+        if (cr) {
+            // Shallow equality check. Since this function is used
+            // to construct every type object, this should be mostly
+            // equivalent to a deep equality check, except if there's
+            // a conflict, we don't keep the old one around, so it's
+            // not a fully precise implementation of hashcons.
+            if (cr.generics.length === result.generics.length &&
+                cr.generics !== result.generics &&
+                cr.generics.every((x, i) => result.generics[i] === x)
+            ) {
+                result.generics = cr.generics;
+            }
+            if (cr.bindings.size === result.bindings.size && cr.bindings !== result.bindings) {
+                let ok = true;
+                for (const [k, v] of cr.bindings.entries()) {
+                    const v2 = result.bindings.get(k);
+                    if (!v2) {
+                        ok = false;
+                        break;
+                    }
+                    if (v !== v2 && v.length === v2.length && v.every((x, i) => v2[i] === x)) {
+                        result.bindings.set(k, v);
+                    } else if (v !== v2) {
+                        ok = false;
+                        break;
+                    }
+                }
+                if (ok) {
+                    result.bindings = cr.bindings;
+                }
+            }
+            if (cr.ty === result.ty && cr.path === result.path
+                && cr.bindings === result.bindings && cr.generics === result.generics
+                && cr.ty === result.ty && cr.name === result.name
+                && cr.unboxFlag === result.unboxFlag
+            ) {
+                return cr;
+            }
+        }
+        this.TYPES_POOL.set(result.id, result);
+        return result;
+    }
 
-        // @ts-expect-error
+    /**
+     * Executes the parsed query and builds a {ResultsTable}.
+     *
+     * @param  {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} parsedQuery
+     *     - The parsed user query
+     * @param  {Object} filterCrates - Crate to search in if defined
+     * @param  {string} currentCrate - Current crate, to rank results from this crate higher
+     *
+     * @return {Promise<rustdoc.ResultsTable>}
+     */
+    async execQuery(parsedQuery, filterCrates, currentCrate) {
+        const queryLen =
+            parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
+            parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
+        const maxEditDistance = Math.floor(queryLen / 3);
+
+        /**
+         * @param {rustdoc.Row} item
+         * @returns {[string, string, string]}
+         */
         const buildHrefAndPath = item => {
             let displayPath;
             let href;
-            if (item.is_alias) {
-                this.FOUND_ALIASES.add(item.word);
-                item = item.original;
-            }
             const type = itemTypes[item.ty];
             const name = item.name;
-            let path = item.path;
-            let exactPath = item.exactPath;
+            let path = item.modulePath;
+            let exactPath = item.exactModulePath;
 
             if (type === "mod") {
                 displayPath = path + "::";
                 href = this.rootPath + path.replace(/::/g, "/") + "/" +
                     name + "/index.html";
             } else if (type === "import") {
-                displayPath = item.path + "::";
-                href = this.rootPath + item.path.replace(/::/g, "/") +
+                displayPath = item.modulePath + "::";
+                href = this.rootPath + item.modulePath.replace(/::/g, "/") +
                     "/index.html#reexport." + name;
             } else if (type === "primitive" || type === "keyword") {
                 displayPath = "";
@@ -2754,13 +2050,13 @@ class DocSearch {
             } else if (type === "externcrate") {
                 displayPath = "";
                 href = this.rootPath + name + "/index.html";
-            } else if (item.parent !== undefined) {
+            } else if (item.parent) {
                 const myparent = item.parent;
                 let anchor = type + "." + name;
-                const parentType = itemTypes[myparent.ty];
+                const parentType = itemTypes[myparent.path.ty];
                 let pageType = parentType;
                 let pageName = myparent.name;
-                exactPath = `${myparent.exactPath}::${myparent.name}`;
+                exactPath = `${myparent.path.exactModulePath}::${myparent.name}`;
 
                 if (parentType === "primitive") {
                     displayPath = myparent.name + "::";
@@ -2768,9 +2064,9 @@ class DocSearch {
                 } else if (type === "structfield" && parentType === "variant") {
                     // Structfields belonging to variants are special: the
                     // final path element is the enum name.
-                    const enumNameIdx = item.path.lastIndexOf("::");
-                    const enumName = item.path.substr(enumNameIdx + 2);
-                    path = item.path.substr(0, enumNameIdx);
+                    const enumNameIdx = item.modulePath.lastIndexOf("::");
+                    const enumName = item.modulePath.substr(enumNameIdx + 2);
+                    path = item.modulePath.substr(0, enumNameIdx);
                     displayPath = path + "::" + enumName + "::" + myparent.name + "::";
                     anchor = "variant." + myparent.name + ".field." + name;
                     pageType = "enum";
@@ -2778,16 +2074,16 @@ class DocSearch {
                 } else {
                     displayPath = path + "::" + myparent.name + "::";
                 }
-                if (item.implDisambiguator !== null) {
-                    anchor = item.implDisambiguator + "/" + anchor;
+                if (item.entry && item.entry.associatedItemDisambiguator !== null) {
+                    anchor = item.entry.associatedItemDisambiguator + "/" + anchor;
                 }
                 href = this.rootPath + path.replace(/::/g, "/") +
                     "/" + pageType +
                     "." + pageName +
                     ".html#" + anchor;
             } else {
-                displayPath = item.path + "::";
-                href = this.rootPath + item.path.replace(/::/g, "/") +
+                displayPath = item.modulePath + "::";
+                href = this.rootPath + item.modulePath.replace(/::/g, "/") +
                     "/" + type + "." + name + ".html";
             }
             return [displayPath, href, `${exactPath}::${name}`];
@@ -2810,82 +2106,16 @@ class DocSearch {
          * Add extra data to result objects, and filter items that have been
          * marked for removal.
          *
-         * @param {rustdoc.ResultObject[]} results
-         * @param {"sig"|"elems"|"returned"|null} typeInfo
-         * @returns {rustdoc.ResultObject[]}
-         */
-        const transformResults = (results, typeInfo) => {
-            const duplicates = new Set();
-            const out = [];
-
-            for (const result of results) {
-                if (result.id !== -1) {
-                    const res = buildHrefAndPath(this.searchIndex[result.id]);
-                    // many of these properties don't strictly need to be
-                    // copied over, but copying them over satisfies tsc,
-                    // and hopefully plays nice with the shape optimization
-                    // of the browser engine.
-                    /** @type {rustdoc.ResultObject} */
-                    const obj = Object.assign({
-                        parent: result.parent,
-                        type: result.type,
-                        dist: result.dist,
-                        path_dist: result.path_dist,
-                        index: result.index,
-                        desc: result.desc,
-                        item: result.item,
-                        displayPath: pathSplitter(res[0]),
-                        fullPath: "",
-                        href: "",
-                        displayTypeSignature: null,
-                    }, this.searchIndex[result.id]);
-
-                    // To be sure than it some items aren't considered as duplicate.
-                    obj.fullPath = res[2] + "|" + obj.ty;
-
-                    if (duplicates.has(obj.fullPath)) {
-                        continue;
-                    }
-
-                    // Exports are specifically not shown if the items they point at
-                    // are already in the results.
-                    if (obj.ty === TY_IMPORT && duplicates.has(res[2])) {
-                        continue;
-                    }
-                    if (duplicates.has(res[2] + "|" + TY_IMPORT)) {
-                        continue;
-                    }
-                    duplicates.add(obj.fullPath);
-                    duplicates.add(res[2]);
-
-                    if (typeInfo !== null) {
-                        obj.displayTypeSignature =
-                            // @ts-expect-error
-                            this.formatDisplayTypeSignature(obj, typeInfo);
-                    }
-
-                    obj.href = res[1];
-                    out.push(obj);
-                    if (out.length >= MAX_RESULTS) {
-                        break;
-                    }
-                }
-            }
-            return out;
-        };
-
-        /**
-         * Add extra data to result objects, and filter items that have been
-         * marked for removal.
-         *
          * The output is formatted as an array of hunks, where odd numbered
          * hunks are highlighted and even numbered ones are not.
          *
          * @param {rustdoc.ResultObject} obj
          * @param {"sig"|"elems"|"returned"|null} typeInfo
+         * @param {rustdoc.QueryElement[]} elems
+         * @param {rustdoc.QueryElement[]} returned
          * @returns {Promise<rustdoc.DisplayTypeSignature>}
          */
-        this.formatDisplayTypeSignature = async(obj, typeInfo) => {
+        const formatDisplayTypeSignature = async(obj, typeInfo, elems, returned) => {
             const objType = obj.type;
             if (!objType) {
                 return {type: [], mappedNames: new Map(), whereClause: new Map()};
@@ -2897,13 +2127,13 @@ class DocSearch {
             if (typeInfo !== "elems" && typeInfo !== "returned") {
                 fnInputs = unifyFunctionTypes(
                     objType.inputs,
-                    parsedQuery.elems,
+                    elems,
                     objType.where_clause,
                     null,
                     mgensScratch => {
                         fnOutput = unifyFunctionTypes(
                             objType.output,
-                            parsedQuery.returned,
+                            returned,
                             objType.where_clause,
                             mgensScratch,
                             mgensOut => {
@@ -2917,10 +2147,9 @@ class DocSearch {
                     0,
                 );
             } else {
-                const arr = typeInfo === "elems" ? objType.inputs : objType.output;
                 const highlighted = unifyFunctionTypes(
-                    arr,
-                    parsedQuery.elems,
+                    typeInfo === "elems" ? objType.inputs : objType.output,
+                    typeInfo === "elems" ? elems : returned,
                     objType.where_clause,
                     null,
                     mgensOut => {
@@ -2969,15 +2198,15 @@ class DocSearch {
                 }
             };
 
-            parsedQuery.elems.forEach(remapQuery);
-            parsedQuery.returned.forEach(remapQuery);
+            elems.forEach(remapQuery);
+            returned.forEach(remapQuery);
 
             /**
              * Write text to a highlighting array.
              * Index 0 is not highlighted, index 1 is highlighted,
              * index 2 is not highlighted, etc.
              *
-             * @param {{name?: string, highlighted?: boolean}} fnType - input
+             * @param {{name: string|null, highlighted?: boolean}} fnType - input
              * @param {string[]} result
              */
             const pushText = (fnType, result) => {
@@ -3004,8 +2233,9 @@ class DocSearch {
              *
              * @param {rustdoc.HighlightedFunctionType} fnType - input
              * @param {string[]} result
+             * @returns {Promise<void>}
              */
-            const writeHof = (fnType, result) => {
+            const writeHof = async(fnType, result) => {
                 const hofOutput = fnType.bindings.get(this.typeNameIdOfOutput) || [];
                 const hofInputs = fnType.generics;
                 pushText(fnType, result);
@@ -3016,7 +2246,7 @@ class DocSearch {
                         pushText({ name: ", ", highlighted: false }, result);
                     }
                     needsComma = true;
-                    writeFn(fnType, result);
+                    await writeFn(fnType, result);
                 }
                 pushText({
                     name: hofOutput.length === 0 ? ")" : ") -> ",
@@ -3031,7 +2261,7 @@ class DocSearch {
                         pushText({ name: ", ", highlighted: false }, result);
                     }
                     needsComma = true;
-                    writeFn(fnType, result);
+                    await writeFn(fnType, result);
                 }
                 if (hofOutput.length > 1) {
                     pushText({name: ")", highlighted: false}, result);
@@ -3044,8 +2274,9 @@ class DocSearch {
              *
              * @param {rustdoc.HighlightedFunctionType} fnType
              * @param {string[]} result
+             * @returns {Promise<boolean>}
              */
-            const writeSpecialPrimitive = (fnType, result) => {
+            const writeSpecialPrimitive = async(fnType, result) => {
                 if (fnType.id === this.typeNameIdOfArray || fnType.id === this.typeNameIdOfSlice ||
                     fnType.id === this.typeNameIdOfTuple || fnType.id === this.typeNameIdOfUnit) {
                     const [ob, sb] =
@@ -3054,7 +2285,7 @@ class DocSearch {
                         ["[", "]"] :
                         ["(", ")"];
                     pushText({ name: ob, highlighted: fnType.highlighted }, result);
-                    onEachBtwn(
+                    await onEachBtwnAsync(
                         fnType.generics,
                         nested => writeFn(nested, result),
                         // @ts-expect-error
@@ -3065,11 +2296,11 @@ class DocSearch {
                 } else if (fnType.id === this.typeNameIdOfReference) {
                     pushText({ name: "&", highlighted: fnType.highlighted }, result);
                     let prevHighlighted = false;
-                    onEachBtwn(
+                    await onEachBtwnAsync(
                         fnType.generics,
-                        value => {
+                        async value => {
                             prevHighlighted = !!value.highlighted;
-                            writeFn(value, result);
+                            await writeFn(value, result);
                         },
                         // @ts-expect-error
                         value => pushText({
@@ -3078,8 +2309,16 @@ class DocSearch {
                         }, result),
                     );
                     return true;
-                } else if (fnType.id === this.typeNameIdOfFn) {
-                    writeHof(fnType, result);
+                } else if (
+                    fnType.id === this.typeNameIdOfFn ||
+                    fnType.id === this.typeNameIdOfFnMut ||
+                    fnType.id === this.typeNameIdOfFnOnce ||
+                    fnType.id === this.typeNameIdOfFnPtr
+                ) {
+                    await writeHof(fnType, result);
+                    return true;
+                } else if (fnType.id === this.typeNameIdOfNever) {
+                    pushText({ name: "!", highlighted: fnType.highlighted }, result);
                     return true;
                 }
                 return false;
@@ -3091,8 +2330,9 @@ class DocSearch {
              *
              * @param {rustdoc.HighlightedFunctionType} fnType
              * @param {string[]} result
+             * @returns {Promise<void>}
              */
-            const writeFn = (fnType, result) => {
+            const writeFn = async(fnType, result) => {
                 if (fnType.id !== null && fnType.id < 0) {
                     if (fnParamNames[-1 - fnType.id] === "") {
                         // Normally, there's no need to shown an unhighlighted
@@ -3101,7 +2341,7 @@ class DocSearch {
                             fnType.generics :
                             objType.where_clause[-1 - fnType.id];
                         for (const nested of generics) {
-                            writeFn(nested, result);
+                            await writeFn(nested, result);
                         }
                         return;
                     } else if (mgens) {
@@ -3120,7 +2360,7 @@ class DocSearch {
                     }, result);
                     /** @type{string[]} */
                     const where = [];
-                    onEachBtwn(
+                    await onEachBtwnAsync(
                         fnType.generics,
                         nested => writeFn(nested, where),
                         // @ts-expect-error
@@ -3131,32 +2371,61 @@ class DocSearch {
                     }
                 } else {
                     if (fnType.ty === TY_PRIMITIVE) {
-                        if (writeSpecialPrimitive(fnType, result)) {
+                        if (await writeSpecialPrimitive(fnType, result)) {
                             return;
                         }
                     } else if (fnType.ty === TY_TRAIT && (
                         fnType.id === this.typeNameIdOfFn ||
-                            fnType.id === this.typeNameIdOfFnMut ||
-                            fnType.id === this.typeNameIdOfFnOnce)) {
-                        writeHof(fnType, result);
+                        fnType.id === this.typeNameIdOfFnMut ||
+                        fnType.id === this.typeNameIdOfFnOnce ||
+                        fnType.id === this.typeNameIdOfFnPtr
+                    )) {
+                        await writeHof(fnType, result);
+                        return;
+                    } else if (fnType.name === "" &&
+                        fnType.bindings.size === 0 &&
+                        fnType.generics.length !== 0
+                    ) {
+                        pushText({ name: "impl ", highlighted: false }, result);
+                        if (fnType.generics.length > 1) {
+                            pushText({ name: "(", highlighted: false }, result);
+                        }
+                        await onEachBtwnAsync(
+                            fnType.generics,
+                            value => writeFn(value, result),
+                            // @ts-expect-error
+                            () => pushText({ name: ", ",  highlighted: false }, result),
+                        );
+                        if (fnType.generics.length > 1) {
+                            pushText({ name: ")", highlighted: false }, result);
+                        }
                         return;
                     }
                     pushText(fnType, result);
                     let hasBindings = false;
                     if (fnType.bindings.size > 0) {
-                        onEachBtwn(
-                            fnType.bindings,
-                            ([key, values]) => {
-                                const name = this.assocTypeIdNameMap.get(key);
+                        await onEachBtwnAsync(
+                            await Promise.all([...fnType.bindings.entries()].map(
+                                /**
+                                 * @param {[number, rustdoc.HighlightedFunctionType[]]} param0
+                                 * @returns {Promise<[
+                                 *     string|null,
+                                 *     rustdoc.HighlightedFunctionType[],
+                                 * ]>}
+                                 */
+                                async([key, values]) => [await this.getName(key), values],
+                            )),
+                            async([name, values]) => {
                                 // @ts-expect-error
                                 if (values.length === 1 && values[0].id < 0 &&
                                     // @ts-expect-error
-                                    `${fnType.name}::${name}` === fnParamNames[-1 - values[0].id]) {
+                                    `${fnType.name}::${name}` === fnParamNames[-1 - values[0].id]
+                                ) {
                                     // the internal `Item=Iterator::Item` type variable should be
                                     // shown in the where clause and name mapping output, but is
                                     // redundant in this spot
                                     for (const value of values) {
-                                        writeFn(value, []);
+                                        await writeFn(value, []);
                                     }
                                     return true;
                                 }
@@ -3169,7 +2438,7 @@ class DocSearch {
                                     name: values.length !== 1 ? "=(" : "=",
                                     highlighted: false,
                                 }, result);
-                                onEachBtwn(
+                                await onEachBtwnAsync(
                                     values || [],
                                     value => writeFn(value, result),
                                     // @ts-expect-error
@@ -3186,7 +2455,7 @@ class DocSearch {
                     if (fnType.generics.length > 0) {
                         pushText({ name: hasBindings ? ", " : "<", highlighted: false }, result);
                     }
-                    onEachBtwn(
+                    await onEachBtwnAsync(
                         fnType.generics,
                         value => writeFn(value, result),
                         // @ts-expect-error
@@ -3199,14 +2468,14 @@ class DocSearch {
             };
             /** @type {string[]} */
             const type = [];
-            onEachBtwn(
+            await onEachBtwnAsync(
                 fnInputs,
                 fnType => writeFn(fnType, type),
                 // @ts-expect-error
                 () => pushText({ name: ", ",  highlighted: false }, type),
             );
             pushText({ name: " -> ", highlighted: false }, type);
-            onEachBtwn(
+            await onEachBtwnAsync(
                 fnOutput,
                 fnType => writeFn(fnType, type),
                 // @ts-expect-error
@@ -3217,176 +2486,252 @@ class DocSearch {
         };
 
         /**
-         * This function takes a result map, and sorts it by various criteria, including edit
-         * distance, substring match, and the crate it comes from.
+         * Add extra data to result objects, and filter items that have been
+         * marked for removal.
          *
-         * @param {rustdoc.Results} results
+         * @param {[rustdoc.PlainResultObject, rustdoc.Row][]} results
          * @param {"sig"|"elems"|"returned"|null} typeInfo
-         * @param {string} preferredCrate
-         * @returns {Promise<rustdoc.ResultObject[]>}
+         * @param {Set<string>} duplicates
+         * @returns {rustdoc.ResultObject[]}
          */
-        const sortResults = async(results, typeInfo, preferredCrate) => {
-            const userQuery = parsedQuery.userQuery;
-            const normalizedUserQuery = parsedQuery.userQuery.toLowerCase();
-            const isMixedCase = normalizedUserQuery !== userQuery;
-            const result_list = [];
-            const isReturnTypeQuery = parsedQuery.elems.length === 0 ||
-                typeInfo === "returned";
-            for (const result of results.values()) {
-                result.item = this.searchIndex[result.id];
-                result.word = this.searchIndex[result.id].word;
-                if (isReturnTypeQuery) {
-                    // We are doing a return-type based search, deprioritize "clone-like" results,
-                    // ie. functions that also take the queried type as an argument.
-                    const resultItemType = result.item && result.item.type;
-                    if (!resultItemType) {
+        const transformResults = (results, typeInfo, duplicates) => {
+            const out = [];
+
+            for (const [result, item] of results) {
+                if (item.id !== -1) {
+                    const res = buildHrefAndPath(item);
+                    // many of these properties don't strictly need to be
+                    // copied over, but copying them over satisfies tsc,
+                    // and hopefully plays nice with the shape optimization
+                    // of the browser engine.
+                    /** @type {rustdoc.ResultObject} */
+                    const obj = Object.assign({
+                        parent: item.parent ? {
+                            path: item.parent.path.modulePath,
+                            exactPath: item.parent.path.exactModulePath ||
+                                item.parent.path.modulePath,
+                            name: item.parent.name,
+                            ty: item.parent.path.ty,
+                        } : undefined,
+                        type: item.type && item.type.functionSignature ?
+                            item.type.functionSignature :
+                            undefined,
+                        paramNames: item.type && item.type.paramNames ?
+                            item.type.paramNames :
+                            undefined,
+                        dist: result.dist,
+                        path_dist: result.path_dist,
+                        index: result.index,
+                        desc: this.getDesc(result.id),
+                        item,
+                        displayPath: pathSplitter(res[0]),
+                        fullPath: "",
+                        href: "",
+                        displayTypeSignature: null,
+                    }, result);
+
+                    // To be sure than it some items aren't considered as duplicate.
+                    obj.fullPath = res[2] + "|" + obj.item.ty;
+
+                    if (duplicates.has(obj.fullPath)) {
                         continue;
                     }
-                    const inputs = resultItemType.inputs;
-                    const where_clause = resultItemType.where_clause;
-                    if (containsTypeFromQuery(inputs, where_clause)) {
-                        result.path_dist *= 100;
-                        result.dist *= 100;
+
+                    // Exports are specifically not shown if the items they point at
+                    // are already in the results.
+                    if (obj.item.ty === TY_IMPORT && duplicates.has(res[2])) {
+                        continue;
+                    }
+                    if (duplicates.has(res[2] + "|" + TY_IMPORT)) {
+                        continue;
+                    }
+                    duplicates.add(obj.fullPath);
+                    duplicates.add(res[2]);
+
+                    if (typeInfo !== null) {
+                        obj.displayTypeSignature = formatDisplayTypeSignature(
+                            obj,
+                            typeInfo,
+                            result.elems,
+                            result.returned,
+                        );
+                    }
+
+                    obj.href = res[1];
+                    out.push(obj);
+                    if (out.length >= MAX_RESULTS) {
+                        break;
                     }
                 }
-                result_list.push(result);
             }
 
-            result_list.sort((aaa, bbb) => {
-                /** @type {number} */
-                let a;
-                /** @type {number} */
-                let b;
+            return out;
+        };
 
-                // sort by exact case-sensitive match
-                if (isMixedCase) {
-                    a = Number(aaa.item.name !== userQuery);
-                    b = Number(bbb.item.name !== userQuery);
-                    if (a !== b) {
-                        return a - b;
+        const sortAndTransformResults =
+            /**
+             * @this {DocSearch}
+             * @param {Array<rustdoc.PlainResultObject|null>} results
+             * @param {"sig"|"elems"|"returned"|null} typeInfo
+             * @param {string} preferredCrate
+             * @param {Set<string>} duplicates
+             * @returns {AsyncGenerator<rustdoc.ResultObject, number>}
+             */
+            async function*(results, typeInfo, preferredCrate, duplicates) {
+                const userQuery = parsedQuery.userQuery;
+                const normalizedUserQuery = parsedQuery.userQuery.toLowerCase();
+                const isMixedCase = normalizedUserQuery !== userQuery;
+                /**
+                 * @type {[rustdoc.PlainResultObject, rustdoc.Row][]}
+                 */
+                const result_list = [];
+                for (const result of results.values()) {
+                    if (!result) {
+                        continue;
+                    }
+                    /**
+                     * @type {rustdoc.Row?}
+                     */
+                    const item = await this.getRow(result.id);
+                    if (!item) {
+                        continue;
+                    }
+                    if (filterCrates !== null && item.crate !== filterCrates) {
+                        continue;
+                    }
+                    if (item) {
+                        result_list.push([result, item]);
+                    } else {
+                        continue;
                     }
                 }
 
-                // sort by exact match with regard to the last word (mismatch goes later)
-                a = Number(aaa.word !== normalizedUserQuery);
-                b = Number(bbb.word !== normalizedUserQuery);
-                if (a !== b) {
-                    return a - b;
-                }
+                result_list.sort(([aaa, aai], [bbb, bbi]) => {
+                    /** @type {number} */
+                    let a;
+                    /** @type {number} */
+                    let b;
+
+                    if (typeInfo === null) {
+                        // in name based search...
+
+                        // sort by exact case-sensitive match
+                        if (isMixedCase) {
+                            a = Number(aai.name !== userQuery);
+                            b = Number(bbi.name !== userQuery);
+                            if (a !== b) {
+                                return a - b;
+                            }
+                        }
 
-                // sort by index of keyword in item name (no literal occurrence goes later)
-                a = Number(aaa.index < 0);
-                b = Number(bbb.index < 0);
-                if (a !== b) {
-                    return a - b;
-                }
+                        // sort by exact match with regard to the last word (mismatch goes later)
+                        a = Number(aai.normalizedName !== normalizedUserQuery);
+                        b = Number(bbi.normalizedName !== normalizedUserQuery);
+                        if (a !== b) {
+                            return a - b;
+                        }
 
-                // in type based search, put functions first
-                if (parsedQuery.hasReturnArrow) {
-                    a = Number(!isFnLikeTy(aaa.item.ty));
-                    b = Number(!isFnLikeTy(bbb.item.ty));
+                        // sort by index of keyword in item name (no literal occurrence goes later)
+                        a = Number(aaa.index < 0);
+                        b = Number(bbb.index < 0);
+                        if (a !== b) {
+                            return a - b;
+                        }
+                    }
+
+                    // Sort by distance in the path part, if specified
+                    // (less changes required to match means higher rankings)
+                    a = Number(aaa.path_dist);
+                    b = Number(bbb.path_dist);
                     if (a !== b) {
                         return a - b;
                     }
-                }
 
-                // Sort by distance in the path part, if specified
-                // (less changes required to match means higher rankings)
-                a = Number(aaa.path_dist);
-                b = Number(bbb.path_dist);
-                if (a !== b) {
-                    return a - b;
-                }
-
-                // (later literal occurrence, if any, goes later)
-                a = Number(aaa.index);
-                b = Number(bbb.index);
-                if (a !== b) {
-                    return a - b;
-                }
+                    // (later literal occurrence, if any, goes later)
+                    a = Number(aaa.index);
+                    b = Number(bbb.index);
+                    if (a !== b) {
+                        return a - b;
+                    }
 
-                // Sort by distance in the name part, the last part of the path
-                // (less changes required to match means higher rankings)
-                a = Number(aaa.dist);
-                b = Number(bbb.dist);
-                if (a !== b) {
-                    return a - b;
-                }
+                    // Sort by distance in the name part, the last part of the path
+                    // (less changes required to match means higher rankings)
+                    a = Number(aaa.dist);
+                    b = Number(bbb.dist);
+                    if (a !== b) {
+                        return a - b;
+                    }
 
-                // sort deprecated items later
-                a = Number(
-                    // @ts-expect-error
-                    this.searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex),
-                );
-                b = Number(
-                    // @ts-expect-error
-                    this.searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex),
-                );
-                if (a !== b) {
-                    return a - b;
-                }
+                    // sort aliases lower
+                    a = Number(aaa.is_alias);
+                    b = Number(bbb.is_alias);
+                    if (a !== b) {
+                        return a - b;
+                    }
 
-                // sort by crate (current crate comes first)
-                a = Number(aaa.item.crate !== preferredCrate);
-                b = Number(bbb.item.crate !== preferredCrate);
-                if (a !== b) {
-                    return a - b;
-                }
+                    // sort deprecated items later
+                    a = Number(aai.deprecated);
+                    b = Number(bbi.deprecated);
+                    if (a !== b) {
+                        return a - b;
+                    }
 
-                // sort by item name length (longer goes later)
-                a = Number(aaa.word.length);
-                b = Number(bbb.word.length);
-                if (a !== b) {
-                    return a - b;
-                }
+                    // sort by crate (current crate comes first)
+                    a = Number(aai.crate !== preferredCrate);
+                    b = Number(bbi.crate !== preferredCrate);
+                    if (a !== b) {
+                        return a - b;
+                    }
 
-                // sort doc alias items later
-                a = Number(aaa.item.is_alias === true);
-                b = Number(bbb.item.is_alias === true);
-                if (a !== b) {
-                    return a - b;
-                }
+                    // sort by item name length (longer goes later)
+                    a = Number(aai.normalizedName.length);
+                    b = Number(bbi.normalizedName.length);
+                    if (a !== b) {
+                        return a - b;
+                    }
 
-                // sort by item name (lexicographically larger goes later)
-                let aw = aaa.word;
-                let bw = bbb.word;
-                if (aw !== bw) {
-                    return (aw > bw ? +1 : -1);
-                }
+                    // sort by item name (lexicographically larger goes later)
+                    let aw = aai.normalizedName;
+                    let bw = bbi.normalizedName;
+                    if (aw !== bw) {
+                        return (aw > bw ? +1 : -1);
+                    }
 
-                // sort by description (no description goes later)
-                a = Number(
-                    // @ts-expect-error
-                    this.searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex),
-                );
-                b = Number(
-                    // @ts-expect-error
-                    this.searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex),
-                );
-                if (a !== b) {
-                    return a - b;
-                }
+                    // sort by description (no description goes later)
+                    const di = this.database.getData("desc");
+                    if (di) {
+                        a = Number(di.isEmpty(aaa.id));
+                        b = Number(di.isEmpty(bbb.id));
+                        if (a !== b) {
+                            return a - b;
+                        }
+                    }
 
-                // sort by type (later occurrence in `itemTypes` goes later)
-                a = Number(aaa.item.ty);
-                b = Number(bbb.item.ty);
-                if (a !== b) {
-                    return a - b;
-                }
+                    // sort by type (later occurrence in `itemTypes` goes later)
+                    a = Number(aai.ty);
+                    b = Number(bbi.ty);
+                    if (a !== b) {
+                        return a - b;
+                    }
 
-                // sort by path (lexicographically larger goes later)
-                aw = aaa.item.path;
-                bw = bbb.item.path;
-                if (aw !== bw) {
-                    return (aw > bw ? +1 : -1);
-                }
+                    // sort by path (lexicographically larger goes later)
+                    const ap = aai.modulePath;
+                    const bp = bbi.modulePath;
+                    aw = ap === undefined ? "" : ap;
+                    bw = bp === undefined ? "" : bp;
+                    if (aw !== bw) {
+                        return (aw > bw ? +1 : -1);
+                    }
 
-                // que sera, sera
-                return 0;
-            });
+                    // que sera, sera
+                    return 0;
+                });
 
-            return transformResults(result_list, typeInfo);
-        };
+                const transformed_result_list = transformResults(result_list, typeInfo, duplicates);
+                yield* transformed_result_list;
+                return transformed_result_list.length;
+            }
+            .bind(this);
 
         /**
          * This function checks if a list of search query `queryElems` can all be found in the
@@ -3938,6 +3283,8 @@ class DocSearch {
                 }
                 return true;
             } else {
+                // For these special cases, matching code need added to the inverted index.
+                // search_index.rs -> convert_render_type does this
                 if (queryElem.id === this.typeNameIdOfArrayOrSlice &&
                     (fnType.id === this.typeNameIdOfSlice || fnType.id === this.typeNameIdOfArray)
                 ) {
@@ -3948,10 +3295,12 @@ class DocSearch {
                 ) {
                     // () matches primitive:tuple or primitive:unit
                     // if it matches, then we're fine, and this is an appropriate match candidate
-                } else if (queryElem.id === this.typeNameIdOfHof &&
-                    (fnType.id === this.typeNameIdOfFn || fnType.id === this.typeNameIdOfFnMut ||
-                        fnType.id === this.typeNameIdOfFnOnce)
-                ) {
+                } else if (queryElem.id === this.typeNameIdOfHof && (
+                    fnType.id === this.typeNameIdOfFn ||
+                    fnType.id === this.typeNameIdOfFnMut ||
+                    fnType.id === this.typeNameIdOfFnOnce ||
+                    fnType.id === this.typeNameIdOfFnPtr
+                )) {
                     // -> matches fn, fnonce, and fnmut
                     // if it matches, then we're fine, and this is an appropriate match candidate
                 } else if (fnType.id !== queryElem.id || queryElem.id === null) {
@@ -4134,21 +3483,13 @@ class DocSearch {
          * This function checks if the given list contains any
          * (non-generic) types mentioned in the query.
          *
+         * @param {rustdoc.QueryElement[]} elems
          * @param {rustdoc.FunctionType[]} list    - A list of function types.
          * @param {rustdoc.FunctionType[][]} where_clause - Trait bounds for generic items.
          */
-        function containsTypeFromQuery(list, where_clause) {
+        function containsTypeFromQuery(elems, list, where_clause) {
             if (!list) return false;
-            for (const ty of parsedQuery.returned) {
-                // negative type ids are generics
-                if (ty.id !== null && ty.id < 0) {
-                    continue;
-                }
-                if (checkIfInList(list, ty, where_clause, null, 0)) {
-                    return true;
-                }
-            }
-            for (const ty of parsedQuery.elems) {
+            for (const ty of elems) {
                 if (ty.id !== null && ty.id < 0) {
                     continue;
                 }
@@ -4240,10 +3581,10 @@ class DocSearch {
         /**
          * Compute an "edit distance" that ignores missing path elements.
          * @param {string[]} contains search query path
-         * @param {rustdoc.Row} ty indexed item
+         * @param {string[]} path indexed page path
          * @returns {null|number} edit distance
          */
-        function checkPath(contains, ty) {
+        function checkPath(contains, path) {
             if (contains.length === 0) {
                 return 0;
             }
@@ -4251,11 +3592,6 @@ class DocSearch {
                 contains.reduce((acc, next) => acc + next.length, 0) / 3,
             );
             let ret_dist = maxPathEditDistance + 1;
-            const path = ty.path.split("::");
-
-            if (ty.parent && ty.parent.name) {
-                path.push(ty.parent.name.toLowerCase());
-            }
 
             const length = path.length;
             const clength = contains.length;
@@ -4281,7 +3617,32 @@ class DocSearch {
             return ret_dist > maxPathEditDistance ? null : ret_dist;
         }
 
-        // @ts-expect-error
+        /**
+         * Compute an "edit distance" that ignores missing path elements.
+         * @param {string[]} contains search query path
+         * @param {rustdoc.Row} row indexed item
+         * @returns {null|number} edit distance
+         */
+        function checkRowPath(contains, row) {
+            if (contains.length === 0) {
+                return 0;
+            }
+
+            const path = row.modulePath.split("::");
+
+            if (row.parent && row.parent.name) {
+                path.push(row.parent.name.toLowerCase());
+            }
+
+            return checkPath(contains, path);
+        }
+
+        /**
+         *
+         * @param {number} filter
+         * @param {rustdoc.ItemType} type
+         * @returns
+         */
         function typePassesFilter(filter, type) {
             // No filter or Exact mach
             if (filter <= NO_TYPE_FILTER || filter === type) return true;
@@ -4303,366 +3664,839 @@ class DocSearch {
             return false;
         }
 
-        // @ts-expect-error
-        const handleAliases = async(ret, query, filterCrates, currentCrate) => {
-            const lowerQuery = query.toLowerCase();
-            if (this.FOUND_ALIASES.has(lowerQuery)) {
-                return;
-            }
-            this.FOUND_ALIASES.add(lowerQuery);
-            // We separate aliases and crate aliases because we want to have current crate
-            // aliases to be before the others in the displayed results.
-            // @ts-expect-error
-            const aliases = [];
-            // @ts-expect-error
-            const crateAliases = [];
-            if (filterCrates !== null) {
-                if (this.ALIASES.has(filterCrates)
-                    && this.ALIASES.get(filterCrates).has(lowerQuery)) {
-                    const query_aliases = this.ALIASES.get(filterCrates).get(lowerQuery);
-                    for (const alias of query_aliases) {
-                        aliases.push(alias);
-                    }
+        const innerRunNameQuery =
+            /**
+             * @this {DocSearch}
+             * @param {string} currentCrate
+             * @returns {AsyncGenerator<rustdoc.ResultObject>}
+             */
+            async function*(currentCrate) {
+                const index = this.database.getIndex("normalizedName");
+                if (!index) {
+                    return;
                 }
-            } else {
-                for (const [crate, crateAliasesIndex] of this.ALIASES) {
-                    if (crateAliasesIndex.has(lowerQuery)) {
-                        // @ts-expect-error
-                        const pushTo = crate === currentCrate ? crateAliases : aliases;
-                        const query_aliases = crateAliasesIndex.get(lowerQuery);
-                        for (const alias of query_aliases) {
-                            pushTo.push(alias);
+                const idDuplicates = new Set();
+                const pathDuplicates = new Set();
+                let count = 0;
+                const prefixResults = [];
+                const normalizedUserQuery = parsedQuery.userQuery
+                    .replace(/[_"]/g, "")
+                    .toLowerCase();
+                /**
+                 * @param {string} name
+                 * @param {number} alias
+                 * @param {number} dist
+                 * @param {number} index
+                 * @returns {Promise<rustdoc.PlainResultObject?>}
+                 */
+                const handleAlias = async(name, alias, dist, index) => {
+                    return {
+                        id: alias,
+                        dist,
+                        path_dist: 0,
+                        index,
+                        alias: name,
+                        is_alias: true,
+                        elems: [], // only used in type-based queries
+                        returned: [], // only used in type-based queries
+                        original: await this.getRow(alias),
+                    };
+                };
+                /**
+                 * @param {Promise<rustdoc.PlainResultObject|null>[]} data
+                 * @returns {AsyncGenerator<rustdoc.ResultObject, boolean>}
+                 */
+                const flush = async function* (data) {
+                    const satr = sortAndTransformResults(
+                        await Promise.all(data),
+                        null,
+                        currentCrate,
+                        pathDuplicates,
+                    );
+                    data.length = 0;
+                    for await (const processed of satr) {
+                        yield processed;
+                        count += 1;
+                        if ((count & 0x7F) === 0) {
+                            await yieldToBrowser();
+                        }
+                        if (count >= MAX_RESULTS) {
+                            return true;
                         }
                     }
-                }
-            }
-
-            // @ts-expect-error
-            const sortFunc = (aaa, bbb) => {
-                if (aaa.original.path < bbb.original.path) {
-                    return 1;
-                } else if (aaa.original.path === bbb.original.path) {
-                    return 0;
-                }
-                return -1;
-            };
-            // @ts-expect-error
-            crateAliases.sort(sortFunc);
-            aliases.sort(sortFunc);
-
-            // @ts-expect-error
-            const pushFunc = alias => {
-                // Cloning `alias` to prevent its fields to be updated.
-                alias = {...alias};
-                const res = buildHrefAndPath(alias);
-                alias.displayPath = pathSplitter(res[0]);
-                alias.fullPath = alias.displayPath + alias.name;
-                alias.href = res[1];
-
-                ret.others.unshift(alias);
-                if (ret.others.length > MAX_RESULTS) {
-                    ret.others.pop();
-                }
-            };
-
-            aliases.forEach(pushFunc);
-            // @ts-expect-error
-            crateAliases.forEach(pushFunc);
-        };
-
-        /**
-         * This function adds the given result into the provided `results` map if it matches the
-         * following condition:
-         *
-         * * If it is a "literal search" (`parsedQuery.literalSearch`), then `dist` must be 0.
-         * * If it is not a "literal search", `dist` must be <= `maxEditDistance`.
-         *
-         * The `results` map contains information which will be used to sort the search results:
-         *
-         * * `fullId` is an `integer`` used as the key of the object we use for the `results` map.
-         * * `id` is the index in the `searchIndex` array for this element.
-         * * `index` is an `integer`` used to sort by the position of the word in the item's name.
-         * * `dist` is the main metric used to sort the search results.
-         * * `path_dist` is zero if a single-component search query is used, otherwise it's the
-         *   distance computed for everything other than the last path component.
-         *
-         * @param {rustdoc.Results} results
-         * @param {number} fullId
-         * @param {number} id
-         * @param {number} index
-         * @param {number} dist
-         * @param {number} path_dist
-         * @param {number} maxEditDistance
-         */
-        function addIntoResults(results, fullId, id, index, dist, path_dist, maxEditDistance) {
-            if (dist <= maxEditDistance || index !== -1) {
-                if (results.has(fullId)) {
-                    const result = results.get(fullId);
-                    if (result === undefined || result.dontValidate || result.dist <= dist) {
-                        return;
+                    return false;
+                };
+                const aliasResults = await index.search(normalizedUserQuery);
+                if (aliasResults) {
+                    for (const id of aliasResults.matches().entries()) {
+                        const [name, alias] = await Promise.all([
+                            this.getName(id),
+                            this.getAliasTarget(id),
+                        ]);
+                        if (name !== null &&
+                            alias !== null &&
+                            !idDuplicates.has(id) &&
+                            name.replace(/[_"]/g, "").toLowerCase() === normalizedUserQuery
+                        ) {
+                            prefixResults.push(handleAlias(name, alias, 0, 0));
+                            idDuplicates.add(id);
+                        }
                     }
                 }
-                // @ts-expect-error
-                results.set(fullId, {
-                    id: id,
-                    index: index,
-                    dontValidate: parsedQuery.literalSearch,
-                    dist: dist,
-                    path_dist: path_dist,
-                });
-            }
-        }
-
-        /**
-         * This function is called in case the query has more than one element. In this case, it'll
-         * try to match the items which validates all the elements. For `aa -> bb` will look for
-         * functions which have a parameter `aa` and has `bb` in its returned values.
-         *
-         * @param {rustdoc.Row} row
-         * @param {number} pos      - Position in the `searchIndex`.
-         * @param {rustdoc.Results} results
-         */
-        function handleArgs(row, pos, results) {
-            if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
-                return;
-            }
-            const rowType = row.type;
-            if (!rowType) {
-                return;
-            }
-
-            const tfpDist = compareTypeFingerprints(
-                row.id,
-                parsedQuery.typeFingerprint,
-            );
-            if (tfpDist === null) {
-                return;
-            }
-            // @ts-expect-error
-            if (results.size >= MAX_RESULTS && tfpDist > results.max_dist) {
-                return;
-            }
-
-            // If the result is too "bad", we return false and it ends this search.
-            if (!unifyFunctionTypes(
-                rowType.inputs,
-                parsedQuery.elems,
-                rowType.where_clause,
-                null,
-                // @ts-expect-error
-                mgens => {
-                    return unifyFunctionTypes(
-                        rowType.output,
-                        parsedQuery.returned,
-                        rowType.where_clause,
-                        mgens,
-                        checkTypeMgensForConflict,
-                        0, // unboxing depth
-                    );
-                },
-                0, // unboxing depth
-            )) {
-                return;
-            }
-
-            results.max_dist = Math.max(results.max_dist || 0, tfpDist);
-            addIntoResults(results, row.id, pos, 0, tfpDist, 0, Number.MAX_VALUE);
-        }
-
-        /**
-         * Compare the query fingerprint with the function fingerprint.
-         *
-         * @param {number} fullId - The function
-         * @param {Uint32Array} queryFingerprint - The query
-         * @returns {number|null} - Null if non-match, number if distance
-         *                          This function might return 0!
-         */
-        const compareTypeFingerprints = (fullId, queryFingerprint) => {
-            const fh0 = this.functionTypeFingerprint[fullId * 4];
-            const fh1 = this.functionTypeFingerprint[(fullId * 4) + 1];
-            const fh2 = this.functionTypeFingerprint[(fullId * 4) + 2];
-            const [qh0, qh1, qh2] = queryFingerprint;
-            // Approximate set intersection with bloom filters.
-            // This can be larger than reality, not smaller, because hashes have
-            // the property that if they've got the same value, they hash to the
-            // same thing. False positives exist, but not false negatives.
-            const [in0, in1, in2] = [fh0 & qh0, fh1 & qh1, fh2 & qh2];
-            // Approximate the set of items in the query but not the function.
-            // This might be smaller than reality, but cannot be bigger.
-            //
-            // | in_ | qh_ | XOR | Meaning                                          |
-            // | --- | --- | --- | ------------------------------------------------ |
-            // |  0  |  0  |  0  | Not present                                      |
-            // |  1  |  0  |  1  | IMPOSSIBLE because `in_` is `fh_ & qh_`          |
-            // |  1  |  1  |  0  | If one or both is false positive, false negative |
-            // |  0  |  1  |  1  | Since in_ has no false negatives, must be real   |
-            if ((in0 ^ qh0) || (in1 ^ qh1) || (in2 ^ qh2)) {
-                return null;
-            }
-            return this.functionTypeFingerprint[(fullId * 4) + 3];
-        };
-
-
-        const innerRunQuery = () => {
-            if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) {
+                if (parsedQuery.error !== null || parsedQuery.elems.length === 0) {
+                    yield* flush(prefixResults);
+                    return;
+                }
                 const elem = parsedQuery.elems[0];
-                // use arrow functions to preserve `this`.
-                /** @type {function(number): void} */
-                const handleNameSearch = id => {
-                    const row = this.searchIndex[id];
-                    if (!typePassesFilter(elem.typeFilter, row.ty) ||
+                const typeFilter = itemTypeFromName(elem.typeFilter);
+                /**
+                 * @param {number} id
+                 * @returns {Promise<rustdoc.PlainResultObject?>}
+                 */
+                const handleNameSearch = async id => {
+                    const row = await this.getRow(id);
+                    if (!row || !row.entry) {
+                        return null;
+                    }
+                    if (!typePassesFilter(typeFilter, row.ty) ||
                         (filterCrates !== null && row.crate !== filterCrates)) {
-                        return;
+                        return null;
                     }
 
+                    /** @type {number|null} */
                     let pathDist = 0;
                     if (elem.fullPath.length > 1) {
-
-                        const maybePathDist = checkPath(elem.pathWithoutLast, row);
-                        if (maybePathDist === null) {
-                            return;
+                        pathDist = checkRowPath(elem.pathWithoutLast, row);
+                        if (pathDist === null) {
+                            return null;
                         }
-                        pathDist = maybePathDist;
                     }
 
                     if (parsedQuery.literalSearch) {
-                        if (row.word === elem.pathLast) {
-                            addIntoResults(results_others, row.id, id, 0, 0, pathDist, 0);
-                        }
+                        return row.name.toLowerCase() === elem.pathLast ? {
+                            id,
+                            dist: 0,
+                            path_dist: 0,
+                            index: 0,
+                            elems: [], // only used in type-based queries
+                            returned: [], // only used in type-based queries
+                            is_alias: false,
+                        } : null;
                     } else {
-                        addIntoResults(
-                            results_others,
-                            row.id,
+                        return {
                             id,
-                            row.normalizedName.indexOf(elem.normalizedPathLast),
-                            editDistance(
+                            dist: editDistance(
                                 row.normalizedName,
                                 elem.normalizedPathLast,
                                 maxEditDistance,
                             ),
-                            pathDist,
-                            maxEditDistance,
-                        );
+                            path_dist: pathDist,
+                            index: row.normalizedName.indexOf(elem.normalizedPathLast),
+                            elems: [], // only used in type-based queries
+                            returned: [], // only used in type-based queries
+                            is_alias: false,
+                        };
                     }
                 };
-                if (elem.normalizedPathLast !== "") {
-                    const last = elem.normalizedPathLast;
-                    for (const id of this.nameTrie.search(last, this.tailTable)) {
-                        handleNameSearch(id);
+                if (elem.normalizedPathLast === "") {
+                    // faster full-table scan for this specific case.
+                    const nameData = this.database.getData("name");
+                    const l = nameData ? nameData.length : 0;
+                    for (let id = 0; id < l; ++id) {
+                        if (!idDuplicates.has(id)) {
+                            idDuplicates.add(id);
+                            prefixResults.push(handleNameSearch(id));
+                        }
+                        if (yield* flush(prefixResults)) {
+                            return;
+                        }
                     }
+                    return;
                 }
-                const length = this.searchIndex.length;
-
-                for (let i = 0, nSearchIndex = length; i < nSearchIndex; ++i) {
-                    // queries that end in :: bypass the trie
-                    if (elem.normalizedPathLast === "") {
-                        handleNameSearch(i);
+                const results = await index.search(elem.normalizedPathLast);
+                if (results) {
+                    for await (const result of results.prefixMatches()) {
+                        for (const id of result.entries()) {
+                            if (!idDuplicates.has(id)) {
+                                idDuplicates.add(id);
+                                prefixResults.push(handleNameSearch(id));
+                                const [name, alias] = await Promise.all([
+                                    this.getName(id),
+                                    this.getAliasTarget(id),
+                                ]);
+                                if (name !== null && alias !== null) {
+                                    prefixResults.push(handleAlias(name, alias, 0, 0));
+                                }
+                            }
+                        }
+                        if (yield* flush(prefixResults)) {
+                            return;
+                        }
                     }
-                    const row = this.searchIndex[i];
-                    if (filterCrates !== null && row.crate !== filterCrates) {
-                        continue;
+                    if (yield* flush(prefixResults)) {
+                        return;
                     }
-                    const tfpDist = compareTypeFingerprints(
-                        row.id,
-                        parsedQuery.typeFingerprint,
-                    );
-                    if (tfpDist !== null) {
-                        const in_args = row.type && row.type.inputs
-                            && checkIfInList(row.type.inputs, elem, row.type.where_clause, null, 0);
-                        const returned = row.type && row.type.output
-                            && checkIfInList(row.type.output, elem, row.type.where_clause, null, 0);
-                        if (in_args) {
-                            results_in_args.max_dist = Math.max(
-                                results_in_args.max_dist || 0,
-                                tfpDist,
-                            );
-                            const maxDist = results_in_args.size < MAX_RESULTS ?
-                                (tfpDist + 1) :
-                                results_in_args.max_dist;
-                            addIntoResults(results_in_args, row.id, i, -1, tfpDist, 0, maxDist);
-                        }
-                        if (returned) {
-                            results_returned.max_dist = Math.max(
-                                results_returned.max_dist || 0,
-                                tfpDist,
-                            );
-                            const maxDist = results_returned.size < MAX_RESULTS ?
-                                (tfpDist + 1) :
-                                results_returned.max_dist;
-                            addIntoResults(results_returned, row.id, i, -1, tfpDist, 0, maxDist);
+                }
+                const levSearchResults = index.searchLev(elem.normalizedPathLast);
+                const levResults = [];
+                for await (const levResult of levSearchResults) {
+                    for (const id of levResult.matches().entries()) {
+                        if (!idDuplicates.has(id)) {
+                            idDuplicates.add(id);
+                            levResults.push(handleNameSearch(id));
+                            const [name, alias] = await Promise.all([
+                                this.getName(id),
+                                this.getAliasTarget(id),
+                            ]);
+                            if (name !== null && alias !== null) {
+                                levResults.push(handleAlias(
+                                    name,
+                                    alias,
+                                    editDistance(elem.normalizedPathLast, name, maxEditDistance),
+                                    name.indexOf(elem.normalizedPathLast),
+                                ));
+                            }
                         }
                     }
                 }
-            } else if (parsedQuery.foundElems > 0) {
-                // Sort input and output so that generic type variables go first and
-                // types with generic parameters go last.
-                // That's because of the way unification is structured: it eats off
-                // the end, and hits a fast path if the last item is a simple atom.
-                /** @type {function(rustdoc.QueryElement, rustdoc.QueryElement): number} */
-                const sortQ = (a, b) => {
-                    const ag = a.generics.length === 0 && a.bindings.size === 0;
-                    const bg = b.generics.length === 0 && b.bindings.size === 0;
-                    if (ag !== bg) {
-                        // unary `+` converts booleans into integers.
-                        return +ag - +bg;
+                yield* flush(levResults);
+                if (results) {
+                    const substringResults = [];
+                    for await (const result of results.substringMatches()) {
+                        for (const id of result.entries()) {
+                            if (!idDuplicates.has(id)) {
+                                idDuplicates.add(id);
+                                substringResults.push(handleNameSearch(id));
+                                const [name, alias] = await Promise.all([
+                                    this.getName(id),
+                                    this.getAliasTarget(id),
+                                ]);
+                                if (name !== null && alias !== null) {
+                                    levResults.push(handleAlias(
+                                        name,
+                                        alias,
+                                        editDistance(
+                                            elem.normalizedPathLast,
+                                            name,
+                                            maxEditDistance,
+                                        ),
+                                        name.indexOf(elem.normalizedPathLast),
+                                    ));
+                                }
+                            }
+                        }
+                        if (yield* flush(substringResults)) {
+                            return;
+                        }
                     }
-                    const ai = a.id !== null && a.id > 0;
-                    const bi = b.id !== null && b.id > 0;
-                    return +ai - +bi;
-                };
-                parsedQuery.elems.sort(sortQ);
-                parsedQuery.returned.sort(sortQ);
-                for (let i = 0, nSearchIndex = this.searchIndex.length; i < nSearchIndex; ++i) {
-                    handleArgs(this.searchIndex[i], i, results_others);
                 }
             }
-        };
+            .bind(this);
 
-        if (parsedQuery.error === null) {
-            innerRunQuery();
-        }
+        const innerRunTypeQuery =
+            /**
+             * @this {DocSearch}
+             * @param {rustdoc.ParserQueryElement[]} inputs
+             * @param {rustdoc.ParserQueryElement[]} output
+             * @param {"sig"|"elems"|"returned"|null} typeInfo
+             * @param {string} currentCrate
+             * @returns {AsyncGenerator<rustdoc.ResultObject>}
+             */
+            async function*(inputs, output, typeInfo, currentCrate) {
+                const index = this.database.getIndex("normalizedName");
+                if (!index) {
+                    return;
+                }
+                /** @type {Map<string, number>} */
+                const genericMap = new Map();
+                /**
+                 * @template Q
+                 * @typedef {{
+                 *     invertedIndex: stringdex.RoaringBitmap[],
+                 *     queryElem: Q,
+                 * }} PostingsList
+                 */
+                /** @type {stringdex.RoaringBitmap[]} */
+                const empty_inverted_index = [];
+                /** @type {PostingsList<any>[]} */
+                const empty_postings_list = [];
+                /** @type {stringdex.RoaringBitmap[]} */
+                const everything_inverted_index = [];
+                for (let i = 0; i < 64; ++i) {
+                    everything_inverted_index.push(RoaringBitmap.everything());
+                }
+                /**
+                 * @type {PostingsList<rustdoc.QueryElement[]>}
+                 */
+                const everything_postings_list = {
+                    invertedIndex: everything_inverted_index,
+                    queryElem: [],
+                };
+                /**
+                 * @type {PostingsList<rustdoc.QueryElement[]>[]}
+                 */
+                const nested_everything_postings_list = [everything_postings_list];
+                /**
+                 * @param {...stringdex.RoaringBitmap[]} idx
+                 * @returns {stringdex.RoaringBitmap[]}
+                 */
+                const intersectInvertedIndexes = (...idx) => {
+                    let i = 0;
+                    const l = idx.length;
+                    while (i < l - 1 && idx[i] === everything_inverted_index) {
+                        i += 1;
+                    }
+                    const result = [...idx[i]];
+                    for (; i < l; ++i) {
+                        if (idx[i] === everything_inverted_index) {
+                            continue;
+                        }
+                        if (idx[i].length < result.length) {
+                            result.length = idx[i].length;
+                        }
+                        for (let j = 0; j < result.length; ++j) {
+                            result[j] = result[j].intersection(idx[i][j]);
+                        }
+                    }
+                    return result;
+                };
+                /**
+                 * Fetch a bitmap of potentially-matching functions,
+                 * plus a list of query elements annotated with the correct IDs.
+                 *
+                 * More than one ID can exist because, for example, q=`Iter` can match
+                 * `std::vec::Iter`, or `std::btree_set::Iter`, or anything else, and those
+                 * items different IDs. What's worse, q=`Iter<Iter>` has N**2 possible
+                 * matches, because it could be `vec::Iter<btree_set::Iter>`,
+                 * `btree_set::Iter<vec::Iter>`, `vec::Iter<vec::Iter>`,
+                 * `btree_set::Iter<btree_set::Iter>`,
+                 * or anything else. This function returns all possible permutations.
+                 *
+                 * @param {rustdoc.ParserQueryElement|null} elem
+                 * @returns {Promise<PostingsList<rustdoc.QueryElement>[]>}
+                 */
+                const unpackPostingsList = async elem => {
+                    if (!elem) {
+                        return empty_postings_list;
+                    }
+                    const typeFilter = itemTypeFromName(elem.typeFilter);
+                    const searchResults = await index.search(elem.normalizedPathLast);
+                    /**
+                     * @type {Promise<[
+                     *     number,
+                     *     string|null,
+                     *     rustdoc.TypeData|null,
+                     *     rustdoc.PathData|null,
+                     * ]>[]}
+                     * */
+                    const typePromises = [];
+                    if (typeFilter !== TY_GENERIC && searchResults) {
+                        for (const id of searchResults.matches().entries()) {
+                            typePromises.push(Promise.all([
+                                this.getName(id),
+                                this.getTypeData(id),
+                                this.getPathData(id),
+                            ]).then(([name, typeData, pathData]) =>
+                                [id, name, typeData, pathData]));
+                        }
+                    }
+                    const types = (await Promise.all(typePromises))
+                        .filter(([_id, name, ty, path]) =>
+                            name !== null && name.toLowerCase() === elem.pathLast &&
+                            ty && !ty.invertedFunctionSignatureIndex.every(bitmap => {
+                                return bitmap.isEmpty();
+                            }) &&
+                            path && path.ty !== TY_ASSOCTYPE &&
+                            (elem.pathWithoutLast.length === 0 ||
+                                checkPath(
+                                    elem.pathWithoutLast,
+                                    path.modulePath.split("::"),
+                                ) === 0),
+                            );
+                    if (types.length === 0) {
+                        const areGenericsAllowed = typeFilter === TY_GENERIC || (
+                            typeFilter === -1 &&
+                            (parsedQuery.totalElems > 1 || parsedQuery.hasReturnArrow) &&
+                            elem.pathWithoutLast.length === 0 &&
+                            elem.generics.length === 0 &&
+                            elem.bindings.size === 0
+                        );
+                        if (typeFilter !== TY_GENERIC &&
+                            (elem.name.length >= 3 || !areGenericsAllowed)
+                        ) {
+                            /** @type {string|null} */
+                            let chosenName = null;
+                            /** @type {rustdoc.TypeData[]} */
+                            let chosenType = [];
+                            /** @type {rustdoc.PathData[]} */
+                            let chosenPath = [];
+                            /** @type {number[]} */
+                            let chosenId = [];
+                            let chosenDist = Number.MAX_SAFE_INTEGER;
+                            const levResults = index.searchLev(elem.normalizedPathLast);
+                            for await (const searchResults of levResults) {
+                                for (const id of searchResults.matches().entries()) {
+                                    const [name, ty, path] = await Promise.all([
+                                        this.getName(id),
+                                        this.getTypeData(id),
+                                        this.getPathData(id),
+                                    ]);
+                                    if (name !== null && ty !== null && path !== null &&
+                                        !ty.invertedFunctionSignatureIndex.every(bitmap => {
+                                            return bitmap.isEmpty();
+                                        }) &&
+                                        path.ty !== TY_ASSOCTYPE
+                                    ) {
+                                        let dist = editDistance(
+                                            name,
+                                            elem.pathLast,
+                                            maxEditDistance,
+                                        );
+                                        if (elem.pathWithoutLast.length !== 0) {
+                                            const pathDist = checkPath(
+                                                elem.pathWithoutLast,
+                                                path.modulePath.split("::"),
+                                            );
+                                            // guaranteed to be higher than the path limit
+                                            dist += pathDist === null ?
+                                                Number.MAX_SAFE_INTEGER :
+                                                pathDist;
+                                        }
+                                        if (name === chosenName) {
+                                            chosenId.push(id);
+                                            chosenType.push(ty);
+                                            chosenPath.push(path);
+                                        } else if (dist < chosenDist) {
+                                            chosenName = name;
+                                            chosenId = [id];
+                                            chosenType = [ty];
+                                            chosenPath = [path];
+                                            chosenDist = dist;
+                                        }
+                                    }
+                                }
+                                if (chosenId.length !== 0) {
+                                    // searchLev returns results in order
+                                    // if we have working matches, we're done
+                                    break;
+                                }
+                            }
+                            if (areGenericsAllowed) {
+                                parsedQuery.proposeCorrectionFrom = elem.name;
+                                parsedQuery.proposeCorrectionTo = chosenName;
+                            } else {
+                                parsedQuery.correction = chosenName;
+                                for (let i = 0; i < chosenType.length; ++i) {
+                                    types.push([
+                                        chosenId[i],
+                                        chosenName,
+                                        chosenType[i],
+                                        chosenPath[i],
+                                    ]);
+                                }
+                            }
+                        }
+                        if (areGenericsAllowed) {
+                            let genericId = genericMap.get(elem.normalizedPathLast);
+                            if (genericId === undefined) {
+                                genericId = genericMap.size;
+                                genericMap.set(elem.normalizedPathLast, genericId);
+                            }
+                            return [{
+                                invertedIndex: await this.getGenericInvertedIndex(genericId),
+                                queryElem: {
+                                    name: elem.name,
+                                    id: (-genericId) - 1,
+                                    typeFilter: TY_GENERIC,
+                                    generics: [],
+                                    bindings: EMPTY_BINDINGS_MAP,
+                                    fullPath: elem.fullPath,
+                                    pathLast: elem.pathLast,
+                                    normalizedPathLast: elem.normalizedPathLast,
+                                    pathWithoutLast: elem.pathWithoutLast,
+                                },
+                            }];
+                        }
+                    }
+                    types.sort(([_i, name1, _t, pathData1], [_i2, name2, _t2, pathData2]) => {
+                        const p1 = !pathData1 ? "" : pathData1.modulePath;
+                        const p2 = !pathData2 ? "" : pathData2.modulePath;
+                        const n1 = name1 === null ? "" : name1;
+                        const n2 = name2 === null ? "" : name2;
+                        if (p1.length !== p2.length) {
+                            return p1.length > p2.length ? +1 : -1;
+                        }
+                        if (n1.length !== n2.length) {
+                            return n1.length > n2.length ? +1 : -1;
+                        }
+                        if (n1 !== n2) {
+                            return n1 > n2 ? +1 : -1;
+                        }
+                        if (p1 !== p2) {
+                            return p1 > p2 ? +1 : -1;
+                        }
+                        return 0;
+                    });
+                    /** @type {PostingsList<rustdoc.QueryElement>[]} */
+                    const results = [];
+                    for (const [id, _name, typeData] of types) {
+                        if (!typeData || typeData.invertedFunctionSignatureIndex.every(bitmap => {
+                            return bitmap.isEmpty();
+                        })) {
+                            continue;
+                        }
+                        const upla = await unpackPostingsListAll(elem.generics);
+                        const uplb = await unpackPostingsListBindings(elem.bindings);
+                        for (const {invertedIndex: genericsIdx, queryElem: generics} of upla) {
+                            for (const {invertedIndex: bindingsIdx, queryElem: bindings} of uplb) {
+                                results.push({
+                                    invertedIndex: intersectInvertedIndexes(
+                                        typeData.invertedFunctionSignatureIndex,
+                                        genericsIdx,
+                                        bindingsIdx,
+                                    ),
+                                    queryElem: {
+                                        name: elem.name,
+                                        id,
+                                        typeFilter,
+                                        generics,
+                                        bindings,
+                                        fullPath: elem.fullPath,
+                                        pathLast: elem.pathLast,
+                                        normalizedPathLast: elem.normalizedPathLast,
+                                        pathWithoutLast: elem.pathWithoutLast,
+                                    },
+                                });
+                                if ((results.length & 0x7F) === 0) {
+                                    await yieldToBrowser();
+                                }
+                            }
+                        }
+                    }
+                    return results;
+                };
+                /**
+                 * Fetch all possible matching permutations of a list of query elements.
+                 *
+                 * The empty list returns an "identity postings list", with a bitmap that
+                 * matches everything and an empty list of elems. This allows you to safely
+                 * take the intersection of this bitmap.
+                 *
+                 * @param {(rustdoc.ParserQueryElement|null)[]|null} elems
+                 * @returns {Promise<PostingsList<rustdoc.QueryElement[]>[]>}
+                 */
+                const unpackPostingsListAll = async elems => {
+                    if (!elems || elems.length === 0) {
+                        return nested_everything_postings_list;
+                    }
+                    const [firstPostingsList, remainingAll] = await Promise.all([
+                        unpackPostingsList(elems[0]),
+                        unpackPostingsListAll(elems.slice(1)),
+                    ]);
+                    /** @type {PostingsList<rustdoc.QueryElement[]>[]} */
+                    const results = [];
+                    for (const {
+                        invertedIndex: firstIdx,
+                        queryElem: firstElem,
+                    } of firstPostingsList) {
+                        for (const {
+                            invertedIndex: remainingIdx,
+                            queryElem: remainingElems,
+                        } of remainingAll) {
+                            results.push({
+                                invertedIndex: intersectInvertedIndexes(firstIdx, remainingIdx),
+                                queryElem: [firstElem, ...remainingElems],
+                            });
+                            if ((results.length & 0x7F) === 0) {
+                                await yieldToBrowser();
+                            }
+                        }
+                    }
+                    return results;
+                };
+                /**
+                 * Fetch all possible matching permutations of a map query element bindings.
+                 *
+                 * The empty list returns an "identity postings list", with a bitmap that
+                 * matches everything and an empty list of elems. This allows you to safely
+                 * take the intersection of this bitmap.
+                 *
+                 * Heads up! This function mutates the Map that you provide.
+                 * Before passing an actual parser item to it, make sure to clone the map.
+                 *
+                 * @param {Map<string, rustdoc.ParserQueryElement[]>} elems
+                 * @returns {Promise<PostingsList<
+                 *     Map<number, rustdoc.QueryElement[]>,
+                 * >[]>}
+                 */
+                const unpackPostingsListBindings = async elems => {
+                    if (!elems) {
+                        return [{
+                            invertedIndex: everything_inverted_index,
+                            queryElem: new Map(),
+                        }];
+                    }
+                    const firstKey = elems.keys().next().value;
+                    if (firstKey === undefined) {
+                        return [{
+                            invertedIndex: everything_inverted_index,
+                            queryElem: new Map(),
+                        }];
+                    }
+                    const firstList = elems.get(firstKey);
+                    if (firstList === undefined) {
+                        return [{
+                            invertedIndex: everything_inverted_index,
+                            queryElem: new Map(),
+                        }];
+                    }
+                    const firstKeyIds = await index.search(firstKey);
+                    if (!firstKeyIds) {
+                        // User specified a non-existent key.
+                        return [{
+                            invertedIndex: empty_inverted_index,
+                            queryElem: new Map(),
+                        }];
+                    }
+                    elems.delete(firstKey);
+                    const [firstPostingsList, remainingAll] = await Promise.all([
+                        unpackPostingsListAll(firstList),
+                        unpackPostingsListBindings(elems),
+                    ]);
+                    /** @type {PostingsList<Map<number, rustdoc.QueryElement[]>>[]} */
+                    const results = [];
+                    for (const keyId of firstKeyIds.matches().entries()) {
+                        for (const {
+                            invertedIndex: firstIdx,
+                            queryElem: firstElem,
+                        } of firstPostingsList) {
+                            for (const {
+                                invertedIndex: remainingIdx,
+                                queryElem: remainingElems,
+                            } of remainingAll) {
+                                const elems = new Map(remainingElems);
+                                elems.set(keyId, firstElem);
+                                results.push({
+                                    invertedIndex: intersectInvertedIndexes(firstIdx, remainingIdx),
+                                    queryElem: elems,
+                                });
+                                if ((results.length & 0x7F) === 0) {
+                                    await yieldToBrowser();
+                                }
+                            }
+                        }
+                    }
+                    elems.set(firstKey, firstList);
+                    if (results.length === 0) {
+                        // User specified a non-existent key.
+                        return [{
+                            invertedIndex: empty_inverted_index,
+                            queryElem: new Map(),
+                        }];
+                    }
+                    return results;
+                };
 
-        const isType = parsedQuery.foundElems !== 1 || parsedQuery.hasReturnArrow;
-        const [sorted_in_args, sorted_returned, sorted_others] = await Promise.all([
-            sortResults(results_in_args, "elems", currentCrate),
-            sortResults(results_returned, "returned", currentCrate),
-            // @ts-expect-error
-            sortResults(results_others, (isType ? "query" : null), currentCrate),
-        ]);
-        const ret = createQueryResults(
-            sorted_in_args,
-            sorted_returned,
-            sorted_others,
-            parsedQuery);
-        await handleAliases(ret, parsedQuery.userQuery.replace(/"/g, ""),
-            filterCrates, currentCrate);
-        await Promise.all([ret.others, ret.returned, ret.in_args].map(async list => {
-            const descs = await Promise.all(list.map(result => {
-                // @ts-expect-error
-                return this.searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex) ?
-                    "" :
-                    // @ts-expect-error
-                    this.searchState.loadDesc(result);
-            }));
-            for (const [i, result] of list.entries()) {
-                // @ts-expect-error
-                result.desc = descs[i];
+                // finally, we can do the actual unification loop
+                const [allInputs, allOutput] = await Promise.all([
+                    unpackPostingsListAll(inputs),
+                    unpackPostingsListAll(output),
+                ]);
+                let checkCounter = 0;
+                /**
+                 * Finally, we can perform an incremental search, sorted by the number of
+                 * entries that match a given query.
+                 *
+                 * The outer list gives the number of elements. The inner one is separate
+                 * for each distinct name resolution.
+                 *
+                 * @type {{
+                 *     bitmap: stringdex.RoaringBitmap,
+                 *     inputs: rustdoc.QueryElement[],
+                 *     output: rustdoc.QueryElement[],
+                 * }[][]}
+                 */
+                const queryPlan = [];
+                for (const {invertedIndex: inputsIdx, queryElem: inputs} of allInputs) {
+                    for (const {invertedIndex: outputIdx, queryElem: output} of allOutput) {
+                        const invertedIndex = intersectInvertedIndexes(inputsIdx, outputIdx);
+                        for (const [size, bitmap] of invertedIndex.entries()) {
+                            checkCounter += 1;
+                            if ((checkCounter & 0x7F) === 0) {
+                                await yieldToBrowser();
+                            }
+                            if (!queryPlan[size]) {
+                                queryPlan[size] = [];
+                            }
+                            queryPlan[size].push({
+                                bitmap, inputs, output,
+                            });
+                        }
+                    }
+                }
+                const resultPromises = [];
+                const dedup = new Set();
+                let resultCounter = 0;
+                const isReturnTypeQuery = inputs.length === 0;
+                /** @type {rustdoc.PlainResultObject[]} */
+                const pushToBottom = [];
+                plan: for (const queryStep of queryPlan) {
+                    for (const {bitmap, inputs, output} of queryStep) {
+                        for (const id of bitmap.entries()) {
+                            checkCounter += 1;
+                            if ((checkCounter & 0x7F) === 0) {
+                                await yieldToBrowser();
+                            }
+                            resultPromises.push(this.getFunctionData(id).then(async fnData => {
+                                if (!fnData || !fnData.functionSignature) {
+                                    return null;
+                                }
+                                checkCounter += 1;
+                                if ((checkCounter & 0x7F) === 0) {
+                                    await yieldToBrowser();
+                                }
+                                const functionSignature = fnData.functionSignature;
+                                if (!unifyFunctionTypes(
+                                    functionSignature.inputs,
+                                    inputs,
+                                    functionSignature.where_clause,
+                                    null,
+                                    mgens => {
+                                        return !!unifyFunctionTypes(
+                                            functionSignature.output,
+                                            output,
+                                            functionSignature.where_clause,
+                                            mgens,
+                                            checkTypeMgensForConflict,
+                                            0, // unboxing depth
+                                        );
+                                    },
+                                    0, // unboxing depth
+                                )) {
+                                    return null;
+                                }
+                                const result = {
+                                    id,
+                                    dist: fnData.elemCount,
+                                    path_dist: 0,
+                                    index: -1,
+                                    elems: inputs,
+                                    returned: output,
+                                    is_alias: false,
+                                };
+                                const entry = await this.getEntryData(id);
+                                if ((entry && !isFnLikeTy(entry.ty)) ||
+                                    (isReturnTypeQuery &&
+                                        functionSignature &&
+                                        containsTypeFromQuery(
+                                            output,
+                                            functionSignature.inputs,
+                                            functionSignature.where_clause,
+                                        )
+                                    )
+                                ) {
+                                    pushToBottom.push(result);
+                                    return null;
+                                }
+                                return result;
+                            }));
+                        }
+                    }
+                    for await (const result of sortAndTransformResults(
+                        await Promise.all(resultPromises),
+                        typeInfo,
+                        currentCrate,
+                        dedup,
+                    )) {
+                        if (resultCounter >= MAX_RESULTS) {
+                            break plan;
+                        }
+                        yield result;
+                        resultCounter += 1;
+                    }
+                    resultPromises.length = 0;
+                }
+                if (resultCounter >= MAX_RESULTS) {
+                    return;
+                }
+                for await (const result of sortAndTransformResults(
+                    await Promise.all(pushToBottom),
+                    typeInfo,
+                    currentCrate,
+                    dedup,
+                )) {
+                    if (resultCounter >= MAX_RESULTS) {
+                        break;
+                    }
+                    yield result;
+                    resultCounter += 1;
+                }
             }
-        }));
-        if (parsedQuery.error !== null && ret.others.length !== 0) {
-            // It means some doc aliases were found so let's "remove" the error!
-            ret.query.error = null;
+            .bind(this);
+
+        if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) {
+            // We never want the main tab to delay behind the other two tabs.
+            // This is a bit of a hack (because JS's scheduler doesn't have much of an API),
+            // along with making innerRunTypeQuery yield to the UI thread.
+            const {
+                promise: donePromise,
+                resolve: doneResolve,
+                reject: doneReject,
+            } = Promise.withResolvers();
+            const doneTimeout = timeout(250);
+            return {
+                "in_args": (async function*() {
+                    await Promise.race([donePromise, doneTimeout]);
+                    yield* innerRunTypeQuery(parsedQuery.elems, [], "elems", currentCrate);
+                })(),
+                "returned": (async function*() {
+                    await Promise.race([donePromise, doneTimeout]);
+                    yield* innerRunTypeQuery([], parsedQuery.elems, "returned", currentCrate);
+                })(),
+                "others": (async function*() {
+                    try {
+                        yield* innerRunNameQuery(currentCrate);
+                        doneResolve(null);
+                    } catch (e) {
+                        doneReject(e);
+                        throw e;
+                    }
+                })(),
+                "query": parsedQuery,
+            };
+        } else if (parsedQuery.error !== null) {
+            return {
+                "in_args": (async function*() {})(),
+                "returned": (async function*() {})(),
+                "others": innerRunNameQuery(currentCrate),
+                "query": parsedQuery,
+            };
+        } else {
+            const typeInfo = parsedQuery.elems.length === 0 ?
+                "returned" : (
+                    parsedQuery.returned.length === 0 ? "elems" : "sig"
+                );
+            return {
+                "in_args": (async function*() {})(),
+                "returned": (async function*() {})(),
+                "others": parsedQuery.foundElems === 0 ?
+                    (async function*() {})() :
+                    innerRunTypeQuery(
+                        parsedQuery.elems,
+                        parsedQuery.returned,
+                        typeInfo,
+                        currentCrate,
+                    ),
+                "query": parsedQuery,
+            };
         }
-        return ret;
     }
 }
 
 
 // ==================== Core search logic end ====================
 
-/** @type {Map<string, rustdoc.RawSearchIndexCrate>} */
-let rawSearchIndex;
-// @ts-expect-error
+/** @type {DocSearch} */
 let docSearch;
 const longItemTypes = [
     "keyword",
@@ -4762,12 +4596,8 @@ function buildUrl(search, filterCrates) {
 function getFilterCrates() {
     const elem = document.getElementById("crate-search");
 
-    if (elem &&
-        // @ts-expect-error
-        elem.value !== "all crates" &&
-        // @ts-expect-error
-        window.searchIndex.has(elem.value)
-    ) {
+    // @ts-expect-error
+    if (elem && elem.value !== "all crates") {
         // @ts-expect-error
         return elem.value;
     }
@@ -4777,8 +4607,7 @@ function getFilterCrates() {
 // @ts-expect-error
 function nextTab(direction) {
     const next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
-    // @ts-expect-error
-    searchState.focusedByTab[searchState.currentTab] = document.activeElement;
+    window.searchState.focusedByTab[searchState.currentTab] = document.activeElement;
     printTab(next);
     focusSearchResult();
 }
@@ -4790,133 +4619,182 @@ function focusSearchResult() {
         document.querySelectorAll(".search-results.active a").item(0) ||
         document.querySelectorAll("#search-tabs button").item(searchState.currentTab);
     searchState.focusedByTab[searchState.currentTab] = null;
-    if (target) {
-        // @ts-expect-error
+    if (target && target instanceof HTMLElement) {
         target.focus();
     }
 }
 
 /**
  * Render a set of search results for a single tab.
- * @param {Array<?>}    array   - The search results for this tab
- * @param {rustdoc.ParsedQuery<rustdoc.QueryElement>} query
+ * @param {AsyncGenerator<rustdoc.ResultObject>} results   - The search results for this tab
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
  * @param {boolean}     display - True if this is the active tab
+ * @param {function(number, HTMLElement): any} finishedCallback
+ * @param {boolean} isTypeSearch
+ * @returns {Promise<HTMLElement>}
  */
-async function addTab(array, query, display) {
+async function addTab(results, query, display, finishedCallback, isTypeSearch) {
     const extraClass = display ? " active" : "";
 
-    const output = document.createElement(
-        array.length === 0 && query.error === null ? "div" : "ul",
-    );
-    if (array.length > 0) {
-        output.className = "search-results " + extraClass;
+    /** @type {HTMLElement} */
+    let output = document.createElement("ul");
+    output.className = "search-results " + extraClass;
 
-        const lis = Promise.all(array.map(async item => {
-            const name = item.is_alias ? item.original.name : item.name;
-            const type = itemTypes[item.ty];
-            const longType = longItemTypes[item.ty];
-            const typeName = longType.length !== 0 ? `${longType}` : "?";
+    let count = 0;
+
+    /** @type {Promise<string|null>[]} */
+    const descList = [];
+
+    /** @param {rustdoc.ResultObject} obj */
+    const addNextResultToOutput = async obj => {
+        count += 1;
+
+        const name = obj.item.name;
+        const type = itemTypes[obj.item.ty];
+        const longType = longItemTypes[obj.item.ty];
+        const typeName = longType.length !== 0 ? `${longType}` : "?";
 
-            const link = document.createElement("a");
-            link.className = "result-" + type;
-            link.href = item.href;
+        const link = document.createElement("a");
+        link.className = "result-" + type;
+        link.href = obj.href;
 
-            const resultName = document.createElement("span");
-            resultName.className = "result-name";
+        const resultName = document.createElement("span");
+        resultName.className = "result-name";
 
-            resultName.insertAdjacentHTML(
-                "beforeend",
-                `<span class="typename">${typeName}</span>`);
-            link.appendChild(resultName);
+        resultName.insertAdjacentHTML(
+            "beforeend",
+            `<span class="typename">${typeName}</span>`);
+        link.appendChild(resultName);
 
-            let alias = " ";
-            if (item.is_alias) {
-                alias = ` <div class="alias">\
-<b>${item.name}</b><i class="grey">&nbsp;- see&nbsp;</i>\
+        let alias = " ";
+        if (obj.alias !== undefined) {
+            alias = ` <div class="alias">\
+<b>${obj.alias}</b><i class="grey">&nbsp;- see&nbsp;</i>\
 </div>`;
-            }
-            resultName.insertAdjacentHTML(
-                "beforeend",
-                `<div class="path">${alias}\
-${item.displayPath}<span class="${type}">${name}</span>\
+        }
+        resultName.insertAdjacentHTML(
+            "beforeend",
+            `<div class="path">${alias}\
+${obj.displayPath}<span class="${type}">${name}</span>\
 </div>`);
 
-            const description = document.createElement("div");
-            description.className = "desc";
-            description.insertAdjacentHTML("beforeend", item.desc);
-            if (item.displayTypeSignature) {
-                const {type, mappedNames, whereClause} = await item.displayTypeSignature;
-                const displayType = document.createElement("div");
-                // @ts-expect-error
-                type.forEach((value, index) => {
-                    if (index % 2 !== 0) {
-                        const highlight = document.createElement("strong");
-                        highlight.appendChild(document.createTextNode(value));
-                        displayType.appendChild(highlight);
-                    } else {
-                        displayType.appendChild(document.createTextNode(value));
+        const description = document.createElement("div");
+        description.className = "desc";
+        obj.desc.then(desc => {
+            if (desc !== null) {
+                description.insertAdjacentHTML("beforeend", desc);
+            }
+        });
+        descList.push(obj.desc);
+        if (obj.displayTypeSignature) {
+            const {type, mappedNames, whereClause} = await obj.displayTypeSignature;
+            const displayType = document.createElement("div");
+            type.forEach((value, index) => {
+                if (index % 2 !== 0) {
+                    const highlight = document.createElement("strong");
+                    highlight.appendChild(document.createTextNode(value));
+                    displayType.appendChild(highlight);
+                } else {
+                    displayType.appendChild(document.createTextNode(value));
+                }
+            });
+            if (mappedNames.size > 0 || whereClause.size > 0) {
+                let addWhereLineFn = () => {
+                    const line = document.createElement("div");
+                    line.className = "where";
+                    line.appendChild(document.createTextNode("where"));
+                    displayType.appendChild(line);
+                    addWhereLineFn = () => {};
+                };
+                for (const [qname, name] of mappedNames) {
+                    // don't care unless the generic name is different
+                    if (name === qname) {
+                        continue;
                     }
-                });
-                if (mappedNames.size > 0 || whereClause.size > 0) {
-                    let addWhereLineFn = () => {
-                        const line = document.createElement("div");
-                        line.className = "where";
-                        line.appendChild(document.createTextNode("where"));
-                        displayType.appendChild(line);
-                        addWhereLineFn = () => {};
-                    };
-                    for (const [qname, name] of mappedNames) {
-                        // don't care unless the generic name is different
-                        if (name === qname) {
-                            continue;
-                        }
-                        addWhereLineFn();
-                        const line = document.createElement("div");
-                        line.className = "where";
-                        line.appendChild(document.createTextNode(`    ${qname} matches `));
-                        const lineStrong = document.createElement("strong");
-                        lineStrong.appendChild(document.createTextNode(name));
-                        line.appendChild(lineStrong);
-                        displayType.appendChild(line);
+                    addWhereLineFn();
+                    const line = document.createElement("div");
+                    line.className = "where";
+                    line.appendChild(document.createTextNode(`    ${qname} matches `));
+                    const lineStrong = document.createElement("strong");
+                    lineStrong.appendChild(document.createTextNode(name));
+                    line.appendChild(lineStrong);
+                    displayType.appendChild(line);
+                }
+                for (const [name, innerType] of whereClause) {
+                    // don't care unless there's at least one highlighted entry
+                    if (innerType.length <= 1) {
+                        continue;
                     }
-                    for (const [name, innerType] of whereClause) {
-                        // don't care unless there's at least one highlighted entry
-                        if (innerType.length <= 1) {
-                            continue;
+                    addWhereLineFn();
+                    const line = document.createElement("div");
+                    line.className = "where";
+                    line.appendChild(document.createTextNode(`    ${name}: `));
+                    innerType.forEach((value, index) => {
+                        if (index % 2 !== 0) {
+                            const highlight = document.createElement("strong");
+                            highlight.appendChild(document.createTextNode(value));
+                            line.appendChild(highlight);
+                        } else {
+                            line.appendChild(document.createTextNode(value));
                         }
-                        addWhereLineFn();
-                        const line = document.createElement("div");
-                        line.className = "where";
-                        line.appendChild(document.createTextNode(`    ${name}: `));
-                        // @ts-expect-error
-                        innerType.forEach((value, index) => {
-                            if (index % 2 !== 0) {
-                                const highlight = document.createElement("strong");
-                                highlight.appendChild(document.createTextNode(value));
-                                line.appendChild(highlight);
-                            } else {
-                                line.appendChild(document.createTextNode(value));
-                            }
-                        });
-                        displayType.appendChild(line);
-                    }
+                    });
+                    displayType.appendChild(line);
                 }
-                displayType.className = "type-signature";
-                link.appendChild(displayType);
             }
+            displayType.className = "type-signature";
+            link.appendChild(displayType);
+        }
 
-            link.appendChild(description);
-            return link;
-        }));
-        lis.then(lis => {
-            for (const li of lis) {
-                output.appendChild(li);
+        link.appendChild(description);
+        output.appendChild(link);
+
+        results.next().then(async nextResult => {
+            if (nextResult.value) {
+                addNextResultToOutput(nextResult.value);
+            } else {
+                await Promise.all(descList);
+                // need to make sure the element is shown before
+                // running this callback
+                yieldToBrowser().then(() => finishedCallback(count, output));
             }
         });
-    } else if (query.error === null) {
-        const dlroChannel = `https://doc.rust-lang.org/${getVar("channel")}`;
+    };
+    const firstResult = await results.next();
+    let correctionOutput = "";
+    if (query.correction !== null && isTypeSearch) {
+        const orig = query.returned.length > 0
+            ? query.returned[0].name
+            : query.elems[0].name;
+        correctionOutput = "<h3 class=\"search-corrections\">" +
+            `Type "${orig}" not found. ` +
+            "Showing results for closest type name " +
+            `"${query.correction}" instead.</h3>`;
+    }
+    if (query.proposeCorrectionFrom !== null && isTypeSearch) {
+        const orig = query.proposeCorrectionFrom;
+        const targ = query.proposeCorrectionTo;
+        correctionOutput = "<h3 class=\"search-corrections\">" +
+            `Type "${orig}" not found and used as generic parameter. ` +
+            `Consider searching for "${targ}" instead.</h3>`;
+    }
+    if (firstResult.value) {
+        if (correctionOutput !== "") {
+            const h3 = document.createElement("h3");
+            h3.innerHTML = correctionOutput;
+            output.appendChild(h3);
+        }
+        await addNextResultToOutput(firstResult.value);
+    } else {
+        output = document.createElement("div");
+        if (correctionOutput !== "") {
+            const h3 = document.createElement("h3");
+            h3.innerHTML = correctionOutput;
+            output.appendChild(h3);
+        }
         output.className = "search-failed" + extraClass;
-        output.innerHTML = "No results :(<br/>" +
+        const dlroChannel = `https://doc.rust-lang.org/${getVar("channel")}`;
+        if (query.userQuery !== "") {
+            output.innerHTML += "No results :(<br/>" +
             "Try on <a href=\"https://duckduckgo.com/?q=" +
             encodeURIComponent("rust " + query.userQuery) +
             "\">DuckDuckGo</a>?<br/><br/>" +
@@ -4929,192 +4807,198 @@ ${item.displayPath}<span class="${type}">${name}</span>\
             "introductions to language features and the language itself.</li><li><a " +
             "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
             " <a href=\"https://crates.io/\">crates.io</a>.</li></ul>";
+        }
+        output.innerHTML += "Example searches:<ul>" +
+            "<li><a href=\"" + getNakedUrl() + "?search=std::vec\">std::vec</a></li>" +
+            "<li><a href=\"" + getNakedUrl() + "?search=u32+->+bool\">u32 -> bool</a></li>" +
+            "<li><a href=\"" + getNakedUrl() + "?search=Option<T>,+(T+->+U)+->+Option<U>\">" +
+                "Option&lt;T>, (T -> U) -> Option&lt;U></a></li>" +
+            "</ul>";
+        // need to make sure the element is shown before
+        // running this callback
+        yieldToBrowser().then(() => finishedCallback(0, output));
     }
     return output;
 }
 
-// @ts-expect-error
-function makeTabHeader(tabNb, text, nbElems) {
-    // https://blog.horizon-eda.org/misc/2020/02/19/ui.html
-    //
-    // CSS runs with `font-variant-numeric: tabular-nums` to ensure all
-    // digits are the same width. \u{2007} is a Unicode space character
-    // that is defined to be the same width as a digit.
-    const fmtNbElems =
-        nbElems < 10  ? `\u{2007}(${nbElems})\u{2007}\u{2007}` :
-        nbElems < 100 ? `\u{2007}(${nbElems})\u{2007}` : `\u{2007}(${nbElems})`;
-    if (searchState.currentTab === tabNb) {
-        return "<button class=\"selected\">" + text +
-            "<span class=\"count\">" + fmtNbElems + "</span></button>";
-    }
-    return "<button>" + text + "<span class=\"count\">" + fmtNbElems + "</span></button>";
+/**
+ * returns [tab, output]
+ * @param {number} tabNb
+ * @param {string} text
+ * @param {AsyncGenerator<rustdoc.ResultObject>} results
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {boolean} isTypeSearch
+ * @param {boolean} goToFirst
+ * @returns {[HTMLElement, Promise<HTMLElement>]}
+ */
+function makeTab(tabNb, text, results, query, isTypeSearch, goToFirst) {
+    const isCurrentTab = window.searchState.currentTab === tabNb;
+    const tabButton = document.createElement("button");
+    tabButton.appendChild(document.createTextNode(text));
+    tabButton.className = isCurrentTab ? "selected" : "";
+    const tabCount = document.createElement("span");
+    tabCount.className = "count loading";
+    tabCount.innerHTML = "\u{2007}(\u{2007})\u{2007}\u{2007}";
+    tabButton.appendChild(tabCount);
+    return [
+        tabButton,
+        addTab(results, query, isCurrentTab, (count, output) => {
+            const search = window.searchState.outputElement();
+            const error = query.error;
+            if (count === 0 && error !== null && search) {
+                error.forEach((value, index) => {
+                    value = value.split("<").join("&lt;").split(">").join("&gt;");
+                    if (index % 2 !== 0) {
+                        error[index] = `<code>${value.replaceAll(" ", "&nbsp;")}</code>`;
+                    } else {
+                        error[index] = value;
+                    }
+                });
+                const errorReport = document.createElement("h3");
+                errorReport.className = "error";
+                errorReport.innerHTML = `Query parser error: "${error.join("")}".`;
+                search.insertBefore(errorReport, search.firstElementChild);
+            } else if (goToFirst ||
+                (count === 1 && getSettingValue("go-to-only-result") === "true")
+            ) {
+                // Needed to force re-execution of JS when coming back to a page. Let's take this
+                // scenario as example:
+                //
+                // 1. You have the "Directly go to item in search if there is only one result"
+                //    option enabled.
+                // 2. You make a search which results only one result, leading you automatically to
+                //    this result.
+                // 3. You go back to previous page.
+                //
+                // Now, without the call below, the JS will not be re-executed and the previous
+                // state will be used, starting search again since the search input is not empty,
+                // leading you back to the previous page again.
+                window.onunload = () => { };
+                window.searchState.removeQueryParameters();
+                const a = output.querySelector("a");
+                if (a) {
+                    a.click();
+                    return;
+                }
+            }
+
+            // https://blog.horizon-eda.org/misc/2020/02/19/ui.html
+            //
+            // CSS runs with `font-variant-numeric: tabular-nums` to ensure all
+            // digits are the same width. \u{2007} is a Unicode space character
+            // that is defined to be the same width as a digit.
+            const fmtNbElems =
+                count < 10  ? `\u{2007}(${count})\u{2007}\u{2007}` :
+                count < 100 ? `\u{2007}(${count})\u{2007}` : `\u{2007}(${count})`;
+            tabCount.innerHTML = fmtNbElems;
+            tabCount.className = "count";
+        }, isTypeSearch),
+    ];
 }
 
 /**
+ * @param {DocSearch} docSearch
  * @param {rustdoc.ResultsTable} results
- * @param {boolean} go_to_first
+ * @param {boolean} goToFirst
  * @param {string} filterCrates
  */
-async function showResults(results, go_to_first, filterCrates) {
-    const search = searchState.outputElement();
-    if (go_to_first || (results.others.length === 1
-        && getSettingValue("go-to-only-result") === "true")
-    ) {
-        // Needed to force re-execution of JS when coming back to a page. Let's take this
-        // scenario as example:
-        //
-        // 1. You have the "Directly go to item in search if there is only one result" option
-        //    enabled.
-        // 2. You make a search which results only one result, leading you automatically to
-        //    this result.
-        // 3. You go back to previous page.
-        //
-        // Now, without the call below, the JS will not be re-executed and the previous state
-        // will be used, starting search again since the search input is not empty, leading you
-        // back to the previous page again.
-        window.onunload = () => { };
-        searchState.removeQueryParameters();
-        const elem = document.createElement("a");
-        elem.href = results.others[0].href;
-        removeClass(elem, "active");
-        // For firefox, we need the element to be in the DOM so it can be clicked.
-        document.body.appendChild(elem);
-        elem.click();
-        return;
-    }
-    if (results.query === undefined) {
-        // @ts-expect-error
-        results.query = DocSearch.parseQuery(searchState.input.value);
-    }
+async function showResults(docSearch, results, goToFirst, filterCrates) {
+    const search = window.searchState.outputElement();
 
-    currentResults = results.query.userQuery;
-
-    // Navigate to the relevant tab if the current tab is empty, like in case users search
-    // for "-> String". If they had selected another tab previously, they have to click on
-    // it again.
-    let currentTab = searchState.currentTab;
-    if ((currentTab === 0 && results.others.length === 0) ||
-        (currentTab === 1 && results.in_args.length === 0) ||
-        (currentTab === 2 && results.returned.length === 0)) {
-        if (results.others.length !== 0) {
-            currentTab = 0;
-        } else if (results.in_args.length) {
-            currentTab = 1;
-        } else if (results.returned.length) {
-            currentTab = 2;
-        }
+    if (!search) {
+        return;
     }
 
     let crates = "";
-    if (rawSearchIndex.size > 1) {
-        crates = "<div class=\"sub-heading\"> in&nbsp;<div id=\"crate-search-div\">" +
+    const crateNames = await docSearch.getCrateNameList();
+    if (crateNames.length > 1) {
+        crates = "&nbsp;in&nbsp;<div id=\"crate-search-div\">" +
             "<select id=\"crate-search\"><option value=\"all crates\">all crates</option>";
-        for (const c of rawSearchIndex.keys()) {
+        const l = crateNames.length;
+        for (let i = 0; i < l; i += 1) {
+            const c = crateNames[i];
             crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`;
         }
-        crates += "</select></div></div>";
+        crates += "</select></div>";
     }
+    nonnull(document.querySelector(".search-switcher")).innerHTML = `Search results${crates}`;
 
-    let output = `<div class="main-heading">\
-        <h1 class="search-results-title">Results</h1>${crates}</div>`;
+    /** @type {[HTMLElement, Promise<HTMLElement>][]} */
+    const tabs = [];
+    searchState.currentTab = 0;
     if (results.query.error !== null) {
-        const error = results.query.error;
-        // @ts-expect-error
-        error.forEach((value, index) => {
-            value = value.split("<").join("&lt;").split(">").join("&gt;");
-            if (index % 2 !== 0) {
-                error[index] = `<code>${value.replaceAll(" ", "&nbsp;")}</code>`;
-            } else {
-                error[index] = value;
-            }
-        });
-        output += `<h3 class="error">Query parser error: "${error.join("")}".</h3>`;
-        output += "<div id=\"search-tabs\">" +
-            makeTabHeader(0, "In Names", results.others.length) +
-            "</div>";
-        currentTab = 0;
-    } else if (results.query.foundElems <= 1 && results.query.returned.length === 0) {
-        output += "<div id=\"search-tabs\">" +
-            makeTabHeader(0, "In Names", results.others.length) +
-            makeTabHeader(1, "In Parameters", results.in_args.length) +
-            makeTabHeader(2, "In Return Types", results.returned.length) +
-            "</div>";
+        tabs.push(makeTab(0, "In Names", results.others, results.query, false, goToFirst));
+    } else if (
+        results.query.foundElems <= 1 &&
+        results.query.returned.length === 0 &&
+        !results.query.hasReturnArrow
+    ) {
+        tabs.push(makeTab(0, "In Names", results.others, results.query, false, goToFirst));
+        tabs.push(makeTab(1, "In Parameters", results.in_args, results.query, true, false));
+        tabs.push(makeTab(2, "In Return Types", results.returned, results.query, true, false));
     } else {
         const signatureTabTitle =
             results.query.elems.length === 0 ? "In Function Return Types" :
                 results.query.returned.length === 0 ? "In Function Parameters" :
                     "In Function Signatures";
-        output += "<div id=\"search-tabs\">" +
-            makeTabHeader(0, signatureTabTitle, results.others.length) +
-            "</div>";
-        currentTab = 0;
+        tabs.push(makeTab(0, signatureTabTitle, results.others, results.query, true, goToFirst));
     }
 
-    if (results.query.correction !== null) {
-        const orig = results.query.returned.length > 0
-            ? results.query.returned[0].name
-            : results.query.elems[0].name;
-        output += "<h3 class=\"search-corrections\">" +
-            `Type "${orig}" not found. ` +
-            "Showing results for closest type name " +
-            `"${results.query.correction}" instead.</h3>`;
-    }
-    if (results.query.proposeCorrectionFrom !== null) {
-        const orig = results.query.proposeCorrectionFrom;
-        const targ = results.query.proposeCorrectionTo;
-        output += "<h3 class=\"search-corrections\">" +
-            `Type "${orig}" not found and used as generic parameter. ` +
-            `Consider searching for "${targ}" instead.</h3>`;
-    }
-
-    const [ret_others, ret_in_args, ret_returned] = await Promise.all([
-        addTab(results.others, results.query, currentTab === 0),
-        addTab(results.in_args, results.query, currentTab === 1),
-        addTab(results.returned, results.query, currentTab === 2),
-    ]);
+    const tabsElem = document.createElement("div");
+    tabsElem.id = "search-tabs";
 
     const resultsElem = document.createElement("div");
     resultsElem.id = "results";
-    resultsElem.appendChild(ret_others);
-    resultsElem.appendChild(ret_in_args);
-    resultsElem.appendChild(ret_returned);
 
-    // @ts-expect-error
-    search.innerHTML = output;
-    if (searchState.rustdocToolbar) {
-        // @ts-expect-error
-        search.querySelector(".main-heading").appendChild(searchState.rustdocToolbar);
+    search.innerHTML = "";
+    for (const [tab, output] of tabs) {
+        tabsElem.appendChild(tab);
+        const placeholder = document.createElement("div");
+        output.then(output => {
+            if (placeholder.parentElement) {
+                placeholder.parentElement.replaceChild(output, placeholder);
+            }
+        });
+        resultsElem.appendChild(placeholder);
+    }
+
+    if (window.searchState.rustdocToolbar) {
+        nonnull(
+            nonnull(window.searchState.containerElement())
+                .querySelector(".main-heading"),
+        ).appendChild(window.searchState.rustdocToolbar);
     }
     const crateSearch = document.getElementById("crate-search");
     if (crateSearch) {
         crateSearch.addEventListener("input", updateCrate);
     }
-    // @ts-expect-error
+    search.appendChild(tabsElem);
     search.appendChild(resultsElem);
     // Reset focused elements.
-    searchState.showResults(search);
-    // @ts-expect-error
-    const elems = document.getElementById("search-tabs").childNodes;
-    // @ts-expect-error
-    searchState.focusedByTab = [];
+    window.searchState.showResults();
+    window.searchState.focusedByTab = [null, null, null];
     let i = 0;
-    for (const elem of elems) {
+    for (const elem of tabsElem.childNodes) {
         const j = i;
         // @ts-expect-error
         elem.onclick = () => printTab(j);
-        searchState.focusedByTab.push(null);
+        window.searchState.focusedByTab[i] = null;
         i += 1;
     }
-    printTab(currentTab);
+    printTab(0);
 }
 
 // @ts-expect-error
 function updateSearchHistory(url) {
+    const btn = document.querySelector("#search-button a");
+    if (btn instanceof HTMLAnchorElement) {
+        btn.href = url;
+    }
     if (!browserSupportsHistoryApi()) {
         return;
     }
     const params = searchState.getQueryStringParams();
-    if (!history.state && !params.search) {
+    if (!history.state && params.search === undefined) {
         history.pushState(null, "", url);
     } else {
         history.replaceState(null, "", url);
@@ -5127,8 +5011,8 @@ function updateSearchHistory(url) {
  * @param {boolean} [forced]
  */
 async function search(forced) {
-    // @ts-expect-error
-    const query = DocSearch.parseQuery(searchState.input.value.trim());
+    const query = DocSearch.parseQuery(nonnull(window.searchState.inputElement()).value.trim());
+
     let filterCrates = getFilterCrates();
 
     // @ts-expect-error
@@ -5138,6 +5022,7 @@ async function search(forced) {
         }
         return;
     }
+    currentResults = query.userQuery;
 
     searchState.setLoadingSearch();
 
@@ -5149,6 +5034,12 @@ async function search(forced) {
         filterCrates = params["filter-crate"];
     }
 
+    if (filterCrates !== null &&
+        (await docSearch.getCrateNameList()).indexOf(filterCrates) === -1
+    ) {
+        filterCrates = null;
+    }
+
     // Update document title to maintain a meaningful browser history
     searchState.title = "\"" + query.userQuery + "\" Search - Rust";
 
@@ -5157,6 +5048,7 @@ async function search(forced) {
     updateSearchHistory(buildUrl(query.userQuery, filterCrates));
 
     await showResults(
+        docSearch,
         // @ts-expect-error
         await docSearch.execQuery(query, filterCrates, window.currentCrate),
         params.go_to_first,
@@ -5176,16 +5068,14 @@ function onSearchSubmit(e) {
 }
 
 function putBackSearch() {
-    const search_input = searchState.input;
-    if (!searchState.input) {
+    const search_input = window.searchState.inputElement();
+    if (!search_input) {
         return;
     }
-    // @ts-expect-error
     if (search_input.value !== "" && !searchState.isDisplayed()) {
         searchState.showResults();
         if (browserSupportsHistoryApi()) {
             history.replaceState(null, "",
-                // @ts-expect-error
                 buildUrl(search_input.value, getFilterCrates()));
         }
         document.title = searchState.title;
@@ -5199,30 +5089,21 @@ function registerSearchEvents() {
     // but only if the input bar is empty. This avoid the obnoxious issue
     // where you start trying to do a search, and the index loads, and
     // suddenly your search is gone!
-    // @ts-expect-error
-    if (searchState.input.value === "") {
-        // @ts-expect-error
-        searchState.input.value = params.search || "";
+    const inputElement = nonnull(window.searchState.inputElement());
+    if (inputElement.value === "") {
+        inputElement.value = params.search || "";
     }
 
     const searchAfter500ms = () => {
         searchState.clearInputTimeout();
-        // @ts-expect-error
-        if (searchState.input.value.length === 0) {
-            searchState.hideResults();
-        } else {
-            // @ts-ignore
-            searchState.timeout = setTimeout(search, 500);
-        }
+        window.searchState.timeout = setTimeout(search, 500);
     };
-    // @ts-expect-error
-    searchState.input.onkeyup = searchAfter500ms;
-    // @ts-expect-error
-    searchState.input.oninput = searchAfter500ms;
-    // @ts-expect-error
-    document.getElementsByClassName("search-form")[0].onsubmit = onSearchSubmit;
-    // @ts-expect-error
-    searchState.input.onchange = e => {
+    inputElement.onkeyup = searchAfter500ms;
+    inputElement.oninput = searchAfter500ms;
+    if (inputElement.form) {
+        inputElement.form.onsubmit = onSearchSubmit;
+    }
+    inputElement.onchange = e => {
         if (e.target !== document.activeElement) {
             // To prevent doing anything when it's from a blur event.
             return;
@@ -5234,11 +5115,13 @@ function registerSearchEvents() {
         // change, though.
         setTimeout(search, 0);
     };
-    // @ts-expect-error
-    searchState.input.onpaste = searchState.input.onchange;
+    inputElement.onpaste = inputElement.onchange;
 
     // @ts-expect-error
     searchState.outputElement().addEventListener("keydown", e => {
+        if (!(e instanceof KeyboardEvent)) {
+            return;
+        }
         // We only handle unmodified keystrokes here. We don't want to interfere with,
         // for instance, alt-left and alt-right for history navigation.
         if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
@@ -5278,88 +5161,23 @@ function registerSearchEvents() {
         }
     });
 
-    // @ts-expect-error
-    searchState.input.addEventListener("keydown", e => {
+    inputElement.addEventListener("keydown", e => {
         if (e.which === 40) { // down
             focusSearchResult();
             e.preventDefault();
         }
     });
 
-    // @ts-expect-error
-    searchState.input.addEventListener("focus", () => {
+    inputElement.addEventListener("focus", () => {
         putBackSearch();
     });
-
-    // @ts-expect-error
-    searchState.input.addEventListener("blur", () => {
-        if (window.searchState.input) {
-            window.searchState.input.placeholder = window.searchState.origPlaceholder;
-        }
-    });
-
-    // Push and pop states are used to add search results to the browser
-    // history.
-    if (browserSupportsHistoryApi()) {
-        // Store the previous <title> so we can revert back to it later.
-        const previousTitle = document.title;
-
-        window.addEventListener("popstate", e => {
-            const params = searchState.getQueryStringParams();
-            // Revert to the previous title manually since the History
-            // API ignores the title parameter.
-            document.title = previousTitle;
-            // When browsing forward to search results the previous
-            // search will be repeated, so the currentResults are
-            // cleared to ensure the search is successful.
-            currentResults = null;
-            // Synchronize search bar with query string state and
-            // perform the search. This will empty the bar if there's
-            // nothing there, which lets you really go back to a
-            // previous state with nothing in the bar.
-            if (params.search && params.search.length > 0) {
-                // @ts-expect-error
-                searchState.input.value = params.search;
-                // Some browsers fire "onpopstate" for every page load
-                // (Chrome), while others fire the event only when actually
-                // popping a state (Firefox), which is why search() is
-                // called both here and at the end of the startSearch()
-                // function.
-                e.preventDefault();
-                search();
-            } else {
-                // @ts-expect-error
-                searchState.input.value = "";
-                // When browsing back from search results the main page
-                // visibility must be reset.
-                searchState.hideResults();
-            }
-        });
-    }
-
-    // This is required in firefox to avoid this problem: Navigating to a search result
-    // with the keyboard, hitting enter, and then hitting back would take you back to
-    // the doc page, rather than the search that should overlay it.
-    // This was an interaction between the back-forward cache and our handlers
-    // that try to sync state between the URL and the search input. To work around it,
-    // do a small amount of re-init on page show.
-    window.onpageshow = () => {
-        const qSearch = searchState.getQueryStringParams().search;
-        // @ts-expect-error
-        if (searchState.input.value === "" && qSearch) {
-            // @ts-expect-error
-            searchState.input.value = qSearch;
-        }
-        search();
-    };
 }
 
 // @ts-expect-error
 function updateCrate(ev) {
     if (ev.target.value === "all crates") {
         // If we don't remove it from the URL, it'll be picked up again by the search.
-        // @ts-expect-error
-        const query = searchState.input.value.trim();
+        const query = nonnull(window.searchState.inputElement()).value.trim();
         updateSearchHistory(buildUrl(query, null));
     }
     // In case you "cut" the entry from the search input, then change the crate filter
@@ -5369,522 +5187,91 @@ function updateCrate(ev) {
     search(true);
 }
 
-// Parts of this code are based on Lucene, which is licensed under the
-// Apache/2.0 license.
-// More information found here:
-// https://fossies.org/linux/lucene/lucene/core/src/java/org/apache/lucene/util/automaton/
-//   LevenshteinAutomata.java
-class ParametricDescription {
-    // @ts-expect-error
-    constructor(w, n, minErrors) {
-        this.w = w;
-        this.n = n;
-        this.minErrors = minErrors;
-    }
-    // @ts-expect-error
-    isAccept(absState) {
-        const state = Math.floor(absState / (this.w + 1));
-        const offset = absState % (this.w + 1);
-        return this.w - offset + this.minErrors[state] <= this.n;
-    }
-    // @ts-expect-error
-    getPosition(absState) {
-        return absState % (this.w + 1);
-    }
-    // @ts-expect-error
-    getVector(name, charCode, pos, end) {
-        let vector = 0;
-        for (let i = pos; i < end; i += 1) {
-            vector = vector << 1;
-            if (name.charCodeAt(i) === charCode) {
-                vector |= 1;
-            }
-        }
-        return vector;
-    }
-    // @ts-expect-error
-    unpack(data, index, bitsPerValue) {
-        const bitLoc = (bitsPerValue * index);
-        const dataLoc = bitLoc >> 5;
-        const bitStart = bitLoc & 31;
-        if (bitStart + bitsPerValue <= 32) {
-            // not split
-            return ((data[dataLoc] >> bitStart) & this.MASKS[bitsPerValue - 1]);
-        } else {
-            // split
-            const part = 32 - bitStart;
-            return ~~(((data[dataLoc] >> bitStart) & this.MASKS[part - 1]) +
-                ((data[1 + dataLoc] & this.MASKS[bitsPerValue - part - 1]) << part));
-        }
+// eslint-disable-next-line max-len
+// polyfill https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64
+/**
+ * @type {function(string): Uint8Array} base64
+ */
+//@ts-expect-error
+const makeUint8ArrayFromBase64 = Uint8Array.fromBase64 ? Uint8Array.fromBase64 : (string => {
+    const bytes_as_string = atob(string);
+    const l = bytes_as_string.length;
+    const bytes = new Uint8Array(l);
+    for (let i = 0; i < l; ++i) {
+        bytes[i] = bytes_as_string.charCodeAt(i);
     }
-}
-ParametricDescription.prototype.MASKS = new Int32Array([
-    0x1, 0x3, 0x7, 0xF,
-    0x1F, 0x3F, 0x7F, 0xFF,
-    0x1FF, 0x3F, 0x7FF, 0xFFF,
-    0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
-    0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
-    0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
-    0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
-    0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
-]);
-
-// The following code was generated with the moman/finenight pkg
-// This package is available under the MIT License, see NOTICE.txt
-// for more details.
-// This class is auto-generated, Please do not modify it directly.
-// You should modify the https://gitlab.com/notriddle/createAutomata.py instead.
-// The following code was generated with the moman/finenight pkg
-// This package is available under the MIT License, see NOTICE.txt
-// for more details.
-// This class is auto-generated, Please do not modify it directly.
-// You should modify https://gitlab.com/notriddle/moman-rustdoc instead.
-
-class Lev2TParametricDescription extends ParametricDescription {
-    /**
-     * @param {number} absState
-     * @param {number} position
-     * @param {number} vector
-     * @returns {number}
-    */
-    transition(absState, position, vector) {
-        let state = Math.floor(absState / (this.w + 1));
-        let offset = absState % (this.w + 1);
-
-        if (position === this.w) {
-            if (state < 3) { // eslint-disable-line no-lonely-if
-                const loc = Math.imul(vector, 3) + state;
-                offset += this.unpack(this.offsetIncrs0, loc, 1);
-                state = this.unpack(this.toStates0, loc, 2) - 1;
-            }
-        } else if (position === this.w - 1) {
-            if (state < 5) { // eslint-disable-line no-lonely-if
-                const loc = Math.imul(vector, 5) + state;
-                offset += this.unpack(this.offsetIncrs1, loc, 1);
-                state = this.unpack(this.toStates1, loc, 3) - 1;
-            }
-        } else if (position === this.w - 2) {
-            if (state < 13) { // eslint-disable-line no-lonely-if
-                const loc = Math.imul(vector, 13) + state;
-                offset += this.unpack(this.offsetIncrs2, loc, 2);
-                state = this.unpack(this.toStates2, loc, 4) - 1;
-            }
-        } else if (position === this.w - 3) {
-            if (state < 28) { // eslint-disable-line no-lonely-if
-                const loc = Math.imul(vector, 28) + state;
-                offset += this.unpack(this.offsetIncrs3, loc, 2);
-                state = this.unpack(this.toStates3, loc, 5) - 1;
-            }
-        } else if (position === this.w - 4) {
-            if (state < 45) { // eslint-disable-line no-lonely-if
-                const loc = Math.imul(vector, 45) + state;
-                offset += this.unpack(this.offsetIncrs4, loc, 3);
-                state = this.unpack(this.toStates4, loc, 6) - 1;
-            }
-        } else {
-            if (state < 45) { // eslint-disable-line no-lonely-if
-                const loc = Math.imul(vector, 45) + state;
-                offset += this.unpack(this.offsetIncrs5, loc, 3);
-                state = this.unpack(this.toStates5, loc, 6) - 1;
-            }
-        }
+    return bytes;
+});
 
-        if (state === -1) {
-            // null state
-            return -1;
-        } else {
-            // translate back to abs
-            return Math.imul(state, this.w + 1) + offset;
-        }
-    }
 
-    // state map
-    //   0 -> [(0, 0)]
-    //   1 -> [(0, 1)]
-    //   2 -> [(0, 2)]
-    //   3 -> [(0, 1), (1, 1)]
-    //   4 -> [(0, 2), (1, 2)]
-    //   5 -> [(0, 1), (1, 1), (2, 1)]
-    //   6 -> [(0, 2), (1, 2), (2, 2)]
-    //   7 -> [(0, 1), (2, 1)]
-    //   8 -> [(0, 1), (2, 2)]
-    //   9 -> [(0, 2), (2, 1)]
-    //   10 -> [(0, 2), (2, 2)]
-    //   11 -> [t(0, 1), (0, 1), (1, 1), (2, 1)]
-    //   12 -> [t(0, 2), (0, 2), (1, 2), (2, 2)]
-    //   13 -> [(0, 2), (1, 2), (2, 2), (3, 2)]
-    //   14 -> [(0, 1), (1, 1), (3, 2)]
-    //   15 -> [(0, 1), (2, 2), (3, 2)]
-    //   16 -> [(0, 1), (3, 2)]
-    //   17 -> [(0, 1), t(1, 2), (2, 2), (3, 2)]
-    //   18 -> [(0, 2), (1, 2), (3, 1)]
-    //   19 -> [(0, 2), (1, 2), (3, 2)]
-    //   20 -> [(0, 2), (1, 2), t(1, 2), (2, 2), (3, 2)]
-    //   21 -> [(0, 2), (2, 1), (3, 1)]
-    //   22 -> [(0, 2), (2, 2), (3, 2)]
-    //   23 -> [(0, 2), (3, 1)]
-    //   24 -> [(0, 2), (3, 2)]
-    //   25 -> [(0, 2), t(1, 2), (1, 2), (2, 2), (3, 2)]
-    //   26 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (3, 2)]
-    //   27 -> [t(0, 2), (0, 2), (1, 2), (3, 1)]
-    //   28 -> [(0, 2), (1, 2), (2, 2), (3, 2), (4, 2)]
-    //   29 -> [(0, 2), (1, 2), (2, 2), (4, 2)]
-    //   30 -> [(0, 2), (1, 2), (2, 2), t(2, 2), (3, 2), (4, 2)]
-    //   31 -> [(0, 2), (1, 2), (3, 2), (4, 2)]
-    //   32 -> [(0, 2), (1, 2), (4, 2)]
-    //   33 -> [(0, 2), (1, 2), t(1, 2), (2, 2), (3, 2), (4, 2)]
-    //   34 -> [(0, 2), (1, 2), t(2, 2), (2, 2), (3, 2), (4, 2)]
-    //   35 -> [(0, 2), (2, 1), (4, 2)]
-    //   36 -> [(0, 2), (2, 2), (3, 2), (4, 2)]
-    //   37 -> [(0, 2), (2, 2), (4, 2)]
-    //   38 -> [(0, 2), (3, 2), (4, 2)]
-    //   39 -> [(0, 2), (4, 2)]
-    //   40 -> [(0, 2), t(1, 2), (1, 2), (2, 2), (3, 2), (4, 2)]
-    //   41 -> [(0, 2), t(2, 2), (2, 2), (3, 2), (4, 2)]
-    //   42 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (3, 2), (4, 2)]
-    //   43 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (4, 2)]
-    //   44 -> [t(0, 2), (0, 2), (1, 2), (2, 2), t(2, 2), (3, 2), (4, 2)]
-
-
-    /** @param {number} w - length of word being checked */
-    constructor(w) {
-        super(w, 2, new Int32Array([
-            0,1,2,0,1,-1,0,-1,0,-1,0,-1,0,-1,-1,-1,-1,-1,-2,-1,-1,-2,-1,-2,
-            -1,-1,-1,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
-        ]));
+if (ROOT_PATH === null) {
+    return;
+}
+const database = await Stringdex.loadDatabase(hooks);
+if (typeof window !== "undefined") {
+    docSearch = new DocSearch(ROOT_PATH, database);
+    await docSearch.buildIndex();
+    onEachLazy(document.querySelectorAll(
+        ".search-form.loading",
+    ), form => {
+        removeClass(form, "loading");
+    });
+    registerSearchEvents();
+    // If there's a search term in the URL, execute the search now.
+    if (window.searchState.getQueryStringParams().search !== undefined) {
+        search();
     }
+} else if (typeof exports !== "undefined") {
+    docSearch = new DocSearch(ROOT_PATH, database);
+    await docSearch.buildIndex();
+    return { docSearch, DocSearch };
 }
+};
 
-Lev2TParametricDescription.prototype.toStates0 = /*2 bits per value */ new Int32Array([
-    0xe,
-]);
-Lev2TParametricDescription.prototype.offsetIncrs0 = /*1 bits per value */ new Int32Array([
-    0x0,
-]);
-
-Lev2TParametricDescription.prototype.toStates1 = /*3 bits per value */ new Int32Array([
-    0x1a688a2c,
-]);
-Lev2TParametricDescription.prototype.offsetIncrs1 = /*1 bits per value */ new Int32Array([
-    0x3e0,
-]);
-
-Lev2TParametricDescription.prototype.toStates2 = /*4 bits per value */ new Int32Array([
-    0x70707054,0xdc07035,0x3dd3a3a,0x2323213a,
-    0x15435223,0x22545432,0x5435,
-]);
-Lev2TParametricDescription.prototype.offsetIncrs2 = /*2 bits per value */ new Int32Array([
-    0x80000,0x55582088,0x55555555,0x55,
-]);
-
-Lev2TParametricDescription.prototype.toStates3 = /*5 bits per value */ new Int32Array([
-    0x1c0380a4,0x700a570,0xca529c0,0x180a00,
-    0xa80af180,0xc5498e60,0x5a546398,0x8c4300e8,
-    0xac18c601,0xd8d43501,0x863500ad,0x51976d6a,
-    0x8ca0180a,0xc3501ac2,0xb0c5be16,0x76dda8a5,
-    0x18c4519,0xc41294a,0xe248d231,0x1086520c,
-    0xce31ac42,0x13946358,0x2d0348c4,0x6732d494,
-    0x1ad224a5,0xd635ad4b,0x520c4139,0xce24948,
-    0x22110a52,0x58ce729d,0xc41394e3,0x941cc520,
-    0x90e732d4,0x4729d224,0x39ce35ad,
-]);
-Lev2TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new Int32Array([
-    0x80000,0xc0c830,0x300f3c30,0x2200fcff,
-    0xcaa00a08,0x3c2200a8,0xa8fea00a,0x55555555,
-    0x55555555,0x55555555,0x55555555,0x55555555,
-    0x55555555,0x55555555,
-]);
-
-Lev2TParametricDescription.prototype.toStates4 = /*6 bits per value */ new Int32Array([
-    0x801c0144,0x1453803,0x14700038,0xc0005145,
-    0x1401,0x14,0x140000,0x0,
-    0x510000,0x6301f007,0x301f00d1,0xa186178,
-    0xc20ca0c3,0xc20c30,0xc30030c,0xc00c00cd,
-    0xf0c00c30,0x4c054014,0xc30944c3,0x55150c34,
-    0x8300550,0x430c0143,0x50c31,0xc30850c,
-    0xc3143000,0x50053c50,0x5130d301,0x850d30c2,
-    0x30a08608,0xc214414,0x43142145,0x21450031,
-    0x1400c314,0x4c143145,0x32832803,0x28014d6c,
-    0xcd34a0c3,0x1c50c76,0x1c314014,0x430c30c3,
-    0x1431,0xc300500,0xca00d303,0xd36d0e40,
-    0x90b0e400,0xcb2abb2c,0x70c20ca1,0x2c32ca2c,
-    0xcd2c70cb,0x31c00c00,0x34c2c32c,0x5583280,
-    0x558309b7,0x6cd6ca14,0x430850c7,0x51c51401,
-    0x1430c714,0xc3087,0x71451450,0xca00d30,
-    0xc26dc156,0xb9071560,0x1cb2abb2,0xc70c2144,
-    0xb1c51ca1,0x1421c70c,0xc51c00c3,0x30811c51,
-    0x24324308,0xc51031c2,0x70820820,0x5c33830d,
-    0xc33850c3,0x30c30c30,0xc30c31c,0x451450c3,
-    0x20c20c20,0xda0920d,0x5145914f,0x36596114,
-    0x51965865,0xd9643653,0x365a6590,0x51964364,
-    0x43081505,0x920b2032,0x2c718b28,0xd7242249,
-    0x35cb28b0,0x2cb3872c,0x972c30d7,0xb0c32cb2,
-    0x4e1c75c,0xc80c90c2,0x62ca2482,0x4504171c,
-    0xd65d9610,0x33976585,0xd95cb5d,0x4b5ca5d7,
-    0x73975c36,0x10308138,0xc2245105,0x41451031,
-    0x14e24208,0xc35c3387,0x51453851,0x1c51c514,
-    0xc70c30c3,0x20451450,0x14f1440c,0x4f0da092,
-    0x4513d41,0x6533944d,0x1350e658,0xe1545055,
-    0x64365a50,0x5519383,0x51030815,0x28920718,
-    0x441c718b,0x714e2422,0x1c35cb28,0x4e1c7387,
-    0xb28e1c51,0x5c70c32c,0xc204e1c7,0x81c61440,
-    0x1c62ca24,0xd04503ce,0x85d63944,0x39338e65,
-    0x8e154387,0x364b5ca3,0x38739738,
-]);
-Lev2TParametricDescription.prototype.offsetIncrs4 = /*3 bits per value */ new Int32Array([
-    0x10000000,0xc00000,0x60061,0x400,
-    0x0,0x80010008,0x249248a4,0x8229048,
-    0x2092,0x6c3603,0xb61b6c30,0x6db6036d,
-    0xdb6c0,0x361b0180,0x91b72000,0xdb11b71b,
-    0x6db6236,0x1008200,0x12480012,0x24924906,
-    0x48200049,0x80410002,0x24000900,0x4924a489,
-    0x10822492,0x20800125,0x48360,0x9241b692,
-    0x6da4924,0x40009268,0x241b010,0x291b4900,
-    0x6d249249,0x49493423,0x92492492,0x24924924,
-    0x49249249,0x92492492,0x24924924,0x49249249,
-    0x92492492,0x24924924,0x49249249,0x92492492,
-    0x24924924,0x49249249,0x92492492,0x24924924,
-    0x49249249,0x92492492,0x24924924,0x49249249,
-    0x92492492,0x24924924,0x49249249,0x92492492,
-    0x24924924,0x49249249,0x92492492,0x24924924,
-    0x49249249,0x92492492,0x24924924,0x49249249,
-    0x92492492,0x24924924,0x49249249,0x2492,
-]);
-
-Lev2TParametricDescription.prototype.toStates5 = /*6 bits per value */ new Int32Array([
-    0x801c0144,0x1453803,0x14700038,0xc0005145,
-    0x1401,0x14,0x140000,0x0,
-    0x510000,0x4e00e007,0xe0051,0x3451451c,
-    0xd015000,0x30cd0000,0xc30c30c,0xc30c30d4,
-    0x40c30c30,0x7c01c014,0xc03458c0,0x185e0c07,
-    0x2830c286,0x830c3083,0xc30030,0x33430c,
-    0x30c3003,0x70051030,0x16301f00,0x8301f00d,
-    0x30a18617,0xc20ca0c,0x431420c3,0xb1450c51,
-    0x14314315,0x4f143145,0x34c05401,0x4c30944c,
-    0x55150c3,0x30830055,0x1430c014,0xc00050c3,
-    0xc30850,0xc314300,0x150053c5,0x25130d30,
-    0x5430d30c,0xc0354154,0x300d0c90,0x1cb2cd0c,
-    0xc91cb0c3,0x72c30cb2,0x14f1cb2c,0xc34c0540,
-    0x34c30944,0x82182214,0x851050c2,0x50851430,
-    0x1400c50c,0x30c5085,0x50c51450,0x150053c,
-    0xc25130d3,0x8850d30,0x1430a086,0x450c2144,
-    0x51cb1c21,0x1c91c70c,0xc71c314b,0x34c1cb1,
-    0x6c328328,0xc328014d,0x76cd34a0,0x1401c50c,
-    0xc31c3140,0x31430c30,0x14,0x30c3005,
-    0xa0ca00d3,0x535b0c,0x4d2830ca,0x514369b3,
-    0xc500d01,0x5965965a,0x30d46546,0x6435030c,
-    0x8034c659,0xdb439032,0x2c390034,0xcaaecb24,
-    0x30832872,0xcb28b1c,0x4b1c32cb,0x70030033,
-    0x30b0cb0c,0xe40ca00d,0x400d36d0,0xb2c90b0e,
-    0xca1cb2ab,0xa2c70c20,0x6575d95c,0x4315b5ce,
-    0x95c53831,0x28034c5d,0x9b705583,0xa1455830,
-    0xc76cd6c,0x40143085,0x71451c51,0x871430c,
-    0x450000c3,0xd3071451,0x1560ca00,0x560c26dc,
-    0xb35b2851,0xc914369,0x1a14500d,0x46593945,
-    0xcb2c939,0x94507503,0x328034c3,0x9b70558,
-    0xe41c5583,0x72caaeca,0x1c308510,0xc7147287,
-    0x50871c32,0x1470030c,0xd307147,0xc1560ca0,
-    0x1560c26d,0xabb2b907,0x21441cb2,0x38a1c70c,
-    0x8e657394,0x314b1c93,0x39438738,0x43083081,
-    0x31c22432,0x820c510,0x830d7082,0x50c35c33,
-    0xc30c338,0xc31c30c3,0x50c30c30,0xc204514,
-    0x890c90c2,0x31440c70,0xa8208208,0xea0df0c3,
-    0x8a231430,0xa28a28a2,0x28a28a1e,0x1861868a,
-    0x48308308,0xc3682483,0x14516453,0x4d965845,
-    0xd4659619,0x36590d94,0xd969964,0x546590d9,
-    0x20c20541,0x920d20c,0x5914f0da,0x96114514,
-    0x65865365,0xe89d3519,0x99e7a279,0x9e89e89e,
-    0x81821827,0xb2032430,0x18b28920,0x422492c7,
-    0xb28b0d72,0x3872c35c,0xc30d72cb,0x32cb2972,
-    0x1c75cb0c,0xc90c204e,0xa2482c80,0x24b1c62c,
-    0xc3a89089,0xb0ea2e42,0x9669a31c,0xa4966a28,
-    0x59a8a269,0x8175e7a,0xb203243,0x718b2892,
-    0x4114105c,0x17597658,0x74ce5d96,0x5c36572d,
-    0xd92d7297,0xe1ce5d70,0xc90c204,0xca2482c8,
-    0x4171c62,0x5d961045,0x976585d6,0x79669533,
-    0x964965a2,0x659689e6,0x308175e7,0x24510510,
-    0x451031c2,0xe2420841,0x5c338714,0x453851c3,
-    0x51c51451,0xc30c31c,0x451450c7,0x41440c20,
-    0xc708914,0x82105144,0xf1c58c90,0x1470ea0d,
-    0x61861863,0x8a1e85e8,0x8687a8a2,0x3081861,
-    0x24853c51,0x5053c368,0x1341144f,0x96194ce5,
-    0x1544d439,0x94385514,0xe0d90d96,0x5415464,
-    0x4f1440c2,0xf0da0921,0x4513d414,0x533944d0,
-    0x350e6586,0x86082181,0xe89e981d,0x18277689,
-    0x10308182,0x89207185,0x41c718b2,0x14e24224,
-    0xc35cb287,0xe1c73871,0x28e1c514,0xc70c32cb,
-    0x204e1c75,0x1c61440c,0xc62ca248,0x90891071,
-    0x2e41c58c,0xa31c70ea,0xe86175e7,0xa269a475,
-    0x5e7a57a8,0x51030817,0x28920718,0xf38718b,
-    0xe5134114,0x39961758,0xe1ce4ce,0x728e3855,
-    0x5ce0d92d,0xc204e1ce,0x81c61440,0x1c62ca24,
-    0xd04503ce,0x85d63944,0x75338e65,0x5d86075e,
-    0x89e69647,0x75e76576,
-]);
-Lev2TParametricDescription.prototype.offsetIncrs5 = /*3 bits per value */ new Int32Array([
-    0x10000000,0xc00000,0x60061,0x400,
-    0x0,0x60000008,0x6b003080,0xdb6ab6db,
-    0x2db6,0x800400,0x49245240,0x11482412,
-    0x104904,0x40020000,0x92292000,0xa4b25924,
-    0x9649658,0xd80c000,0xdb0c001b,0x80db6d86,
-    0x6db01b6d,0xc0600003,0x86000d86,0x6db6c36d,
-    0xddadb6ed,0x300001b6,0x6c360,0xe37236e4,
-    0x46db6236,0xdb6c,0x361b018,0xb91b7200,
-    0x6dbb1b71,0x6db763,0x20100820,0x61248001,
-    0x92492490,0x24820004,0x8041000,0x92400090,
-    0x24924830,0x555b6a49,0x2080012,0x20004804,
-    0x49252449,0x84112492,0x4000928,0x240201,
-    0x92922490,0x58924924,0x49456,0x120d8082,
-    0x6da4800,0x69249249,0x249a01b,0x6c04100,
-    0x6d240009,0x92492483,0x24d5adb4,0x60208001,
-    0x92000483,0x24925236,0x6846da49,0x10400092,
-    0x241b0,0x49291b49,0x636d2492,0x92494935,
-    0x24924924,0x49249249,0x92492492,0x24924924,
-    0x49249249,0x92492492,0x24924924,0x49249249,
-    0x92492492,0x24924924,0x49249249,0x92492492,
-    0x24924924,0x49249249,0x92492492,0x24924924,
-    0x49249249,0x92492492,0x24924924,0x49249249,
-    0x92492492,0x24924924,0x49249249,0x92492492,
-    0x24924924,0x49249249,0x92492492,0x24924924,
-    0x49249249,0x92492492,0x24924924,0x49249249,
-    0x92492492,0x24924924,0x49249249,0x92492492,
-    0x24924924,0x49249249,0x92492492,0x24924924,
-    0x49249249,0x92492492,0x24924924,0x49249249,
-    0x92492492,0x24924924,0x49249249,0x92492492,
-    0x24924924,0x49249249,0x92492492,0x24924924,
-    0x49249249,0x92492492,0x24924924,0x49249249,
-    0x92492492,0x24924924,0x49249249,0x92492492,
-    0x24924924,0x49249249,0x92492492,0x24924924,
-    0x49249249,0x92492492,0x24924924,
-]);
-
-class Lev1TParametricDescription extends ParametricDescription {
-    /**
-     * @param {number} absState
-     * @param {number} position
-     * @param {number} vector
-     * @returns {number}
-    */
-    transition(absState, position, vector) {
-        let state = Math.floor(absState / (this.w + 1));
-        let offset = absState % (this.w + 1);
-
-        if (position === this.w) {
-            if (state < 2) { // eslint-disable-line no-lonely-if
-                const loc = Math.imul(vector, 2) + state;
-                offset += this.unpack(this.offsetIncrs0, loc, 1);
-                state = this.unpack(this.toStates0, loc, 2) - 1;
-            }
-        } else if (position === this.w - 1) {
-            if (state < 3) { // eslint-disable-line no-lonely-if
-                const loc = Math.imul(vector, 3) + state;
-                offset += this.unpack(this.offsetIncrs1, loc, 1);
-                state = this.unpack(this.toStates1, loc, 2) - 1;
-            }
-        } else if (position === this.w - 2) {
-            if (state < 6) { // eslint-disable-line no-lonely-if
-                const loc = Math.imul(vector, 6) + state;
-                offset += this.unpack(this.offsetIncrs2, loc, 2);
-                state = this.unpack(this.toStates2, loc, 3) - 1;
+if (typeof window !== "undefined") {
+    const ROOT_PATH = window.rootPath;
+    /** @type {stringdex.Callbacks|null} */
+    let databaseCallbacks = null;
+    initSearch(window.Stringdex, window.RoaringBitmap, {
+        loadRoot: callbacks => {
+            for (const key in callbacks) {
+                if (Object.hasOwn(callbacks, key)) {
+                    // @ts-ignore
+                    window[key] = callbacks[key];
+                }
             }
-        } else {
-            if (state < 6) { // eslint-disable-line no-lonely-if
-                const loc = Math.imul(vector, 6) + state;
-                offset += this.unpack(this.offsetIncrs3, loc, 2);
-                state = this.unpack(this.toStates3, loc, 3) - 1;
+            databaseCallbacks = callbacks;
+            // search.index/root is loaded by main.js, so
+            // this script doesn't need to launch it, but
+            // must pick it up
+            // @ts-ignore
+            if (window.searchIndex) {
+                // @ts-ignore
+                window.rr_(window.searchIndex);
             }
-        }
-
-        if (state === -1) {
-            // null state
-            return -1;
-        } else {
-            // translate back to abs
-            return Math.imul(state, this.w + 1) + offset;
-        }
-    }
-
-    // state map
-    //   0 -> [(0, 0)]
-    //   1 -> [(0, 1)]
-    //   2 -> [(0, 1), (1, 1)]
-    //   3 -> [(0, 1), (1, 1), (2, 1)]
-    //   4 -> [(0, 1), (2, 1)]
-    //   5 -> [t(0, 1), (0, 1), (1, 1), (2, 1)]
-
-
-    /** @param {number} w - length of word being checked */
-    constructor(w) {
-        super(w, 1, new Int32Array([0,1,0,-1,-1,-1]));
-    }
-}
-
-Lev1TParametricDescription.prototype.toStates0 = /*2 bits per value */ new Int32Array([
-    0x2,
-]);
-Lev1TParametricDescription.prototype.offsetIncrs0 = /*1 bits per value */ new Int32Array([
-    0x0,
-]);
-
-Lev1TParametricDescription.prototype.toStates1 = /*2 bits per value */ new Int32Array([
-    0xa43,
-]);
-Lev1TParametricDescription.prototype.offsetIncrs1 = /*1 bits per value */ new Int32Array([
-    0x38,
-]);
-
-Lev1TParametricDescription.prototype.toStates2 = /*3 bits per value */ new Int32Array([
-    0x12180003,0xb45a4914,0x69,
-]);
-Lev1TParametricDescription.prototype.offsetIncrs2 = /*2 bits per value */ new Int32Array([
-    0x558a0000,0x5555,
-]);
-
-Lev1TParametricDescription.prototype.toStates3 = /*3 bits per value */ new Int32Array([
-    0x900c0003,0xa1904864,0x45a49169,0x5a6d196a,
-    0x9634,
-]);
-Lev1TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new Int32Array([
-    0xa0fc0000,0x5555ba08,0x55555555,
-]);
-
-// ====================
-// WARNING: Nothing should be added below this comment: we need the `initSearch` function to
-// be called ONLY when the whole file has been parsed and loaded.
-
-// @ts-expect-error
-function initSearch(searchIndex) {
-    rawSearchIndex = searchIndex;
-    if (typeof window !== "undefined") {
-        // @ts-expect-error
-        docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState);
-        registerSearchEvents();
-        // If there's a search term in the URL, execute the search now.
-        if (window.searchState.getQueryStringParams().search) {
-            search();
-        }
-    } else if (typeof exports !== "undefined") {
-        // @ts-expect-error
-        docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState);
-        exports.docSearch = docSearch;
-        exports.parseQuery = DocSearch.parseQuery;
-    }
-}
-
-if (typeof exports !== "undefined") {
+        },
+        loadTreeByHash: hashHex => {
+            const script = document.createElement("script");
+            script.src = `${ROOT_PATH}/search.index/${hashHex}.js`;
+            script.onerror = e => {
+                if (databaseCallbacks) {
+                    databaseCallbacks.err_rn_(hashHex, e);
+                }
+            };
+            document.documentElement.appendChild(script);
+        },
+        loadDataByNameAndHash: (name, hashHex) => {
+            const script = document.createElement("script");
+            script.src = `${ROOT_PATH}/search.index/${name}/${hashHex}.js`;
+            script.onerror = e => {
+                if (databaseCallbacks) {
+                    databaseCallbacks.err_rd_(hashHex, e);
+                }
+            };
+            document.documentElement.appendChild(script);
+        },
+    });
+} else if (typeof exports !== "undefined") {
+    // eslint-disable-next-line no-undef
     exports.initSearch = initSearch;
 }
-
-if (typeof window !== "undefined") {
-    // @ts-expect-error
-    window.initSearch = initSearch;
-    // @ts-expect-error
-    if (window.searchIndex !== undefined) {
-        // @ts-expect-error
-        initSearch(window.searchIndex);
-    }
-} else {
-    // Running in Node, not a browser. Run initSearch just to produce the
-    // exports.
-    initSearch(new Map());
-}
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 2430b5829b2..347d3d0750e 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -1,7 +1,7 @@
 // Local js definitions:
 /* global getSettingValue, updateLocalStorage, updateTheme */
 /* global addClass, removeClass, onEach, onEachLazy */
-/* global MAIN_ID, getVar, getSettingsButton, getHelpButton, nonnull */
+/* global MAIN_ID, getVar, nonnull */
 
 "use strict";
 
@@ -9,18 +9,6 @@
     const isSettingsPage = window.location.pathname.endsWith("/settings.html");
 
     /**
-     * @param {Element} elem
-     * @param {EventTarget|null} target
-     */
-    function elemContainsTarget(elem, target) {
-        if (target instanceof Node) {
-            return elem.contains(target);
-        } else {
-            return false;
-        }
-    }
-
-    /**
      * @overload {"theme"|"preferred-dark-theme"|"preferred-light-theme"}
      * @param {string} settingName
      * @param {string} value
@@ -305,10 +293,12 @@
             }
         } else {
             el.setAttribute("tabindex", "-1");
-            const settingsBtn = getSettingsButton();
-            if (settingsBtn !== null) {
-                settingsBtn.appendChild(el);
-            }
+            onEachLazy(document.querySelectorAll(".settings-menu"), menu => {
+                if (menu.offsetWidth !== 0) {
+                    menu.appendChild(el);
+                    return true;
+                }
+            });
         }
         return el;
     }
@@ -317,6 +307,15 @@
 
     function displaySettings() {
         settingsMenu.style.display = "";
+        onEachLazy(document.querySelectorAll(".settings-menu"), menu => {
+            if (menu.offsetWidth !== 0) {
+                if (!menu.contains(settingsMenu) && settingsMenu.parentElement) {
+                    settingsMenu.parentElement.removeChild(settingsMenu);
+                    menu.appendChild(settingsMenu);
+                }
+                return true;
+            }
+        });
         onEachLazy(settingsMenu.querySelectorAll("input[type='checkbox']"), el => {
             const val = getSettingValue(el.id);
             const checked = val === "true";
@@ -330,40 +329,37 @@
      * @param {FocusEvent} event
      */
     function settingsBlurHandler(event) {
-        const helpBtn = getHelpButton();
-        const settingsBtn = getSettingsButton();
-        const helpUnfocused = helpBtn === null ||
-              (!helpBtn.contains(document.activeElement) &&
-               !elemContainsTarget(helpBtn, event.relatedTarget));
-        const settingsUnfocused = settingsBtn === null ||
-              (!settingsBtn.contains(document.activeElement) &&
-               !elemContainsTarget(settingsBtn, event.relatedTarget));
-        if (helpUnfocused && settingsUnfocused) {
+        const isInPopover = onEachLazy(
+            document.querySelectorAll(".settings-menu, .help-menu"),
+            menu => {
+                return menu.contains(document.activeElement) || menu.contains(event.relatedTarget);
+            },
+        );
+        if (!isInPopover) {
             window.hidePopoverMenus();
         }
     }
 
     if (!isSettingsPage) {
         // We replace the existing "onclick" callback.
-        // These elements must exist, as (outside of the settings page)
-        // `settings.js` is only loaded after the settings button is clicked.
-        const settingsButton = nonnull(getSettingsButton());
         const settingsMenu = nonnull(document.getElementById("settings"));
-        settingsButton.onclick = event => {
-            if (elemContainsTarget(settingsMenu, event.target)) {
-                return;
-            }
-            event.preventDefault();
-            const shouldDisplaySettings = settingsMenu.style.display === "none";
+        onEachLazy(document.querySelectorAll(".settings-menu"), settingsButton => {
+            /** @param {MouseEvent} event */
+            settingsButton.querySelector("a").onclick = event => {
+                if (!(event.target instanceof Element) || settingsMenu.contains(event.target)) {
+                    return;
+                }
+                event.preventDefault();
+                const shouldDisplaySettings = settingsMenu.style.display === "none";
 
-            window.hideAllModals(false);
-            if (shouldDisplaySettings) {
-                displaySettings();
-            }
-        };
-        settingsButton.onblur = settingsBlurHandler;
-        // the settings button should always have a link in it
-        nonnull(settingsButton.querySelector("a")).onblur = settingsBlurHandler;
+                window.hideAllModals(false);
+                if (shouldDisplaySettings) {
+                    displaySettings();
+                }
+            };
+            settingsButton.onblur = settingsBlurHandler;
+            settingsButton.querySelector("a").onblur = settingsBlurHandler;
+        });
         onEachLazy(settingsMenu.querySelectorAll("input"), el => {
             el.onblur = settingsBlurHandler;
         });
@@ -377,6 +373,8 @@
         if (!isSettingsPage) {
             displaySettings();
         }
-        removeClass(getSettingsButton(), "rotate");
+        onEachLazy(document.querySelectorAll(".settings-menu"), settingsButton => {
+            removeClass(settingsButton, "rotate");
+        });
     }, 0);
 })();
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index ca13b891638..c055eb0f808 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -7,6 +7,7 @@
 
 /**
  * @import * as rustdoc from "./rustdoc.d.ts";
+ * @import * as stringdex from "./stringdex.d.ts";
  */
 
 const builtinThemes = ["light", "dark", "ayu"];
@@ -172,7 +173,7 @@ function updateLocalStorage(name, value) {
         } else {
             window.localStorage.setItem("rustdoc-" + name, value);
         }
-    } catch (e) {
+    } catch {
         // localStorage is not accessible, do nothing
     }
 }
@@ -189,7 +190,7 @@ function updateLocalStorage(name, value) {
 function getCurrentValue(name) {
     try {
         return window.localStorage.getItem("rustdoc-" + name);
-    } catch (e) {
+    } catch {
         return null;
     }
 }
@@ -375,32 +376,6 @@ window.addEventListener("pageshow", ev => {
 // That's also why this is in storage.js and not main.js.
 //
 // [parser]: https://html.spec.whatwg.org/multipage/parsing.html
-class RustdocSearchElement extends HTMLElement {
-    constructor() {
-        super();
-    }
-    connectedCallback() {
-        const rootPath = getVar("root-path");
-        const currentCrate = getVar("current-crate");
-        this.innerHTML = `<nav class="sub">
-            <form class="search-form">
-                <span></span> <!-- This empty span is a hacky fix for Safari - See #93184 -->
-                <div id="sidebar-button" tabindex="-1">
-                    <a href="${rootPath}${currentCrate}/all.html" title="show sidebar"></a>
-                </div>
-                <input
-                    class="search-input"
-                    name="search"
-                    aria-label="Run search in the documentation"
-                    autocomplete="off"
-                    spellcheck="false"
-                    placeholder="Type ‘S’ or ‘/’ to search, ‘?’ for more options…"
-                    type="search">
-            </form>
-        </nav>`;
-    }
-}
-window.customElements.define("rustdoc-search", RustdocSearchElement);
 class RustdocToolbarElement extends HTMLElement {
     constructor() {
         super();
@@ -411,11 +386,15 @@ class RustdocToolbarElement extends HTMLElement {
             return;
         }
         const rootPath = getVar("root-path");
+        const currentUrl = window.location.href.split("?")[0].split("#")[0];
         this.innerHTML = `
-        <div id="settings-menu" tabindex="-1">
+        <div id="search-button" tabindex="-1">
+            <a href="${currentUrl}?search="><span class="label">Search</span></a>
+        </div>
+        <div class="settings-menu" tabindex="-1">
             <a href="${rootPath}settings.html"><span class="label">Settings</span></a>
         </div>
-        <div id="help-button" tabindex="-1">
+        <div class="help-menu" tabindex="-1">
             <a href="${rootPath}help.html"><span class="label">Help</span></a>
         </div>
         <button id="toggle-all-docs"
@@ -424,3 +403,31 @@ class="label">Summary</span></button>`;
     }
 }
 window.customElements.define("rustdoc-toolbar", RustdocToolbarElement);
+class RustdocTopBarElement extends HTMLElement {
+    constructor() {
+        super();
+    }
+    connectedCallback() {
+        const rootPath = getVar("root-path");
+        const tmplt = document.createElement("template");
+        tmplt.innerHTML = `
+        <slot name="sidebar-menu-toggle"></slot>
+        <slot></slot>
+        <slot name="settings-menu"></slot>
+        <slot name="help-menu"></slot>
+        `;
+        const shadow = this.attachShadow({ mode: "open" });
+        shadow.appendChild(tmplt.content.cloneNode(true));
+        this.innerHTML += `
+        <button class="sidebar-menu-toggle" slot="sidebar-menu-toggle" title="show sidebar">
+        </button>
+        <div class="settings-menu" slot="settings-menu" tabindex="-1">
+            <a href="${rootPath}settings.html"><span class="label">Settings</span></a>
+        </div>
+        <div class="help-menu" slot="help-menu" tabindex="-1">
+            <a href="${rootPath}help.html"><span class="label">Help</span></a>
+        </div>
+        `;
+    }
+}
+window.customElements.define("rustdoc-topbar", RustdocTopBarElement);
diff --git a/src/librustdoc/html/static/js/stringdex.d.ts b/src/librustdoc/html/static/js/stringdex.d.ts
new file mode 100644
index 00000000000..cf9a8b6b564
--- /dev/null
+++ b/src/librustdoc/html/static/js/stringdex.d.ts
@@ -0,0 +1,165 @@
+export = stringdex;
+
+declare namespace stringdex {
+    /**
+     * The client interface to Stringdex.
+     */
+    interface Database {
+        getIndex(colname: string): SearchTree|undefined;
+        getData(colname: string): DataColumn|undefined;
+    }
+    /**
+     * A search index file.
+     */
+    interface SearchTree {
+        trie(): Trie;
+        search(name: Uint8Array|string): Promise<Trie?>;
+        searchLev(name: Uint8Array|string): AsyncGenerator<Trie>;
+    }
+    /**
+     * A compressed node in the search tree.
+     *
+     * This object logically addresses two interleaved trees:
+     * a "prefix tree", and a "suffix tree". If you ask for
+     * generic matches, you get both, but if you ask for one
+     * that excludes suffix-only entries, you'll get prefixes
+     * alone.
+     */
+    interface Trie {
+        matches(): RoaringBitmap;
+        substringMatches(): AsyncGenerator<RoaringBitmap>;
+        prefixMatches(): AsyncGenerator<RoaringBitmap>;
+        keys(): Uint8Array;
+        keysExcludeSuffixOnly(): Uint8Array;
+        children(): [number, Promise<Trie>][];
+        childrenExcludeSuffixOnly(): [number, Promise<Trie>][];
+        child(id: number): Promise<Trie>?;
+    }
+    /**
+     * The client interface to Stringdex.
+     */
+    interface DataColumn {
+        isEmpty(id: number): boolean;
+        at(id: number): Promise<Uint8Array|undefined>;
+        length: number,
+    }
+    /**
+     * Callbacks for a host application and VFS backend.
+     *
+     * These functions are calleb with mostly-raw data,
+     * except the JSONP wrapper is removed. For example,
+     * a file with the contents `rr_('{"A":"B"}')` should,
+     * after being pulled in, result in the `rr_` callback
+     * being invoked.
+     *
+     * The success callbacks don't need to supply the name of
+     * the file that succeeded, but, if you want successful error
+     * reporting, you'll need to remember which files are
+     * in flight and report the filename as the first parameter.
+     */
+    interface Callbacks {
+        /**
+         * Load the root of the search database
+         * @param {string} dataString
+         */
+        rr_: function(string);
+        err_rr_: function(any);
+        /**
+         * Load a nodefile in the search tree.
+         * A node file may contain multiple nodes;
+         * each node has five fields, separated by newlines.
+         * @param {string} inputBase64
+         */
+        rn_: function(string);
+        err_rn_: function(string, any);
+        /**
+         * Load a database column partition from a string
+         * @param {string} dataString
+         */
+        rd_: function(string);
+        err_rd_: function(string, any);
+        /**
+         * Load a database column partition from base64
+         * @param {string} dataString
+         */
+        rb_: function(string);
+        err_rb_: function(string, any);
+    };
+    /**
+     * Hooks that a VFS layer must provide for stringdex to load data.
+     *
+     * When the root is loaded, the Callbacks object is provided. These
+     * functions should result in callback functions being called with
+     * the contents of the file, or in error callbacks being invoked with
+     * the failed-to-load filename.
+     */
+    interface Hooks {
+        /**
+         * The first function invoked as part of loading a search database.
+         * This function must, eventually, invoke `rr_` with the string
+         * representation of the root file (the function call wrapper,
+         * `rr_('` and `')`, must be removed).
+         *
+         * The supplied callbacks object is used to feed search data back
+         * to the search engine core. You have to store it, so that
+         * loadTreeByHash and loadDataByNameAndHash can use it.
+         *
+         * If this fails, either throw an exception, or call `err_rr_`
+         * with the error object.
+         */
+        loadRoot: function(Callbacks);
+        /**
+         * Load a subtree file from the search index.
+         * 
+         * If this function succeeds, call `rn_` on the callbacks
+         * object. If it fails, call `err_rn_(hashHex, error)`.
+         * 
+         * @param {string} hashHex
+         */
+        loadTreeByHash: function(string);
+        /**
+         * Load a column partition from the search database.
+         *
+         * If this function succeeds, call `rd_` or `rb_` on the callbacks
+         * object. If it fails, call `err_rd_(hashHex, error)`. or `err_rb_`.
+         * To determine which one, the wrapping function call in the js file
+         * specifies it.
+         *
+         * @param {string} columnName
+         * @param {string} hashHex
+         */
+        loadDataByNameAndHash: function(string, string);
+    };
+    class RoaringBitmap {
+        constructor(array: Uint8Array|null, start?: number);
+        static makeSingleton(number: number);
+        static everything(): RoaringBitmap;
+        static empty(): RoaringBitmap;
+        isEmpty(): boolean;
+        union(that: RoaringBitmap): RoaringBitmap;
+        intersection(that: RoaringBitmap): RoaringBitmap;
+        contains(number: number): boolean;
+        entries(): Generator<number>;
+        first(): number|null;
+        consumed_len_bytes: number;
+    };
+
+    type Stringdex = {
+        /**
+         * Initialize Stringdex with VFS hooks.
+         * Returns a database that you can use.
+         */
+        loadDatabase: function(Hooks): Promise<Database>,
+    };
+
+    const Stringdex: Stringdex;
+    const RoaringBitmap: Class<stringdex.RoaringBitmap>;
+}
+
+declare global {
+    interface Window {
+        Stringdex: stringdex.Stringdex;
+        RoaringBitmap: Class<stringdex.RoaringBitmap>;
+        StringdexOnload: Array<function(stringdex.Stringdex): any>?;
+    };
+}
\ No newline at end of file
diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js
new file mode 100644
index 00000000000..cb956d926db
--- /dev/null
+++ b/src/librustdoc/html/static/js/stringdex.js
@@ -0,0 +1,3217 @@
+/**
+ * @import * as stringdex from "./stringdex.d.ts"
+ */
+
+const EMPTY_UINT8 = new Uint8Array();
+
+/**
+ * @property {Uint8Array} keysAndCardinalities
+ * @property {Uint8Array[]} containers
+ */
+class RoaringBitmap {
+    /**
+     * @param {Uint8Array|null} u8array
+     * @param {number} [startingOffset]
+    */
+    constructor(u8array, startingOffset) {
+        const start = startingOffset ? startingOffset : 0;
+        let i = start;
+        /** @type {Uint8Array} */
+        this.keysAndCardinalities = EMPTY_UINT8;
+        /** @type {(RoaringBitmapArray|RoaringBitmapBits|RoaringBitmapRun)[]} */
+        this.containers = [];
+        /** @type {number} */
+        this.consumed_len_bytes = 0;
+        if (u8array === null || u8array.length === i || u8array[i] === 0) {
+            return this;
+        } else if (u8array[i] > 0xf0) {
+            // Special representation of tiny sets that are close together
+            const lspecial = u8array[i] & 0x0f;
+            this.keysAndCardinalities = new Uint8Array(lspecial * 4);
+            let pspecial = i + 1;
+            let key = u8array[pspecial + 2] | (u8array[pspecial + 3] << 8);
+            let value = u8array[pspecial] | (u8array[pspecial + 1] << 8);
+            let entry = (key << 16) | value;
+            let container;
+            container = new RoaringBitmapArray(1, new Uint8Array(4));
+            container.array[0] = value & 0xFF;
+            container.array[1] = (value >> 8) & 0xFF;
+            this.containers.push(container);
+            this.keysAndCardinalities[0] = key;
+            this.keysAndCardinalities[1] = key >> 8;
+            pspecial += 4;
+            for (let ispecial = 1; ispecial < lspecial; ispecial += 1) {
+                entry += u8array[pspecial] | (u8array[pspecial + 1] << 8);
+                value = entry & 0xffff;
+                key = entry >> 16;
+                container = this.addToArrayAt(key);
+                const cardinalityOld = container.cardinality;
+                container.array[cardinalityOld * 2] = value & 0xFF;
+                container.array[(cardinalityOld * 2) + 1] = (value >> 8) & 0xFF;
+                container.cardinality = cardinalityOld + 1;
+                pspecial += 2;
+            }
+            this.consumed_len_bytes = pspecial - i;
+            return this;
+        } else if (u8array[i] < 0x3a) {
+            // Special representation of tiny sets with arbitrary 32-bit integers
+            const lspecial = u8array[i];
+            this.keysAndCardinalities = new Uint8Array(lspecial * 4);
+            let pspecial = i + 1;
+            for (let ispecial = 0; ispecial < lspecial; ispecial += 1) {
+                const key = u8array[pspecial + 2] | (u8array[pspecial + 3] << 8);
+                const value = u8array[pspecial] | (u8array[pspecial + 1] << 8);
+                const container = this.addToArrayAt(key);
+                const cardinalityOld = container.cardinality;
+                container.array[cardinalityOld * 2] = value & 0xFF;
+                container.array[(cardinalityOld * 2) + 1] = (value >> 8) & 0xFF;
+                container.cardinality = cardinalityOld + 1;
+                pspecial += 4;
+            }
+            this.consumed_len_bytes = pspecial - i;
+            return this;
+        }
+        // https://github.com/RoaringBitmap/RoaringFormatSpec
+        //
+        // Roaring bitmaps are used for flags that can be kept in their
+        // compressed form, even when loaded into memory. This decoder
+        // turns the containers into objects, but uses byte array
+        // slices of the original format for the data payload.
+        const has_runs = u8array[i] === 0x3b;
+        if (u8array[i] !== 0x3a && u8array[i] !== 0x3b) {
+            throw new Error("not a roaring bitmap: " + u8array[i]);
+        }
+        const size = has_runs ?
+            ((u8array[i + 2] | (u8array[i + 3] << 8)) + 1) :
+            ((u8array[i + 4] | (u8array[i + 5] << 8) |
+             (u8array[i + 6] << 16) | (u8array[i + 7] << 24)));
+        i += has_runs ? 4 : 8;
+        let is_run;
+        if (has_runs) {
+            const is_run_len = (size + 7) >> 3;
+            is_run = new Uint8Array(u8array.buffer, i + u8array.byteOffset, is_run_len);
+            i += is_run_len;
+        } else {
+            is_run = EMPTY_UINT8;
+        }
+        this.keysAndCardinalities = u8array.subarray(i, i + (size * 4));
+        i += size * 4;
+        let offsets = null;
+        if (!has_runs || size >= 4) {
+            offsets = [];
+            for (let j = 0; j < size; ++j) {
+                offsets.push(u8array[i] | (u8array[i + 1] << 8) | (u8array[i + 2] << 16) |
+                    (u8array[i + 3] << 24));
+                i += 4;
+            }
+        }
+        for (let j = 0; j < size; ++j) {
+            if (offsets && offsets[j] !== i - start) {
+                throw new Error(`corrupt bitmap ${j}: ${i - start} / ${offsets[j]}`);
+            }
+            const cardinality = (this.keysAndCardinalities[(j * 4) + 2] |
+                (this.keysAndCardinalities[(j * 4) + 3] << 8)) + 1;
+            if (is_run[j >> 3] & (1 << (j & 0x7))) {
+                const runcount = (u8array[i] | (u8array[i + 1] << 8));
+                i += 2;
+                this.containers.push(new RoaringBitmapRun(
+                    runcount,
+                    new Uint8Array(u8array.buffer, i + u8array.byteOffset, runcount * 4),
+                ));
+                i += runcount * 4;
+            } else if (cardinality >= 4096) {
+                this.containers.push(new RoaringBitmapBits(new Uint8Array(
+                    u8array.buffer,
+                    i + u8array.byteOffset, 8192,
+                )));
+                i += 8192;
+            } else {
+                const end = cardinality * 2;
+                this.containers.push(new RoaringBitmapArray(
+                    cardinality,
+                    new Uint8Array(u8array.buffer, i + u8array.byteOffset, end),
+                ));
+                i += end;
+            }
+        }
+        this.consumed_len_bytes = i - start;
+    }
+    /**
+     * @param {number} number
+     * @returns {RoaringBitmap}
+     */
+    static makeSingleton(number) {
+        const result = new RoaringBitmap(null, 0);
+        result.keysAndCardinalities = Uint8Array.of(
+            (number >> 16), (number >> 24),
+            0, 0, // keysAndCardinalities stores the true cardinality minus 1
+        );
+        result.containers.push(new RoaringBitmapArray(
+            1,
+            Uint8Array.of(number, number >> 8),
+        ));
+        return result;
+    }
+    /** @returns {RoaringBitmap} */
+    static everything() {
+        if (EVERYTHING_BITMAP.isEmpty()) {
+            let i = 0;
+            const l = 1 << 16;
+            const everything_range = new RoaringBitmapRun(1, Uint8Array.of(0, 0, 0xff, 0xff));
+            EVERYTHING_BITMAP.keysAndCardinalities = new Uint8Array(l * 4);
+            while (i < l) {
+                EVERYTHING_BITMAP.containers.push(everything_range);
+                // key
+                EVERYTHING_BITMAP.keysAndCardinalities[(i * 4) + 0] = i;
+                EVERYTHING_BITMAP.keysAndCardinalities[(i * 4) + 1] = i >> 8;
+                // cardinality (minus one)
+                EVERYTHING_BITMAP.keysAndCardinalities[(i * 4) + 2] = 0xff;
+                EVERYTHING_BITMAP.keysAndCardinalities[(i * 4) + 3] = 0xff;
+                i += 1;
+            }
+        }
+        return EVERYTHING_BITMAP;
+    }
+    /** @returns {RoaringBitmap} */
+    static empty() {
+        return EMPTY_BITMAP;
+    }
+    /** @returns {boolean} */
+    isEmpty() {
+        return this.containers.length === 0;
+    }
+    /**
+     * Helper function used when constructing bitmaps from lists.
+     * Returns an array container with at least two free byte slots
+     * and bumps `this.cardinalities`.
+     * @param {number} key
+     * @returns {RoaringBitmapArray}
+     */
+    addToArrayAt(key) {
+        let mid = this.getContainerId(key);
+        /** @type {RoaringBitmapArray|RoaringBitmapBits|RoaringBitmapRun} */
+        let container;
+        if (mid === -1) {
+            container = new RoaringBitmapArray(0, new Uint8Array(2));
+            mid = this.containers.length;
+            this.containers.push(container);
+            if (mid * 4 > this.keysAndCardinalities.length) {
+                const keysAndContainers = new Uint8Array(mid * 8);
+                keysAndContainers.set(this.keysAndCardinalities);
+                this.keysAndCardinalities = keysAndContainers;
+            }
+            this.keysAndCardinalities[(mid * 4) + 0] = key;
+            this.keysAndCardinalities[(mid * 4) + 1] = key >> 8;
+        } else {
+            container = this.containers[mid];
+            const cardinalityOld =
+                this.keysAndCardinalities[(mid * 4) + 2] |
+                (this.keysAndCardinalities[(mid * 4) + 3] << 8);
+            const cardinality = cardinalityOld + 1;
+            this.keysAndCardinalities[(mid * 4) + 2] = cardinality;
+            this.keysAndCardinalities[(mid * 4) + 3] = cardinality >> 8;
+        }
+        // the logic for handing this number is annoying, because keysAndCardinalities stores
+        // the cardinality *minus one*, so that it can count up to 65536 with only two bytes
+        // (because empty containers are never stored).
+        //
+        // So, if this is a new container, the stored cardinality contains `0 0`, which is
+        // the proper value of the old cardinality (an imaginary empty container existed).
+        // If this is adding to an existing container, then the above `else` branch bumps it
+        // by one, leaving us with a proper value of `cardinality - 1`.
+        const cardinalityOld =
+            this.keysAndCardinalities[(mid * 4) + 2] |
+            (this.keysAndCardinalities[(mid * 4) + 3] << 8);
+        if (!(container instanceof RoaringBitmapArray) ||
+            container.array.byteLength < ((cardinalityOld + 1) * 2)
+        ) {
+            const newBuf = new Uint8Array((cardinalityOld + 1) * 4);
+            let idx = 0;
+            for (const cvalue of container.values()) {
+                newBuf[idx] = cvalue & 0xFF;
+                newBuf[idx + 1] = (cvalue >> 8) & 0xFF;
+                idx += 2;
+            }
+            if (container instanceof RoaringBitmapArray) {
+                container.cardinality = cardinalityOld;
+                container.array = newBuf;
+                return container;
+            }
+            const newcontainer = new RoaringBitmapArray(cardinalityOld, newBuf);
+            this.containers[mid] = newcontainer;
+            return newcontainer;
+        } else {
+            return container;
+        }
+    }
+    /**
+     * @param {RoaringBitmap} that
+     * @returns {RoaringBitmap}
+     */
+    union(that) {
+        if (this.isEmpty()) {
+            return that;
+        }
+        if (that.isEmpty()) {
+            return this;
+        }
+        if (this === RoaringBitmap.everything() || that === RoaringBitmap.everything()) {
+            return RoaringBitmap.everything();
+        }
+        let i = 0;
+        const il = this.containers.length;
+        let j = 0;
+        const jl = that.containers.length;
+        const result = new RoaringBitmap(null, 0);
+        result.keysAndCardinalities = new Uint8Array((il + jl) * 4);
+        while (i < il || j < jl) {
+            const ik = i * 4;
+            const jk = j * 4;
+            const k = result.containers.length * 4;
+            if (j >= jl || (i < il && (
+                (this.keysAndCardinalities[ik + 1] < that.keysAndCardinalities[jk + 1]) ||
+                (this.keysAndCardinalities[ik + 1] === that.keysAndCardinalities[jk + 1] &&
+                    this.keysAndCardinalities[ik] < that.keysAndCardinalities[jk])
+            ))) {
+                result.keysAndCardinalities[k + 0] = this.keysAndCardinalities[ik + 0];
+                result.keysAndCardinalities[k + 1] = this.keysAndCardinalities[ik + 1];
+                result.keysAndCardinalities[k + 2] = this.keysAndCardinalities[ik + 2];
+                result.keysAndCardinalities[k + 3] = this.keysAndCardinalities[ik + 3];
+                result.containers.push(this.containers[i]);
+                i += 1;
+            } else if (i >= il || (j < jl && (
+                (that.keysAndCardinalities[jk + 1] < this.keysAndCardinalities[ik + 1]) ||
+                (that.keysAndCardinalities[jk + 1] === this.keysAndCardinalities[ik + 1] &&
+                    that.keysAndCardinalities[jk] < this.keysAndCardinalities[ik])
+            ))) {
+                result.keysAndCardinalities[k + 0] = that.keysAndCardinalities[jk + 0];
+                result.keysAndCardinalities[k + 1] = that.keysAndCardinalities[jk + 1];
+                result.keysAndCardinalities[k + 2] = that.keysAndCardinalities[jk + 2];
+                result.keysAndCardinalities[k + 3] = that.keysAndCardinalities[jk + 3];
+                result.containers.push(that.containers[j]);
+                j += 1;
+            } else {
+                // this key is not smaller than that key
+                // that key is not smaller than this key
+                // they must be equal
+                const thisContainer = this.containers[i];
+                const thatContainer = that.containers[j];
+                let card = 0;
+                if (thisContainer instanceof RoaringBitmapBits &&
+                    thatContainer instanceof RoaringBitmapBits
+                ) {
+                    const resultArray = new Uint8Array(
+                        thisContainer.array.length > thatContainer.array.length ?
+                            thisContainer.array.length :
+                            thatContainer.array.length,
+                    );
+                    let k = 0;
+                    const kl = resultArray.length;
+                    while (k < kl) {
+                        const c = thisContainer.array[k] | thatContainer.array[k];
+                        resultArray[k] = c;
+                        card += bitCount(c);
+                        k += 1;
+                    }
+                    result.containers.push(new RoaringBitmapBits(resultArray));
+                } else {
+                    const thisValues = thisContainer.values();
+                    const thatValues = thatContainer.values();
+                    let thisResult = thisValues.next();
+                    let thatResult = thatValues.next();
+                    /** @type {Array<number>} */
+                    const resultValues = [];
+                    while (!thatResult.done || !thisResult.done) {
+                        // generator will definitely implement the iterator protocol correctly
+                        /** @type {number} */
+                        const thisValue = thisResult.value;
+                        /** @type {number} */
+                        const thatValue = thatResult.value;
+                        if (thatResult.done || thisValue < thatValue) {
+                            resultValues.push(thisValue);
+                            thisResult = thisValues.next();
+                        } else if (thisResult.done || thatValue < thisValue) {
+                            resultValues.push(thatValue);
+                            thatResult = thatValues.next();
+                        } else {
+                            // this value is not smaller than that value
+                            // that value is not smaller than this value
+                            // they must be equal
+                            resultValues.push(thisValue);
+                            thisResult = thisValues.next();
+                            thatResult = thatValues.next();
+                        }
+                    }
+                    const resultArray = new Uint8Array(resultValues.length * 2);
+                    let k = 0;
+                    for (const value of resultValues) {
+                        // roaring bitmap is little endian
+                        resultArray[k] = value & 0xFF;
+                        resultArray[k + 1] = (value >> 8) & 0xFF;
+                        k += 2;
+                    }
+                    result.containers.push(new RoaringBitmapArray(
+                        resultValues.length,
+                        resultArray,
+                    ));
+                    card = resultValues.length;
+                }
+                result.keysAndCardinalities[k + 0] = this.keysAndCardinalities[ik + 0];
+                result.keysAndCardinalities[k + 1] = this.keysAndCardinalities[ik + 1];
+                card -= 1;
+                result.keysAndCardinalities[k + 2] = card;
+                result.keysAndCardinalities[k + 3] = card >> 8;
+                i += 1;
+                j += 1;
+            }
+        }
+        return result;
+    }
+    /**
+     * @param {RoaringBitmap} that
+     * @returns {RoaringBitmap}
+     */
+    intersection(that) {
+        if (this.isEmpty() || that.isEmpty()) {
+            return EMPTY_BITMAP;
+        }
+        if (this === RoaringBitmap.everything()) {
+            return that;
+        }
+        if (that === RoaringBitmap.everything()) {
+            return this;
+        }
+        let i = 0;
+        const il = this.containers.length;
+        let j = 0;
+        const jl = that.containers.length;
+        const result = new RoaringBitmap(null, 0);
+        result.keysAndCardinalities = new Uint8Array((il > jl ? il : jl) * 4);
+        while (i < il && j < jl) {
+            const ik = i * 4;
+            const jk = j * 4;
+            const k = result.containers.length * 4;
+            if (j >= jl || (i < il && (
+                (this.keysAndCardinalities[ik + 1] < that.keysAndCardinalities[jk + 1]) ||
+                (this.keysAndCardinalities[ik + 1] === that.keysAndCardinalities[jk + 1] &&
+                    this.keysAndCardinalities[ik] < that.keysAndCardinalities[jk])
+            ))) {
+                i += 1;
+            } else if (i >= il || (j < jl && (
+                (that.keysAndCardinalities[jk + 1] < this.keysAndCardinalities[ik + 1]) ||
+                (that.keysAndCardinalities[jk + 1] === this.keysAndCardinalities[ik + 1] &&
+                    that.keysAndCardinalities[jk] < this.keysAndCardinalities[ik])
+            ))) {
+                j += 1;
+            } else {
+                // this key is not smaller than that key
+                // that key is not smaller than this key
+                // they must be equal
+                const thisContainer = this.containers[i];
+                const thatContainer = that.containers[j];
+                let card = 0;
+                if (thisContainer instanceof RoaringBitmapBits &&
+                    thatContainer instanceof RoaringBitmapBits
+                ) {
+                    const resultArray = new Uint8Array(
+                        thisContainer.array.length > thatContainer.array.length ?
+                            thisContainer.array.length :
+                            thatContainer.array.length,
+                    );
+                    let k = 0;
+                    const kl = resultArray.length;
+                    while (k < kl) {
+                        const c = thisContainer.array[k] & thatContainer.array[k];
+                        resultArray[k] = c;
+                        card += bitCount(c);
+                        k += 1;
+                    }
+                    if (card !== 0) {
+                        result.containers.push(new RoaringBitmapBits(resultArray));
+                    }
+                } else {
+                    const thisValues = thisContainer.values();
+                    const thatValues = thatContainer.values();
+                    let thisValue = thisValues.next();
+                    let thatValue = thatValues.next();
+                    const resultValues = [];
+                    while (!thatValue.done && !thisValue.done) {
+                        if (thisValue.value < thatValue.value) {
+                            thisValue = thisValues.next();
+                        } else if (thatValue.value < thisValue.value) {
+                            thatValue = thatValues.next();
+                        } else {
+                            // this value is not smaller than that value
+                            // that value is not smaller than this value
+                            // they must be equal
+                            resultValues.push(thisValue.value);
+                            thisValue = thisValues.next();
+                            thatValue = thatValues.next();
+                        }
+                    }
+                    card = resultValues.length;
+                    if (card !== 0) {
+                        const resultArray = new Uint8Array(resultValues.length * 2);
+                        let k = 0;
+                        for (const value of resultValues) {
+                            // roaring bitmap is little endian
+                            resultArray[k] = value & 0xFF;
+                            resultArray[k + 1] = (value >> 8) & 0xFF;
+                            k += 2;
+                        }
+                        result.containers.push(new RoaringBitmapArray(
+                            resultValues.length,
+                            resultArray,
+                        ));
+                    }
+                }
+                if (card !== 0) {
+                    result.keysAndCardinalities[k + 0] = this.keysAndCardinalities[ik + 0];
+                    result.keysAndCardinalities[k + 1] = this.keysAndCardinalities[ik + 1];
+                    card -= 1;
+                    result.keysAndCardinalities[k + 2] = card;
+                    result.keysAndCardinalities[k + 3] = card >> 8;
+                }
+                i += 1;
+                j += 1;
+            }
+        }
+        return result;
+    }
+    /** @param {number} keyvalue */
+    contains(keyvalue) {
+        const key = keyvalue >> 16;
+        const value = keyvalue & 0xFFFF;
+        const mid = this.getContainerId(key);
+        return mid === -1 ? false : this.containers[mid].contains(value);
+    }
+    /**
+     * @param {number} key
+     * @returns {number}
+     */
+    getContainerId(key) {
+        // Binary search algorithm copied from
+        // https://en.wikipedia.org/wiki/Binary_search#Procedure
+        //
+        // Format is required by specification to be sorted.
+        // Because keys are 16 bits and unique, length can't be
+        // bigger than 2**16, and because we have 32 bits of safe int,
+        // left + right can't overflow.
+        let left = 0;
+        let right = this.containers.length - 1;
+        while (left <= right) {
+            const mid = Math.floor((left + right) / 2);
+            const x = this.keysAndCardinalities[(mid * 4)] |
+                (this.keysAndCardinalities[(mid * 4) + 1] << 8);
+            if (x < key) {
+                left = mid + 1;
+            } else if (x > key) {
+                right = mid - 1;
+            } else {
+                return mid;
+            }
+        }
+        return -1;
+    }
+    * entries() {
+        const l = this.containers.length;
+        for (let i = 0; i < l; ++i) {
+            const key = this.keysAndCardinalities[i * 4] |
+                (this.keysAndCardinalities[(i * 4) + 1] << 8);
+            for (const value of this.containers[i].values()) {
+                yield (key << 16) | value;
+            }
+        }
+    }
+    /**
+     * @returns {number|null}
+     */
+    first() {
+        for (const entry of this.entries()) {
+            return entry;
+        }
+        return null;
+    }
+    /**
+     * @returns {number}
+     */
+    cardinality() {
+        let result = 0;
+        const l = this.containers.length;
+        for (let i = 0; i < l; ++i) {
+            const card = this.keysAndCardinalities[(i * 4) + 2] |
+                (this.keysAndCardinalities[(i * 4) + 3] << 8);
+            result += card + 1;
+        }
+        return result;
+    }
+}
+
+class RoaringBitmapRun {
+    /**
+     * @param {number} runcount
+     * @param {Uint8Array} array
+     */
+    constructor(runcount, array) {
+        this.runcount = runcount;
+        this.array = array;
+    }
+    /** @param {number} value */
+    contains(value) {
+        // Binary search algorithm copied from
+        // https://en.wikipedia.org/wiki/Binary_search#Procedure
+        //
+        // Since runcount is stored as 16 bits, left + right
+        // can't overflow.
+        let left = 0;
+        let right = this.runcount - 1;
+        while (left <= right) {
+            const mid = (left + right) >> 1;
+            const i = mid * 4;
+            const start = this.array[i] | (this.array[i + 1] << 8);
+            const lenm1 = this.array[i + 2] | (this.array[i + 3] << 8);
+            if ((start + lenm1) < value) {
+                left = mid + 1;
+            } else if (start > value) {
+                right = mid - 1;
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+    * values() {
+        let i = 0;
+        while (i < this.runcount) {
+            const start = this.array[i * 4] | (this.array[(i * 4) + 1] << 8);
+            const lenm1 = this.array[(i * 4) + 2] | (this.array[(i * 4) + 3] << 8);
+            let value = start;
+            let j = 0;
+            while (j <= lenm1) {
+                yield value;
+                value += 1;
+                j += 1;
+            }
+            i += 1;
+        }
+    }
+}
+class RoaringBitmapArray {
+    /**
+     * @param {number} cardinality
+     * @param {Uint8Array} array
+     */
+    constructor(cardinality, array) {
+        this.cardinality = cardinality;
+        this.array = array;
+    }
+    /** @param {number} value */
+    contains(value) {
+        // Binary search algorithm copied from
+        // https://en.wikipedia.org/wiki/Binary_search#Procedure
+        //
+        // Since cardinality can't be higher than 4096, left + right
+        // cannot overflow.
+        let left = 0;
+        let right = this.cardinality - 1;
+        while (left <= right) {
+            const mid = (left + right) >> 1;
+            const i = mid * 2;
+            const x = this.array[i] | (this.array[i + 1] << 8);
+            if (x < value) {
+                left = mid + 1;
+            } else if (x > value) {
+                right = mid - 1;
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+    /** @returns {Generator<number>} */
+    * values() {
+        let i = 0;
+        const l = this.cardinality * 2;
+        while (i < l) {
+            yield this.array[i] | (this.array[i + 1] << 8);
+            i += 2;
+        }
+    }
+}
+class RoaringBitmapBits {
+    /**
+     * @param {Uint8Array} array
+     */
+    constructor(array) {
+        this.array = array;
+    }
+    /** @param {number} value */
+    contains(value) {
+        return !!(this.array[value >> 3] & (1 << (value & 7)));
+    }
+    * values() {
+        let i = 0;
+        const l = this.array.length << 3;
+        while (i < l) {
+            if (this.contains(i)) {
+                yield i;
+            }
+            i += 1;
+        }
+    }
+}
+
+const EMPTY_BITMAP = new RoaringBitmap(null, 0);
+EMPTY_BITMAP.consumed_len_bytes = 0;
+const EMPTY_BITMAP1 = new RoaringBitmap(null, 0);
+EMPTY_BITMAP1.consumed_len_bytes = 1;
+const EVERYTHING_BITMAP = new RoaringBitmap(null, 0);
+
+/**
+ * A mapping from six byte nodeids to an arbitrary value.
+ * We don't just use `Map` because that requires double hashing.
+ * @template T
+ * @property {Uint8Array} keys
+ * @property {T[]} values
+ * @property {number} size
+ * @property {number} capacityClass
+ */
+class HashTable {
+    /**
+     * Construct an empty hash table.
+     */
+    constructor() {
+        this.keys = EMPTY_UINT8;
+        /** @type {(T|undefined)[]} */
+        this.values = [];
+        this.size = 0;
+        this.capacityClass = 0;
+    }
+    /**
+     * @returns {Generator<[Uint8Array, T]>}
+     */
+    * entries() {
+        const keys = this.keys;
+        const values = this.values;
+        const l = this.values.length;
+        for (let i = 0; i < l; i += 1) {
+            const value = values[i];
+            if (value !== undefined) {
+                yield [keys.subarray(i * 6, (i + 1) * 6), value];
+            }
+        }
+    }
+    /**
+     * Add a value to the hash table.
+     * @param {Uint8Array} key
+     * @param {T} value
+     */
+    set(key, value) {
+        // 90 % load factor
+        if (this.size * 10 >= this.values.length * 9) {
+            const keys = this.keys;
+            const values = this.values;
+            const l = values.length;
+            this.capacityClass += 1;
+            const capacity = 1 << this.capacityClass;
+            this.keys = new Uint8Array(capacity * 6);
+            this.values = [];
+            for (let i = 0; i < capacity; i += 1) {
+                this.values.push(undefined);
+            }
+            this.size = 0;
+            for (let i = 0; i < l; i += 1) {
+                const oldValue = values[i];
+                if (oldValue !== undefined) {
+                    this.setNoGrow(keys, i * 6, oldValue);
+                }
+            }
+        }
+        this.setNoGrow(key, 0, value);
+    }
+    /**
+     * @param {Uint8Array} key
+     * @param {number} start
+     * @param {T} value
+     */
+    setNoGrow(key, start, value) {
+        const mask = ~(0xffffffff << this.capacityClass);
+        const keys = this.keys;
+        const values = this.values;
+        const l = 1 << this.capacityClass;
+        // because we know that our values are already hashed,
+        // just chop off the lower four bytes
+        let slot = (
+            (key[start + 2] << 24) |
+            (key[start + 3] << 16) |
+            (key[start + 4] << 8) |
+            key[start + 5]
+        ) & mask;
+        for (let distance = 0; distance < l; ) {
+            const j = slot * 6;
+            const otherValue = values[slot];
+            if (otherValue === undefined) {
+                values[slot] = value;
+                const keysStart = slot * 6;
+                keys[keysStart + 0] = key[start + 0];
+                keys[keysStart + 1] = key[start + 1];
+                keys[keysStart + 2] = key[start + 2];
+                keys[keysStart + 3] = key[start + 3];
+                keys[keysStart + 4] = key[start + 4];
+                keys[keysStart + 5] = key[start + 5];
+                this.size += 1;
+                break;
+            } else if (
+                key[start + 0] === keys[j + 0] &&
+                key[start + 1] === keys[j + 1] &&
+                key[start + 2] === keys[j + 2] &&
+                key[start + 3] === keys[j + 3] &&
+                key[start + 4] === keys[j + 4] &&
+                key[start + 5] === keys[j + 5]
+            ) {
+                values[slot] = value;
+                break;
+            } else {
+                const otherPreferredSlot = (
+                    (keys[j + 2] << 24) | (keys[j + 3] << 16) |
+                    (keys[j + 4] << 8) | keys[j + 5]
+                ) & mask;
+                const otherDistance = otherPreferredSlot <= slot ?
+                    slot - otherPreferredSlot :
+                    (l - otherPreferredSlot) + slot;
+                if (distance > otherDistance) {
+                    // if the other key is closer to its preferred slot than this one,
+                    // then insert our node in its place and swap
+                    //
+                    // https://cglab.ca/~abeinges/blah/robinhood-part-1/
+                    const otherKey = keys.slice(j, j + 6);
+                    values[slot] = value;
+                    value = otherValue;
+                    keys[j + 0] = key[start + 0];
+                    keys[j + 1] = key[start + 1];
+                    keys[j + 2] = key[start + 2];
+                    keys[j + 3] = key[start + 3];
+                    keys[j + 4] = key[start + 4];
+                    keys[j + 5] = key[start + 5];
+                    key = otherKey;
+                    start = 0;
+                    distance = otherDistance;
+                }
+                distance += 1;
+                slot = (slot + 1) & mask;
+            }
+        }
+    }
+    /**
+     * Retrieve a value
+     * @param {Uint8Array} key
+     * @returns {T|undefined}
+     */
+    get(key) {
+        if (key.length !== 6) {
+            throw "invalid key";
+        }
+        return this.getWithOffsetKey(key, 0);
+    }
+    /**
+     * Retrieve a value
+     * @param {Uint8Array} key
+     * @param {number} start
+     * @returns {T|undefined}
+     */
+    getWithOffsetKey(key, start) {
+        const mask = ~(0xffffffff << this.capacityClass);
+        const keys = this.keys;
+        const values = this.values;
+        const l = 1 << this.capacityClass;
+        // because we know that our values are already hashed,
+        // just chop off the lower four bytes
+        let slot = (
+            (key[start + 2] << 24) |
+            (key[start + 3] << 16) |
+            (key[start + 4] << 8) |
+            key[start + 5]
+        ) & mask;
+        for (let distance = 0; distance < l; distance += 1) {
+            const j = slot * 6;
+            const value = values[slot];
+            if (value === undefined) {
+                break;
+            } else if (
+                key[start + 0] === keys[j + 0] &&
+                key[start + 1] === keys[j + 1] &&
+                key[start + 2] === keys[j + 2] &&
+                key[start + 3] === keys[j + 3] &&
+                key[start + 4] === keys[j + 4] &&
+                key[start + 5] === keys[j + 5]
+            ) {
+                return value;
+            } else {
+                const otherPreferredSlot = (
+                    (keys[j + 2] << 24) | (keys[j + 3] << 16) |
+                    (keys[j + 4] << 8) | keys[j + 5]
+                ) & mask;
+                const otherDistance = otherPreferredSlot <= slot ?
+                    slot - otherPreferredSlot :
+                    (l - otherPreferredSlot) + slot;
+                if (distance > otherDistance) {
+                    break;
+                }
+            }
+            slot = (slot + 1) & mask;
+        }
+        return undefined;
+    }
+}
+
+/*eslint-disable */
+// ignore-tidy-linelength
+/** <https://stackoverflow.com/questions/43122082/efficiently-count-the-number-of-bits-in-an-integer-in-javascript>
+ * @param {number} n
+ * @returns {number}
+ */
+function bitCount(n) {
+    n = (~~n) - ((n >> 1) & 0x55555555);
+    n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
+    return ((n + (n >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
+}
+/*eslint-enable */
+
+/**
+ * @param {stringdex.Hooks} hooks
+ * @returns {Promise<stringdex.Database>}
+ */
+function loadDatabase(hooks) {
+    /** @type {stringdex.Callbacks} */
+    const callbacks = {
+        rr_: function(data) {
+            const dataObj = JSON.parse(data);
+            for (const colName of Object.keys(dataObj)) {
+                if (Object.hasOwn(dataObj[colName], "I")) {
+                    registry.searchTreeRoots.set(
+                        colName,
+                        makeSearchTreeFromBase64(dataObj[colName].I)[1],
+                    );
+                }
+                if (Object.hasOwn(dataObj[colName], "N")) {
+                    const counts = [];
+                    const countsstring = dataObj[colName]["N"];
+                    let i = 0;
+                    const l = countsstring.length;
+                    while (i < l) {
+                        let n = 0;
+                        let c = countsstring.charCodeAt(i);
+                        while (c < 96) { // 96 = "`"
+                            n = (n << 4) | (c & 0xF);
+                            i += 1;
+                            c = countsstring.charCodeAt(i);
+                        }
+                        n = (n << 4) | (c & 0xF);
+                        counts.push(n);
+                        i += 1;
+                    }
+                    registry.dataColumns.set(colName, new DataColumn(
+                        counts,
+                        makeUint8ArrayFromBase64(dataObj[colName]["H"]),
+                        new RoaringBitmap(makeUint8ArrayFromBase64(dataObj[colName]["E"]), 0),
+                        colName,
+                    ));
+                }
+            }
+            const cb = registry.searchTreeRootCallback;
+            if (cb) {
+                cb(null, new Database(registry.searchTreeRoots, registry.dataColumns));
+            }
+        },
+        err_rr_: function(err) {
+            const cb = registry.searchTreeRootCallback;
+            if (cb) {
+                cb(err, null);
+            }
+        },
+        rd_: function(dataString) {
+            const l = dataString.length;
+            const data = new Uint8Array(l);
+            for (let i = 0; i < l; ++i) {
+                data[i] = dataString.charCodeAt(i);
+            }
+            loadColumnFromBytes(data);
+        },
+        err_rd_: function(filename, err) {
+            const nodeid = makeUint8ArrayFromHex(filename);
+            const cb = registry.dataColumnLoadPromiseCallbacks.get(nodeid);
+            if (cb) {
+                cb(err, null);
+            }
+        },
+        rb_: function(dataString64) {
+            loadColumnFromBytes(makeUint8ArrayFromBase64(dataString64));
+        },
+        err_rb_: function(filename, err) {
+            const nodeid = makeUint8ArrayFromHex(filename);
+            const cb = registry.dataColumnLoadPromiseCallbacks.get(nodeid);
+            if (cb) {
+                cb(err, null);
+            }
+        },
+        rn_: function(inputBase64) {
+            const [nodeid, tree] = makeSearchTreeFromBase64(inputBase64);
+            const cb = registry.searchTreeLoadPromiseCallbacks.get(nodeid);
+            if (cb) {
+                cb(null, tree);
+                registry.searchTreeLoadPromiseCallbacks.set(nodeid, null);
+            }
+        },
+        err_rn_: function(filename, err) {
+            const nodeid = makeUint8ArrayFromHex(filename);
+            const cb = registry.searchTreeLoadPromiseCallbacks.get(nodeid);
+            if (cb) {
+                cb(err, null);
+            }
+        },
+    };
+
+    /**
+     * @type {{
+     *      searchTreeRoots: Map<string, SearchTree>;
+     *      searchTreeLoadPromiseCallbacks: HashTable<(function(any, SearchTree?): any)|null>;
+     *      searchTreePromises: HashTable<Promise<SearchTree>>;
+     *      dataColumnLoadPromiseCallbacks: HashTable<function(any, Uint8Array[]?): any>;
+     *      dataColumns: Map<string, DataColumn>;
+     *      dataColumnsBuckets: Map<string, HashTable<Promise<Uint8Array[]>>>;
+     *      searchTreeLoadByNodeID: function(Uint8Array): Promise<SearchTree>;
+     *      searchTreeRootCallback?: function(any, Database?): any;
+     *      dataLoadByNameAndHash: function(string, Uint8Array): Promise<Uint8Array[]>;
+     * }}
+     */
+    const registry = {
+        searchTreeRoots: new Map(),
+        searchTreeLoadPromiseCallbacks: new HashTable(),
+        searchTreePromises: new HashTable(),
+        dataColumnLoadPromiseCallbacks: new HashTable(),
+        dataColumns: new Map(),
+        dataColumnsBuckets: new Map(),
+        searchTreeLoadByNodeID: function(nodeid) {
+            const existingPromise = registry.searchTreePromises.get(nodeid);
+            if (existingPromise) {
+                return existingPromise;
+            }
+            /** @type {Promise<SearchTree>} */
+            let newPromise;
+            if ((nodeid[0] & 0x80) !== 0) {
+                const isWhole = (nodeid[0] & 0x40) !== 0;
+                let leaves;
+                if ((nodeid[0] & 0x10) !== 0) {
+                    let id1 = (nodeid[2] << 8) | nodeid[3];
+                    if ((nodeid[0] & 0x20) !== 0) {
+                        // when data is present, id1 can be up to 20 bits
+                        id1 |= ((nodeid[1] & 0x0f) << 16);
+                    } else {
+                        // otherwise, we fit in 28
+                        id1 |= ((nodeid[0] & 0x0f) << 24) | (nodeid[1] << 16);
+                    }
+                    const id2 = id1 + ((nodeid[4] << 8) | nodeid[5]);
+                    leaves = RoaringBitmap.makeSingleton(id1)
+                        .union(RoaringBitmap.makeSingleton(id2));
+                } else {
+                    leaves = RoaringBitmap.makeSingleton(
+                        (nodeid[2] << 24) | (nodeid[3] << 16) |
+                        (nodeid[4] << 8) | nodeid[5],
+                    );
+                }
+                const data = (nodeid[0] & 0x20) !== 0 ?
+                    Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) :
+                    EMPTY_UINT8;
+                newPromise = Promise.resolve(new SearchTree(
+                    EMPTY_SEARCH_TREE_BRANCHES,
+                    EMPTY_SEARCH_TREE_BRANCHES,
+                    data,
+                    isWhole ? leaves : EMPTY_BITMAP,
+                    isWhole ? EMPTY_BITMAP : leaves,
+                ));
+            } else {
+                const hashHex = makeHexFromUint8Array(nodeid);
+                newPromise = new Promise((resolve, reject) => {
+                    const cb = registry.searchTreeLoadPromiseCallbacks.get(nodeid);
+                    if (cb) {
+                        registry.searchTreeLoadPromiseCallbacks.set(nodeid, (err, data) => {
+                            cb(err, data);
+                            if (data) {
+                                resolve(data);
+                            } else {
+                                reject(err);
+                            }
+                        });
+                    } else {
+                        registry.searchTreeLoadPromiseCallbacks.set(nodeid, (err, data) => {
+                            if (data) {
+                                resolve(data);
+                            } else {
+                                reject(err);
+                            }
+                        });
+                        hooks.loadTreeByHash(hashHex);
+                    }
+                });
+            }
+            registry.searchTreePromises.set(nodeid, newPromise);
+            return newPromise;
+        },
+        dataLoadByNameAndHash: function(name, hash) {
+            let dataColumnBuckets = registry.dataColumnsBuckets.get(name);
+            if (dataColumnBuckets === undefined) {
+                dataColumnBuckets = new HashTable();
+                registry.dataColumnsBuckets.set(name, dataColumnBuckets);
+            }
+            const existingBucket = dataColumnBuckets.get(hash);
+            if (existingBucket) {
+                return existingBucket;
+            }
+            const hashHex = makeHexFromUint8Array(hash);
+            /** @type {Promise<Uint8Array[]>} */
+            const newBucket = new Promise((resolve, reject) => {
+                const cb = registry.dataColumnLoadPromiseCallbacks.get(hash);
+                if (cb) {
+                    registry.dataColumnLoadPromiseCallbacks.set(hash, (err, data) => {
+                        cb(err, data);
+                        if (data) {
+                            resolve(data);
+                        } else {
+                            reject(err);
+                        }
+                    });
+                } else {
+                    registry.dataColumnLoadPromiseCallbacks.set(hash, (err, data) => {
+                        if (data) {
+                            resolve(data);
+                        } else {
+                            reject(err);
+                        }
+                    });
+                    hooks.loadDataByNameAndHash(name, hashHex);
+                }
+            });
+            dataColumnBuckets.set(hash, newBucket);
+            return newBucket;
+        },
+    };
+
+    /**
+     * The set of child subtrees.
+     * @type {{
+     *    nodeids: Uint8Array,
+     *    subtrees: Array<Promise<SearchTree>|null>,
+     * }}
+     */
+    class SearchTreeBranches {
+        /**
+         * Construct the subtree list with `length` nulls
+         * @param {number} length
+         * @param {Uint8Array} nodeids
+         */
+        constructor(length, nodeids) {
+            this.nodeids = nodeids;
+            this.subtrees = [];
+            for (let i = 0; i < length; ++i) {
+                this.subtrees.push(null);
+            }
+        }
+        /**
+         * @param {number} i
+         * @returns {Uint8Array}
+        */
+        getNodeID(i) {
+            return new Uint8Array(
+                this.nodeids.buffer,
+                this.nodeids.byteOffset + (i * 6),
+                6,
+            );
+        }
+        // https://github.com/microsoft/TypeScript/issues/17227
+        /** @returns {Generator<[number, Promise<SearchTree>|null]>} */
+        entries() {
+            throw new Error();
+        }
+        /**
+         * @param {number} _k
+         * @returns {number}
+         */
+        getIndex(_k) {
+            throw new Error();
+        }
+        /**
+         * @param {number} _i
+         * @returns {number}
+         */
+        getKey(_i) {
+            throw new Error();
+        }
+        /**
+         * @returns {Uint8Array}
+         */
+        getKeys() {
+            throw new Error();
+        }
+    }
+
+    /**
+     * A sorted array of search tree branches.
+     *
+     * @type {{
+     *    keys: Uint8Array,
+     *    nodeids: Uint8Array,
+     *    subtrees: Array<Promise<SearchTree>|null>,
+     * }}
+     */
+    class SearchTreeBranchesArray extends SearchTreeBranches {
+        /**
+         * @param {Uint8Array} keys
+         * @param {Uint8Array} nodeids
+         */
+        constructor(keys, nodeids) {
+            super(keys.length, nodeids);
+            this.keys = keys;
+            let i = 1;
+            while (i < this.keys.length) {
+                if (this.keys[i - 1] >= this.keys[i]) {
+                    throw new Error("HERE");
+                }
+                i += 1;
+            }
+        }
+        /** @returns {Generator<[number, Promise<SearchTree>|null]>} */
+        * entries() {
+            let i = 0;
+            const l = this.keys.length;
+            while (i < l) {
+                yield [this.keys[i], this.subtrees[i]];
+                i += 1;
+            }
+        }
+        /**
+         * @param {number} k
+         * @returns {number}
+         */
+        getIndex(k) {
+            // Since length can't be bigger than 256,
+            // left + right can't overflow.
+            let left = 0;
+            let right = this.keys.length - 1;
+            while (left <= right) {
+                const mid = (left + right) >> 1;
+                if (this.keys[mid] < k) {
+                    left = mid + 1;
+                } else if (this.keys[mid] > k) {
+                    right = mid - 1;
+                } else {
+                    return mid;
+                }
+            }
+            return -1;
+        }
+        /**
+         * @param {number} i
+         * @returns {number}
+         */
+        getKey(i) {
+            return this.keys[i];
+        }
+        /**
+         * @returns {Uint8Array}
+         */
+        getKeys() {
+            return this.keys;
+        }
+    }
+
+    const EMPTY_SEARCH_TREE_BRANCHES = new SearchTreeBranchesArray(
+        EMPTY_UINT8,
+        EMPTY_UINT8,
+    );
+
+    /** @type {number[]} */
+    const SHORT_ALPHABITMAP_CHARS = [];
+    for (let i = 0x61; i <= 0x7A; ++i) {
+        if (i === 0x76 || i === 0x71) {
+            // 24 entries, 26 letters, so we skip q and v
+            continue;
+        }
+        SHORT_ALPHABITMAP_CHARS.push(i);
+    }
+
+    /** @type {number[]} */
+    const LONG_ALPHABITMAP_CHARS = [0x31, 0x32, 0x33, 0x34, 0x35, 0x36];
+    for (let i = 0x61; i <= 0x7A; ++i) {
+        LONG_ALPHABITMAP_CHARS.push(i);
+    }
+
+    /**
+     * @param {number[]} alphabitmap_chars
+     * @param {number} width
+     * @return {(typeof SearchTreeBranches)&{"ALPHABITMAP_CHARS": number[], "width": number}}
+     */
+    function makeSearchTreeBranchesAlphaBitmapClass(alphabitmap_chars, width) {
+        const bitwidth = width * 8;
+        const cls = class SearchTreeBranchesAlphaBitmap extends SearchTreeBranches {
+            /**
+             * @param {number} bitmap
+             * @param {Uint8Array} nodeids
+             */
+            constructor(bitmap, nodeids) {
+                super(nodeids.length / 6, nodeids);
+                if (nodeids.length / 6 !== bitCount(bitmap)) {
+                    throw new Error(`mismatch ${bitmap} ${nodeids}`);
+                }
+                this.bitmap = bitmap;
+                this.nodeids = nodeids;
+            }
+            /** @returns {Generator<[number, Promise<SearchTree>|null]>} */
+            * entries() {
+                let i = 0;
+                let j = 0;
+                while (i < bitwidth) {
+                    if (this.bitmap & (1 << i)) {
+                        yield [alphabitmap_chars[i], this.subtrees[j]];
+                        j += 1;
+                    }
+                    i += 1;
+                }
+            }
+            /**
+             * @param {number} k
+             * @returns {number}
+             */
+            getIndex(k) {
+                //return this.getKeys().indexOf(k);
+                const ix = alphabitmap_chars.indexOf(k);
+                if (ix < 0) {
+                    return ix;
+                }
+                const result = bitCount(~(0xffffffff << ix) & this.bitmap);
+                return result >= this.subtrees.length ? -1 : result;
+            }
+            /**
+             * @param {number} branch_index
+             * @returns {number}
+             */
+            getKey(branch_index) {
+                //return this.getKeys()[branch_index];
+                let alpha_index = 0;
+                while (branch_index >= 0) {
+                    if (this.bitmap & (1 << alpha_index)) {
+                        branch_index -= 1;
+                    }
+                    alpha_index += 1;
+                }
+                return alphabitmap_chars[alpha_index];
+            }
+            /**
+             * @returns {Uint8Array}
+             */
+            getKeys() {
+                const length = bitCount(this.bitmap);
+                const result = new Uint8Array(length);
+                let result_index = 0;
+                for (let alpha_index = 0; alpha_index < bitwidth; ++alpha_index) {
+                    if (this.bitmap & (1 << alpha_index)) {
+                        result[result_index] = alphabitmap_chars[alpha_index];
+                        result_index += 1;
+                    }
+                }
+                return result;
+            }
+        };
+        cls.ALPHABITMAP_CHARS = alphabitmap_chars;
+        cls.width = width;
+        return cls;
+    }
+
+    const SearchTreeBranchesShortAlphaBitmap =
+        makeSearchTreeBranchesAlphaBitmapClass(SHORT_ALPHABITMAP_CHARS, 3);
+
+    const SearchTreeBranchesLongAlphaBitmap =
+        makeSearchTreeBranchesAlphaBitmapClass(LONG_ALPHABITMAP_CHARS, 4);
+
+    /**
+     * A [suffix tree], used for name-based search.
+     *
+     * This data structure is used to drive substring matches,
+     * such as matching the query "link" to `LinkedList`,
+     * and Lev-distance matches, such as matching the
+     * query "hahsmap" to `HashMap`.
+     *
+     * [suffix tree]: https://en.wikipedia.org/wiki/Suffix_tree
+     *
+     * branches
+     * : A sorted-array map of subtrees.
+     *
+     * data
+     * : The substring represented by this node. The root node
+     *   is always empty.
+     *
+     * leaves_suffix
+     * : The IDs of every entry that matches. Levenshtein matches
+     *   won't include these.
+     *
+     * leaves_whole
+     * : The IDs of every entry that matches exactly. Levenshtein matches
+     *   will include these.
+     *
+     * @type {{
+     *     might_have_prefix_branches: SearchTreeBranches,
+     *     branches: SearchTreeBranches,
+     *     data: Uint8Array,
+     *     leaves_suffix: RoaringBitmap,
+     *     leaves_whole: RoaringBitmap,
+     * }}
+     */
+    class SearchTree {
+        /**
+         * @param {SearchTreeBranches} branches
+         * @param {SearchTreeBranches} might_have_prefix_branches
+         * @param {Uint8Array} data
+         * @param {RoaringBitmap} leaves_whole
+         * @param {RoaringBitmap} leaves_suffix
+         */
+        constructor(
+            branches,
+            might_have_prefix_branches,
+            data,
+            leaves_whole,
+            leaves_suffix,
+        ) {
+            this.might_have_prefix_branches = might_have_prefix_branches;
+            this.branches = branches;
+            this.data = data;
+            this.leaves_suffix = leaves_suffix;
+            this.leaves_whole = leaves_whole;
+        }
+        /**
+         * Returns the Trie for the root node.
+         *
+         * A Trie pointer refers to a single node in a logical decompressed search tree
+         * (the real search tree is compressed).
+         *
+         * @return {Trie}
+         */
+        trie() {
+            return new Trie(this, 0);
+        }
+
+        /**
+         * Return the trie representing `name`
+         * @param {Uint8Array|string} name
+         * @returns {Promise<Trie?>}
+         */
+        async search(name) {
+            if (typeof name === "string") {
+                const utf8encoder = new TextEncoder();
+                name = utf8encoder.encode(name);
+            }
+            let trie = this.trie();
+            for (const datum of name) {
+                // code point definitely exists
+                const newTrie = trie.child(datum);
+                if (newTrie) {
+                    trie = await newTrie;
+                } else {
+                    return null;
+                }
+            }
+            return trie;
+        }
+
+        /**
+         * @param {Uint8Array|string} name
+         * @returns {AsyncGenerator<Trie>}
+         */
+        async* searchLev(name) {
+            if (typeof name === "string") {
+                const utf8encoder = new TextEncoder();
+                name = utf8encoder.encode(name);
+            }
+            const w = name.length;
+            if (w < 3) {
+                const trie = await this.search(name);
+                if (trie !== null) {
+                    yield trie;
+                }
+                return;
+            }
+            const levParams = w >= 6 ?
+                new Lev2TParametricDescription(w) :
+                new Lev1TParametricDescription(w);
+            /** @type {Array<[Promise<Trie>, number]>} */
+            const stack = [[Promise.resolve(this.trie()), 0]];
+            const n = levParams.n;
+            while (stack.length !== 0) {
+                // It's not empty
+                /** @type {[Promise<Trie>, number]} */
+                //@ts-expect-error
+                const [triePromise, levState] = stack.pop();
+                const trie = await triePromise;
+                for (const byte of trie.keysExcludeSuffixOnly()) {
+                    const levPos = levParams.getPosition(levState);
+                    const vector = levParams.getVector(
+                        name,
+                        byte,
+                        levPos,
+                        Math.min(w, levPos + (2 * n) + 1),
+                    );
+                    const newLevState = levParams.transition(
+                        levState,
+                        levPos,
+                        vector,
+                    );
+                    if (newLevState >= 0) {
+                        const child = trie.child(byte);
+                        if (child) {
+                            stack.push([child, newLevState]);
+                            if (levParams.isAccept(newLevState)) {
+                                yield child;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * A representation of a set of strings in the search index,
+     * as a subset of the entire tree.
+     */
+    class Trie {
+        /**
+         * @param {SearchTree} tree
+         * @param {number} offset
+         */
+        constructor(tree, offset) {
+            this.tree = tree;
+            this.offset = offset;
+        }
+
+        /**
+         * All exact matches for the string represented by this node.
+         * @returns {RoaringBitmap}
+         */
+        matches() {
+            if (this.offset === this.tree.data.length) {
+                return this.tree.leaves_whole;
+            } else {
+                return EMPTY_BITMAP;
+            }
+        }
+
+        /**
+         * All matches for strings that contain the string represented by this node.
+         * @returns {AsyncGenerator<RoaringBitmap>}
+         */
+        async* substringMatches() {
+            /** @type {Promise<SearchTree>[]} */
+            let layer = [Promise.resolve(this.tree)];
+            while (layer.length) {
+                const current_layer = layer;
+                layer = [];
+                for await (const tree of current_layer) {
+                    yield tree.leaves_whole.union(tree.leaves_suffix);
+                }
+                /** @type {HashTable<[number, SearchTree][]>} */
+                const subnodes = new HashTable();
+                for await (const node of current_layer) {
+                    const branches = node.branches;
+                    const l = branches.subtrees.length;
+                    for (let i = 0; i < l; ++i) {
+                        const subtree = branches.subtrees[i];
+                        if (subtree) {
+                            layer.push(subtree);
+                        } else if (subtree === null) {
+                            const byte = branches.getKey(i);
+                            const newnode = branches.getNodeID(i);
+                            if (!newnode) {
+                                throw new Error(`malformed tree; no node for key ${byte}`);
+                            } else {
+                                let subnode_list = subnodes.get(newnode);
+                                if (!subnode_list) {
+                                    subnode_list = [[byte, node]];
+                                    subnodes.set(newnode, subnode_list);
+                                } else {
+                                    subnode_list.push([byte, node]);
+                                }
+                            }
+                        } else {
+                            throw new Error(`malformed tree; index ${i} does not exist`);
+                        }
+                    }
+                }
+                for (const [newnode, subnode_list] of subnodes.entries()) {
+                    const res = registry.searchTreeLoadByNodeID(newnode);
+                    for (const [byte, node] of subnode_list) {
+                        const branches = node.branches;
+                        const might_have_prefix_branches = node.might_have_prefix_branches;
+                        const i = branches.getIndex(byte);
+                        branches.subtrees[i] = res;
+                        const mhpI = might_have_prefix_branches.getIndex(byte);
+                        if (mhpI !== -1) {
+                            might_have_prefix_branches.subtrees[mhpI] = res;
+                        }
+                    }
+                    layer.push(res);
+                }
+            }
+        }
+
+        /**
+         * All matches for strings that start with the string represented by this node.
+         * @returns {AsyncGenerator<RoaringBitmap>}
+         */
+        async* prefixMatches() {
+            /** @type {{node: Promise<SearchTree>, len: number}[]} */
+            let layer = [{node: Promise.resolve(this.tree), len: 0}];
+            // https://en.wikipedia.org/wiki/Heap_(data_structure)#Implementation_using_arrays
+            /** @type {{bitmap: RoaringBitmap, length: number}[]} */
+            const backlog = [];
+            while (layer.length !== 0 || backlog.length !== 0) {
+                const current_layer = layer;
+                layer = [];
+                let minLength = null;
+                // push every entry in the current layer into the backlog,
+                // a min-heap of result entries
+                // we then yield the smallest ones (can't yield bigger ones
+                // if we want to do them in order)
+                for (const {node, len} of current_layer) {
+                    const tree = await node;
+                    const length = len + tree.data.length;
+                    if (minLength === null || length < minLength) {
+                        minLength = length;
+                    }
+                    let backlogSlot = backlog.length;
+                    backlog.push({bitmap: tree.leaves_whole, length});
+                    while (backlogSlot > 0 &&
+                        backlog[backlogSlot].length < backlog[(backlogSlot - 1) >> 1].length
+                    ) {
+                        const parentSlot = (backlogSlot - 1) >> 1;
+                        const parent = backlog[parentSlot];
+                        backlog[parentSlot] = backlog[backlogSlot];
+                        backlog[backlogSlot] = parent;
+                        backlogSlot = parentSlot;
+                    }
+                }
+                // yield nodes in length order, smallest one first
+                // we know that, whatever the smallest item is
+                // every child will be bigger than that
+                while (backlog.length !== 0) {
+                    const backlogEntry = backlog[0];
+                    if (minLength !== null && backlogEntry.length > minLength) {
+                        break;
+                    }
+                    if (!backlogEntry.bitmap.isEmpty()) {
+                        yield backlogEntry.bitmap;
+                    }
+                    backlog[0] = backlog[backlog.length - 1];
+                    backlog.length -= 1;
+                    let backlogSlot = 0;
+                    const backlogLength = backlog.length;
+                    while (backlogSlot < backlogLength) {
+                        const leftSlot = (backlogSlot << 1) + 1;
+                        const rightSlot = (backlogSlot << 1) + 2;
+                        let smallest = backlogSlot;
+                        if (leftSlot < backlogLength &&
+                            backlog[leftSlot].length < backlog[smallest].length
+                        ) {
+                            smallest = leftSlot;
+                        }
+                        if (rightSlot < backlogLength &&
+                            backlog[rightSlot].length < backlog[smallest].length
+                        ) {
+                            smallest = rightSlot;
+                        }
+                        if (smallest === backlogSlot) {
+                            break;
+                        } else {
+                            const tmp = backlog[backlogSlot];
+                            backlog[backlogSlot] = backlog[smallest];
+                            backlog[smallest] = tmp;
+                            backlogSlot = smallest;
+                        }
+                    }
+                }
+                // if we still have more subtrees to walk, then keep going
+                /** @type {HashTable<{byte: number, tree: SearchTree, len: number}[]>} */
+                const subnodes = new HashTable();
+                for await (const {node, len} of current_layer) {
+                    const tree = await node;
+                    const length = len + tree.data.length;
+                    const mhp_branches = tree.might_have_prefix_branches;
+                    const l = mhp_branches.subtrees.length;
+                    for (let i = 0; i < l; ++i) {
+                        const len = length + 1;
+                        const subtree = mhp_branches.subtrees[i];
+                        if (subtree) {
+                            layer.push({node: subtree, len});
+                        } else if (subtree === null) {
+                            const byte = mhp_branches.getKey(i);
+                            const newnode = mhp_branches.getNodeID(i);
+                            if (!newnode) {
+                                throw new Error(`malformed tree; no node for key ${byte}`);
+                            } else {
+                                let subnode_list = subnodes.get(newnode);
+                                if (!subnode_list) {
+                                    subnode_list = [{byte, tree, len}];
+                                    subnodes.set(newnode, subnode_list);
+                                } else {
+                                    subnode_list.push({byte, tree, len});
+                                }
+                            }
+                        } else {
+                            throw new Error(`malformed tree; index ${i} does not exist`);
+                        }
+                    }
+                }
+                for (const [newnode, subnode_list] of subnodes.entries()) {
+                    const res = registry.searchTreeLoadByNodeID(newnode);
+                    let len = Number.MAX_SAFE_INTEGER;
+                    for (const {byte, tree, len: subtreelen} of subnode_list) {
+                        if (subtreelen < len) {
+                            len = subtreelen;
+                        }
+                        const mhp_branches = tree.might_have_prefix_branches;
+                        const i = mhp_branches.getIndex(byte);
+                        mhp_branches.subtrees[i] = res;
+                        const branches = tree.branches;
+                        const bi = branches.getIndex(byte);
+                        branches.subtrees[bi] = res;
+                    }
+                    layer.push({node: res, len});
+                }
+            }
+        }
+
+        /**
+         * Returns all keys that are children of this node.
+         * @returns {Uint8Array}
+         */
+        keys() {
+            const data = this.tree.data;
+            if (this.offset === data.length) {
+                return this.tree.branches.getKeys();
+            } else {
+                return Uint8Array.of(data[this.offset]);
+            }
+        }
+
+        /**
+         * Returns all nodes that are direct children of this node.
+         * @returns {[number, Promise<Trie>][]}
+         */
+        children() {
+            const data = this.tree.data;
+            if (this.offset === data.length) {
+                /** @type {[number, Promise<Trie>][]} */
+                const nodes = [];
+                let i = 0;
+                for (const [k, v] of this.tree.branches.entries()) {
+                    /** @type {Promise<SearchTree>} */
+                    let node;
+                    if (v) {
+                        node = v;
+                    } else {
+                        const newnode = this.tree.branches.getNodeID(i);
+                        if (!newnode) {
+                            throw new Error(`malformed tree; no hash for key ${k}: ${newnode} \
+                                ${this.tree.branches.nodeids} ${this.tree.branches.getKeys()}`);
+                        }
+                        node = registry.searchTreeLoadByNodeID(newnode);
+                        this.tree.branches.subtrees[i] = node;
+                        const mhpI = this.tree.might_have_prefix_branches.getIndex(k);
+                        if (mhpI !== -1) {
+                            this.tree.might_have_prefix_branches.subtrees[mhpI] = node;
+                        }
+                    }
+                    nodes.push([k, node.then(node => node.trie())]);
+                    i += 1;
+                }
+                return nodes;
+            } else {
+                /** @type {number} */
+                const codePoint = data[this.offset];
+                const trie = new Trie(this.tree, this.offset + 1);
+                return [[codePoint, Promise.resolve(trie)]];
+            }
+        }
+
+        /**
+         * Returns all keys that are children of this node.
+         * @returns {Uint8Array}
+         */
+        keysExcludeSuffixOnly() {
+            const data = this.tree.data;
+            if (this.offset === data.length) {
+                return this.tree.might_have_prefix_branches.getKeys();
+            } else {
+                return Uint8Array.of(data[this.offset]);
+            }
+        }
+
+        /**
+         * Returns all nodes that are direct children of this node.
+         * @returns {[number, Promise<Trie>][]}
+         */
+        childrenExcludeSuffixOnly() {
+            const data = this.tree.data;
+            if (this.offset === data.length) {
+                /** @type {[number, Promise<Trie>][]} */
+                const nodes = [];
+                let i = 0;
+                for (const [k, v] of this.tree.might_have_prefix_branches.entries()) {
+                    /** @type {Promise<SearchTree>} */
+                    let node;
+                    if (v) {
+                        node = v;
+                    } else {
+                        const newnode = this.tree.might_have_prefix_branches.getNodeID(i);
+                        if (!newnode) {
+                            throw new Error(`malformed tree; no node for key ${k}`);
+                        }
+                        node = registry.searchTreeLoadByNodeID(newnode);
+                        this.tree.might_have_prefix_branches.subtrees[i] = node;
+                        this.tree.branches.subtrees[this.tree.branches.getIndex(k)] = node;
+                    }
+                    nodes.push([k, node.then(node => node.trie())]);
+                    i += 1;
+                }
+                return nodes;
+            } else {
+                /** @type {number} */
+                const codePoint = data[this.offset];
+                const trie = new Trie(this.tree, this.offset + 1);
+                return [[codePoint, Promise.resolve(trie)]];
+            }
+        }
+
+        /**
+         * Returns a single node that is a direct child of this node.
+         * @param {number} byte
+         * @returns {Promise<Trie>?}
+         */
+        child(byte) {
+            if (this.offset === this.tree.data.length) {
+                const i = this.tree.branches.getIndex(byte);
+                if (i !== -1) {
+                    let branch = this.tree.branches.subtrees[i];
+                    if (branch === null) {
+                        const newnode = this.tree.branches.getNodeID(i);
+                        if (!newnode) {
+                            throw new Error(`malformed tree; no node for key ${byte}`);
+                        }
+                        branch = registry.searchTreeLoadByNodeID(newnode);
+                        this.tree.branches.subtrees[i] = branch;
+                        const mhpI = this.tree.might_have_prefix_branches.getIndex(byte);
+                        if (mhpI !== -1) {
+                            this.tree.might_have_prefix_branches.subtrees[mhpI] = branch;
+                        }
+                    }
+                    return branch.then(branch => branch.trie());
+                }
+            } else if (this.tree.data[this.offset] === byte) {
+                return Promise.resolve(new Trie(this.tree, this.offset + 1));
+            }
+            return null;
+        }
+    }
+
+    class DataColumn {
+        /**
+         * Construct the wrapper object for a data column.
+         * @param {number[]} counts
+         * @param {Uint8Array} hashes
+         * @param {RoaringBitmap} emptyset
+         * @param {string} name
+         */
+        constructor(counts, hashes, emptyset, name) {
+            this.hashes = hashes;
+            this.emptyset = emptyset;
+            this.name = name;
+            /** @type {{"hash": Uint8Array, "data": Promise<Uint8Array[]>?, "end": number}[]} */
+            this.buckets = [];
+            this.bucket_keys = [];
+            const l = counts.length;
+            let k = 0;
+            let totalLength = 0;
+            for (let i = 0; i < l; ++i) {
+                const count = counts[i];
+                totalLength += count;
+                const start = k;
+                for (let j = 0; j < count; ++j) {
+                    if (emptyset.contains(k)) {
+                        j -= 1;
+                    }
+                    k += 1;
+                }
+                const end = k;
+                const bucket = {hash: hashes.subarray(i * 6, (i + 1) * 6), data: null, end, count};
+                this.buckets.push(bucket);
+                this.bucket_keys.push(start);
+            }
+            this.length = totalLength;
+        }
+        /**
+         * Check if a cell contains the empty string.
+         * @param {number} id
+         * @returns {boolean}
+         */
+        isEmpty(id) {
+            return this.emptyset.contains(id);
+        }
+        /**
+         * Look up a cell by row ID.
+         * @param {number} id
+         * @returns {Promise<Uint8Array|undefined>}
+         */
+        async at(id) {
+            if (this.emptyset.contains(id)) {
+                return Promise.resolve(EMPTY_UINT8);
+            } else {
+                let idx = -1;
+                while (this.bucket_keys[idx + 1] <= id) {
+                    idx += 1;
+                }
+                if (idx === -1 || idx >= this.bucket_keys.length) {
+                    return Promise.resolve(undefined);
+                } else {
+                    const start = this.bucket_keys[idx];
+                    const {hash, end} = this.buckets[idx];
+                    let data = this.buckets[idx].data;
+                    if (data === null) {
+                        const dataSansEmptyset = await registry.dataLoadByNameAndHash(
+                            this.name,
+                            hash,
+                        );
+                        // After the `await` resolves, another task might fill
+                        // in the data. If so, we should use that.
+                        data = this.buckets[idx].data;
+                        if (data !== null) {
+                            return (await data)[id - start];
+                        }
+                        /** @type {(Uint8Array[])|null} */
+                        let dataWithEmptyset = null;
+                        let pos = start;
+                        let insertCount = 0;
+                        while (pos < end) {
+                            if (this.emptyset.contains(pos)) {
+                                if (dataWithEmptyset === null) {
+                                    dataWithEmptyset = dataSansEmptyset.splice(0, insertCount);
+                                } else if (insertCount !== 0) {
+                                    dataWithEmptyset.push(
+                                        ...dataSansEmptyset.splice(0, insertCount),
+                                    );
+                                }
+                                insertCount = 0;
+                                dataWithEmptyset.push(EMPTY_UINT8);
+                            } else {
+                                insertCount += 1;
+                            }
+                            pos += 1;
+                        }
+                        data = Promise.resolve(
+                            dataWithEmptyset === null ?
+                                dataSansEmptyset :
+                                dataWithEmptyset.concat(dataSansEmptyset),
+                        );
+                        this.buckets[idx].data = data;
+                    }
+                    return (await data)[id - start];
+                }
+            }
+        }
+    }
+
+    class Database {
+        /**
+         * The primary frontend for accessing data in this index.
+         *
+         * @param {Map<string, SearchTree>} searchTreeRoots
+         * @param {Map<string, DataColumn>} dataColumns
+         */
+        constructor(searchTreeRoots, dataColumns) {
+            this.searchTreeRoots = searchTreeRoots;
+            this.dataColumns = dataColumns;
+        }
+        /**
+         * Search a column by name, returning verbatim matched IDs.
+         * @param {string} colname
+         * @returns {SearchTree|undefined}
+         */
+        getIndex(colname) {
+            return this.searchTreeRoots.get(colname);
+        }
+        /**
+         * Look up a cell by column ID and row ID.
+         * @param {string} colname
+         * @returns {DataColumn|undefined}
+         */
+        getData(colname) {
+            return this.dataColumns.get(colname);
+        }
+    }
+
+    /**
+     * Load a data column.
+     * @param {Uint8Array} data
+     */
+    function loadColumnFromBytes(data) {
+        const hashBuf = Uint8Array.of(0, 0, 0, 0, 0, 0, 0, 0);
+        const truncatedHash = hashBuf.subarray(2, 8);
+        siphashOfBytes(data, 0, 0, 0, 0, hashBuf);
+        const cb = registry.dataColumnLoadPromiseCallbacks.get(truncatedHash);
+        if (cb) {
+            const backrefs = [];
+            const dataSansEmptyset = [];
+            let i = 0;
+            const l = data.length;
+            while (i < l) {
+                let c = data[i];
+                if (c >= 48 && c <= 63) { // 48 = "0", 63 = "?"
+                    dataSansEmptyset.push(backrefs[c - 48]);
+                    i += 1;
+                } else {
+                    let n = 0;
+                    while (c < 96) { // 96 = "`"
+                        n = (n << 4) | (c & 0xF);
+                        i += 1;
+                        c = data[i];
+                    }
+                    n = (n << 4) | (c & 0xF);
+                    i += 1;
+                    const item = data.subarray(i, i + n);
+                    dataSansEmptyset.push(item);
+                    i += n;
+                    backrefs.unshift(item);
+                    if (backrefs.length > 16) {
+                        backrefs.pop();
+                    }
+                }
+            }
+            cb(null, dataSansEmptyset);
+        }
+    }
+
+    /**
+     * @param {string} inputBase64
+     * @returns {[Uint8Array, SearchTree]}
+     */
+    function makeSearchTreeFromBase64(inputBase64) {
+        const input = makeUint8ArrayFromBase64(inputBase64);
+        let i = 0;
+        const l = input.length;
+        /** @type {HashTable<SearchTree>} */
+        const stash = new HashTable();
+        const hash = Uint8Array.of(0, 0, 0, 0, 0, 0, 0, 0);
+        const truncatedHash = new Uint8Array(hash.buffer, 2, 6);
+        // used for handling compressed (that is, relative-offset) nodes
+        /** @type {{hash: Uint8Array, used: boolean}[]} */
+        const hash_history = [];
+        /** @type {Uint8Array[]} */
+        const data_history = [];
+        let canonical = EMPTY_UINT8;
+        /** @type {SearchTree} */
+        let tree = new SearchTree(
+            EMPTY_SEARCH_TREE_BRANCHES,
+            EMPTY_SEARCH_TREE_BRANCHES,
+            EMPTY_UINT8,
+            EMPTY_BITMAP,
+            EMPTY_BITMAP,
+        );
+        /**
+         * @param {Uint8Array} input
+         * @param {number} i
+         * @param {number} compression_tag
+         * @returns {{
+         *     "cpbranches": Uint8Array,
+         *     "csbranches": Uint8Array,
+         *     "might_have_prefix_branches": SearchTreeBranches,
+         *     "branches": SearchTreeBranches,
+         *     "cpnodes": Uint8Array,
+         *     "csnodes": Uint8Array,
+         *     "consumed_len_bytes": number,
+         * }}
+         */
+        function makeBranchesFromBinaryData(
+            input,
+            i,
+            compression_tag,
+        ) {
+            const is_pure_suffixes_only_node = (compression_tag & 0x01) !== 0x00;
+            const is_stack_compressed = (compression_tag & 0x02) !== 0;
+            const is_long_compressed = (compression_tag & 0x04) !== 0;
+            const all_children_are_compressed =
+                (compression_tag & 0xF0) === 0xF0 && !is_long_compressed;
+            const any_children_are_compressed =
+                (compression_tag & 0xF0) !== 0x00 || is_long_compressed;
+            const start_point = i;
+            let cplen;
+            let cslen;
+            let alphabitmap = null;
+            if (is_pure_suffixes_only_node) {
+                cplen = 0;
+                cslen = input[i];
+                i += 1;
+                if (cslen >= 0xc0) {
+                    alphabitmap = SearchTreeBranchesLongAlphaBitmap;
+                    cslen = cslen & 0x3F;
+                } else if (cslen >= 0x80) {
+                    alphabitmap = SearchTreeBranchesShortAlphaBitmap;
+                    cslen = cslen & 0x7F;
+                }
+            } else {
+                cplen = input[i];
+                i += 1;
+                cslen = input[i];
+                i += 1;
+                if (cplen === 0xff && cslen === 0xff) {
+                    cplen = 0x100;
+                    cslen = 0;
+                } else if (cplen >= 0xc0 && cslen >= 0xc0) {
+                    alphabitmap = SearchTreeBranchesLongAlphaBitmap;
+                    cplen = cplen & 0x3F;
+                    cslen = cslen & 0x3F;
+                } else if (cplen >= 0x80 && cslen >= 0x80) {
+                    alphabitmap = SearchTreeBranchesShortAlphaBitmap;
+                    cplen = cplen & 0x7F;
+                    cslen = cslen & 0x7F;
+                }
+            }
+            let j = 0;
+            /** @type {Uint8Array} */
+            let cpnodes;
+            if (any_children_are_compressed) {
+                cpnodes = cplen === 0 ? EMPTY_UINT8 : new Uint8Array(cplen * 6);
+                while (j < cplen) {
+                    const is_compressed = all_children_are_compressed ||
+                        ((0x10 << j) & compression_tag) !== 0;
+                    if (is_compressed) {
+                        let slot = hash_history.length - 1;
+                        if (is_stack_compressed) {
+                            while (hash_history[slot].used) {
+                                slot -= 1;
+                            }
+                        } else {
+                            slot -= input[i];
+                            i += 1;
+                        }
+                        hash_history[slot].used = true;
+                        cpnodes.set(
+                            hash_history[slot].hash,
+                            j * 6,
+                        );
+                    } else {
+                        const joff = j * 6;
+                        cpnodes[joff + 0] = input[i + 0];
+                        cpnodes[joff + 1] = input[i + 1];
+                        cpnodes[joff + 2] = input[i + 2];
+                        cpnodes[joff + 3] = input[i + 3];
+                        cpnodes[joff + 4] = input[i + 4];
+                        cpnodes[joff + 5] = input[i + 5];
+                        i += 6;
+                    }
+                    j += 1;
+                }
+            } else {
+                cpnodes = cplen === 0 ? EMPTY_UINT8 : input.subarray(i, i + (cplen * 6));
+                i += cplen * 6;
+            }
+            j = 0;
+            /** @type {Uint8Array} */
+            let csnodes;
+            if (any_children_are_compressed) {
+                csnodes = cslen === 0 ? EMPTY_UINT8 : new Uint8Array(cslen * 6);
+                while (j < cslen) {
+                    const is_compressed = all_children_are_compressed ||
+                        ((0x10 << (cplen + j)) & compression_tag) !== 0;
+                    if (is_compressed) {
+                        let slot = hash_history.length - 1;
+                        if (is_stack_compressed) {
+                            while (hash_history[slot].used) {
+                                slot -= 1;
+                            }
+                        } else {
+                            slot -= input[i];
+                            i += 1;
+                        }
+                        hash_history[slot].used = true;
+                        csnodes.set(
+                            hash_history[slot].hash,
+                            j * 6,
+                        );
+                    } else {
+                        const joff = j * 6;
+                        csnodes[joff + 0] = input[i + 0];
+                        csnodes[joff + 1] = input[i + 1];
+                        csnodes[joff + 2] = input[i + 2];
+                        csnodes[joff + 3] = input[i + 3];
+                        csnodes[joff + 4] = input[i + 4];
+                        csnodes[joff + 5] = input[i + 5];
+                        i += 6;
+                    }
+                    j += 1;
+                }
+            } else {
+                csnodes = cslen === 0 ? EMPTY_UINT8 : input.subarray(i, i + (cslen * 6));
+                i += cslen * 6;
+            }
+            let cpbranches;
+            let might_have_prefix_branches;
+            if (cplen === 0) {
+                cpbranches = EMPTY_UINT8;
+                might_have_prefix_branches = EMPTY_SEARCH_TREE_BRANCHES;
+            } else if (alphabitmap) {
+                cpbranches = new Uint8Array(input.buffer, i + input.byteOffset, alphabitmap.width);
+                const branchset = (alphabitmap.width === 4 ? (input[i + 3] << 24) : 0) |
+                    (input[i + 2] << 16) |
+                    (input[i + 1] << 8) |
+                    input[i];
+                might_have_prefix_branches = new alphabitmap(branchset, cpnodes);
+                i += alphabitmap.width;
+            } else {
+                cpbranches = new Uint8Array(input.buffer, i + input.byteOffset, cplen);
+                might_have_prefix_branches = new SearchTreeBranchesArray(cpbranches, cpnodes);
+                i += cplen;
+            }
+            let csbranches;
+            let branches;
+            if (cslen === 0) {
+                csbranches = EMPTY_UINT8;
+                branches = might_have_prefix_branches;
+            } else if (alphabitmap) {
+                csbranches = new Uint8Array(input.buffer, i + input.byteOffset, alphabitmap.width);
+                const branchset = (alphabitmap.width === 4 ? (input[i + 3] << 24) : 0) |
+                    (input[i + 2] << 16) |
+                    (input[i + 1] << 8) |
+                    input[i];
+                if (cplen === 0) {
+                    branches = new alphabitmap(branchset, csnodes);
+                } else {
+                    const cpoffset = i - alphabitmap.width;
+                    const cpbranchset =
+                        (alphabitmap.width === 4 ? (input[cpoffset + 3] << 24) : 0) |
+                        (input[cpoffset + 2] << 16) |
+                        (input[cpoffset + 1] << 8) |
+                        input[cpoffset];
+                    const hashes = new Uint8Array((cplen + cslen) * 6);
+                    let cpi = 0;
+                    let csi = 0;
+                    let j = 0;
+                    for (let k = 0; k < alphabitmap.ALPHABITMAP_CHARS.length; k += 1) {
+                        if (branchset & (1 << k)) {
+                            hashes[j + 0] = csnodes[csi + 0];
+                            hashes[j + 1] = csnodes[csi + 1];
+                            hashes[j + 2] = csnodes[csi + 2];
+                            hashes[j + 3] = csnodes[csi + 3];
+                            hashes[j + 4] = csnodes[csi + 4];
+                            hashes[j + 5] = csnodes[csi + 5];
+                            j += 6;
+                            csi += 6;
+                        } else if (cpbranchset & (1 << k)) {
+                            hashes[j + 0] = cpnodes[cpi + 0];
+                            hashes[j + 1] = cpnodes[cpi + 1];
+                            hashes[j + 2] = cpnodes[cpi + 2];
+                            hashes[j + 3] = cpnodes[cpi + 3];
+                            hashes[j + 4] = cpnodes[cpi + 4];
+                            hashes[j + 5] = cpnodes[cpi + 5];
+                            j += 6;
+                            cpi += 6;
+                        }
+                    }
+                    branches = new alphabitmap(branchset | cpbranchset, hashes);
+                }
+                i += alphabitmap.width;
+            } else {
+                csbranches = new Uint8Array(input.buffer, i + input.byteOffset, cslen);
+                if (cplen === 0) {
+                    branches = new SearchTreeBranchesArray(csbranches, csnodes);
+                } else {
+                    const branchset = new Uint8Array(cplen + cslen);
+                    const hashes = new Uint8Array((cplen + cslen) * 6);
+                    let cpi = 0;
+                    let csi = 0;
+                    let j = 0;
+                    while (cpi < cplen || csi < cslen) {
+                        if (cpi >= cplen || (csi < cslen && cpbranches[cpi] > csbranches[csi])) {
+                            branchset[j] = csbranches[csi];
+                            const joff = j * 6;
+                            const csioff = csi * 6;
+                            hashes[joff + 0] = csnodes[csioff + 0];
+                            hashes[joff + 1] = csnodes[csioff + 1];
+                            hashes[joff + 2] = csnodes[csioff + 2];
+                            hashes[joff + 3] = csnodes[csioff + 3];
+                            hashes[joff + 4] = csnodes[csioff + 4];
+                            hashes[joff + 5] = csnodes[csioff + 5];
+                            csi += 1;
+                        } else {
+                            branchset[j] = cpbranches[cpi];
+                            const joff = j * 6;
+                            const cpioff = cpi * 6;
+                            hashes[joff + 0] = cpnodes[cpioff + 0];
+                            hashes[joff + 1] = cpnodes[cpioff + 1];
+                            hashes[joff + 2] = cpnodes[cpioff + 2];
+                            hashes[joff + 3] = cpnodes[cpioff + 3];
+                            hashes[joff + 4] = cpnodes[cpioff + 4];
+                            hashes[joff + 5] = cpnodes[cpioff + 5];
+                            cpi += 1;
+                        }
+                        j += 1;
+                    }
+                    branches = new SearchTreeBranchesArray(branchset, hashes);
+                }
+                i += cslen;
+            }
+            return {
+                consumed_len_bytes: i - start_point,
+                cpbranches,
+                csbranches,
+                cpnodes,
+                csnodes,
+                branches,
+                might_have_prefix_branches,
+            };
+        }
+        while (i < l) {
+            const start = i;
+            let data;
+            // compression_tag = 1 means pure-suffixes-only,
+            // which is not considered "compressed" for the purposes of this loop
+            // because that's the canonical, hashed version of the data
+            let compression_tag = input[i];
+            const is_pure_suffixes_only_node = (compression_tag & 0x01) !== 0;
+            if (compression_tag > 1) {
+                // compressed node
+                const is_long_compressed = (compression_tag & 0x04) !== 0;
+                const is_data_compressed = (compression_tag & 0x08) !== 0;
+                i += 1;
+                if (is_long_compressed) {
+                    compression_tag |= input[i] << 8;
+                    i += 1;
+                    compression_tag |= input[i] << 16;
+                    i += 1;
+                }
+                let dlen = input[i];
+                i += 1;
+                if (is_data_compressed) {
+                    data = data_history[data_history.length - dlen - 1];
+                    dlen = data.length;
+                } else {
+                    data = dlen === 0 ?
+                        EMPTY_UINT8 :
+                        new Uint8Array(input.buffer, i + input.byteOffset, dlen);
+                    i += dlen;
+                }
+                const coffset = i;
+                const {
+                    cpbranches,
+                    csbranches,
+                    cpnodes,
+                    csnodes,
+                    consumed_len_bytes: branches_consumed_len_bytes,
+                    branches,
+                    might_have_prefix_branches,
+                } = makeBranchesFromBinaryData(input, i, compression_tag);
+                i += branches_consumed_len_bytes;
+                let whole;
+                let suffix;
+                if (is_pure_suffixes_only_node) {
+                    whole = EMPTY_BITMAP;
+                    suffix = input[i] === 0 ?
+                        EMPTY_BITMAP1 :
+                        new RoaringBitmap(input, i);
+                    i += suffix.consumed_len_bytes;
+                } else if (input[i] === 0xff) {
+                    whole = EMPTY_BITMAP;
+                    suffix = EMPTY_BITMAP1;
+                    i += 1;
+                } else {
+                    whole = input[i] === 0 ?
+                        EMPTY_BITMAP1 :
+                        new RoaringBitmap(input, i);
+                    i += whole.consumed_len_bytes;
+                    suffix = input[i] === 0 ?
+                        EMPTY_BITMAP1 :
+                        new RoaringBitmap(input, i);
+                    i += suffix.consumed_len_bytes;
+                }
+                tree = new SearchTree(
+                    branches,
+                    might_have_prefix_branches,
+                    data,
+                    whole,
+                    suffix,
+                );
+                const clen = (
+                    (is_pure_suffixes_only_node ? 3 : 4) + // lengths of children and data
+                    dlen +
+                    cpnodes.length + csnodes.length +
+                    cpbranches.length + csbranches.length +
+                    whole.consumed_len_bytes +
+                    suffix.consumed_len_bytes
+                );
+                if (canonical.length < clen) {
+                    canonical = new Uint8Array(clen);
+                }
+                let ci = 0;
+                canonical[ci] = is_pure_suffixes_only_node ? 1 : 0;
+                ci += 1;
+                canonical[ci] = dlen;
+                ci += 1;
+                canonical.set(data, ci);
+                ci += dlen;
+                canonical[ci] = input[coffset];
+                ci += 1;
+                if (!is_pure_suffixes_only_node) {
+                    canonical[ci] = input[coffset + 1];
+                    ci += 1;
+                }
+                canonical.set(cpnodes, ci);
+                ci += cpnodes.length;
+                canonical.set(csnodes, ci);
+                ci += csnodes.length;
+                canonical.set(cpbranches, ci);
+                ci += cpbranches.length;
+                canonical.set(csbranches, ci);
+                ci += csbranches.length;
+                const leavesOffset = i - whole.consumed_len_bytes - suffix.consumed_len_bytes;
+                for (let j = leavesOffset; j < i; j += 1) {
+                    canonical[ci + j - leavesOffset] = input[j];
+                }
+                siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash);
+                hash[2] &= 0x7f;
+            } else {
+                // uncompressed node
+                const dlen = input [i + 1];
+                i += 2;
+                if (dlen === 0) {
+                    data = EMPTY_UINT8;
+                } else {
+                    data = new Uint8Array(input.buffer, i + input.byteOffset, dlen);
+                }
+                i += dlen;
+                const {
+                    consumed_len_bytes: branches_consumed_len_bytes,
+                    branches,
+                    might_have_prefix_branches,
+                } = makeBranchesFromBinaryData(input, i, compression_tag);
+                i += branches_consumed_len_bytes;
+                let whole;
+                let suffix;
+                if (is_pure_suffixes_only_node) {
+                    whole = EMPTY_BITMAP;
+                    suffix = input[i] === 0 ?
+                        EMPTY_BITMAP1 :
+                        new RoaringBitmap(input, i);
+                    i += suffix.consumed_len_bytes;
+                } else if (input[i] === 0xff) {
+                    whole = EMPTY_BITMAP;
+                    suffix = EMPTY_BITMAP;
+                    i += 1;
+                } else {
+                    whole = input[i] === 0 ?
+                        EMPTY_BITMAP1 :
+                        new RoaringBitmap(input, i);
+                    i += whole.consumed_len_bytes;
+                    suffix = input[i] === 0 ?
+                        EMPTY_BITMAP1 :
+                        new RoaringBitmap(input, i);
+                    i += suffix.consumed_len_bytes;
+                }
+                siphashOfBytes(new Uint8Array(
+                    input.buffer,
+                    start + input.byteOffset,
+                    i - start,
+                ), 0, 0, 0, 0, hash);
+                hash[2] &= 0x7f;
+                tree = new SearchTree(
+                    branches,
+                    might_have_prefix_branches,
+                    data,
+                    whole,
+                    suffix,
+                );
+            }
+            hash_history.push({hash: truncatedHash.slice(), used: false});
+            if (data.length !== 0) {
+                data_history.push(data);
+            }
+            const tree_branch_nodeids = tree.branches.nodeids;
+            const tree_branch_subtrees = tree.branches.subtrees;
+            let j = 0;
+            let lb = tree.branches.subtrees.length;
+            while (j < lb) {
+                // node id with a 1 in its most significant bit is inlined, and, so
+                // it won't be in the stash
+                if ((tree_branch_nodeids[j * 6] & 0x80) === 0) {
+                    const subtree = stash.getWithOffsetKey(tree_branch_nodeids, j * 6);
+                    if (subtree !== undefined) {
+                        tree_branch_subtrees[j] = Promise.resolve(subtree);
+                    }
+                }
+                j += 1;
+            }
+            const tree_mhp_branch_nodeids = tree.might_have_prefix_branches.nodeids;
+            const tree_mhp_branch_subtrees = tree.might_have_prefix_branches.subtrees;
+            j = 0;
+            lb = tree.might_have_prefix_branches.subtrees.length;
+            while (j < lb) {
+                // node id with a 1 in its most significant bit is inlined, and, so
+                // it won't be in the stash
+                if ((tree_mhp_branch_nodeids[j * 6] & 0x80) === 0) {
+                    const subtree = stash.getWithOffsetKey(tree_mhp_branch_nodeids, j * 6);
+                    if (subtree !== undefined) {
+                        tree_mhp_branch_subtrees[j] = Promise.resolve(subtree);
+                    }
+                }
+                j += 1;
+            }
+            if (i !== l) {
+                stash.set(truncatedHash, tree);
+            }
+        }
+        return [truncatedHash, tree];
+    }
+
+    return new Promise((resolve, reject) => {
+        registry.searchTreeRootCallback = (error, data) => {
+            if (data) {
+                resolve(data);
+            } else {
+                reject(error);
+            }
+        };
+        hooks.loadRoot(callbacks);
+    });
+}
+
+if (typeof window !== "undefined") {
+    window.Stringdex = {
+        loadDatabase,
+    };
+    window.RoaringBitmap = RoaringBitmap;
+    if (window.StringdexOnload) {
+        window.StringdexOnload.forEach(cb => cb(window.Stringdex));
+    }
+} else {
+    /** @type {stringdex.Stringdex} */
+    // eslint-disable-next-line no-undef
+    module.exports.Stringdex = {
+        loadDatabase,
+    };
+    /** @type {stringdex.RoaringBitmap} */
+    // eslint-disable-next-line no-undef
+    module.exports.RoaringBitmap = RoaringBitmap;
+}
+
+// eslint-disable-next-line max-len
+// polyfill https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64
+/**
+ * @type {function(string): Uint8Array} base64
+ */
+//@ts-expect-error
+const makeUint8ArrayFromBase64 = Uint8Array.fromBase64 ? Uint8Array.fromBase64 : (string => {
+    const bytes_as_string = atob(string);
+    const l = bytes_as_string.length;
+    const bytes = new Uint8Array(l);
+    for (let i = 0; i < l; ++i) {
+        bytes[i] = bytes_as_string.charCodeAt(i);
+    }
+    return bytes;
+});
+/**
+ * @type {function(string): Uint8Array} base64
+ */
+//@ts-expect-error
+const makeUint8ArrayFromHex = Uint8Array.fromHex ? Uint8Array.fromHex : (string => {
+    /** @type {Object<string, number>} */
+    const alpha = {
+        "0": 0, "1": 1,
+        "2": 2, "3": 3,
+        "4": 4, "5": 5,
+        "6": 6, "7": 7,
+        "8": 8, "9": 9,
+        "a": 10, "b": 11,
+        "A": 10, "B": 11,
+        "c": 12, "d": 13,
+        "C": 12, "D": 13,
+        "e": 14, "f": 15,
+        "E": 14, "F": 15,
+    };
+    const l = string.length >> 1;
+    const bytes = new Uint8Array(l);
+    for (let i = 0; i < l; i += 1) {
+        const top = string[i << 1];
+        const bottom = string[(i << 1) + 1];
+        bytes[i] = (alpha[top] << 4) | alpha[bottom];
+    }
+    return bytes;
+});
+
+/**
+ * @type {function(Uint8Array): string} base64
+ */
+//@ts-expect-error
+const makeHexFromUint8Array = Uint8Array.prototype.toHex ? (array => array.toHex()) : (array => {
+    /** @type {string[]} */
+    const alpha = [
+        "0", "1",
+        "2", "3",
+        "4", "5",
+        "6", "7",
+        "8", "9",
+        "a", "b",
+        "c", "d",
+        "e", "f",
+    ];
+    const l = array.length;
+    const v = [];
+    for (let i = 0; i < l; ++i) {
+        v.push(alpha[array[i] >> 4]);
+        v.push(alpha[array[i] & 0xf]);
+    }
+    return v.join("");
+});
+
+//////////////
+
+/**
+ * SipHash 1-3
+ * @param {Uint8Array} input data to be hashed; all codepoints in string should be less than 256
+ * @param {number} k0lo first word of key
+ * @param {number} k0hi second word of key
+ * @param {number} k1lo third word of key
+ * @param {number} k1hi fourth word of key
+ * @param {Uint8Array} output the data to write (clobber the first eight bytes)
+ */
+function siphashOfBytes(input, k0lo, k0hi, k1lo, k1hi, output) {
+    // hash state
+    // While siphash uses 64 bit state, js only has native support
+    // for 32 bit numbers. BigInt, unfortunately, doesn't count.
+    // It's too slow.
+    let v0lo = k0lo ^ 0x70736575;
+    let v0hi = k0hi ^ 0x736f6d65;
+    let v1lo = k1lo ^ 0x6e646f6d;
+    let v1hi = k1hi ^ 0x646f7261;
+    let v2lo = k0lo ^ 0x6e657261;
+    let v2hi = k0hi ^ 0x6c796765;
+    let v3lo = k1lo ^ 0x79746573;
+    let v3hi = k1hi ^ 0x74656462;
+    const inputLength = input.length;
+    let inputI = 0;
+    // main hash loop
+    const left = inputLength & 0x7;
+    let milo = 0;
+    let mihi = 0;
+    while (inputI < inputLength - left) {
+        u8ToU64le(inputI, inputI + 8);
+        v3lo ^= milo;
+        v3hi ^= mihi;
+        siphashCompress();
+        v0lo ^= milo;
+        v0hi ^= mihi;
+        inputI += 8;
+    }
+    u8ToU64le(inputI, inputI + left);
+    // finish
+    const blo = milo;
+    const bhi = ((inputLength & 0xff) << 24) | mihi;
+    v3lo ^= blo;
+    v3hi ^= bhi;
+    siphashCompress();
+    v0lo ^= blo;
+    v0hi ^= bhi;
+    v2lo ^= 0xff;
+    siphashCompress();
+    siphashCompress();
+    siphashCompress();
+    output[7] = (v0lo ^ v1lo ^ v2lo ^ v3lo) & 0xff;
+    output[6] = (v0lo ^ v1lo ^ v2lo ^ v3lo) >>> 8;
+    output[5] = (v0lo ^ v1lo ^ v2lo ^ v3lo) >>> 16;
+    output[4] = (v0lo ^ v1lo ^ v2lo ^ v3lo) >>> 24;
+    output[3] = (v0hi ^ v1hi ^ v2hi ^ v3hi) & 0xff;
+    output[2] = (v0hi ^ v1hi ^ v2hi ^ v3hi) >>> 8;
+    output[1] = (v0hi ^ v1hi ^ v2hi ^ v3hi) >>> 16;
+    output[0] = (v0hi ^ v1hi ^ v2hi ^ v3hi) >>> 24;
+    /**
+     * Convert eight bytes to a single 64-bit number
+     * @param {number} offset
+     * @param {number} length
+     */
+    function u8ToU64le(offset, length) {
+        const n0 = offset < length ? input[offset] & 0xff : 0;
+        const n1 = offset + 1 < length ? input[offset + 1] & 0xff : 0;
+        const n2 = offset + 2 < length ? input[offset + 2] & 0xff : 0;
+        const n3 = offset + 3 < length ? input[offset + 3] & 0xff : 0;
+        const n4 = offset + 4 < length ? input[offset + 4] & 0xff : 0;
+        const n5 = offset + 5 < length ? input[offset + 5] & 0xff : 0;
+        const n6 = offset + 6 < length ? input[offset + 6] & 0xff : 0;
+        const n7 = offset + 7 < length ? input[offset + 7] & 0xff : 0;
+        milo = n0 | (n1 << 8) | (n2 << 16) | (n3 << 24);
+        mihi = n4 | (n5 << 8) | (n6 << 16) | (n7 << 24);
+    }
+    function siphashCompress() {
+        // v0 += v1;
+        v0hi = (v0hi + v1hi + (((v0lo >>> 0) + (v1lo >>> 0) > 0xffffffff) ? 1 : 0)) | 0;
+        v0lo = (v0lo + v1lo) | 0;
+        // rotl(v1, 13)
+        let v1lo_ = v1lo;
+        let v1hi_ = v1hi;
+        v1lo = (v1lo_ << 13) | (v1hi_ >>> 19);
+        v1hi = (v1hi_ << 13) | (v1lo_ >>> 19);
+        // v1 ^= v0
+        v1lo ^= v0lo;
+        v1hi ^= v0hi;
+        // rotl(v0, 32)
+        const v0lo_ = v0lo;
+        const v0hi_ = v0hi;
+        v0lo = v0hi_;
+        v0hi = v0lo_;
+        // v2 += v3
+        v2hi = (v2hi + v3hi + (((v2lo >>> 0) + (v3lo >>> 0) > 0xffffffff) ? 1 : 0)) | 0;
+        v2lo = (v2lo + v3lo) | 0;
+        // rotl(v3, 16)
+        let v3lo_ = v3lo;
+        let v3hi_ = v3hi;
+        v3lo = (v3lo_ << 16) | (v3hi_ >>> 16);
+        v3hi = (v3hi_ << 16) | (v3lo_ >>> 16);
+        // v3 ^= v2
+        v3lo ^= v2lo;
+        v3hi ^= v2hi;
+        // v0 += v3
+        v0hi = (v0hi + v3hi + (((v0lo >>> 0) + (v3lo >>> 0) > 0xffffffff) ? 1 : 0)) | 0;
+        v0lo = (v0lo + v3lo) | 0;
+        // rotl(v3, 21)
+        v3lo_ = v3lo;
+        v3hi_ = v3hi;
+        v3lo = (v3lo_ << 21) | (v3hi_ >>> 11);
+        v3hi = (v3hi_ << 21) | (v3lo_ >>> 11);
+        // v3 ^= v0
+        v3lo ^= v0lo;
+        v3hi ^= v0hi;
+        // v2 += v1
+        v2hi = (v2hi + v1hi + (((v2lo >>> 0) + (v1lo >>> 0) > 0xffffffff) ? 1 : 0)) | 0;
+        v2lo = (v2lo + v1lo) | 0;
+        // rotl(v1, 17)
+        v1lo_ = v1lo;
+        v1hi_ = v1hi;
+        v1lo = (v1lo_ << 17) | (v1hi_ >>> 15);
+        v1hi = (v1hi_ << 17) | (v1lo_ >>> 15);
+        // v1 ^= v2
+        v1lo ^= v2lo;
+        v1hi ^= v2hi;
+        // rotl(v2, 32)
+        const v2lo_ = v2lo;
+        const v2hi_ = v2hi;
+        v2lo = v2hi_;
+        v2hi = v2lo_;
+    }
+}
+
+//////////////
+
+
+// Parts of this code are based on Lucene, which is licensed under the
+// Apache/2.0 license.
+// More information found here:
+// https://fossies.org/linux/lucene/lucene/core/src/java/org/apache/lucene/util/automaton/
+//   LevenshteinAutomata.java
+class ParametricDescription {
+    /**
+     * @param {number} w
+     * @param {number} n
+     * @param {Int32Array} minErrors
+     */
+    constructor(w, n, minErrors) {
+        this.w = w;
+        this.n = n;
+        this.minErrors = minErrors;
+    }
+    /**
+     * @param {number} absState
+     * @returns {boolean}
+     */
+    isAccept(absState) {
+        const state = Math.floor(absState / (this.w + 1));
+        const offset = absState % (this.w + 1);
+        return this.w - offset + this.minErrors[state] <= this.n;
+    }
+    /**
+     * @param {number} absState
+     * @returns {number}
+     */
+    getPosition(absState) {
+        return absState % (this.w + 1);
+    }
+    /**
+     * @param {Uint8Array} name
+     * @param {number} charCode
+     * @param {number} pos
+     * @param {number} end
+     * @returns {number}
+     */
+    getVector(name, charCode, pos, end) {
+        let vector = 0;
+        for (let i = pos; i < end; i += 1) {
+            vector = vector << 1;
+            if (name[i] === charCode) {
+                vector |= 1;
+            }
+        }
+        return vector;
+    }
+    /**
+     * @param {Int32Array} data
+     * @param {number} index
+     * @param {number} bitsPerValue
+     * @returns {number}
+     */
+    unpack(data, index, bitsPerValue) {
+        const bitLoc = (bitsPerValue * index);
+        const dataLoc = bitLoc >> 5;
+        const bitStart = bitLoc & 31;
+        if (bitStart + bitsPerValue <= 32) {
+            // not split
+            return ((data[dataLoc] >> bitStart) & this.MASKS[bitsPerValue - 1]);
+        } else {
+            // split
+            const part = 32 - bitStart;
+            return ~~(((data[dataLoc] >> bitStart) & this.MASKS[part - 1]) +
+                ((data[1 + dataLoc] & this.MASKS[bitsPerValue - part - 1]) << part));
+        }
+    }
+}
+ParametricDescription.prototype.MASKS = new Int32Array([
+    0x1, 0x3, 0x7, 0xF,
+    0x1F, 0x3F, 0x7F, 0xFF,
+    0x1FF, 0x3F, 0x7FF, 0xFFF,
+    0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
+    0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
+    0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
+    0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
+    0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
+]);
+
+// The following code was generated with the moman/finenight pkg
+// This package is available under the MIT License, see NOTICE.txt
+// for more details.
+// This class is auto-generated, Please do not modify it directly.
+// You should modify the https://gitlab.com/notriddle/createAutomata.py instead.
+// The following code was generated with the moman/finenight pkg
+// This package is available under the MIT License, see NOTICE.txt
+// for more details.
+// This class is auto-generated, Please do not modify it directly.
+// You should modify https://gitlab.com/notriddle/moman-rustdoc instead.
+
+class Lev2TParametricDescription extends ParametricDescription {
+    /**
+     * @param {number} absState
+     * @param {number} position
+     * @param {number} vector
+     * @returns {number}
+    */
+    transition(absState, position, vector) {
+        let state = Math.floor(absState / (this.w + 1));
+        let offset = absState % (this.w + 1);
+
+        if (position === this.w) {
+            if (state < 3) {
+                const loc = Math.imul(vector, 3) + state;
+                offset += this.unpack(this.offsetIncrs0, loc, 1);
+                state = this.unpack(this.toStates0, loc, 2) - 1;
+            }
+        } else if (position === this.w - 1) {
+            if (state < 5) {
+                const loc = Math.imul(vector, 5) + state;
+                offset += this.unpack(this.offsetIncrs1, loc, 1);
+                state = this.unpack(this.toStates1, loc, 3) - 1;
+            }
+        } else if (position === this.w - 2) {
+            if (state < 13) {
+                const loc = Math.imul(vector, 13) + state;
+                offset += this.unpack(this.offsetIncrs2, loc, 2);
+                state = this.unpack(this.toStates2, loc, 4) - 1;
+            }
+        } else if (position === this.w - 3) {
+            if (state < 28) {
+                const loc = Math.imul(vector, 28) + state;
+                offset += this.unpack(this.offsetIncrs3, loc, 2);
+                state = this.unpack(this.toStates3, loc, 5) - 1;
+            }
+        } else if (position === this.w - 4) {
+            if (state < 45) {
+                const loc = Math.imul(vector, 45) + state;
+                offset += this.unpack(this.offsetIncrs4, loc, 3);
+                state = this.unpack(this.toStates4, loc, 6) - 1;
+            }
+        } else {
+            // eslint-disable-next-line no-lonely-if
+            if (state < 45) {
+                const loc = Math.imul(vector, 45) + state;
+                offset += this.unpack(this.offsetIncrs5, loc, 3);
+                state = this.unpack(this.toStates5, loc, 6) - 1;
+            }
+        }
+
+        if (state === -1) {
+            // null state
+            return -1;
+        } else {
+            // translate back to abs
+            return Math.imul(state, this.w + 1) + offset;
+        }
+    }
+
+    // state map
+    //   0 -> [(0, 0)]
+    //   1 -> [(0, 1)]
+    //   2 -> [(0, 2)]
+    //   3 -> [(0, 1), (1, 1)]
+    //   4 -> [(0, 2), (1, 2)]
+    //   5 -> [(0, 1), (1, 1), (2, 1)]
+    //   6 -> [(0, 2), (1, 2), (2, 2)]
+    //   7 -> [(0, 1), (2, 1)]
+    //   8 -> [(0, 1), (2, 2)]
+    //   9 -> [(0, 2), (2, 1)]
+    //   10 -> [(0, 2), (2, 2)]
+    //   11 -> [t(0, 1), (0, 1), (1, 1), (2, 1)]
+    //   12 -> [t(0, 2), (0, 2), (1, 2), (2, 2)]
+    //   13 -> [(0, 2), (1, 2), (2, 2), (3, 2)]
+    //   14 -> [(0, 1), (1, 1), (3, 2)]
+    //   15 -> [(0, 1), (2, 2), (3, 2)]
+    //   16 -> [(0, 1), (3, 2)]
+    //   17 -> [(0, 1), t(1, 2), (2, 2), (3, 2)]
+    //   18 -> [(0, 2), (1, 2), (3, 1)]
+    //   19 -> [(0, 2), (1, 2), (3, 2)]
+    //   20 -> [(0, 2), (1, 2), t(1, 2), (2, 2), (3, 2)]
+    //   21 -> [(0, 2), (2, 1), (3, 1)]
+    //   22 -> [(0, 2), (2, 2), (3, 2)]
+    //   23 -> [(0, 2), (3, 1)]
+    //   24 -> [(0, 2), (3, 2)]
+    //   25 -> [(0, 2), t(1, 2), (1, 2), (2, 2), (3, 2)]
+    //   26 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (3, 2)]
+    //   27 -> [t(0, 2), (0, 2), (1, 2), (3, 1)]
+    //   28 -> [(0, 2), (1, 2), (2, 2), (3, 2), (4, 2)]
+    //   29 -> [(0, 2), (1, 2), (2, 2), (4, 2)]
+    //   30 -> [(0, 2), (1, 2), (2, 2), t(2, 2), (3, 2), (4, 2)]
+    //   31 -> [(0, 2), (1, 2), (3, 2), (4, 2)]
+    //   32 -> [(0, 2), (1, 2), (4, 2)]
+    //   33 -> [(0, 2), (1, 2), t(1, 2), (2, 2), (3, 2), (4, 2)]
+    //   34 -> [(0, 2), (1, 2), t(2, 2), (2, 2), (3, 2), (4, 2)]
+    //   35 -> [(0, 2), (2, 1), (4, 2)]
+    //   36 -> [(0, 2), (2, 2), (3, 2), (4, 2)]
+    //   37 -> [(0, 2), (2, 2), (4, 2)]
+    //   38 -> [(0, 2), (3, 2), (4, 2)]
+    //   39 -> [(0, 2), (4, 2)]
+    //   40 -> [(0, 2), t(1, 2), (1, 2), (2, 2), (3, 2), (4, 2)]
+    //   41 -> [(0, 2), t(2, 2), (2, 2), (3, 2), (4, 2)]
+    //   42 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (3, 2), (4, 2)]
+    //   43 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (4, 2)]
+    //   44 -> [t(0, 2), (0, 2), (1, 2), (2, 2), t(2, 2), (3, 2), (4, 2)]
+
+
+    /** @param {number} w - length of word being checked */
+    constructor(w) {
+        super(w, 2, new Int32Array([
+            0,1,2,0,1,-1,0,-1,0,-1,0,-1,0,-1,-1,-1,-1,-1,-2,-1,-1,-2,-1,-2,
+            -1,-1,-1,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
+        ]));
+    }
+}
+
+Lev2TParametricDescription.prototype.toStates0 = /*2 bits per value */ new Int32Array([
+    0xe,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs0 = /*1 bits per value */ new Int32Array([
+    0x0,
+]);
+
+Lev2TParametricDescription.prototype.toStates1 = /*3 bits per value */ new Int32Array([
+    0x1a688a2c,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs1 = /*1 bits per value */ new Int32Array([
+    0x3e0,
+]);
+
+Lev2TParametricDescription.prototype.toStates2 = /*4 bits per value */ new Int32Array([
+    0x70707054,0xdc07035,0x3dd3a3a,0x2323213a,
+    0x15435223,0x22545432,0x5435,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs2 = /*2 bits per value */ new Int32Array([
+    0x80000,0x55582088,0x55555555,0x55,
+]);
+
+Lev2TParametricDescription.prototype.toStates3 = /*5 bits per value */ new Int32Array([
+    0x1c0380a4,0x700a570,0xca529c0,0x180a00,
+    0xa80af180,0xc5498e60,0x5a546398,0x8c4300e8,
+    0xac18c601,0xd8d43501,0x863500ad,0x51976d6a,
+    0x8ca0180a,0xc3501ac2,0xb0c5be16,0x76dda8a5,
+    0x18c4519,0xc41294a,0xe248d231,0x1086520c,
+    0xce31ac42,0x13946358,0x2d0348c4,0x6732d494,
+    0x1ad224a5,0xd635ad4b,0x520c4139,0xce24948,
+    0x22110a52,0x58ce729d,0xc41394e3,0x941cc520,
+    0x90e732d4,0x4729d224,0x39ce35ad,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new Int32Array([
+    0x80000,0xc0c830,0x300f3c30,0x2200fcff,
+    0xcaa00a08,0x3c2200a8,0xa8fea00a,0x55555555,
+    0x55555555,0x55555555,0x55555555,0x55555555,
+    0x55555555,0x55555555,
+]);
+
+Lev2TParametricDescription.prototype.toStates4 = /*6 bits per value */ new Int32Array([
+    0x801c0144,0x1453803,0x14700038,0xc0005145,
+    0x1401,0x14,0x140000,0x0,
+    0x510000,0x6301f007,0x301f00d1,0xa186178,
+    0xc20ca0c3,0xc20c30,0xc30030c,0xc00c00cd,
+    0xf0c00c30,0x4c054014,0xc30944c3,0x55150c34,
+    0x8300550,0x430c0143,0x50c31,0xc30850c,
+    0xc3143000,0x50053c50,0x5130d301,0x850d30c2,
+    0x30a08608,0xc214414,0x43142145,0x21450031,
+    0x1400c314,0x4c143145,0x32832803,0x28014d6c,
+    0xcd34a0c3,0x1c50c76,0x1c314014,0x430c30c3,
+    0x1431,0xc300500,0xca00d303,0xd36d0e40,
+    0x90b0e400,0xcb2abb2c,0x70c20ca1,0x2c32ca2c,
+    0xcd2c70cb,0x31c00c00,0x34c2c32c,0x5583280,
+    0x558309b7,0x6cd6ca14,0x430850c7,0x51c51401,
+    0x1430c714,0xc3087,0x71451450,0xca00d30,
+    0xc26dc156,0xb9071560,0x1cb2abb2,0xc70c2144,
+    0xb1c51ca1,0x1421c70c,0xc51c00c3,0x30811c51,
+    0x24324308,0xc51031c2,0x70820820,0x5c33830d,
+    0xc33850c3,0x30c30c30,0xc30c31c,0x451450c3,
+    0x20c20c20,0xda0920d,0x5145914f,0x36596114,
+    0x51965865,0xd9643653,0x365a6590,0x51964364,
+    0x43081505,0x920b2032,0x2c718b28,0xd7242249,
+    0x35cb28b0,0x2cb3872c,0x972c30d7,0xb0c32cb2,
+    0x4e1c75c,0xc80c90c2,0x62ca2482,0x4504171c,
+    0xd65d9610,0x33976585,0xd95cb5d,0x4b5ca5d7,
+    0x73975c36,0x10308138,0xc2245105,0x41451031,
+    0x14e24208,0xc35c3387,0x51453851,0x1c51c514,
+    0xc70c30c3,0x20451450,0x14f1440c,0x4f0da092,
+    0x4513d41,0x6533944d,0x1350e658,0xe1545055,
+    0x64365a50,0x5519383,0x51030815,0x28920718,
+    0x441c718b,0x714e2422,0x1c35cb28,0x4e1c7387,
+    0xb28e1c51,0x5c70c32c,0xc204e1c7,0x81c61440,
+    0x1c62ca24,0xd04503ce,0x85d63944,0x39338e65,
+    0x8e154387,0x364b5ca3,0x38739738,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs4 = /*3 bits per value */ new Int32Array([
+    0x10000000,0xc00000,0x60061,0x400,
+    0x0,0x80010008,0x249248a4,0x8229048,
+    0x2092,0x6c3603,0xb61b6c30,0x6db6036d,
+    0xdb6c0,0x361b0180,0x91b72000,0xdb11b71b,
+    0x6db6236,0x1008200,0x12480012,0x24924906,
+    0x48200049,0x80410002,0x24000900,0x4924a489,
+    0x10822492,0x20800125,0x48360,0x9241b692,
+    0x6da4924,0x40009268,0x241b010,0x291b4900,
+    0x6d249249,0x49493423,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x2492,
+]);
+
+Lev2TParametricDescription.prototype.toStates5 = /*6 bits per value */ new Int32Array([
+    0x801c0144,0x1453803,0x14700038,0xc0005145,
+    0x1401,0x14,0x140000,0x0,
+    0x510000,0x4e00e007,0xe0051,0x3451451c,
+    0xd015000,0x30cd0000,0xc30c30c,0xc30c30d4,
+    0x40c30c30,0x7c01c014,0xc03458c0,0x185e0c07,
+    0x2830c286,0x830c3083,0xc30030,0x33430c,
+    0x30c3003,0x70051030,0x16301f00,0x8301f00d,
+    0x30a18617,0xc20ca0c,0x431420c3,0xb1450c51,
+    0x14314315,0x4f143145,0x34c05401,0x4c30944c,
+    0x55150c3,0x30830055,0x1430c014,0xc00050c3,
+    0xc30850,0xc314300,0x150053c5,0x25130d30,
+    0x5430d30c,0xc0354154,0x300d0c90,0x1cb2cd0c,
+    0xc91cb0c3,0x72c30cb2,0x14f1cb2c,0xc34c0540,
+    0x34c30944,0x82182214,0x851050c2,0x50851430,
+    0x1400c50c,0x30c5085,0x50c51450,0x150053c,
+    0xc25130d3,0x8850d30,0x1430a086,0x450c2144,
+    0x51cb1c21,0x1c91c70c,0xc71c314b,0x34c1cb1,
+    0x6c328328,0xc328014d,0x76cd34a0,0x1401c50c,
+    0xc31c3140,0x31430c30,0x14,0x30c3005,
+    0xa0ca00d3,0x535b0c,0x4d2830ca,0x514369b3,
+    0xc500d01,0x5965965a,0x30d46546,0x6435030c,
+    0x8034c659,0xdb439032,0x2c390034,0xcaaecb24,
+    0x30832872,0xcb28b1c,0x4b1c32cb,0x70030033,
+    0x30b0cb0c,0xe40ca00d,0x400d36d0,0xb2c90b0e,
+    0xca1cb2ab,0xa2c70c20,0x6575d95c,0x4315b5ce,
+    0x95c53831,0x28034c5d,0x9b705583,0xa1455830,
+    0xc76cd6c,0x40143085,0x71451c51,0x871430c,
+    0x450000c3,0xd3071451,0x1560ca00,0x560c26dc,
+    0xb35b2851,0xc914369,0x1a14500d,0x46593945,
+    0xcb2c939,0x94507503,0x328034c3,0x9b70558,
+    0xe41c5583,0x72caaeca,0x1c308510,0xc7147287,
+    0x50871c32,0x1470030c,0xd307147,0xc1560ca0,
+    0x1560c26d,0xabb2b907,0x21441cb2,0x38a1c70c,
+    0x8e657394,0x314b1c93,0x39438738,0x43083081,
+    0x31c22432,0x820c510,0x830d7082,0x50c35c33,
+    0xc30c338,0xc31c30c3,0x50c30c30,0xc204514,
+    0x890c90c2,0x31440c70,0xa8208208,0xea0df0c3,
+    0x8a231430,0xa28a28a2,0x28a28a1e,0x1861868a,
+    0x48308308,0xc3682483,0x14516453,0x4d965845,
+    0xd4659619,0x36590d94,0xd969964,0x546590d9,
+    0x20c20541,0x920d20c,0x5914f0da,0x96114514,
+    0x65865365,0xe89d3519,0x99e7a279,0x9e89e89e,
+    0x81821827,0xb2032430,0x18b28920,0x422492c7,
+    0xb28b0d72,0x3872c35c,0xc30d72cb,0x32cb2972,
+    0x1c75cb0c,0xc90c204e,0xa2482c80,0x24b1c62c,
+    0xc3a89089,0xb0ea2e42,0x9669a31c,0xa4966a28,
+    0x59a8a269,0x8175e7a,0xb203243,0x718b2892,
+    0x4114105c,0x17597658,0x74ce5d96,0x5c36572d,
+    0xd92d7297,0xe1ce5d70,0xc90c204,0xca2482c8,
+    0x4171c62,0x5d961045,0x976585d6,0x79669533,
+    0x964965a2,0x659689e6,0x308175e7,0x24510510,
+    0x451031c2,0xe2420841,0x5c338714,0x453851c3,
+    0x51c51451,0xc30c31c,0x451450c7,0x41440c20,
+    0xc708914,0x82105144,0xf1c58c90,0x1470ea0d,
+    0x61861863,0x8a1e85e8,0x8687a8a2,0x3081861,
+    0x24853c51,0x5053c368,0x1341144f,0x96194ce5,
+    0x1544d439,0x94385514,0xe0d90d96,0x5415464,
+    0x4f1440c2,0xf0da0921,0x4513d414,0x533944d0,
+    0x350e6586,0x86082181,0xe89e981d,0x18277689,
+    0x10308182,0x89207185,0x41c718b2,0x14e24224,
+    0xc35cb287,0xe1c73871,0x28e1c514,0xc70c32cb,
+    0x204e1c75,0x1c61440c,0xc62ca248,0x90891071,
+    0x2e41c58c,0xa31c70ea,0xe86175e7,0xa269a475,
+    0x5e7a57a8,0x51030817,0x28920718,0xf38718b,
+    0xe5134114,0x39961758,0xe1ce4ce,0x728e3855,
+    0x5ce0d92d,0xc204e1ce,0x81c61440,0x1c62ca24,
+    0xd04503ce,0x85d63944,0x75338e65,0x5d86075e,
+    0x89e69647,0x75e76576,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs5 = /*3 bits per value */ new Int32Array([
+    0x10000000,0xc00000,0x60061,0x400,
+    0x0,0x60000008,0x6b003080,0xdb6ab6db,
+    0x2db6,0x800400,0x49245240,0x11482412,
+    0x104904,0x40020000,0x92292000,0xa4b25924,
+    0x9649658,0xd80c000,0xdb0c001b,0x80db6d86,
+    0x6db01b6d,0xc0600003,0x86000d86,0x6db6c36d,
+    0xddadb6ed,0x300001b6,0x6c360,0xe37236e4,
+    0x46db6236,0xdb6c,0x361b018,0xb91b7200,
+    0x6dbb1b71,0x6db763,0x20100820,0x61248001,
+    0x92492490,0x24820004,0x8041000,0x92400090,
+    0x24924830,0x555b6a49,0x2080012,0x20004804,
+    0x49252449,0x84112492,0x4000928,0x240201,
+    0x92922490,0x58924924,0x49456,0x120d8082,
+    0x6da4800,0x69249249,0x249a01b,0x6c04100,
+    0x6d240009,0x92492483,0x24d5adb4,0x60208001,
+    0x92000483,0x24925236,0x6846da49,0x10400092,
+    0x241b0,0x49291b49,0x636d2492,0x92494935,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,
+]);
+
+class Lev1TParametricDescription extends ParametricDescription {
+    /**
+     * @param {number} absState
+     * @param {number} position
+     * @param {number} vector
+     * @returns {number}
+    */
+    transition(absState, position, vector) {
+        let state = Math.floor(absState / (this.w + 1));
+        let offset = absState % (this.w + 1);
+
+        if (position === this.w) {
+            if (state < 2) {
+                const loc = Math.imul(vector, 2) + state;
+                offset += this.unpack(this.offsetIncrs0, loc, 1);
+                state = this.unpack(this.toStates0, loc, 2) - 1;
+            }
+        } else if (position === this.w - 1) {
+            if (state < 3) {
+                const loc = Math.imul(vector, 3) + state;
+                offset += this.unpack(this.offsetIncrs1, loc, 1);
+                state = this.unpack(this.toStates1, loc, 2) - 1;
+            }
+        } else if (position === this.w - 2) {
+            if (state < 6) {
+                const loc = Math.imul(vector, 6) + state;
+                offset += this.unpack(this.offsetIncrs2, loc, 2);
+                state = this.unpack(this.toStates2, loc, 3) - 1;
+            }
+        } else {
+            // eslint-disable-next-line no-lonely-if
+            if (state < 6) {
+                const loc = Math.imul(vector, 6) + state;
+                offset += this.unpack(this.offsetIncrs3, loc, 2);
+                state = this.unpack(this.toStates3, loc, 3) - 1;
+            }
+        }
+
+        if (state === -1) {
+            // null state
+            return -1;
+        } else {
+            // translate back to abs
+            return Math.imul(state, this.w + 1) + offset;
+        }
+    }
+
+    // state map
+    //   0 -> [(0, 0)]
+    //   1 -> [(0, 1)]
+    //   2 -> [(0, 1), (1, 1)]
+    //   3 -> [(0, 1), (1, 1), (2, 1)]
+    //   4 -> [(0, 1), (2, 1)]
+    //   5 -> [t(0, 1), (0, 1), (1, 1), (2, 1)]
+
+
+    /** @param {number} w - length of word being checked */
+    constructor(w) {
+        super(w, 1, new Int32Array([0,1,0,-1,-1,-1]));
+    }
+}
+
+Lev1TParametricDescription.prototype.toStates0 = /*2 bits per value */ new Int32Array([
+    0x2,
+]);
+Lev1TParametricDescription.prototype.offsetIncrs0 = /*1 bits per value */ new Int32Array([
+    0x0,
+]);
+
+Lev1TParametricDescription.prototype.toStates1 = /*2 bits per value */ new Int32Array([
+    0xa43,
+]);
+Lev1TParametricDescription.prototype.offsetIncrs1 = /*1 bits per value */ new Int32Array([
+    0x38,
+]);
+
+Lev1TParametricDescription.prototype.toStates2 = /*3 bits per value */ new Int32Array([
+    0x12180003,0xb45a4914,0x69,
+]);
+Lev1TParametricDescription.prototype.offsetIncrs2 = /*2 bits per value */ new Int32Array([
+    0x558a0000,0x5555,
+]);
+
+Lev1TParametricDescription.prototype.toStates3 = /*3 bits per value */ new Int32Array([
+    0x900c0003,0xa1904864,0x45a49169,0x5a6d196a,
+    0x9634,
+]);
+Lev1TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new Int32Array([
+    0xa0fc0000,0x5555ba08,0x55555555,
+]);
diff --git a/src/librustdoc/html/static/js/tsconfig.json b/src/librustdoc/html/static/js/tsconfig.json
index b81099bb9df..42993cb0f2a 100644
--- a/src/librustdoc/html/static/js/tsconfig.json
+++ b/src/librustdoc/html/static/js/tsconfig.json
@@ -10,6 +10,6 @@
     "skipLibCheck": true
   },
   "typeAcquisition": {
-    "include": ["./rustdoc.d.ts"]
+    "include": ["./rustdoc.d.ts", "./stringdex.d.ts"]
   }
 }
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 45589a37069..e670c2f39e7 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -80,6 +80,7 @@ static_files! {
     normalize_css => "static/css/normalize.css",
     main_js => "static/js/main.js",
     search_js => "static/js/search.js",
+    stringdex_js => "static/js/stringdex.js",
     settings_js => "static/js/settings.js",
     src_script_js => "static/js/src-script.js",
     storage_js => "static/js/storage.js",
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 398436e3fe1..1f8ec9f30c5 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -29,6 +29,7 @@
          data-rustdoc-version="{{rustdoc_version}}" {#+ #}
          data-channel="{{rust_channel}}" {#+ #}
          data-search-js="{{files.search_js}}" {#+ #}
+         data-stringdex-js="{{files.stringdex_js}}" {#+ #}
          data-settings-js="{{files.settings_js}}" {#+ #}
     > {# #}
     <script src="{{static_root_path|safe}}{{files.storage_js}}"></script>
@@ -72,18 +73,9 @@
     <![endif]-->
     {{ layout.external_html.before_content|safe }}
     {% if page.css_class != "src" %}
-    <nav class="mobile-topbar"> {# #}
-        <button class="sidebar-menu-toggle" title="show sidebar"></button>
-        {% if !layout.logo.is_empty() || page.rust_logo %}
-        <a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">
-        {% if page.rust_logo %}
-            <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="">
-        {% else if !layout.logo.is_empty() %}
-            <img src="{{layout.logo}}" alt="">
-        {% endif %}
-        </a>
-        {% endif %}
-    </nav>
+    <rustdoc-topbar> {# #}
+        <h2><a href="#">{{page.short_title}}</a></h2> {# #}
+    </rustdoc-topbar>
     {% endif %}
     <nav class="sidebar">
         {% if page.css_class != "src" %}
@@ -117,9 +109,6 @@
     <div class="sidebar-resizer" title="Drag to resize sidebar"></div> {# #}
     <main>
         {% if page.css_class != "src" %}<div class="width-limiter">{% endif %}
-            {# defined in storage.js to avoid duplicating complex UI across every page #}
-            {# and because the search form only works if JS is enabled anyway #}
-            <rustdoc-search></rustdoc-search> {# #}
             <section id="main-content" class="content">{{ content|safe }}</section>
         {% if page.css_class != "src" %}</div>{% endif %}
     </main>
diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
index 62954dbb023..640fd3dfee4 100644
--- a/src/librustdoc/html/templates/print_item.html
+++ b/src/librustdoc/html/templates/print_item.html
@@ -12,8 +12,8 @@
     <h1>
         {{typ}}
         <span{% if item_type != "mod" +%} class="{{item_type}}"{% endif %}>
-        {{name}}
-        </span> {# #}
+        {{name|wrapped|safe}}
+        </span>&nbsp;{# #}
         <button id="copy-path" title="Copy item path to clipboard"> {# #}
             Copy item path {# #}
         </button> {# #}
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 0520eff0fa2..8f88ab10bf7 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -205,7 +205,7 @@ static TARGETS: &[&str] = &[
 ///
 /// The order here matters, more specific entries should be first.
 static DOCS_FALLBACK: &[(&str, &str)] = &[
-    ("-apple-", "x86_64-apple-darwin"),
+    ("-apple-", "aarch64-apple-darwin"),
     ("aarch64", "aarch64-unknown-linux-gnu"),
     ("arm-", "aarch64-unknown-linux-gnu"),
     ("", "x86_64-unknown-linux-gnu"),
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 840b83a10fb0e039a83f4d70ad032892c287570
+Subproject 71eb84f21aef43c07580c6aed6f806a6299f504
diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
index ce551a64d99..759b7b6837b 100644
--- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
+++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
@@ -63,7 +63,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]);
 
 impl EarlyLintPass for DuplicateMod {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if let ItemKind::Mod(_, _, ModKind::Loaded(_, Inline::No, mod_spans, _)) = &item.kind
+        if let ItemKind::Mod(_, _, ModKind::Loaded(_, Inline::No { .. }, mod_spans)) = &item.kind
             && let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span)
             && let Some(local_path) = real.into_local_path()
             && let Ok(absolute_path) = local_path.canonicalize()
diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
index 3bd74856165..76e67b1154b 100644
--- a/src/tools/clippy/clippy_lints/src/empty_line_after.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
@@ -442,7 +442,7 @@ impl EmptyLineAfter {
                 None => span.shrink_to_lo(),
             },
             mod_items: match kind {
-                ItemKind::Mod(_, _, ModKind::Loaded(items, _, _, _)) => items
+                ItemKind::Mod(_, _, ModKind::Loaded(items, _, _)) => items
                     .iter()
                     .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
                     .map(|i| i.id)
diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
index 1d3ae894944..5368701c304 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
@@ -164,7 +164,7 @@ impl Visitor<'_> for NestingVisitor<'_, '_> {
         }
 
         match &item.kind {
-            ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _, _)) => {
+            ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _)) => {
                 self.nest_level += 1;
 
                 if !self.check_indent(item.span, item.id) {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index 24e017f7cf7..d80a9d9dd07 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -403,7 +403,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
             ls == rs
                 && eq_id(*li, *ri)
                 && match (lmk, rmk) {
-                    (ModKind::Loaded(litems, linline, _, _), ModKind::Loaded(ritems, rinline, _, _)) => {
+                    (ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) => {
                         linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind))
                     },
                     (ModKind::Unloaded, ModKind::Unloaded) => true,
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
index 26e360112b6..939b509d85c 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -330,7 +330,7 @@ LL |         if X.is_some() {
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
-   = note: `#[deny(static_mut_refs)]` on by default
+   = note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 
 error: aborting due to 36 previous errors
 
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 2d49b1a7097..7fc80c1edb1 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -692,7 +692,9 @@ pub struct Config {
     pub minicore_path: Utf8PathBuf,
 
     /// Current codegen backend used.
-    pub codegen_backend: CodegenBackend,
+    pub default_codegen_backend: CodegenBackend,
+    /// Name/path of the backend to use instead of `default_codegen_backend`.
+    pub override_codegen_backend: Option<String>,
 }
 
 impl Config {
@@ -796,7 +798,8 @@ impl Config {
             profiler_runtime: Default::default(),
             diff_command: Default::default(),
             minicore_path: Default::default(),
-            codegen_backend: CodegenBackend::Llvm,
+            default_codegen_backend: CodegenBackend::Llvm,
+            override_codegen_backend: None,
         }
     }
 
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index 13e694b7f03..00007aa1d66 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -1624,7 +1624,7 @@ fn ignore_backends(
                 }
             }
         }) {
-            if config.codegen_backend == backend {
+            if config.default_codegen_backend == backend {
                 return IgnoreDecision::Ignore {
                     reason: format!("{} backend is marked as ignore", backend.as_str()),
                 };
@@ -1651,12 +1651,12 @@ fn needs_backends(
                     panic!("Invalid needs-backends value `{backend}` in `{path}`: {error}")
                 }
             })
-            .any(|backend| config.codegen_backend == backend)
+            .any(|backend| config.default_codegen_backend == backend)
         {
             return IgnoreDecision::Ignore {
                 reason: format!(
                     "{} backend is not part of required backends",
-                    config.codegen_backend.as_str()
+                    config.default_codegen_backend.as_str()
                 ),
             };
         }
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index f5409e78341..469dd68207e 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -212,9 +212,15 @@ pub fn parse_config(args: Vec<String>) -> Config {
         )
         .optopt(
             "",
-            "codegen-backend",
+            "default-codegen-backend",
             "the codegen backend currently used",
             "CODEGEN BACKEND NAME",
+        )
+        .optopt(
+            "",
+            "override-codegen-backend",
+            "the codegen backend to use instead of the default one",
+            "CODEGEN BACKEND [NAME | PATH]",
         );
 
     let (argv0, args_) = args.split_first().unwrap();
@@ -276,14 +282,17 @@ pub fn parse_config(args: Vec<String>) -> Config {
             || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
         );
 
-    let codegen_backend = match matches.opt_str("codegen-backend").as_deref() {
+    let default_codegen_backend = match matches.opt_str("default-codegen-backend").as_deref() {
         Some(backend) => match CodegenBackend::try_from(backend) {
             Ok(backend) => backend,
-            Err(error) => panic!("invalid value `{backend}` for `--codegen-backend`: {error}"),
+            Err(error) => {
+                panic!("invalid value `{backend}` for `--defalt-codegen-backend`: {error}")
+            }
         },
         // By default, it's always llvm.
         None => CodegenBackend::Llvm,
     };
+    let override_codegen_backend = matches.opt_str("override-codegen-backend");
 
     let run_ignored = matches.opt_present("ignored");
     let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions");
@@ -472,7 +481,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
 
         minicore_path: opt_path(matches, "minicore-path"),
 
-        codegen_backend,
+        default_codegen_backend,
+        override_codegen_backend,
     }
 }
 
@@ -812,13 +822,13 @@ fn collect_tests_from_dir(
         && let Some(Utf8Component::Normal(parent)) = components.next()
         && parent == "tests"
         && let Ok(backend) = CodegenBackend::try_from(backend)
-        && backend != cx.config.codegen_backend
+        && backend != cx.config.default_codegen_backend
     {
         // We ignore asm tests which don't match the current codegen backend.
         warning!(
             "Ignoring tests in `{dir}` because they don't match the configured codegen \
              backend (`{}`)",
-            cx.config.codegen_backend.as_str(),
+            cx.config.default_codegen_backend.as_str(),
         );
         return Ok(TestCollector::new());
     }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index be4663fffbe..2402ed9a950 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1558,6 +1558,11 @@ impl<'test> TestCx<'test> {
             rustc.arg("--sysroot").arg(&self.config.sysroot_base);
         }
 
+        // If the provided codegen backend is not LLVM, we need to pass it.
+        if let Some(ref backend) = self.config.override_codegen_backend {
+            rustc.arg(format!("-Zcodegen-backend={}", backend));
+        }
+
         // Optionally prevent default --target if specified in test compile-flags.
         let custom_target = self.props.compile_flags.iter().any(|x| x.starts_with("--target"));
 
@@ -2151,7 +2156,7 @@ impl<'test> TestCx<'test> {
 
         #[rustfmt::skip]
         let tidy_args = [
-            "--new-blocklevel-tags", "rustdoc-search,rustdoc-toolbar",
+            "--new-blocklevel-tags", "rustdoc-search,rustdoc-toolbar,rustdoc-topbar",
             "--indent", "yes",
             "--indent-spaces", "2",
             "--wrap", "0",
diff --git a/src/tools/html-checker/main.rs b/src/tools/html-checker/main.rs
index 5cdc4d53ab5..d5335d9e72e 100644
--- a/src/tools/html-checker/main.rs
+++ b/src/tools/html-checker/main.rs
@@ -31,7 +31,7 @@ fn check_html_file(file: &Path) -> usize {
         .arg("--mute-id") // this option is useful in case we want to mute more warnings
         .arg("yes")
         .arg("--new-blocklevel-tags")
-        .arg("rustdoc-search,rustdoc-toolbar") // custom elements
+        .arg("rustdoc-search,rustdoc-toolbar,rustdoc-topbar") // custom elements
         .arg("--mute")
         .arg(&to_mute_s)
         .arg(file);
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 49021b1c4a2..4cad36cf383 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1111,6 +1111,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
     ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
         // For foreign items, try to see if we can emulate them.
         if ecx.tcx.is_foreign_item(instance.def_id()) {
+            let _trace = enter_trace_span!("emulate_foreign_item");
             // An external function call that does not have a MIR body. We either find MIR elsewhere
             // or emulate its effect.
             // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need
@@ -1123,6 +1124,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         }
 
         // Otherwise, load the MIR.
+        let _trace = enter_trace_span!("load_mir");
         interp_ok(Some((ecx.load_mir(instance.def, None)?, instance)))
     }
 
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 21545b68029..23b1d0c4f6e 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -146,7 +146,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         return interp_ok(());
                     }
                     // Skip over items without an explicitly defined symbol name.
-                    if !(attrs.export_name.is_some()
+                    if !(attrs.symbol_name.is_some()
                         || attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
                         || attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL))
                     {
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs
new file mode 100644
index 00000000000..b91a41d7650
--- /dev/null
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs
@@ -0,0 +1,34 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
+// Validation forces more things into memory, which we can't have here.
+//@compile-flags: -Zmiri-disable-validation
+#![feature(custom_mir, core_intrinsics)]
+use std::intrinsics::mir::*;
+
+pub struct S(i32);
+
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+fn main() {
+    mir! {
+        let _unit: ();
+        {
+            let staging = S(42); // This forces `staging` into memory...
+            let non_copy = staging; // ... so we move it to a non-inmemory local here.
+            // This specifically uses a type with scalar representation to tempt Miri to use the
+            // efficient way of storing local variables (outside adressable memory).
+            Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
+            //~[stack]^ ERROR: not granting access
+            //~[tree]| ERROR: /read access .* forbidden/
+        }
+        after_call = {
+            Return()
+        }
+    }
+}
+
+pub fn callee(x: S, mut y: S) {
+    // With the setup above, if `x` and `y` are both moved,
+    // then writing to `y` will change the value stored in `x`!
+    y.0 = 0;
+    assert_eq!(x.0, 42);
+}
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr
new file mode 100644
index 00000000000..0c1100cae63
--- /dev/null
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr
@@ -0,0 +1,25 @@
+error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
+  --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
+   |
+LL |             Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
+   = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
+help: <TAG> was created here, as the root tag for ALLOC
+  --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
+   |
+LL |             Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: <TAG> is this argument
+  --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
+   |
+LL |     y.0 = 0;
+   |     ^^^^^^^
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr
new file mode 100644
index 00000000000..f376c30c879
--- /dev/null
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr
@@ -0,0 +1,33 @@
+error: Undefined Behavior: read access through <TAG> (root of the allocation) at ALLOC[0x0] is forbidden
+  --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
+   |
+LL |             Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
+   = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: protected tags must never be Disabled
+help: the accessed tag <TAG> was created here
+  --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
+   |
+LL |             Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: the protected tag <TAG> was created here, in the initial state Reserved
+  --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
+   |
+LL |     y.0 = 0;
+   |     ^^^^^^^
+help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+  --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
+   |
+LL |     y.0 = 0;
+   |     ^^^^^^^
+   = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr
index 24091547258..d478568ceae 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr
@@ -11,8 +11,8 @@ LL |     unsafe { ptr.read() };
 note: inside `main`
   --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
    |
-LL |             Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation:
 ALLOC (stack variable, size: 4, align: 4) {
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs
index a6e0134bd17..dc22e129e18 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs
@@ -10,11 +10,11 @@ use std::intrinsics::mir::*;
 pub fn main() {
     mir! {
         {
-            let x = 0;
-            let ptr = &raw mut x;
+            let _x = 0;
+            let ptr = &raw mut _x;
             // We arrange for `myfun` to have a pointer that aliases
             // its return place. Even just reading from that pointer is UB.
-            Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
+            Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
         }
 
         after_call = {
@@ -25,7 +25,7 @@ pub fn main() {
 
 fn myfun(ptr: *mut i32) -> i32 {
     unsafe { ptr.read() };
-    //~[stack]^ ERROR: not granting access
+    //~[stack]^ ERROR: does not exist in the borrow stack
     //~[tree]| ERROR: /read access .* forbidden/
     //~[none]| ERROR: uninitialized
     // Without an aliasing model, reads are "fine" but at least they return uninit data.
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr
index 77cc0332a1c..86adbab353b 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
+error: Undefined Behavior: attempting a read access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
   --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
    |
 LL |     unsafe { ptr.read() };
-   |              ^^^^^^^^^^ Undefined Behavior occurred here
+   |              ^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4]
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -11,12 +11,12 @@ help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4]
    |
 LL | /     mir! {
 LL | |         {
-LL | |             let x = 0;
-LL | |             let ptr = &raw mut x;
+LL | |             let _x = 0;
+LL | |             let ptr = &raw mut _x;
 ...  |
 LL | |     }
    | |_____^
-help: <TAG> is this argument
+help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection
   --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
    |
 LL |     unsafe { ptr.read() };
@@ -26,8 +26,8 @@ LL |     unsafe { ptr.read() };
 note: inside `main`
   --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
    |
-LL |             Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr
index bae3819c979..a1cf0b730eb 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr
@@ -13,8 +13,8 @@ help: the accessed tag <TAG> was created here
    |
 LL | /     mir! {
 LL | |         {
-LL | |             let x = 0;
-LL | |             let ptr = &raw mut x;
+LL | |             let _x = 0;
+LL | |             let ptr = &raw mut _x;
 ...  |
 LL | |     }
    | |_____^
@@ -34,8 +34,8 @@ LL |     unsafe { ptr.read() };
 note: inside `main`
   --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
    |
-LL |             Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs
index 6155e925c4b..2fddaf37235 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs
@@ -14,7 +14,7 @@ pub fn main() {
             let ptr = &raw mut _x;
             // We arrange for `myfun` to have a pointer that aliases
             // its return place. Writing to that pointer is UB.
-            Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
+            Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
         }
 
         after_call = {
@@ -26,7 +26,7 @@ pub fn main() {
 fn myfun(ptr: *mut i32) -> i32 {
     // This overwrites the return place, which shouldn't be possible through another pointer.
     unsafe { ptr.write(0) };
-    //~[stack]^ ERROR: strongly protected
+    //~[stack]^ ERROR: does not exist in the borrow stack
     //~[tree]| ERROR: /write access .* forbidden/
     13
 }
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr
index 828b2339f8c..faae6172d75 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
+error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
   --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
    |
 LL |     unsafe { ptr.write(0) };
-   |              ^^^^^^^^^^^^ Undefined Behavior occurred here
+   |              ^^^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4]
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -16,7 +16,7 @@ LL | |             let ptr = &raw mut _x;
 ...  |
 LL | |     }
    | |_____^
-help: <TAG> is this argument
+help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection
   --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
    |
 LL |     unsafe { ptr.write(0) };
@@ -26,8 +26,8 @@ LL |     unsafe { ptr.write(0) };
 note: inside `main`
   --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
    |
-LL |             Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr
index e0df9370fee..01d15f38af6 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr
@@ -34,8 +34,8 @@ LL |     unsafe { ptr.write(0) };
 note: inside `main`
   --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
    |
-LL |             Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs
index 37ee7ae1b0d..5f3ecb65022 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs
@@ -16,7 +16,7 @@ pub fn main() {
             let ptr = &raw mut _x;
             // We arrange for `myfun` to have a pointer that aliases
             // its return place. Writing to that pointer is UB.
-            Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
+            Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
         }
 
         after_call = {
@@ -32,7 +32,7 @@ fn myfun(ptr: *mut i32) -> i32 {
 fn myfun2(ptr: *mut i32) -> i32 {
     // This overwrites the return place, which shouldn't be possible through another pointer.
     unsafe { ptr.write(0) };
-    //~[stack]^ ERROR: strongly protected
+    //~[stack]^ ERROR: does not exist in the borrow stack
     //~[tree]| ERROR: /write access .* forbidden/
     13
 }
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr
index f5183cfaf5b..1a18857bb17 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
+error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
   --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
    |
 LL |     unsafe { ptr.write(0) };
-   |              ^^^^^^^^^^^^ Undefined Behavior occurred here
+   |              ^^^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4]
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -16,18 +16,18 @@ LL | |             let ptr = &raw mut _x;
 ...  |
 LL | |     }
    | |_____^
-help: <TAG> is this argument
+help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection
   --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
    |
-LL |     unsafe { ptr.write(0) };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+LL |     become myfun2(ptr)
+   |     ^^^^^^^^^^^^^^^^^^
    = note: BACKTRACE (of the first span):
    = note: inside `myfun2` at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
 note: inside `main`
   --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
    |
-LL |             Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr
index fa03ed6869b..812ddb94a73 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr
@@ -34,8 +34,8 @@ LL |     unsafe { ptr.write(0) };
 note: inside `main`
   --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
    |
-LL |             Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
diff --git a/src/tools/miri/tests/pass/prefetch.rs b/src/tools/miri/tests/pass/prefetch.rs
new file mode 100644
index 00000000000..99c75c38bde
--- /dev/null
+++ b/src/tools/miri/tests/pass/prefetch.rs
@@ -0,0 +1,23 @@
+#![feature(core_intrinsics)]
+
+// Test that these intrinsics work. Their behavior should be a no-op.
+
+fn main() {
+    static X: [u8; 8] = [0; 8];
+
+    ::std::intrinsics::prefetch_read_data::<_, 1>(::std::ptr::null::<u8>());
+    ::std::intrinsics::prefetch_read_data::<_, 2>(::std::ptr::dangling::<u8>());
+    ::std::intrinsics::prefetch_read_data::<_, 3>(X.as_ptr());
+
+    ::std::intrinsics::prefetch_write_data::<_, 1>(::std::ptr::null::<u8>());
+    ::std::intrinsics::prefetch_write_data::<_, 2>(::std::ptr::dangling::<u8>());
+    ::std::intrinsics::prefetch_write_data::<_, 3>(X.as_ptr());
+
+    ::std::intrinsics::prefetch_read_instruction::<_, 1>(::std::ptr::null::<u8>());
+    ::std::intrinsics::prefetch_read_instruction::<_, 2>(::std::ptr::dangling::<u8>());
+    ::std::intrinsics::prefetch_read_instruction::<_, 3>(X.as_ptr());
+
+    ::std::intrinsics::prefetch_write_instruction::<_, 1>(::std::ptr::null::<u8>());
+    ::std::intrinsics::prefetch_write_instruction::<_, 2>(::std::ptr::dangling::<u8>());
+    ::std::intrinsics::prefetch_write_instruction::<_, 3>(X.as_ptr());
+}
diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix
index 0adbacf7e8d..ad33b121f97 100644
--- a/src/tools/nix-dev-shell/shell.nix
+++ b/src/tools/nix-dev-shell/shell.nix
@@ -14,6 +14,7 @@ pkgs.mkShell {
   packages = [
     pkgs.git
     pkgs.nix
+    pkgs.glibc.static
     x
     # Get the runtime deps of the x wrapper
   ] ++ lists.flatten (attrsets.attrValues env);
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index 0baa179e16b..ff809d58e90 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -1,7 +1,8 @@
 /* global globalThis */
+
 const fs = require("fs");
 const path = require("path");
-
+const { isGeneratorObject } = require("util/types");
 
 function arrayToCode(array) {
     return array.map((value, index) => {
@@ -45,23 +46,16 @@ function shouldIgnoreField(fieldName) {
 }
 
 function valueMapper(key, testOutput) {
-    const isAlias = testOutput["is_alias"];
     let value = testOutput[key];
     // To make our life easier, if there is a "parent" type, we add it to the path.
     if (key === "path") {
-        if (testOutput["parent"] !== undefined) {
+        if (testOutput["parent"]) {
             if (value.length > 0) {
                 value += "::" + testOutput["parent"]["name"];
             } else {
                 value = testOutput["parent"]["name"];
             }
-        } else if (testOutput["is_alias"]) {
-            value = valueMapper(key, testOutput["original"]);
         }
-    } else if (isAlias && key === "alias") {
-        value = testOutput["name"];
-    } else if (isAlias && ["name"].includes(key)) {
-        value = testOutput["original"][key];
     }
     return value;
 }
@@ -237,7 +231,7 @@ async function runSearch(query, expected, doSearch, loadedFile, queryName) {
     const ignore_order = loadedFile.ignore_order;
     const exact_check = loadedFile.exact_check;
 
-    const results = await doSearch(query, loadedFile.FILTER_CRATE);
+    const { resultsTable } = await doSearch(query, loadedFile.FILTER_CRATE);
     const error_text = [];
 
     for (const key in expected) {
@@ -247,37 +241,38 @@ async function runSearch(query, expected, doSearch, loadedFile, queryName) {
         if (!Object.prototype.hasOwnProperty.call(expected, key)) {
             continue;
         }
-        if (!Object.prototype.hasOwnProperty.call(results, key)) {
+        if (!Object.prototype.hasOwnProperty.call(resultsTable, key)) {
             error_text.push("==> Unknown key \"" + key + "\"");
             break;
         }
         const entry = expected[key];
 
-        if (exact_check && entry.length !== results[key].length) {
+        if (exact_check && entry.length !== resultsTable[key].length) {
             error_text.push(queryName + "==> Expected exactly " + entry.length +
-                            " results but found " + results[key].length + " in '" + key + "'");
+                            " results but found " + resultsTable[key].length + " in '" + key + "'");
         }
 
         let prev_pos = -1;
         for (const [index, elem] of entry.entries()) {
-            const entry_pos = lookForEntry(elem, results[key]);
+            const entry_pos = lookForEntry(elem, resultsTable[key]);
             if (entry_pos === -1) {
                 error_text.push(queryName + "==> Result not found in '" + key + "': '" +
                                 JSON.stringify(elem) + "'");
                 // By default, we just compare the two first items.
                 let item_to_diff = 0;
-                if ((!ignore_order || exact_check) && index < results[key].length) {
+                if ((!ignore_order || exact_check) && index < resultsTable[key].length) {
                     item_to_diff = index;
                 }
                 error_text.push("Diff of first error:\n" +
-                    betterLookingDiff(elem, results[key][item_to_diff]));
+                    betterLookingDiff(elem, resultsTable[key][item_to_diff]));
             } else if (exact_check === true && prev_pos + 1 !== entry_pos) {
                 error_text.push(queryName + "==> Exact check failed at position " + (prev_pos + 1) +
                                 ": expected '" + JSON.stringify(elem) + "' but found '" +
-                                JSON.stringify(results[key][index]) + "'");
+                                JSON.stringify(resultsTable[key][index]) + "'");
             } else if (ignore_order === false && entry_pos < prev_pos) {
-                error_text.push(queryName + "==> '" + JSON.stringify(elem) + "' was supposed " +
-                                "to be before '" + JSON.stringify(results[key][prev_pos]) + "'");
+                error_text.push(queryName + "==> '" +
+                                JSON.stringify(elem) + "' was supposed to be before '" +
+                                JSON.stringify(resultsTable[key][prev_pos]) + "'");
             } else {
                 prev_pos = entry_pos;
             }
@@ -286,19 +281,20 @@ async function runSearch(query, expected, doSearch, loadedFile, queryName) {
     return error_text;
 }
 
-async function runCorrections(query, corrections, getCorrections, loadedFile) {
-    const qc = await getCorrections(query, loadedFile.FILTER_CRATE);
+async function runCorrections(query, corrections, doSearch, loadedFile) {
+    const { parsedQuery } = await doSearch(query, loadedFile.FILTER_CRATE);
+    const qc = parsedQuery.correction;
     const error_text = [];
 
     if (corrections === null) {
         if (qc !== null) {
-            error_text.push(`==> expected = null, found = ${qc}`);
+            error_text.push(`==> [correction] expected = null, found = ${qc}`);
         }
         return error_text;
     }
 
-    if (qc !== corrections.toLowerCase()) {
-        error_text.push(`==> expected = ${corrections}, found = ${qc}`);
+    if (qc.toLowerCase() !== corrections.toLowerCase()) {
+        error_text.push(`==> [correction] expected = ${corrections}, found = ${qc}`);
     }
 
     return error_text;
@@ -320,7 +316,7 @@ function checkResult(error_text, loadedFile, displaySuccess) {
     return 1;
 }
 
-async function runCheckInner(callback, loadedFile, entry, getCorrections, extra) {
+async function runCheckInner(callback, loadedFile, entry, extra, doSearch) {
     if (typeof entry.query !== "string") {
         console.log("FAILED");
         console.log("==> Missing `query` field");
@@ -338,7 +334,7 @@ async function runCheckInner(callback, loadedFile, entry, getCorrections, extra)
         error_text = await runCorrections(
             entry.query,
             entry.correction,
-            getCorrections,
+            doSearch,
             loadedFile,
         );
         if (checkResult(error_text, loadedFile, false) !== 0) {
@@ -348,16 +344,16 @@ async function runCheckInner(callback, loadedFile, entry, getCorrections, extra)
     return true;
 }
 
-async function runCheck(loadedFile, key, getCorrections, callback) {
+async function runCheck(loadedFile, key, doSearch, callback) {
     const expected = loadedFile[key];
 
     if (Array.isArray(expected)) {
         for (const entry of expected) {
-            if (!await runCheckInner(callback, loadedFile, entry, getCorrections, true)) {
+            if (!await runCheckInner(callback, loadedFile, entry, true, doSearch)) {
                 return 1;
             }
         }
-    } else if (!await runCheckInner(callback, loadedFile, expected, getCorrections, false)) {
+    } else if (!await runCheckInner(callback, loadedFile, expected, false, doSearch)) {
         return 1;
     }
     console.log("OK");
@@ -368,7 +364,7 @@ function hasCheck(content, checkName) {
     return content.startsWith(`const ${checkName}`) || content.includes(`\nconst ${checkName}`);
 }
 
-async function runChecks(testFile, doSearch, parseQuery, getCorrections) {
+async function runChecks(testFile, doSearch, parseQuery) {
     let checkExpected = false;
     let checkParsed = false;
     let testFileContent = readFile(testFile);
@@ -397,18 +393,36 @@ async function runChecks(testFile, doSearch, parseQuery, getCorrections) {
     let res = 0;
 
     if (checkExpected) {
-        res += await runCheck(loadedFile, "EXPECTED", getCorrections, (query, expected, text) => {
+        res += await runCheck(loadedFile, "EXPECTED", doSearch, (query, expected, text) => {
             return runSearch(query, expected, doSearch, loadedFile, text);
         });
     }
     if (checkParsed) {
-        res += await runCheck(loadedFile, "PARSED", getCorrections, (query, expected, text) => {
+        res += await runCheck(loadedFile, "PARSED", doSearch, (query, expected, text) => {
             return runParser(query, expected, parseQuery, text);
         });
     }
     return res;
 }
 
+function mostRecentMatch(staticFiles, regex) {
+    const matchingEntries = fs.readdirSync(staticFiles)
+        .filter(f => f.match(regex))
+        .map(f => {
+            const stats = fs.statSync(path.join(staticFiles, f));
+            return {
+                path: f,
+                time: stats.mtimeMs,
+            };
+        });
+    if (matchingEntries.length === 0) {
+        throw "No static file matching regex";
+    }
+    // We sort entries in descending order.
+    matchingEntries.sort((a, b) => b.time - a.time);
+    return matchingEntries[0].path;
+}
+
 /**
  * Load searchNNN.js and search-indexNNN.js.
  *
@@ -416,71 +430,89 @@ async function runChecks(testFile, doSearch, parseQuery, getCorrections) {
  * @param {string} resource_suffix - Version number between filename and .js, e.g. "1.59.0"
  * @returns {Object}               - Object containing keys: `doSearch`, which runs a search
  *   with the loaded index and returns a table of results; `parseQuery`, which is the
- *   `parseQuery` function exported from the search module; and `getCorrections`, which runs
+ *   `parseQuery` function exported from the search module, which runs
  *   a search but returns type name corrections instead of results.
  */
-function loadSearchJS(doc_folder, resource_suffix) {
-    const searchIndexJs = path.join(doc_folder, "search-index" + resource_suffix + ".js");
-    const searchIndex = require(searchIndexJs);
-
-    globalThis.searchState = {
-        descShards: new Map(),
-        loadDesc: async function({descShard, descIndex}) {
-            if (descShard.promise === null) {
-                descShard.promise = new Promise((resolve, reject) => {
-                    descShard.resolve = resolve;
-                    const ds = descShard;
-                    const fname = `${ds.crate}-desc-${ds.shard}-${resource_suffix}.js`;
-                    fs.readFile(
-                        `${doc_folder}/search.desc/${descShard.crate}/${fname}`,
-                        (err, data) => {
-                            if (err) {
-                                reject(err);
-                            } else {
-                                eval(data.toString("utf8"));
-                            }
-                        },
-                    );
-                });
-            }
-            const list = await descShard.promise;
-            return list[descIndex];
-        },
-        loadedDescShard: function(crate, shard, data) {
-            this.descShards.get(crate)[shard].resolve(data.split("\n"));
-        },
-    };
-
+async function loadSearchJS(doc_folder, resource_suffix) {
     const staticFiles = path.join(doc_folder, "static.files");
-    const searchJs = fs.readdirSync(staticFiles).find(f => f.match(/search.*\.js$/));
+    const stringdexJs = mostRecentMatch(staticFiles, /stringdex.*\.js$/);
+    const stringdexModule = require(path.join(staticFiles, stringdexJs));
+    const searchJs = mostRecentMatch(staticFiles, /search-[0-9a-f]{8}.*\.js$/);
     const searchModule = require(path.join(staticFiles, searchJs));
-    searchModule.initSearch(searchIndex.searchIndex);
-    const docSearch = searchModule.docSearch;
+    globalThis.nonnull = (x, msg) => {
+        if (x === null) {
+            throw (msg || "unexpected null value!");
+        } else {
+            return x;
+        }
+    };
+    const { docSearch, DocSearch } = await searchModule.initSearch(
+        stringdexModule.Stringdex,
+        stringdexModule.RoaringBitmap,
+        {
+            loadRoot: callbacks => {
+                for (const key in callbacks) {
+                    if (Object.hasOwn(callbacks, key)) {
+                        globalThis[key] = callbacks[key];
+                    }
+                }
+                const rootJs = readFile(path.join(doc_folder, "search.index/root" +
+                    resource_suffix + ".js"));
+                eval(rootJs);
+            },
+            loadTreeByHash: hashHex => {
+                const shardJs = readFile(path.join(doc_folder, "search.index/" + hashHex + ".js"));
+                eval(shardJs);
+            },
+            loadDataByNameAndHash: (name, hashHex) => {
+                const shardJs = readFile(path.join(doc_folder, "search.index/" + name + "/" +
+                    hashHex + ".js"));
+                eval(shardJs);
+            },
+        },
+    );
     return {
         doSearch: async function(queryStr, filterCrate, currentCrate) {
-            const result = await docSearch.execQuery(searchModule.parseQuery(queryStr),
-                filterCrate, currentCrate);
+            const parsedQuery = DocSearch.parseQuery(queryStr);
+            const result = await docSearch.execQuery(parsedQuery, filterCrate, currentCrate);
+            const resultsTable = {};
             for (const tab in result) {
                 if (!Object.prototype.hasOwnProperty.call(result, tab)) {
                     continue;
                 }
-                if (!(result[tab] instanceof Array)) {
+                if (!isGeneratorObject(result[tab])) {
                     continue;
                 }
-                for (const entry of result[tab]) {
+                resultsTable[tab] = [];
+                for await (const entry of result[tab]) {
+                    const flatEntry = Object.assign({
+                        crate: entry.item.crate,
+                        name: entry.item.name,
+                        path: entry.item.modulePath,
+                        exactPath: entry.item.exactModulePath,
+                        ty: entry.item.ty,
+                    }, entry);
                     for (const key in entry) {
                         if (!Object.prototype.hasOwnProperty.call(entry, key)) {
                             continue;
                         }
-                        if (key === "displayTypeSignature" && entry.displayTypeSignature !== null) {
-                            const {type, mappedNames, whereClause} =
-                                await entry.displayTypeSignature;
-                            entry.displayType = arrayToCode(type);
-                            entry.displayMappedNames = [...mappedNames.entries()]
+                        if (key === "desc" && entry.desc !== null) {
+                            flatEntry.desc = await entry.desc;
+                        } else if (key === "displayTypeSignature" &&
+                            entry.displayTypeSignature !== null
+                        ) {
+                            flatEntry.displayTypeSignature = await entry.displayTypeSignature;
+                            const {
+                                type,
+                                mappedNames,
+                                whereClause,
+                            } = flatEntry.displayTypeSignature;
+                            flatEntry.displayType = arrayToCode(type);
+                            flatEntry.displayMappedNames = [...mappedNames.entries()]
                                 .map(([name, qname]) => {
                                     return `${name} = ${qname}`;
                                 }).join(", ");
-                            entry.displayWhereClause = [...whereClause.entries()]
+                            flatEntry.displayWhereClause = [...whereClause.entries()]
                                 .flatMap(([name, value]) => {
                                     if (value.length === 0) {
                                         return [];
@@ -489,16 +521,12 @@ function loadSearchJS(doc_folder, resource_suffix) {
                                 }).join(", ");
                         }
                     }
+                    resultsTable[tab].push(flatEntry);
                 }
             }
-            return result;
+            return { resultsTable, parsedQuery };
         },
-        getCorrections: function(queryStr, filterCrate, currentCrate) {
-            const parsedQuery = searchModule.parseQuery(queryStr);
-            docSearch.execQuery(parsedQuery, filterCrate, currentCrate);
-            return parsedQuery.correction;
-        },
-        parseQuery: searchModule.parseQuery,
+        parseQuery: DocSearch.parseQuery,
     };
 }
 
@@ -570,7 +598,7 @@ async function main(argv) {
         return 1;
     }
 
-    const parseAndSearch = loadSearchJS(
+    const parseAndSearch = await loadSearchJS(
         opts["doc_folder"],
         opts["resource_suffix"],
     );
@@ -579,14 +607,11 @@ async function main(argv) {
     const doSearch = function(queryStr, filterCrate) {
         return parseAndSearch.doSearch(queryStr, filterCrate, opts["crate_name"]);
     };
-    const getCorrections = function(queryStr, filterCrate) {
-        return parseAndSearch.getCorrections(queryStr, filterCrate, opts["crate_name"]);
-    };
 
     if (opts["test_file"].length !== 0) {
         for (const file of opts["test_file"]) {
             process.stdout.write(`Testing ${file} ... `);
-            errors += await runChecks(file, doSearch, parseAndSearch.parseQuery, getCorrections);
+            errors += await runChecks(file, doSearch, parseAndSearch.parseQuery);
         }
     } else if (opts["test_folder"].length !== 0) {
         for (const file of fs.readdirSync(opts["test_folder"])) {
@@ -595,7 +620,7 @@ async function main(argv) {
             }
             process.stdout.write(`Testing ${file} ... `);
             errors += await runChecks(path.join(opts["test_folder"], file), doSearch,
-                    parseAndSearch.parseQuery, getCorrections);
+                    parseAndSearch.parseQuery);
         }
     }
     return errors > 0 ? 1 : 0;
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 10df6f96702..6555679c394 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -3600,7 +3600,7 @@ pub(crate) fn rewrite_extern_crate(
 pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
     !matches!(
         item.kind,
-        ast::ItemKind::Mod(_, _, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _))
+        ast::ItemKind::Mod(_, _, ast::ModKind::Loaded(_, ast::Inline::Yes, _))
     )
 }
 
diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs
index 3bc656b64b3..af9feccb32e 100644
--- a/src/tools/rustfmt/src/modules.rs
+++ b/src/tools/rustfmt/src/modules.rs
@@ -316,11 +316,12 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> {
             self.directory = directory;
         }
         match (sub_mod.ast_mod_kind, sub_mod.items) {
-            (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _, _))), _) => {
+            (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => {
                 self.visit_mod_from_ast(items)
             }
-            (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _, _))), _)
-            | (_, Cow::Owned(items)) => self.visit_mod_outside_ast(items),
+            (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => {
+                self.visit_mod_outside_ast(items)
+            }
             (_, _) => Ok(()),
         }
     }
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 23d07c930d9..a3acbb218ff 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -942,7 +942,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
         let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
         self.push_str(&ident_str);
 
-        if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans, _) = mod_kind {
+        if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans) = mod_kind {
             let ast::ModSpans {
                 inner_span,
                 inject_use_span: _,
diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs
index f90f716cd95..31169ec5967 100644
--- a/src/tools/tidy/src/extra_checks/mod.rs
+++ b/src/tools/tidy/src/extra_checks/mod.rs
@@ -41,7 +41,6 @@ const RUFF_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "ruff.toml
 const RUFF_CACHE_PATH: &[&str] = &["cache", "ruff_cache"];
 const PIP_REQ_PATH: &[&str] = &["src", "tools", "tidy", "config", "requirements.txt"];
 
-// this must be kept in sync with with .github/workflows/spellcheck.yml
 const SPELLCHECK_DIRS: &[&str] = &["compiler", "library", "src/bootstrap", "src/librustdoc"];
 
 pub fn check(
@@ -51,6 +50,7 @@ pub fn check(
     librustdoc_path: &Path,
     tools_path: &Path,
     npm: &Path,
+    cargo: &Path,
     bless: bool,
     extra_checks: Option<&str>,
     pos_args: &[String],
@@ -63,6 +63,7 @@ pub fn check(
         librustdoc_path,
         tools_path,
         npm,
+        cargo,
         bless,
         extra_checks,
         pos_args,
@@ -78,6 +79,7 @@ fn check_impl(
     librustdoc_path: &Path,
     tools_path: &Path,
     npm: &Path,
+    cargo: &Path,
     bless: bool,
     extra_checks: Option<&str>,
     pos_args: &[String],
@@ -293,7 +295,7 @@ fn check_impl(
         } else {
             eprintln!("spellcheck files");
         }
-        spellcheck_runner(&args)?;
+        spellcheck_runner(root_path, &outdir, &cargo, &args)?;
     }
 
     if js_lint || js_typecheck {
@@ -576,34 +578,25 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> {
     if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) }
 }
 
-/// Check that spellchecker is installed then run it at the given path
-fn spellcheck_runner(args: &[&str]) -> Result<(), Error> {
-    // sync version with .github/workflows/spellcheck.yml
-    let expected_version = "typos-cli 1.34.0";
-    match Command::new("typos").arg("--version").output() {
-        Ok(o) => {
-            let stdout = String::from_utf8_lossy(&o.stdout);
-            if stdout.trim() != expected_version {
-                return Err(Error::Version {
-                    program: "typos",
-                    required: expected_version,
-                    installed: stdout.trim().to_string(),
-                });
+/// Ensure that spellchecker is installed then run it at the given path
+fn spellcheck_runner(
+    src_root: &Path,
+    outdir: &Path,
+    cargo: &Path,
+    args: &[&str],
+) -> Result<(), Error> {
+    let bin_path =
+        crate::ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", "1.34.0")?;
+    match Command::new(bin_path).current_dir(src_root).args(args).status() {
+        Ok(status) => {
+            if status.success() {
+                Ok(())
+            } else {
+                Err(Error::FailedCheck("typos"))
             }
         }
-        Err(e) if e.kind() == io::ErrorKind::NotFound => {
-            return Err(Error::MissingReq(
-                "typos",
-                "spellcheck file checks",
-                // sync version with .github/workflows/spellcheck.yml
-                Some("install tool via `cargo install typos-cli@1.34.0`".to_owned()),
-            ));
-        }
-        Err(e) => return Err(e.into()),
+        Err(err) => Err(Error::Generic(format!("failed to run typos tool: {err:?}"))),
     }
-
-    let status = Command::new("typos").args(args).status()?;
-    if status.success() { Ok(()) } else { Err(Error::FailedCheck("typos")) }
 }
 
 /// Check git for tracked files matching an extension
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 4ea9d051ddb..37713cbf75e 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -4,7 +4,9 @@
 //! to be used by tools.
 
 use std::ffi::OsStr;
+use std::path::{Path, PathBuf};
 use std::process::Command;
+use std::{env, io};
 
 use build_helper::ci::CiEnv;
 use build_helper::git::{GitConfig, get_closest_upstream_commit};
@@ -180,6 +182,70 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool {
     !v.is_empty()
 }
 
+/// If the given executable is installed with the given version, use that,
+/// otherwise install via cargo.
+pub fn ensure_version_or_cargo_install(
+    build_dir: &Path,
+    cargo: &Path,
+    pkg_name: &str,
+    bin_name: &str,
+    version: &str,
+) -> io::Result<PathBuf> {
+    // ignore the process exit code here and instead just let the version number check fail.
+    // we also importantly don't return if the program wasn't installed,
+    // instead we want to continue to the fallback.
+    'ck: {
+        // FIXME: rewrite as if-let chain once this crate is 2024 edition.
+        let Ok(output) = Command::new(bin_name).arg("--version").output() else {
+            break 'ck;
+        };
+        let Ok(s) = str::from_utf8(&output.stdout) else {
+            break 'ck;
+        };
+        let Some(v) = s.trim().split_whitespace().last() else {
+            break 'ck;
+        };
+        if v == version {
+            return Ok(PathBuf::from(bin_name));
+        }
+    }
+
+    let tool_root_dir = build_dir.join("misc-tools");
+    let tool_bin_dir = tool_root_dir.join("bin");
+    eprintln!("building external tool {bin_name} from package {pkg_name}@{version}");
+    // use --force to ensure that if the required version is bumped, we update it.
+    // use --target-dir to ensure we have a build cache so repeated invocations aren't slow.
+    // modify PATH so that cargo doesn't print a warning telling the user to modify the path.
+    let cargo_exit_code = Command::new(cargo)
+        .args(["install", "--locked", "--force", "--quiet"])
+        .arg("--root")
+        .arg(&tool_root_dir)
+        .arg("--target-dir")
+        .arg(tool_root_dir.join("target"))
+        .arg(format!("{pkg_name}@{version}"))
+        .env(
+            "PATH",
+            env::join_paths(
+                env::split_paths(&env::var("PATH").unwrap())
+                    .chain(std::iter::once(tool_bin_dir.clone())),
+            )
+            .expect("build dir contains invalid char"),
+        )
+        .env("RUSTFLAGS", "-Copt-level=0")
+        .spawn()?
+        .wait()?;
+    if !cargo_exit_code.success() {
+        return Err(io::Error::other("cargo install failed"));
+    }
+    let bin_path = tool_bin_dir.join(bin_name);
+    assert!(
+        matches!(bin_path.try_exists(), Ok(true)),
+        "cargo install did not produce the expected binary"
+    );
+    eprintln!("finished building tool {bin_name}");
+    Ok(bin_path)
+}
+
 pub mod alphabetical;
 pub mod bins;
 pub mod debug_artifacts;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index cd2567ddb64..bfe30258915 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -184,6 +184,7 @@ fn main() {
             &librustdoc_path,
             &tools_path,
             &npm,
+            &cargo,
             bless,
             extra_checks,
             pos_args
diff --git a/tests/assembly-llvm/regparm-module-flag.rs b/tests/assembly-llvm/regparm-module-flag.rs
new file mode 100644
index 00000000000..67ef44285ea
--- /dev/null
+++ b/tests/assembly-llvm/regparm-module-flag.rs
@@ -0,0 +1,70 @@
+// Test the regparm ABI with builtin and non-builtin calls
+// Issue: https://github.com/rust-lang/rust/issues/145271
+//@ add-core-stubs
+//@ assembly-output: emit-asm
+//@ compile-flags: -O --target=i686-unknown-linux-gnu -Crelocation-model=static
+//@ revisions: REGPARM1 REGPARM2 REGPARM3
+//@[REGPARM1] compile-flags: -Zregparm=1
+//@[REGPARM2] compile-flags: -Zregparm=2
+//@[REGPARM3] compile-flags: -Zregparm=3
+//@ needs-llvm-components: x86
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+unsafe extern "C" {
+    fn memset(p: *mut c_void, val: i32, len: usize) -> *mut c_void;
+    fn non_builtin_memset(p: *mut c_void, val: i32, len: usize) -> *mut c_void;
+}
+
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn entrypoint(len: usize, ptr: *mut c_void, val: i32) -> *mut c_void {
+    // REGPARM1-LABEL: entrypoint
+    // REGPARM1: movl %e{{.*}}, %ecx
+    // REGPARM1: pushl
+    // REGPARM1: pushl
+    // REGPARM1: calll memset
+
+    // REGPARM2-LABEL: entrypoint
+    // REGPARM2: movl 16(%esp), %edx
+    // REGPARM2: movl %e{{.*}}, (%esp)
+    // REGPARM2: movl %e{{.*}}, %eax
+    // REGPARM2: calll memset
+
+    // REGPARM3-LABEL: entrypoint
+    // REGPARM3: movl %e{{.*}}, %esi
+    // REGPARM3: movl %e{{.*}}, %eax
+    // REGPARM3: movl %e{{.*}}, %ecx
+    // REGPARM3: jmp memset
+    unsafe { memset(ptr, val, len) }
+}
+
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn non_builtin_entrypoint(
+    len: usize,
+    ptr: *mut c_void,
+    val: i32,
+) -> *mut c_void {
+    // REGPARM1-LABEL: non_builtin_entrypoint
+    // REGPARM1: movl %e{{.*}}, %ecx
+    // REGPARM1: pushl
+    // REGPARM1: pushl
+    // REGPARM1: calll non_builtin_memset
+
+    // REGPARM2-LABEL: non_builtin_entrypoint
+    // REGPARM2: movl 16(%esp), %edx
+    // REGPARM2: movl %e{{.*}}, (%esp)
+    // REGPARM2: movl %e{{.*}}, %eax
+    // REGPARM2: calll non_builtin_memset
+
+    // REGPARM3-LABEL: non_builtin_entrypoint
+    // REGPARM3: movl %e{{.*}}, %esi
+    // REGPARM3: movl %e{{.*}}, %eax
+    // REGPARM3: movl %e{{.*}}, %ecx
+    // REGPARM3: jmp non_builtin_memset
+    unsafe { non_builtin_memset(ptr, val, len) }
+}
diff --git a/tests/assembly-llvm/x86_64-indirect-branch-cs-prefix.rs b/tests/assembly-llvm/x86_64-indirect-branch-cs-prefix.rs
new file mode 100644
index 00000000000..8e4470ee451
--- /dev/null
+++ b/tests/assembly-llvm/x86_64-indirect-branch-cs-prefix.rs
@@ -0,0 +1,27 @@
+// Test that the `cs` prefix is (not) added into a `call` and a `jmp` to the
+// indirect thunk when the `-Zindirect-branch-cs-prefix` flag is (not) set.
+
+//@ revisions: unset set
+//@ assembly-output: emit-asm
+//@ compile-flags: -Copt-level=3 -Cunsafe-allow-abi-mismatch=retpoline,retpoline-external-thunk,indirect-branch-cs-prefix -Zretpoline-external-thunk
+//@ [set] compile-flags: -Zindirect-branch-cs-prefix
+//@ only-x86_64
+//@ ignore-apple Symbol is called `___x86_indirect_thunk` (Darwin's extra underscore)
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: foo:
+#[no_mangle]
+pub fn foo(g: fn()) {
+    // unset-NOT: cs
+    // unset: callq {{__x86_indirect_thunk.*}}
+    // set: cs
+    // set-NEXT: callq {{__x86_indirect_thunk.*}}
+    g();
+
+    // unset-NOT: cs
+    // unset: jmp {{__x86_indirect_thunk.*}}
+    // set: cs
+    // set-NEXT: jmp {{__x86_indirect_thunk.*}}
+    g();
+}
diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs
index 47dadd51ce0..da880100a10 100644
--- a/tests/auxiliary/minicore.rs
+++ b/tests/auxiliary/minicore.rs
@@ -225,3 +225,10 @@ pub mod mem {
     #[rustc_intrinsic]
     pub unsafe fn transmute<Src, Dst>(src: Src) -> Dst;
 }
+
+#[lang = "c_void"]
+#[repr(u8)]
+pub enum c_void {
+    __variant1,
+    __variant2,
+}
diff --git a/tests/codegen-llvm/enum/enum-aggregate.rs b/tests/codegen-llvm/enum/enum-aggregate.rs
index 0161e5f3fa1..f58d7ef12b6 100644
--- a/tests/codegen-llvm/enum/enum-aggregate.rs
+++ b/tests/codegen-llvm/enum/enum-aggregate.rs
@@ -27,7 +27,7 @@ fn make_none_bool() -> Option<bool> {
 
 #[no_mangle]
 fn make_some_ordering(x: Ordering) -> Option<Ordering> {
-    // CHECK-LABEL: i8 @make_some_ordering(i8 %x)
+    // CHECK-LABEL: i8 @make_some_ordering(i8{{( signext)?}} %x)
     // CHECK-NEXT: start:
     // CHECK-NEXT: ret i8 %x
     Some(x)
@@ -35,7 +35,7 @@ fn make_some_ordering(x: Ordering) -> Option<Ordering> {
 
 #[no_mangle]
 fn make_some_u16(x: u16) -> Option<u16> {
-    // CHECK-LABEL: { i16, i16 } @make_some_u16(i16 %x)
+    // CHECK-LABEL: { i16, i16 } @make_some_u16(i16{{( zeroext)?}} %x)
     // CHECK-NEXT: start:
     // CHECK-NEXT: %0 = insertvalue { i16, i16 } { i16 1, i16 poison }, i16 %x, 1
     // CHECK-NEXT: ret { i16, i16 } %0
@@ -52,7 +52,7 @@ fn make_none_u16() -> Option<u16> {
 
 #[no_mangle]
 fn make_some_nzu32(x: NonZero<u32>) -> Option<NonZero<u32>> {
-    // CHECK-LABEL: i32 @make_some_nzu32(i32 %x)
+    // CHECK-LABEL: i32 @make_some_nzu32(i32{{( signext)?}} %x)
     // CHECK-NEXT: start:
     // CHECK-NEXT: ret i32 %x
     Some(x)
@@ -114,7 +114,7 @@ fn make_uninhabited_err_indirectly(n: Never) -> Result<u32, Never> {
 fn make_fully_uninhabited_result(v: u32, n: Never) -> Result<(u32, Never), (Never, u32)> {
     // Actually reaching this would be UB, so we don't actually build a result.
 
-    // CHECK-LABEL: { i32, i32 } @make_fully_uninhabited_result(i32 %v)
+    // CHECK-LABEL: { i32, i32 } @make_fully_uninhabited_result(i32{{( signext)?}} %v)
     // CHECK-NEXT: start:
     // CHECK-NEXT: call void @llvm.trap()
     // CHECK-NEXT: call void @llvm.trap()
diff --git a/tests/codegen-llvm/enum/enum-match.rs b/tests/codegen-llvm/enum/enum-match.rs
index 091c4e9adf4..20e2006e3eb 100644
--- a/tests/codegen-llvm/enum/enum-match.rs
+++ b/tests/codegen-llvm/enum/enum-match.rs
@@ -739,7 +739,7 @@ pub enum Tricky {
 
 const _: () = assert!(std::intrinsics::discriminant_value(&Tricky::V100) == 100);
 
-// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @discriminant6(i8 noundef %e)
+// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @discriminant6(i8 noundef{{( zeroext)?}} %e)
 // CHECK-NEXT: start:
 // CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %e, -66
 // CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], -56
diff --git a/tests/codegen-llvm/enum/enum-transparent-extract.rs b/tests/codegen-llvm/enum/enum-transparent-extract.rs
index c5efb8d472b..1435e6ec802 100644
--- a/tests/codegen-llvm/enum/enum-transparent-extract.rs
+++ b/tests/codegen-llvm/enum/enum-transparent-extract.rs
@@ -9,7 +9,7 @@ pub enum Never {}
 
 #[no_mangle]
 pub fn make_unmake_result_never(x: i32) -> i32 {
-    // CHECK-LABEL: define i32 @make_unmake_result_never(i32 %x)
+    // CHECK-LABEL: define i32 @make_unmake_result_never(i32{{( signext)?}} %x)
     // CHECK: start:
     // CHECK-NEXT: ret i32 %x
 
diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs
index a3fafbe6f82..db508682862 100644
--- a/tests/codegen-llvm/function-arguments.rs
+++ b/tests/codegen-llvm/function-arguments.rs
@@ -80,7 +80,7 @@ pub fn option_nonzero_int(x: Option<NonZero<u64>>) -> Option<NonZero<u64>> {
     x
 }
 
-// CHECK: @readonly_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
+// CHECK: @readonly_borrow(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn readonly_borrow(_: &i32) {}
@@ -91,12 +91,12 @@ pub fn readonly_borrow_ret() -> &'static i32 {
     loop {}
 }
 
-// CHECK: @static_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
+// CHECK: @static_borrow(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1)
 // static borrow may be captured
 #[no_mangle]
 pub fn static_borrow(_: &'static i32) {}
 
-// CHECK: @named_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
+// CHECK: @named_borrow(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1)
 // borrow with named lifetime may be captured
 #[no_mangle]
 pub fn named_borrow<'r>(_: &'r i32) {}
@@ -129,7 +129,7 @@ pub fn mutable_borrow_ret() -> &'static mut i32 {
 // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>.
 pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {}
 
-// CHECK: @notunpin_borrow(ptr noalias noundef readonly align 4 dereferenceable(4) %_1)
+// CHECK: @notunpin_borrow(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1)
 // But `&NotUnpin` behaves perfectly normal.
 #[no_mangle]
 pub fn notunpin_borrow(_: &NotUnpin) {}
@@ -138,12 +138,12 @@ pub fn notunpin_borrow(_: &NotUnpin) {}
 #[no_mangle]
 pub fn indirect_struct(_: S) {}
 
-// CHECK: @borrowed_struct(ptr noalias noundef readonly align 4 dereferenceable(32) %_1)
+// CHECK: @borrowed_struct(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(32) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn borrowed_struct(_: &S) {}
 
-// CHECK: @option_borrow(ptr noalias noundef readonly align 4 dereferenceable_or_null(4) %_x)
+// CHECK: @option_borrow(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable_or_null(4) %_x)
 #[no_mangle]
 pub fn option_borrow(_x: Option<&i32>) {}
 
@@ -185,7 +185,7 @@ pub fn _box(x: Box<i32>) -> Box<i32> {
 // With a custom allocator, it should *not* have `noalias`. (See
 // <https://github.com/rust-lang/miri/issues/3341> for why.) The second argument is the allocator,
 // which is a reference here that still carries `noalias` as usual.
-// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly align 1 %x.1)
+// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %x.1)
 #[no_mangle]
 pub fn _box_custom(x: Box<i32, &std::alloc::Global>) {
     drop(x)
@@ -208,7 +208,7 @@ pub fn struct_return() -> S {
 #[no_mangle]
 pub fn helper(_: usize) {}
 
-// CHECK: @slice(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
+// CHECK: @slice(ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0, [[USIZE]] noundef %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn slice(_: &[u8]) {}
@@ -227,7 +227,7 @@ pub fn unsafe_slice(_: &[UnsafeInner]) {}
 #[no_mangle]
 pub fn raw_slice(_: *const [u8]) {}
 
-// CHECK: @str(ptr noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] noundef %_1.1)
+// CHECK: @str(ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0, [[USIZE]] noundef %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn str(_: &[u8]) {}
@@ -259,7 +259,7 @@ pub fn trait_option(x: Option<Box<dyn Drop + Unpin>>) -> Option<Box<dyn Drop + U
     x
 }
 
-// CHECK: { ptr, [[USIZE]] } @return_slice(ptr noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] noundef %x.1)
+// CHECK: { ptr, [[USIZE]] } @return_slice(ptr noalias noundef nonnull readonly align 2{{( captures\(address, read_provenance\))?}} %x.0, [[USIZE]] noundef %x.1)
 #[no_mangle]
 pub fn return_slice(x: &[u16]) -> &[u16] {
     x
diff --git a/tests/codegen-llvm/indirect-branch-cs-prefix.rs b/tests/codegen-llvm/indirect-branch-cs-prefix.rs
new file mode 100644
index 00000000000..df25008d5f0
--- /dev/null
+++ b/tests/codegen-llvm/indirect-branch-cs-prefix.rs
@@ -0,0 +1,18 @@
+// Test that the `indirect_branch_cs_prefix` module attribute is (not)
+// emitted when the `-Zindirect-branch-cs-prefix` flag is (not) set.
+
+//@ add-core-stubs
+//@ revisions: unset set
+//@ needs-llvm-components: x86
+//@ compile-flags: --target x86_64-unknown-linux-gnu
+//@ [set] compile-flags: -Zindirect-branch-cs-prefix
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// unset-NOT: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1}
+// set: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1}
diff --git a/tests/codegen-llvm/intrinsics/prefetch.rs b/tests/codegen-llvm/intrinsics/prefetch.rs
index 3f9f21c85cb..41877872019 100644
--- a/tests/codegen-llvm/intrinsics/prefetch.rs
+++ b/tests/codegen-llvm/intrinsics/prefetch.rs
@@ -9,56 +9,48 @@ use std::intrinsics::{
 
 #[no_mangle]
 pub fn check_prefetch_read_data(data: &[i8]) {
-    unsafe {
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 1)
-        prefetch_read_data(data.as_ptr(), 0);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 1)
-        prefetch_read_data(data.as_ptr(), 1);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 1)
-        prefetch_read_data(data.as_ptr(), 2);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 1)
-        prefetch_read_data(data.as_ptr(), 3);
-    }
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 1)
+    prefetch_read_data::<_, 0>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 1)
+    prefetch_read_data::<_, 1>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 1)
+    prefetch_read_data::<_, 2>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 1)
+    prefetch_read_data::<_, 3>(data.as_ptr());
 }
 
 #[no_mangle]
 pub fn check_prefetch_write_data(data: &[i8]) {
-    unsafe {
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 1)
-        prefetch_write_data(data.as_ptr(), 0);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 1)
-        prefetch_write_data(data.as_ptr(), 1);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 1)
-        prefetch_write_data(data.as_ptr(), 2);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 1)
-        prefetch_write_data(data.as_ptr(), 3);
-    }
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 1)
+    prefetch_write_data::<_, 0>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 1)
+    prefetch_write_data::<_, 1>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 1)
+    prefetch_write_data::<_, 2>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 1)
+    prefetch_write_data::<_, 3>(data.as_ptr());
 }
 
 #[no_mangle]
 pub fn check_prefetch_read_instruction(data: &[i8]) {
-    unsafe {
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 0)
-        prefetch_read_instruction(data.as_ptr(), 0);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 0)
-        prefetch_read_instruction(data.as_ptr(), 1);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 0)
-        prefetch_read_instruction(data.as_ptr(), 2);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 0)
-        prefetch_read_instruction(data.as_ptr(), 3);
-    }
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 0, i32 0)
+    prefetch_read_instruction::<_, 0>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 1, i32 0)
+    prefetch_read_instruction::<_, 1>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 2, i32 0)
+    prefetch_read_instruction::<_, 2>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 0, i32 3, i32 0)
+    prefetch_read_instruction::<_, 3>(data.as_ptr());
 }
 
 #[no_mangle]
 pub fn check_prefetch_write_instruction(data: &[i8]) {
-    unsafe {
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 0)
-        prefetch_write_instruction(data.as_ptr(), 0);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 0)
-        prefetch_write_instruction(data.as_ptr(), 1);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 0)
-        prefetch_write_instruction(data.as_ptr(), 2);
-        // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 0)
-        prefetch_write_instruction(data.as_ptr(), 3);
-    }
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 0, i32 0)
+    prefetch_write_instruction::<_, 0>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 1, i32 0)
+    prefetch_write_instruction::<_, 1>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 2, i32 0)
+    prefetch_write_instruction::<_, 2>(data.as_ptr());
+    // CHECK: call void @llvm.prefetch{{.*}}({{.*}}, i32 1, i32 3, i32 0)
+    prefetch_write_instruction::<_, 3>(data.as_ptr());
 }
diff --git a/tests/codegen-llvm/issues/issue-122734-match-eq.rs b/tests/codegen-llvm/issues/issue-122734-match-eq.rs
new file mode 100644
index 00000000000..89858972677
--- /dev/null
+++ b/tests/codegen-llvm/issues/issue-122734-match-eq.rs
@@ -0,0 +1,78 @@
+//@ min-llvm-version: 21
+//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled
+//! Tests that matching + eq on `Option<FieldlessEnum>` produces a simple compare with no branching
+
+#![crate_type = "lib"]
+
+#[derive(PartialEq)]
+pub enum TwoNum {
+    A,
+    B,
+}
+
+#[derive(PartialEq)]
+pub enum ThreeNum {
+    A,
+    B,
+    C,
+}
+
+// CHECK-LABEL: @match_two
+#[no_mangle]
+pub fn match_two(a: Option<TwoNum>, b: Option<TwoNum>) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: icmp eq i8
+    // CHECK-NEXT: ret
+    match (a, b) {
+        (Some(x), Some(y)) => x == y,
+        (Some(_), None) => false,
+        (None, Some(_)) => false,
+        (None, None) => true,
+    }
+}
+
+// CHECK-LABEL: @match_three
+#[no_mangle]
+pub fn match_three(a: Option<ThreeNum>, b: Option<ThreeNum>) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: icmp eq
+    // CHECK-NEXT: ret
+    match (a, b) {
+        (Some(x), Some(y)) => x == y,
+        (Some(_), None) => false,
+        (None, Some(_)) => false,
+        (None, None) => true,
+    }
+}
+
+// CHECK-LABEL: @match_two_ref
+#[no_mangle]
+pub fn match_two_ref(a: &Option<TwoNum>, b: &Option<TwoNum>) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: load i8
+    // CHECK-NEXT: load i8
+    // CHECK-NEXT: icmp eq i8
+    // CHECK-NEXT: ret
+    match (a, b) {
+        (Some(x), Some(y)) => x == y,
+        (Some(_), None) => false,
+        (None, Some(_)) => false,
+        (None, None) => true,
+    }
+}
+
+// CHECK-LABEL: @match_three_ref
+#[no_mangle]
+pub fn match_three_ref(a: &Option<ThreeNum>, b: &Option<ThreeNum>) -> bool {
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: load i8
+    // CHECK-NEXT: load i8
+    // CHECK-NEXT: icmp eq
+    // CHECK-NEXT: ret
+    match (a, b) {
+        (Some(x), Some(y)) => x == y,
+        (Some(_), None) => false,
+        (None, Some(_)) => false,
+        (None, None) => true,
+    }
+}
diff --git a/tests/codegen-llvm/range-attribute.rs b/tests/codegen-llvm/range-attribute.rs
index b81ff9ab3e2..865d36d4747 100644
--- a/tests/codegen-llvm/range-attribute.rs
+++ b/tests/codegen-llvm/range-attribute.rs
@@ -67,7 +67,7 @@ pub fn enum2_value(x: Enum2) -> Enum2 {
     x
 }
 
-// CHECK: noundef [[USIZE]] @takes_slice(ptr noalias noundef nonnull readonly align 4 %x.0, [[USIZE]] noundef %x.1)
+// CHECK: noundef [[USIZE]] @takes_slice(ptr {{.*}} %x.0, [[USIZE]] noundef %x.1)
 #[no_mangle]
 pub fn takes_slice(x: &[i32]) -> usize {
     x.len()
diff --git a/tests/codegen-llvm/read-only-capture-opt.rs b/tests/codegen-llvm/read-only-capture-opt.rs
new file mode 100644
index 00000000000..78d56f8efc2
--- /dev/null
+++ b/tests/codegen-llvm/read-only-capture-opt.rs
@@ -0,0 +1,18 @@
+//@ compile-flags: -C opt-level=3 -Z mir-opt-level=0
+//@ min-llvm-version: 21
+
+#![crate_type = "lib"]
+
+unsafe extern "C" {
+    safe fn do_something(p: &i32);
+}
+
+#[unsafe(no_mangle)]
+pub fn test() -> i32 {
+    // CHECK-LABEL: @test(
+    // CHECK: ret i32 0
+    let i = 0;
+    do_something(&i);
+    do_something(&i);
+    i
+}
diff --git a/tests/codegen-llvm/repeat-operand-zero-len.rs b/tests/codegen-llvm/repeat-operand-zero-len.rs
index b4cec42a07c..8d2a0e77d60 100644
--- a/tests/codegen-llvm/repeat-operand-zero-len.rs
+++ b/tests/codegen-llvm/repeat-operand-zero-len.rs
@@ -11,7 +11,7 @@
 #[repr(transparent)]
 pub struct Wrapper<T, const N: usize>([T; N]);
 
-// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x)
+// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef{{( signext)?}} %x)
 // CHECK-NEXT: start:
 // CHECK-NOT: alloca
 // CHECK-NEXT: ret void
@@ -23,6 +23,6 @@ pub fn do_repeat<T: Copy, const N: usize>(x: T) -> Wrapper<T, N> {
 // CHECK-LABEL: @trigger_repeat_zero_len
 #[no_mangle]
 pub fn trigger_repeat_zero_len() -> Wrapper<u32, 0> {
-    // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4)
+    // CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef{{( signext)?}} 4)
     do_repeat(4)
 }
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs
index 71ccdc8ca62..651afb33228 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs
@@ -4,11 +4,11 @@
 //@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0
 
 #![crate_type = "lib"]
-#![feature(no_sanitize)]
+#![feature(sanitize)]
 
-#[no_sanitize(cfi)]
+#[sanitize(cfi = "off")]
 pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
-    // CHECK-LABEL: emit_type_checks_attr_no_sanitize::foo
+    // CHECK-LABEL: emit_type_checks_attr_sanitize_off::foo
     // CHECK:       Function Attrs: {{.*}}
     // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
     // CHECK:       start:
diff --git a/tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs b/tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs
index 774c9ab53f1..c70aae1703e 100644
--- a/tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs
+++ b/tests/codegen-llvm/sanitizer/kasan-emits-instrumentation.rs
@@ -13,7 +13,7 @@
 //@[x86_64] needs-llvm-components: x86
 
 #![crate_type = "rlib"]
-#![feature(no_core, no_sanitize, lang_items)]
+#![feature(no_core, sanitize, lang_items)]
 #![no_core]
 
 extern crate minicore;
@@ -25,7 +25,7 @@ use minicore::*;
 // CHECK:       start:
 // CHECK-NOT:   call void @__asan_report_load
 // CHECK:       }
-#[no_sanitize(address)]
+#[sanitize(address = "off")]
 pub fn unsanitized(b: &mut u8) -> u8 {
     *b
 }
diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-sanitize-off.rs
index 02c31fb8e9b..2581784ce3e 100644
--- a/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-no-sanitize.rs
+++ b/tests/codegen-llvm/sanitizer/kcfi/emit-kcfi-operand-bundle-attr-sanitize-off.rs
@@ -9,15 +9,15 @@
 //@ compile-flags: -Cno-prepopulate-passes -Zsanitizer=kcfi -Copt-level=0
 
 #![crate_type = "lib"]
-#![feature(no_core, no_sanitize, lang_items)]
+#![feature(no_core, sanitize, lang_items)]
 #![no_core]
 
 extern crate minicore;
 use minicore::*;
 
-#[no_sanitize(kcfi)]
+#[sanitize(kcfi = "off")]
 pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
-    // CHECK-LABEL: emit_kcfi_operand_bundle_attr_no_sanitize::foo
+    // CHECK-LABEL: emit_kcfi_operand_bundle_attr_sanitize_off::foo
     // CHECK:       Function Attrs: {{.*}}
     // CHECK-LABEL: define{{.*}}foo{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
     // CHECK:       start:
diff --git a/tests/codegen-llvm/sanitizer/sanitize-off-asan-kasan.rs b/tests/codegen-llvm/sanitizer/sanitize-off-asan-kasan.rs
new file mode 100644
index 00000000000..37549aba447
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/sanitize-off-asan-kasan.rs
@@ -0,0 +1,42 @@
+// Verifies that the `#[sanitize(address = "off")]` attribute also turns off
+// the kernel address sanitizer.
+//
+//@ add-core-stubs
+//@ compile-flags: -Zsanitizer=kernel-address -Ctarget-feature=-crt-static -Copt-level=0
+//@ revisions: aarch64 riscv64imac riscv64gc x86_64
+//@[aarch64] compile-flags: --target aarch64-unknown-none
+//@[aarch64] needs-llvm-components: aarch64
+//@[riscv64imac] compile-flags: --target riscv64imac-unknown-none-elf
+//@[riscv64imac] needs-llvm-components: riscv
+//@[riscv64gc] compile-flags: --target riscv64gc-unknown-none-elf
+//@[riscv64gc] needs-llvm-components: riscv
+//@[x86_64] compile-flags: --target x86_64-unknown-none
+//@[x86_64] needs-llvm-components: x86
+
+#![crate_type = "rlib"]
+#![feature(no_core, sanitize, lang_items)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: ; sanitize_off_asan_kasan::unsanitized
+// CHECK-NEXT:  ; Function Attrs:
+// CHECK-NOT:   sanitize_address
+// CHECK:       start:
+// CHECK-NOT:   call void @__asan_report_load
+// CHECK:       }
+#[sanitize(address = "off")]
+pub fn unsanitized(b: &mut u8) -> u8 {
+    *b
+}
+
+// CHECK-LABEL: ; sanitize_off_asan_kasan::sanitized
+// CHECK-NEXT:  ; Function Attrs:
+// CHECK:       sanitize_address
+// CHECK:       start:
+// CHECK:       call void @__asan_report_load
+// CHECK:       }
+pub fn sanitized(b: &mut u8) -> u8 {
+    *b
+}
diff --git a/tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs b/tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs
index 4bd832d2ab1..69771827c3a 100644
--- a/tests/codegen-llvm/sanitizer/no-sanitize-inlining.rs
+++ b/tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs
@@ -1,4 +1,4 @@
-// Verifies that no_sanitize attribute prevents inlining when
+// Verifies that sanitize(xyz = "off") attribute prevents inlining when
 // given sanitizer is enabled, but has no effect on inlining otherwise.
 //
 //@ needs-sanitizer-address
@@ -9,7 +9,7 @@
 //@[LSAN] compile-flags: -Zsanitizer=leak
 
 #![crate_type = "lib"]
-#![feature(no_sanitize)]
+#![feature(sanitize)]
 
 // ASAN-LABEL: define void @test
 // ASAN:         call {{.*}} @random_inline
@@ -23,7 +23,7 @@ pub fn test(n: &mut u32) {
     random_inline(n);
 }
 
-#[no_sanitize(address)]
+#[sanitize(address = "off")]
 #[inline]
 #[no_mangle]
 pub fn random_inline(n: &mut u32) {
diff --git a/tests/codegen-llvm/sanitizer/no-sanitize.rs b/tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs
index 2a309f6b9c6..94945f2b2e6 100644
--- a/tests/codegen-llvm/sanitizer/no-sanitize.rs
+++ b/tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs
@@ -1,34 +1,24 @@
-// Verifies that no_sanitize attribute can be used to
-// selectively disable sanitizer instrumentation.
+// Verifies that the `#[sanitize(kernel_address = "off")]` attribute also turns off
+// the address sanitizer.
 //
 //@ needs-sanitizer-address
 //@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0
 
 #![crate_type = "lib"]
-#![feature(no_sanitize)]
+#![feature(sanitize)]
 
-// CHECK:     @UNSANITIZED = constant{{.*}} no_sanitize_address
-// CHECK-NOT: @__asan_global_UNSANITIZED
-#[no_mangle]
-#[no_sanitize(address)]
-pub static UNSANITIZED: u32 = 0;
-
-// CHECK: @__asan_global_SANITIZED
-#[no_mangle]
-pub static SANITIZED: u32 = 0;
-
-// CHECK-LABEL: ; no_sanitize::unsanitized
+// CHECK-LABEL: ; sanitize_off_kasan_asan::unsanitized
 // CHECK-NEXT:  ; Function Attrs:
 // CHECK-NOT:   sanitize_address
 // CHECK:       start:
 // CHECK-NOT:   call void @__asan_report_load
 // CHECK:       }
-#[no_sanitize(address)]
+#[sanitize(kernel_address = "off")]
 pub fn unsanitized(b: &mut u8) -> u8 {
     *b
 }
 
-// CHECK-LABEL: ; no_sanitize::sanitized
+// CHECK-LABEL: ; sanitize_off_kasan_asan::sanitized
 // CHECK-NEXT:  ; Function Attrs:
 // CHECK:       sanitize_address
 // CHECK:       start:
diff --git a/tests/codegen-llvm/sanitizer/sanitize-off.rs b/tests/codegen-llvm/sanitizer/sanitize-off.rs
new file mode 100644
index 00000000000..9f3f7cd9df7
--- /dev/null
+++ b/tests/codegen-llvm/sanitizer/sanitize-off.rs
@@ -0,0 +1,138 @@
+// Verifies that the `#[sanitize(address = "off")]` attribute can be used to
+// selectively disable sanitizer instrumentation.
+//
+//@ needs-sanitizer-address
+//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0
+
+#![crate_type = "lib"]
+#![feature(sanitize)]
+
+// CHECK:     @UNSANITIZED = constant{{.*}} no_sanitize_address
+// CHECK-NOT: @__asan_global_SANITIZED
+#[no_mangle]
+#[sanitize(address = "off")]
+pub static UNSANITIZED: u32 = 0;
+
+// CHECK: @__asan_global_SANITIZED
+#[no_mangle]
+pub static SANITIZED: u32 = 0;
+
+// CHECK-LABEL: ; sanitize_off::unsanitized
+// CHECK-NEXT:  ; Function Attrs:
+// CHECK-NOT:   sanitize_address
+// CHECK:       start:
+// CHECK-NOT:   call void @__asan_report_load
+// CHECK:       }
+#[sanitize(address = "off")]
+pub fn unsanitized(b: &mut u8) -> u8 {
+    *b
+}
+
+// CHECK-LABEL: ; sanitize_off::sanitized
+// CHECK-NEXT:  ; Function Attrs:
+// CHECK:       sanitize_address
+// CHECK:       start:
+// CHECK:       call void @__asan_report_load
+// CHECK:       }
+pub fn sanitized(b: &mut u8) -> u8 {
+    *b
+}
+
+#[sanitize(address = "off")]
+pub mod foo {
+    // CHECK-LABEL: ; sanitize_off::foo::unsanitized
+    // CHECK-NEXT:  ; Function Attrs:
+    // CHECK-NOT:   sanitize_address
+    // CHECK:       start:
+    // CHECK-NOT:   call void @__asan_report_load
+    // CHECK:       }
+    pub fn unsanitized(b: &mut u8) -> u8 {
+        *b
+    }
+
+    // CHECK-LABEL: ; sanitize_off::foo::sanitized
+    // CHECK-NEXT:  ; Function Attrs:
+    // CHECK:       sanitize_address
+    // CHECK:       start:
+    // CHECK:       call void @__asan_report_load
+    // CHECK:       }
+    #[sanitize(address = "on")]
+    pub fn sanitized(b: &mut u8) -> u8 {
+        *b
+    }
+}
+
+pub trait MyTrait {
+    fn unsanitized(&self, b: &mut u8) -> u8;
+    fn sanitized(&self, b: &mut u8) -> u8;
+
+    // CHECK-LABEL: ; sanitize_off::MyTrait::unsanitized_default
+    // CHECK-NEXT:  ; Function Attrs:
+    // CHECK-NOT:   sanitize_address
+    // CHECK:       start:
+    // CHECK-NOT:   call void @__asan_report_load
+    // CHECK:       }
+    #[sanitize(address = "off")]
+    fn unsanitized_default(&self, b: &mut u8) -> u8 {
+        *b
+    }
+
+    // CHECK-LABEL: ; sanitize_off::MyTrait::sanitized_default
+    // CHECK-NEXT:  ; Function Attrs:
+    // CHECK:       sanitize_address
+    // CHECK:       start:
+    // CHECK:       call void @__asan_report_load
+    // CHECK:       }
+    fn sanitized_default(&self, b: &mut u8) -> u8 {
+        *b
+    }
+}
+
+#[sanitize(address = "off")]
+impl MyTrait for () {
+    // CHECK-LABEL: ; <() as sanitize_off::MyTrait>::unsanitized
+    // CHECK-NEXT:  ; Function Attrs:
+    // CHECK-NOT:   sanitize_address
+    // CHECK:       start:
+    // CHECK-NOT:   call void @__asan_report_load
+    // CHECK:       }
+    fn unsanitized(&self, b: &mut u8) -> u8 {
+        *b
+    }
+
+    // CHECK-LABEL: ; <() as sanitize_off::MyTrait>::sanitized
+    // CHECK-NEXT:  ; Function Attrs:
+    // CHECK:       sanitize_address
+    // CHECK:       start:
+    // CHECK:       call void @__asan_report_load
+    // CHECK:       }
+    #[sanitize(address = "on")]
+    fn sanitized(&self, b: &mut u8) -> u8 {
+        *b
+    }
+}
+
+pub fn expose_trait(b: &mut u8) -> u8 {
+    <() as MyTrait>::unsanitized_default(&(), b);
+    <() as MyTrait>::sanitized_default(&(), b)
+}
+
+#[sanitize(address = "off")]
+pub mod outer {
+    #[sanitize(thread = "off")]
+    pub mod inner {
+        // CHECK-LABEL: ; sanitize_off::outer::inner::unsanitized
+        // CHECK-NEXT:  ; Function Attrs:
+        // CHECK-NOT:   sanitize_address
+        // CHECK:       start:
+        // CHECK-NOT:   call void @__asan_report_load
+        // CHECK:       }
+        pub fn unsanitized() {
+            let xs = [0, 1, 2, 3];
+            // Avoid optimizing everything out.
+            let xs = std::hint::black_box(xs.as_ptr());
+            let code = unsafe { *xs.offset(4) };
+            std::process::exit(code);
+        }
+    }
+}
diff --git a/tests/codegen-llvm/sanitizer/scs-attr-check.rs b/tests/codegen-llvm/sanitizer/scs-attr-check.rs
index 6f4cbc2c0a6..f726503503c 100644
--- a/tests/codegen-llvm/sanitizer/scs-attr-check.rs
+++ b/tests/codegen-llvm/sanitizer/scs-attr-check.rs
@@ -5,7 +5,7 @@
 //@ compile-flags: -Zsanitizer=shadow-call-stack
 
 #![crate_type = "lib"]
-#![feature(no_sanitize)]
+#![feature(sanitize)]
 
 // CHECK: ; sanitizer_scs_attr_check::scs
 // CHECK-NEXT: ; Function Attrs:{{.*}}shadowcallstack
@@ -13,5 +13,5 @@ pub fn scs() {}
 
 // CHECK: ; sanitizer_scs_attr_check::no_scs
 // CHECK-NOT: ; Function Attrs:{{.*}}shadowcallstack
-#[no_sanitize(shadow_call_stack)]
+#[sanitize(shadow_call_stack = "off")]
 pub fn no_scs() {}
diff --git a/tests/codegen-llvm/transmute-scalar.rs b/tests/codegen-llvm/transmute-scalar.rs
index ce1b0558b2e..21f7287047c 100644
--- a/tests/codegen-llvm/transmute-scalar.rs
+++ b/tests/codegen-llvm/transmute-scalar.rs
@@ -1,8 +1,9 @@
 //@ add-core-stubs
-//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
+//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu
+//@ needs-llvm-components: x86
 
 #![crate_type = "lib"]
-#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)]
+#![feature(no_core, repr_simd)]
 #![no_core]
 extern crate minicore;
 
@@ -117,11 +118,7 @@ struct S([i64; 1]);
 // CHECK-NEXT: %[[TEMP:.+]] = load i64, ptr %[[RET]]
 // CHECK-NEXT: ret i64 %[[TEMP]]
 #[no_mangle]
-#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
-#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
 #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
-#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
-#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
 pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 {
     unsafe { mem::transmute(b) }
 }
@@ -133,11 +130,7 @@ pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 {
 // CHECK-NEXT: %[[TEMP:.+]] = load <1 x i64>, ptr %[[RET]]
 // CHECK-NEXT: ret <1 x i64> %[[TEMP]]
 #[no_mangle]
-#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
-#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
 #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
-#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
-#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
 pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S {
     unsafe { mem::transmute(b) }
 }
diff --git a/tests/codegen-llvm/uninhabited-transparent-return-abi.rs b/tests/codegen-llvm/uninhabited-transparent-return-abi.rs
index 83d9a7a32ab..507cd7ae2a6 100644
--- a/tests/codegen-llvm/uninhabited-transparent-return-abi.rs
+++ b/tests/codegen-llvm/uninhabited-transparent-return-abi.rs
@@ -36,7 +36,7 @@ pub fn test_uninhabited_ret_by_ref() {
 pub fn test_uninhabited_ret_by_ref_with_arg(rsi: u32) {
     // CHECK: %_2 = alloca [24 x i8], align {{8|4}}
     // CHECK-NEXT: call void @llvm.lifetime.start.p0({{(i64 24, )?}}ptr nonnull %_2)
-    // CHECK-NEXT: call void @opaque_with_arg({{.*}} sret([24 x i8]) {{.*}} %_2, i32 noundef %rsi) #2
+    // CHECK-NEXT: call void @opaque_with_arg({{.*}} sret([24 x i8]) {{.*}} %_2, i32 noundef{{( signext)?}} %rsi) #2
     // CHECK-NEXT: unreachable
     unsafe {
         opaque_with_arg(rsi);
diff --git a/tests/codegen-llvm/vec-calloc.rs b/tests/codegen-llvm/vec-calloc.rs
index d1c320ead01..15971bbfa00 100644
--- a/tests/codegen-llvm/vec-calloc.rs
+++ b/tests/codegen-llvm/vec-calloc.rs
@@ -1,4 +1,6 @@
+//@ revisions: normal llvm21
 //@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
+//@ [llvm21] min-llvm-version: 21
 //@ only-x86_64
 
 #![crate_type = "lib"]
@@ -176,6 +178,24 @@ pub fn vec_option_i32(n: usize) -> Vec<Option<i32>> {
     vec![None; n]
 }
 
+// LLVM21-LABEL: @vec_array
+#[cfg(llvm21)]
+#[no_mangle]
+pub fn vec_array(n: usize) -> Vec<[u32; 1_000_000]> {
+    // LLVM21-NOT: call {{.*}}alloc::vec::from_elem
+    // LLVM21-NOT: call {{.*}}reserve
+    // LLVM21-NOT: call {{.*}}__rust_alloc(
+
+    // LLVM21: call {{.*}}__rust_alloc_zeroed(
+
+    // LLVM21-NOT: call {{.*}}alloc::vec::from_elem
+    // LLVM21-NOT: call {{.*}}reserve
+    // LLVM21-NOT: call {{.*}}__rust_alloc(
+
+    // LLVM21: ret void
+    vec![[0; 1_000_000]; 3]
+}
+
 // Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away.
 // CHECK: declare noalias noundef ptr @{{.*}}__rust_alloc_zeroed(i64 noundef, i64 allocalign noundef) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]]
 
diff --git a/tests/debuginfo/recursive-struct.rs b/tests/debuginfo/recursive-struct.rs
index 5be90992848..427a7100a4f 100644
--- a/tests/debuginfo/recursive-struct.rs
+++ b/tests/debuginfo/recursive-struct.rs
@@ -62,6 +62,7 @@
 
 use self::Opt::{Empty, Val};
 use std::boxed::Box as B;
+use std::marker::PhantomData;
 
 enum Opt<T> {
     Empty,
@@ -98,6 +99,11 @@ struct LongCycleWithAnonymousTypes {
     value: usize,
 }
 
+struct Expanding<T> {
+    a: PhantomData<T>,
+    b: *const Expanding<(T, T)>,
+}
+
 // This test case makes sure that recursive structs are properly described. The Node structs are
 // generic so that we can have a new type (that newly needs to be described) for the different
 // cases. The potential problem with recursive types is that the DI generation algorithm gets
@@ -205,6 +211,9 @@ fn main() {
         value: 30
     })))));
 
+    // This type can generate new instances infinitely if not handled properly.
+    std::hint::black_box(Expanding::<()> { a: PhantomData, b: std::ptr::null() });
+
     zzz(); // #break
 }
 
diff --git a/tests/mir-opt/inline/inline_compatibility.rs b/tests/mir-opt/inline/inline_compatibility.rs
index 1bb102ccda5..a31153dedc9 100644
--- a/tests/mir-opt/inline/inline_compatibility.rs
+++ b/tests/mir-opt/inline/inline_compatibility.rs
@@ -3,7 +3,7 @@
 //@ compile-flags: -Cpanic=abort
 
 #![crate_type = "lib"]
-#![feature(no_sanitize)]
+#![feature(sanitize)]
 #![feature(c_variadic)]
 
 #[inline]
@@ -37,22 +37,22 @@ pub unsafe fn f2() {
 }
 
 #[inline]
-#[no_sanitize(address)]
-pub unsafe fn no_sanitize() {}
+#[sanitize(address = "off")]
+pub unsafe fn sanitize_off() {}
 
-// CHECK-LABEL: fn inlined_no_sanitize()
+// CHECK-LABEL: fn inlined_sanitize_off()
 // CHECK:       bb0: {
 // CHECK-NEXT:  return;
-#[no_sanitize(address)]
-pub unsafe fn inlined_no_sanitize() {
-    no_sanitize();
+#[sanitize(address = "off")]
+pub unsafe fn inlined_sanitize_off() {
+    sanitize_off();
 }
 
-// CHECK-LABEL: fn not_inlined_no_sanitize()
+// CHECK-LABEL: fn not_inlined_sanitize_off()
 // CHECK:       bb0: {
-// CHECK-NEXT:  no_sanitize()
-pub unsafe fn not_inlined_no_sanitize() {
-    no_sanitize();
+// CHECK-NEXT:  sanitize_off()
+pub unsafe fn not_inlined_sanitize_off() {
+    sanitize_off();
 }
 
 // CHECK-LABEL: fn not_inlined_c_variadic()
diff --git a/tests/run-make/emit-shared-files/rmake.rs b/tests/run-make/emit-shared-files/rmake.rs
index f88fe69aa9c..911ceb3adca 100644
--- a/tests/run-make/emit-shared-files/rmake.rs
+++ b/tests/run-make/emit-shared-files/rmake.rs
@@ -19,7 +19,7 @@ fn main() {
         .args(&["--extend-css", "z.css"])
         .input("x.rs")
         .run();
-    assert!(path("invocation-only/search-index-xxx.js").exists());
+    assert!(path("invocation-only/search.index/root-xxx.js").exists());
     assert!(path("invocation-only/crates-xxx.js").exists());
     assert!(path("invocation-only/settings.html").exists());
     assert!(path("invocation-only/x/all.html").exists());
diff --git a/tests/run-make/linker-warning/short-error.txt b/tests/run-make/linker-warning/short-error.txt
index 5b7c040bc50..e5861b732c5 100644
--- a/tests/run-make/linker-warning/short-error.txt
+++ b/tests/run-make/linker-warning/short-error.txt
@@ -1,6 +1,6 @@
 error: linking with `./fake-linker` failed: exit status: 1
   |
-  = note:  "./fake-linker" "-m64" "/symbols.o" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/build-root/test/run-make/linker-warning/rmake_out/{libfoo,libbar}.rlib" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,libcfg_if-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/raw-dylibs" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error"
+  = note:  "./fake-linker" "-m64" "/symbols.o" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/build-root/test/run-make/linker-warning/rmake_out/{libfoo,libbar}.rlib" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,libcfg_if-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/raw-dylibs" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error"
   = note: some arguments are omitted. use `--verbose` to show all linker arguments
   = note: error: baz
           
diff --git a/tests/run-make/rustdoc-determinism/rmake.rs b/tests/run-make/rustdoc-determinism/rmake.rs
index 921baef4a97..5705dff6858 100644
--- a/tests/run-make/rustdoc-determinism/rmake.rs
+++ b/tests/run-make/rustdoc-determinism/rmake.rs
@@ -15,7 +15,7 @@ fn main() {
     rustdoc().input("foo.rs").out_dir(&bar_first).run();
 
     diff()
-        .expected_file(foo_first.join("search-index.js"))
-        .actual_file(bar_first.join("search-index.js"))
+        .expected_file(foo_first.join("search.index/root.js"))
+        .actual_file(bar_first.join("search.index/root.js"))
         .run();
 }
diff --git a/tests/run-make/rustdoc-scrape-examples-paths/rmake.rs b/tests/run-make/rustdoc-scrape-examples-paths/rmake.rs
index 03888f69eab..6784e438762 100644
--- a/tests/run-make/rustdoc-scrape-examples-paths/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-paths/rmake.rs
@@ -1,16 +1,16 @@
 //! Test to ensure that the rustdoc `scrape-examples` feature is not panicking.
 //! Regression test for <https://github.com/rust-lang/rust/issues/144752>.
 
-use run_make_support::{cargo, path, rfs};
+use run_make_support::cargo;
+use run_make_support::scoped_run::run_in_tmpdir;
 
 fn main() {
     // We copy the crate to be documented "outside" to prevent documenting
     // the whole compiler.
-    let tmp = std::env::temp_dir();
-    let test_crate = tmp.join("foo");
-    rfs::copy_dir_all(path("foo"), &test_crate);
-
-    // The `scrape-examples` feature is also implemented in `cargo` so instead of reproducing
-    // what `cargo` does, better to just let `cargo` do it.
-    cargo().current_dir(&test_crate).args(["doc", "-p", "foo", "-Zrustdoc-scrape-examples"]).run();
+    std::env::set_current_dir("foo").unwrap();
+    run_in_tmpdir(|| {
+        // The `scrape-examples` feature is also implemented in `cargo` so instead of reproducing
+        // what `cargo` does, better to just let `cargo` do it.
+        cargo().args(["doc", "-p", "foo", "-Zrustdoc-scrape-examples"]).run();
+    })
 }
diff --git a/tests/rustdoc-gui/code-example-buttons.goml b/tests/rustdoc-gui/code-example-buttons.goml
index b96f6ddcc37..1429f978a28 100644
--- a/tests/rustdoc-gui/code-example-buttons.goml
+++ b/tests/rustdoc-gui/code-example-buttons.goml
@@ -5,25 +5,25 @@ include: "utils.goml"
 // First we check we "hover".
 move-cursor-to: ".example-wrap"
 assert-css: (".example-wrap .copy-button", { "visibility": "visible" })
-move-cursor-to: ".search-input"
+move-cursor-to: "#search-button"
 assert-css: (".example-wrap .copy-button", { "visibility": "hidden" })
 
 // Now we check the click.
 assert-count: (".example-wrap:not(:hover) .button-holder.keep-visible", 0)
 click: ".example-wrap"
-move-cursor-to: ".search-input"
+move-cursor-to: "#search-button"
 // It should have a new class and be visible.
 wait-for-count: (".example-wrap:not(:hover) .button-holder.keep-visible", 1)
 wait-for-css: (".example-wrap:not(:hover) .button-holder.keep-visible", { "visibility": "visible" })
 // Clicking again will remove the class.
 click: ".example-wrap"
-move-cursor-to: ".search-input"
+move-cursor-to: "rustdoc-toolbar #search-button"
 assert-count: (".example-wrap:not(:hover) .button-holder.keep-visible", 0)
 assert-css: (".example-wrap .copy-button", { "visibility": "hidden" })
 
 // Clicking on the "copy code" button shouldn't make the buttons stick.
 click: ".example-wrap .copy-button"
-move-cursor-to: ".search-input"
+move-cursor-to: "#search-button"
 assert-count: (".example-wrap:not(:hover) .button-holder.keep-visible", 0)
 assert-css: (".example-wrap .copy-button", { "visibility": "hidden" })
 // Since we clicked on the copy button, the clipboard content should have been updated.
diff --git a/tests/rustdoc-gui/copy-code.goml b/tests/rustdoc-gui/copy-code.goml
index 9cc717bc67a..a6fb816c4bd 100644
--- a/tests/rustdoc-gui/copy-code.goml
+++ b/tests/rustdoc-gui/copy-code.goml
@@ -12,7 +12,7 @@ define-function: (
         assert-count: (".example-wrap .copy-button", 1)
         // We now ensure it's only displayed when the example is hovered.
         assert-css: (".example-wrap .copy-button", { "visibility": "visible" })
-        move-cursor-to: ".search-input"
+        move-cursor-to: "rustdoc-toolbar #search-button"
         assert-css: (".example-wrap .copy-button", { "visibility": "hidden" })
         // Checking that the copy button has the same size as the "copy path" button.
         compare-elements-size: (
diff --git a/tests/rustdoc-gui/cursor.goml b/tests/rustdoc-gui/cursor.goml
index 9412987fc32..0d78e192606 100644
--- a/tests/rustdoc-gui/cursor.goml
+++ b/tests/rustdoc-gui/cursor.goml
@@ -1,4 +1,5 @@
 // This test ensures that several clickable items actually have the pointer cursor.
+include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html"
 
 // the `[+]/[-]` button
@@ -8,11 +9,7 @@ assert-css: ("#toggle-all-docs", {"cursor": "pointer"})
 assert-css: ("#copy-path", {"cursor": "pointer"})
 
 // the search tabs
-write-into: (".search-input", "Foo")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "Foo"})
 assert-css: ("#search-tabs > button", {"cursor": "pointer"})
 
 // mobile sidebar toggle button
diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml
index 0df9cc2a659..a182124aced 100644
--- a/tests/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml
@@ -69,7 +69,7 @@ call-function: ("check-colors", {
 // and make sure it goes away.
 
 // First, open the settings menu.
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#settings"
 assert-css: ("#settings", {"display": "block"})
 
@@ -121,7 +121,7 @@ call-function: ("check-padding", {
 define-function: ("check-line-numbers-existence", [], block {
     assert-local-storage: {"rustdoc-line-numbers": "true" }
     assert-false: ".example-line-numbers"
-    click: "#settings-menu"
+    click: "rustdoc-toolbar .settings-menu"
     wait-for: "#settings"
 
     // Then, click the toggle button.
@@ -137,7 +137,7 @@ define-function: ("check-line-numbers-existence", [], block {
     // Line numbers should still be there.
     assert-css: ("[data-nosnippet]", { "display": "block"})
     // Closing settings menu.
-    click: "#settings-menu"
+    click: "rustdoc-toolbar .settings-menu"
     wait-for-css: ("#settings", {"display": "none"})
 })
 
@@ -168,7 +168,7 @@ assert: ".example-wrap > pre.rust"
 assert-count: (".example-wrap", 2)
 assert-count: (".example-wrap.digits-1", 2)
 
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#settings"
 
 // Then, click the toggle button.
diff --git a/tests/rustdoc-gui/escape-key.goml b/tests/rustdoc-gui/escape-key.goml
index ff8557b9b81..ab5615ebcd8 100644
--- a/tests/rustdoc-gui/escape-key.goml
+++ b/tests/rustdoc-gui/escape-key.goml
@@ -1,13 +1,10 @@
 // This test ensures that the "Escape" shortcut is handled correctly based on the
 // current content displayed.
+include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // First, we check that the search results are hidden when the Escape key is pressed.
-write-into: (".search-input", "test")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-wait-for: "#search h1" // The search element is empty before the first search
+call-function: ("perform-search", {"query": "test"})
 // Check that the currently displayed element is search.
-wait-for: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content hidden"})
 assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
 press-key: "Escape"
@@ -17,8 +14,8 @@ assert-false: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content"})
 assert-document-property: ({"URL": "index.html"}, [ENDS_WITH])
 
-// Check that focusing the search input brings back the search results
-focus: ".search-input"
+// Check that clicking the search button brings back the search results
+click: "#search-button"
 wait-for: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content hidden"})
 assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
diff --git a/tests/rustdoc-gui/font-serif-change.goml b/tests/rustdoc-gui/font-serif-change.goml
index b14d5ae96f9..1e9f21c3541 100644
--- a/tests/rustdoc-gui/font-serif-change.goml
+++ b/tests/rustdoc-gui/font-serif-change.goml
@@ -8,7 +8,7 @@ assert-css: ("body", {"font-family": |serif_font|})
 assert-css: ("p code", {"font-family": |serif_code_font|})
 
 // We now switch to the sans serif font
-click: "#settings-menu"
+click: "main .settings-menu"
 wait-for: "#sans-serif-fonts"
 click: "#sans-serif-fonts"
 
@@ -23,7 +23,7 @@ assert-css: ("body", {"font-family": |font|})
 assert-css: ("p code", {"font-family": |code_font|})
 
 // We switch back to the serif font
-click: "#settings-menu"
+click: "main .settings-menu"
 wait-for: "#sans-serif-fonts"
 click: "#sans-serif-fonts"
 
diff --git a/tests/rustdoc-gui/globals.goml b/tests/rustdoc-gui/globals.goml
index 7a0e2b9eb74..89f57add816 100644
--- a/tests/rustdoc-gui/globals.goml
+++ b/tests/rustdoc-gui/globals.goml
@@ -1,6 +1,7 @@
 // Make sure search stores its data in `window`
 // It needs to use a global to avoid racing on search-index.js and search.js
 // https://github.com/rust-lang/rust/pull/118961
+include: "utils.goml"
 
 // URL query
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=sa'%3Bda'%3Bds"
@@ -9,9 +10,7 @@ assert-window-property-false: {"searchIndex": null}
 
 // Form input
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write-into: (".search-input", "Foo")
-press-key: 'Enter'
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "Foo"})
 assert-window-property-false: {"searchIndex": null}
 
 // source sidebar
diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml
index 6d6e353ae36..34b40814027 100644
--- a/tests/rustdoc-gui/help-page.goml
+++ b/tests/rustdoc-gui/help-page.goml
@@ -6,12 +6,12 @@ assert-css: ("#help", {"display": "block"})
 assert-css: ("#help dd", {"font-size": "16px"})
 assert-false: "#help-button > a"
 assert-css: ("#help", {"display": "block"})
-compare-elements-property: (".sub", "#help", ["offsetWidth"])
-compare-elements-position: (".sub", "#help", ["x"])
+compare-elements-property: (".main-heading", "#help", ["offsetWidth"])
+compare-elements-position: (".main-heading", "#help", ["x"])
 set-window-size: (500, 1000) // Try mobile next.
 assert-css: ("#help", {"display": "block"})
-compare-elements-property: (".sub", "#help", ["offsetWidth"])
-compare-elements-position: (".sub", "#help", ["x"])
+compare-elements-property: (".main-heading", "#help", ["offsetWidth"])
+compare-elements-position: (".main-heading", "#help", ["x"])
 
 // Checking the color of the elements of the help menu.
 show-text: true
@@ -54,19 +54,17 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a"
 wait-for: "#search-tabs" // Waiting for the search.js to load.
 set-window-size: (1000, 1000) // Only supported on desktop.
 assert-false: "#help"
-click: "#help-button > a"
+click: "rustdoc-toolbar .help-menu > a"
 assert-css: ("#help", {"display": "block"})
 assert-css: ("#help dd", {"font-size": "16px"})
-click: "#help-button > a"
-assert-css: ("#help", {"display": "none"})
-compare-elements-property-false: (".sub", "#help", ["offsetWidth"])
-compare-elements-position-false: (".sub", "#help", ["x"])
+click: "rustdoc-toolbar .help-menu > a"
+assert-false: "#help"
 
 // This test ensures that the "the rustdoc book" anchor link within the help popover works.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a"
 wait-for: "#search-tabs" // Waiting for the search.js to load.
 set-window-size: (1000, 1000) // Popover only appears when the screen width is >700px.
 assert-false: "#help"
-click: "#help-button > a"
+click: "rustdoc-toolbar .help-menu > a"
 click: "//*[@id='help']//a[text()='the rustdoc book']"
 wait-for-document-property: ({"URL": "https://doc.rust-lang.org/"}, STARTS_WITH)
diff --git a/tests/rustdoc-gui/hide-mobile-topbar.goml b/tests/rustdoc-gui/hide-mobile-topbar.goml
index 46eb8acfe8c..1e46d235827 100644
--- a/tests/rustdoc-gui/hide-mobile-topbar.goml
+++ b/tests/rustdoc-gui/hide-mobile-topbar.goml
@@ -1,20 +1,19 @@
 // Checks sidebar resizing stays synced with the setting
-go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+go-to: "file://" + |DOC_PATH| + "/settings.html"
 set-window-size: (400, 600)
 
 // Verify that the "hide" option is unchecked
-click: "#settings-menu"
 wait-for: "#settings"
 assert-css: ("#settings", {"display": "block"})
 assert-property: ("#hide-sidebar", {"checked": "false"})
-assert-css: (".mobile-topbar", {"display": "flex"})
+assert-css: ("rustdoc-topbar", {"display": "flex"})
 
 // Toggle it
 click: "#hide-sidebar"
 assert-property: ("#hide-sidebar", {"checked": "true"})
-assert-css: (".mobile-topbar", {"display": "none"})
+assert-css: ("rustdoc-topbar", {"display": "none"})
 
 // Toggle it again
 click: "#hide-sidebar"
 assert-property: ("#hide-sidebar", {"checked": "false"})
-assert-css: (".mobile-topbar", {"display": "flex"})
+assert-css: ("rustdoc-topbar", {"display": "flex"})
diff --git a/tests/rustdoc-gui/huge-logo.goml b/tests/rustdoc-gui/huge-logo.goml
index d207ab5bb37..6ad6948ef2a 100644
--- a/tests/rustdoc-gui/huge-logo.goml
+++ b/tests/rustdoc-gui/huge-logo.goml
@@ -8,8 +8,3 @@ assert-property: (".sidebar-crate .logo-container", {"offsetWidth": "96", "offse
 // offsetWidth = width of sidebar, offsetHeight = height + top padding
 assert-property: (".sidebar-crate .logo-container img", {"offsetWidth": "48", "offsetHeight": 64})
 assert-css: (".sidebar-crate .logo-container img", {"border-top-width": "16px", "margin-top": "-16px"})
-
-set-window-size: (400, 600)
-// offset = size + margin
-assert-property: (".mobile-topbar .logo-container", {"offsetWidth": "55", "offsetHeight": 45})
-assert-property: (".mobile-topbar .logo-container img", {"offsetWidth": "35", "offsetHeight": 35})
diff --git a/tests/rustdoc-gui/item-info.goml b/tests/rustdoc-gui/item-info.goml
index 647a2fd290d..11388c79e0b 100644
--- a/tests/rustdoc-gui/item-info.goml
+++ b/tests/rustdoc-gui/item-info.goml
@@ -20,7 +20,7 @@ store-position: (
     {"x": second_line_x, "y": second_line_y},
 )
 assert: |first_line_x| != |second_line_x| && |first_line_x| == 521 && |second_line_x| == 277
-assert: |first_line_y| != |second_line_y| && |first_line_y| == 718 && |second_line_y| == 741
+assert: |first_line_y| != |second_line_y| && |first_line_y| == 676 && |second_line_y| == 699
 
 // Now we ensure that they're not rendered on the same line.
 set-window-size: (1100, 800)
diff --git a/tests/rustdoc-gui/mobile-crate-name.goml b/tests/rustdoc-gui/mobile-crate-name.goml
index a0c96eec8a5..524c1d36a8a 100644
--- a/tests/rustdoc-gui/mobile-crate-name.goml
+++ b/tests/rustdoc-gui/mobile-crate-name.goml
@@ -5,18 +5,18 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // First we change the title to make it big.
 set-window-size: (350, 800)
 // We ensure that the "format" of the title is the same as the one we'll use.
-assert-text: (".mobile-topbar .location a", "test_docs")
+assert-text: ("rustdoc-topbar h2 a", "Crate test_docs")
 // We store the height we know is correct.
-store-property: (".mobile-topbar .location", {"offsetHeight": height})
+store-property: ("rustdoc-topbar h2", {"offsetHeight": height})
 // We change the crate name to something longer.
-set-text: (".mobile-topbar .location a", "cargo_packager_resource_resolver")
+set-text: ("rustdoc-topbar h2 a", "cargo_packager_resource_resolver")
 // And we check that the size remained the same.
-assert-property: (".mobile-topbar .location", {"offsetHeight": |height|})
+assert-property: ("rustdoc-topbar h2", {"offsetHeight": |height|})
 
 // Now we check if it works for the non-crate pages as well.
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 // We store the height we know is correct.
-store-property: (".mobile-topbar .location", {"offsetHeight": height})
-set-text: (".mobile-topbar .location a", "Something_incredibly_long_because")
+store-property: ("rustdoc-topbar h2", {"offsetHeight": height})
+set-text: ("rustdoc-topbar h2 a", "Something_incredibly_long_because")
 // And we check that the size remained the same.
-assert-property: (".mobile-topbar .location", {"offsetHeight": |height|})
+assert-property: ("rustdoc-topbar h2", {"offsetHeight": |height|})
diff --git a/tests/rustdoc-gui/mobile.goml b/tests/rustdoc-gui/mobile.goml
index a9eee53dd1d..d292281932d 100644
--- a/tests/rustdoc-gui/mobile.goml
+++ b/tests/rustdoc-gui/mobile.goml
@@ -5,7 +5,7 @@ set-window-size: (400, 600)
 set-font-size: 18
 wait-for: 100 // wait a bit for the resize and the font-size change to be fully taken into account.
 
-assert-property: (".mobile-topbar h2", {"offsetHeight": 33})
+assert-property: ("rustdoc-topbar h2", {"offsetHeight": 33})
 
 // On the settings page, the theme buttons should not line-wrap. Instead, they should
 // all be placed as a group on a line below the setting name "Theme."
diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml
index 423a273fde7..6bd4661ac8f 100644
--- a/tests/rustdoc-gui/notable-trait.goml
+++ b/tests/rustdoc-gui/notable-trait.goml
@@ -82,15 +82,6 @@ call-function: ("check-notable-tooltip-position", {
     "i_x": 528,
 })
 
-// Checking on mobile now.
-set-window-size: (650, 600)
-wait-for-size: ("body", {"width": 650})
-call-function: ("check-notable-tooltip-position-complete", {
-    "x": 26,
-    "i_x": 305,
-    "popover_x": 0,
-})
-
 // Now check the colors.
 define-function: (
     "check-colors",
@@ -176,6 +167,15 @@ call-function: (
     },
 )
 
+// Checking on mobile now.
+set-window-size: (650, 600)
+wait-for-size: ("body", {"width": 650})
+call-function: ("check-notable-tooltip-position-complete", {
+    "x": 26,
+    "i_x": 305,
+    "popover_x": 0,
+})
+
 reload:
 
 // Check that pressing escape works
@@ -189,7 +189,7 @@ assert: "#method\.create_an_iterator_from_read .tooltip:focus"
 // Check that clicking outside works.
 click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
 assert-count: ("//*[@class='tooltip popover']", 1)
-click: ".search-input"
+click: ".main-heading h1"
 assert-count: ("//*[@class='tooltip popover']", 0)
 assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"
 
@@ -219,14 +219,14 @@ define-function: (
         store-window-property: {"scrollY": scroll}
         click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
         wait-for: "//*[@class='tooltip popover']"
-        click: "#settings-menu a"
+        click: ".main-heading h1"
     }
 )
 
 // Now we check that the focus isn't given back to the wrong item when opening
 // another popover.
 call-function: ("setup-popup", {})
-click: ".search-input"
+click: ".main-heading h1"
 // We ensure we didn't come back to the previous focused item.
 assert-window-property-false: {"scrollY": |scroll|}
 
@@ -251,7 +251,7 @@ reload:
 assert-count: ("//*[@class='tooltip popover']", 0)
 click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
 assert-count: ("//*[@class='tooltip popover']", 1)
-click: "#settings-menu a"
+click: "rustdoc-toolbar .settings-menu a"
 wait-for: "#settings"
 assert-count: ("//*[@class='tooltip popover']", 0)
 assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"
diff --git a/tests/rustdoc-gui/pocket-menu.goml b/tests/rustdoc-gui/pocket-menu.goml
index 073172dd8a7..a0815bfa9a0 100644
--- a/tests/rustdoc-gui/pocket-menu.goml
+++ b/tests/rustdoc-gui/pocket-menu.goml
@@ -3,33 +3,33 @@ include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test"
 wait-for: "#crate-search"
 // First we check that the help menu doesn't exist yet.
-assert-false: "#help-button .popover"
+assert-false: "rustdoc-toolbar .help-menu .popover"
 // Then we display the help menu.
-click: "#help-button"
-assert: "#help-button .popover"
-assert-css: ("#help-button .popover", {"display": "block"})
+click: "rustdoc-toolbar .help-menu"
+assert: "rustdoc-toolbar .help-menu .popover"
+assert-css: ("rustdoc-toolbar .help-menu .popover", {"display": "block"})
 
 // Now we click somewhere else on the page to ensure it is handling the blur event
 // correctly.
 click: ".sidebar"
-assert-css: ("#help-button .popover", {"display": "none"})
+assert-false: "rustdoc-toolbar .help-menu .popover"
 
 // Now we will check that we cannot have two "pocket menus" displayed at the same time.
-click: "#help-button"
-assert-css: ("#help-button .popover", {"display": "block"})
-click: "#settings-menu"
-assert-css: ("#help-button .popover", {"display": "none"})
-assert-css: ("#settings-menu .popover", {"display": "block"})
+click: "rustdoc-toolbar .help-menu"
+assert-css: ("rustdoc-toolbar .help-menu .popover", {"display": "block"})
+click: "rustdoc-toolbar .settings-menu"
+assert-false: "rustdoc-toolbar .help-menu .popover"
+assert-css: ("rustdoc-toolbar .settings-menu .popover", {"display": "block"})
 
 // Now the other way.
-click: "#help-button"
-assert-css: ("#help-button .popover", {"display": "block"})
-assert-css: ("#settings-menu .popover", {"display": "none"})
+click: "rustdoc-toolbar .help-menu"
+assert-css: ("rustdoc-toolbar .help-menu .popover", {"display": "block"})
+assert-css: ("rustdoc-toolbar .settings-menu .popover", {"display": "none"})
 
 // Now verify that clicking the help menu again closes it.
-click: "#help-button"
-assert-css: ("#help-button .popover", {"display": "none"})
-assert-css: ("#settings-menu .popover", {"display": "none"})
+click: "rustdoc-toolbar .help-menu"
+assert-false: "rustdoc-toolbar .help-menu .popover"
+assert-css: (".settings-menu .popover", {"display": "none"})
 
 define-function: (
     "check-popover-colors",
@@ -37,13 +37,21 @@ define-function: (
     block {
         call-function: ("switch-theme", {"theme": |theme|})
 
-        click: "#help-button"
+        click: "rustdoc-toolbar .help-menu"
         assert-css: (
-            "#help-button .popover",
+            "rustdoc-toolbar .help-menu .popover",
             {"display": "block", "border-color": |border_color|},
         )
-        compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
-        compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
+        compare-elements-css: (
+            "rustdoc-toolbar .help-menu .popover",
+            "rustdoc-toolbar .help-menu .top",
+            ["border-color"],
+        )
+        compare-elements-css: (
+            "rustdoc-toolbar .help-menu .popover",
+            "rustdoc-toolbar .help-menu .bottom",
+            ["border-color"],
+        )
     }
 )
 
@@ -63,8 +71,21 @@ call-function: ("check-popover-colors", {
 
 // Opening the mobile sidebar should close the settings popover.
 set-window-size: (650, 600)
-click: "#settings-menu a"
-assert-css: ("#settings-menu .popover", {"display": "block"})
+click: "rustdoc-topbar .settings-menu a"
+assert-css: ("rustdoc-topbar .settings-menu .popover", {"display": "block"})
+click: ".sidebar-menu-toggle"
+assert: "//*[@class='sidebar shown']"
+assert-css: ("rustdoc-topbar .settings-menu .popover", {"display": "none"})
+// Opening the settings popover should close the sidebar.
+click: ".settings-menu a"
+assert-css: ("rustdoc-topbar .settings-menu .popover", {"display": "block"})
+assert-false: "//*[@class='sidebar shown']"
+
+// Opening the settings popover at start (which async loads stuff) should also close.
+reload:
 click: ".sidebar-menu-toggle"
 assert: "//*[@class='sidebar shown']"
-assert-css: ("#settings-menu .popover", {"display": "none"})
+assert-false: "rustdoc-topbar .settings-menu .popover"
+click: "rustdoc-topbar .settings-menu a"
+assert-false: "//*[@class='sidebar shown']"
+wait-for: "rustdoc-topbar .settings-menu .popover"
diff --git a/tests/rustdoc-gui/scrape-examples-color.goml b/tests/rustdoc-gui/scrape-examples-color.goml
index b0faca190a5..c84fe1f3411 100644
--- a/tests/rustdoc-gui/scrape-examples-color.goml
+++ b/tests/rustdoc-gui/scrape-examples-color.goml
@@ -27,7 +27,7 @@ define-function: (
             "color": |help_hover_color|,
         })
         // Moving the cursor to another item to not break next runs.
-        move-cursor-to: ".search-input"
+        move-cursor-to: "#search-button"
     }
 )
 
diff --git a/tests/rustdoc-gui/scrape-examples-layout.goml b/tests/rustdoc-gui/scrape-examples-layout.goml
index 85a3b2a6287..681d0c24c6d 100644
--- a/tests/rustdoc-gui/scrape-examples-layout.goml
+++ b/tests/rustdoc-gui/scrape-examples-layout.goml
@@ -64,8 +64,8 @@ assert-size: (".more-scraped-examples .scraped-example .example-wrap", {
 store-value: (offset_y, 4)
 
 // First with desktop
-assert-position: (".scraped-example", {"y": 256})
-assert-position: (".scraped-example .prev", {"y": 256 + |offset_y|})
+assert-position: (".scraped-example", {"y": 214})
+assert-position: (".scraped-example .prev", {"y": 214 + |offset_y|})
 
 // Gradient background should be at the top of the code block.
 assert-css: (".scraped-example .example-wrap::before", {"top": "0px"})
@@ -74,8 +74,8 @@ assert-css: (".scraped-example .example-wrap::after", {"bottom": "0px"})
 // Then with mobile
 set-window-size: (600, 600)
 store-size: (".scraped-example .scraped-example-title", {"height": title_height})
-assert-position: (".scraped-example", {"y": 291})
-assert-position: (".scraped-example .prev", {"y": 291 + |offset_y| + |title_height|})
+assert-position: (".scraped-example", {"y": 249})
+assert-position: (".scraped-example .prev", {"y": 249 + |offset_y| + |title_height|})
 
 define-function: (
     "check_title_and_code_position",
diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml
index 441895a7c0e..ec5710fbcdc 100644
--- a/tests/rustdoc-gui/scrape-examples-toggle.goml
+++ b/tests/rustdoc-gui/scrape-examples-toggle.goml
@@ -25,7 +25,7 @@ define-function: (
         // We put the toggle in the original state.
         click: ".more-examples-toggle"
         // Moving cursor away from the toggle line to prevent disrupting next test.
-        move-cursor-to: ".search-input"
+        move-cursor-to: "rustdoc-toolbar #search-button"
     },
 )
 
diff --git a/tests/rustdoc-gui/search-about-this-result.goml b/tests/rustdoc-gui/search-about-this-result.goml
index 1d45c06dc43..ec1df737c81 100644
--- a/tests/rustdoc-gui/search-about-this-result.goml
+++ b/tests/rustdoc-gui/search-about-this-result.goml
@@ -7,6 +7,7 @@ focus: ".search-input"
 press-key: "Enter"
 
 wait-for: "#search-tabs"
+wait-for-false: "#search-tabs .count.loading"
 assert-count: ("#search-tabs button", 1)
 assert-count: (".search-results > a", 1)
 
@@ -32,6 +33,7 @@ focus: ".search-input"
 press-key: "Enter"
 
 wait-for: "#search-tabs"
+wait-for-false: "#search-tabs .count.loading"
 assert-text: ("//div[@class='type-signature']", "F -> WhereWhitespace<T>")
 assert-count: ("#search-tabs button", 1)
 assert-count: (".search-results > a", 1)
diff --git a/tests/rustdoc-gui/search-corrections.goml b/tests/rustdoc-gui/search-corrections.goml
index f80675730c4..a14a80f357c 100644
--- a/tests/rustdoc-gui/search-corrections.goml
+++ b/tests/rustdoc-gui/search-corrections.goml
@@ -1,101 +1,60 @@
 // ignore-tidy-linelength
+include: "utils.goml"
 
 // Checks that the search tab result tell the user about corrections
 // First, try a search-by-name
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-// Intentionally wrong spelling of "NotableStructWithLongName"
-write-into: (".search-input", "NotableStructWithLongNamr")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "NotableStructWithLongNamr"})
 
 // Corrections aren't shown on the "In Names" tab.
 assert: "#search-tabs button.selected:first-child"
-assert-css: (".search-corrections", {
-    "display": "none"
-})
+assert-false: ".search-results:nth-child(1) .search-corrections"
 
 // Corrections do get shown on the "In Parameters" tab.
 click: "#search-tabs button:nth-child(2)"
 assert: "#search-tabs button.selected:nth-child(2)"
-assert-css: (".search-corrections", {
-    "display": "block"
-})
 assert-text: (
-    ".search-corrections",
-    "Type \"NotableStructWithLongNamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead."
+    ".search-results:nth-child(2) .search-corrections",
+    "Type \"NotableStructWithLongNamr\" not found. Showing results for closest type name \"NotableStructWithLongName\" instead."
 )
 
 // Corrections do get shown on the "In Return Type" tab.
 click: "#search-tabs button:nth-child(3)"
 assert: "#search-tabs button.selected:nth-child(3)"
-assert-css: (".search-corrections", {
-    "display": "block"
-})
 assert-text: (
-    ".search-corrections",
-    "Type \"NotableStructWithLongNamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead."
+    ".search-results:nth-child(3) .search-corrections",
+    "Type \"NotableStructWithLongNamr\" not found. Showing results for closest type name \"NotableStructWithLongName\" instead."
 )
 
 // Now, explicit return values
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-// Intentionally wrong spelling of "NotableStructWithLongName"
-write-into: (".search-input", "-> NotableStructWithLongNamr")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "-> NotableStructWithLongNamr"})
 
-assert-css: (".search-corrections", {
-    "display": "block"
-})
 assert-text: (
-    ".search-corrections",
-    "Type \"NotableStructWithLongNamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead."
+    ".search-results.active .search-corrections",
+    "Type \"NotableStructWithLongNamr\" not found and used as generic parameter. Consider searching for \"NotableStructWithLongName\" instead."
 )
 
 // Now, generic correction
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-// Intentionally wrong spelling of "NotableStructWithLongName"
-write-into: (".search-input", "NotableStructWithLongNamr, NotableStructWithLongNamr")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "NotableStructWithLongNamr, NotableStructWithLongNamr"})
 
-assert-css: (".search-corrections", {
-    "display": "block"
-})
 assert-text: (
-    ".search-corrections",
-    "Type \"NotableStructWithLongNamr\" not found and used as generic parameter. Consider searching for \"notablestructwithlongname\" instead."
+    ".search-failed.active .search-corrections",
+    "Type \"NotableStructWithLongNamr\" not found and used as generic parameter. Consider searching for \"NotableStructWithLongName\" instead."
 )
 
 // Now, generic correction plus error
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-// Intentionally wrong spelling of "NotableStructWithLongName"
-write-into: (".search-input", "Foo<NotableStructWithLongNamr>,y")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "Foo<NotableStructWithLongNamr>,y"})
 
-assert-css: (".search-corrections", {
-    "display": "block"
-})
 assert-text: (
-    ".search-corrections",
-    "Type \"NotableStructWithLongNamr\" not found and used as generic parameter. Consider searching for \"notablestructwithlongname\" instead."
+    ".search-failed.active .search-corrections",
+    "Type \"NotableStructWithLongNamr\" not found and used as generic parameter. Consider searching for \"NotableStructWithLongName\" instead."
 )
 
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-// Intentionally wrong spelling of "NotableStructWithLongName"
-write-into: (".search-input", "generic:NotableStructWithLongNamr<x>,y")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "generic:NotableStructWithLongNamr<x>,y"})
 
 assert-css: (".error", {
     "display": "block"
diff --git a/tests/rustdoc-gui/search-error.goml b/tests/rustdoc-gui/search-error.goml
index 4dc60669c7a..4d7c2263fd1 100644
--- a/tests/rustdoc-gui/search-error.goml
+++ b/tests/rustdoc-gui/search-error.goml
@@ -8,6 +8,7 @@ define-function: (
     [theme, error_background],
     block {
         call-function: ("switch-theme", {"theme": |theme|})
+        wait-for-false: "#search-tabs .count.loading"
         wait-for: "#search .error code"
         assert-css: ("#search .error code", {"background-color": |error_background|})
     }
diff --git a/tests/rustdoc-gui/search-filter.goml b/tests/rustdoc-gui/search-filter.goml
index c5038e0892b..d92d522c119 100644
--- a/tests/rustdoc-gui/search-filter.goml
+++ b/tests/rustdoc-gui/search-filter.goml
@@ -2,11 +2,7 @@
 include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 show-text: true
-write-into: (".search-input", "test")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "test"})
 assert-text: ("#results .externcrate", "test_docs")
 
 wait-for: "#crate-search"
@@ -21,6 +17,7 @@ press-key: "ArrowDown"
 press-key: "Enter"
 // Waiting for the search results to appear...
 wait-for: "#search-tabs"
+wait-for-false: "#search-tabs .count.loading"
 assert-document-property: ({"URL": "&filter-crate="}, CONTAINS)
 // We check that there is no more "test_docs" appearing.
 assert-false: "#results .externcrate"
@@ -31,7 +28,8 @@ assert-property: ("#crate-search", {"value": "lib2"})
 // crate filtering.
 press-key: "Escape"
 wait-for-css: ("#main-content", {"display": "block"})
-focus: ".search-input"
+click: "#search-button"
+wait-for: ".search-input"
 wait-for-css: ("#main-content", {"display": "none"})
 // We check that there is no more "test_docs" appearing.
 assert-false: "#results .externcrate"
@@ -47,6 +45,7 @@ press-key: "ArrowUp"
 press-key: "Enter"
 // Waiting for the search results to appear...
 wait-for: "#search-tabs"
+wait-for-false: "#search-tabs .count.loading"
 assert-property: ("#crate-search", {"value": "all crates"})
 
 // Checking that the URL parameter is taken into account for crate filtering.
@@ -56,8 +55,7 @@ assert-property: ("#crate-search", {"value": "lib2"})
 assert-false: "#results .externcrate"
 
 // Checking that the text for the "title" is correct (the "all crates" comes from the "<select>").
-assert-text: (".search-results-title", "Results", STARTS_WITH)
-assert-text: (".search-results-title + .sub-heading", " in all crates", STARTS_WITH)
+assert-text: (".search-switcher", "Search results in all crates", STARTS_WITH)
 
 // Checking the display of the crate filter.
 // We start with the light theme.
@@ -72,7 +70,7 @@ assert-css: ("#crate-search", {
 })
 
 // We now check the dark theme.
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#settings"
 click: "#theme-dark"
 wait-for-css: ("#crate-search", {
diff --git a/tests/rustdoc-gui/search-form-elements.goml b/tests/rustdoc-gui/search-form-elements.goml
index efe39f7a9d1..fdf0afb7e8f 100644
--- a/tests/rustdoc-gui/search-form-elements.goml
+++ b/tests/rustdoc-gui/search-form-elements.goml
@@ -2,6 +2,7 @@
 include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test"
 wait-for: "#search-tabs" // Waiting for the search.js to load.
+wait-for-false: "#search-tabs .count.loading"
 show-text: true
 
 define-function: (
@@ -31,7 +32,7 @@ define-function: (
             },
         )
         assert-css: (
-            "#help-button > a",
+            "rustdoc-toolbar .help-menu > a",
             {
                 "color": |menu_button_a_color|,
                 "border-color": "transparent",
@@ -39,9 +40,9 @@ define-function: (
             },
         )
         // Hover help button.
-        move-cursor-to: "#help-button"
+        move-cursor-to: "rustdoc-toolbar .help-menu"
         assert-css: (
-            "#help-button > a",
+            "rustdoc-toolbar .help-menu > a",
             {
                 "color": |menu_button_a_color|,
                 "border-color": |menu_button_a_border_hover|,
@@ -49,15 +50,15 @@ define-function: (
             },
         )
         // Link color inside
-        click: "#help-button"
+        click: "rustdoc-toolbar .help-menu"
         assert-css: (
-            "#help a",
+            "rustdoc-toolbar #help a",
             {
                 "color": |menu_a_color|,
             },
         )
         assert-css: (
-            "#settings-menu > a",
+            "rustdoc-toolbar .settings-menu > a",
             {
                 "color": |menu_button_a_color|,
                 "border-color": "transparent",
@@ -65,9 +66,9 @@ define-function: (
             },
         )
         // Hover settings menu.
-        move-cursor-to: "#settings-menu"
+        move-cursor-to: "rustdoc-toolbar .settings-menu"
         assert-css: (
-            "#settings-menu:hover > a",
+            "rustdoc-toolbar .settings-menu:hover > a",
             {
                 "color": |menu_button_a_color|,
                 "border-color": |menu_button_a_border_hover|,
@@ -120,8 +121,10 @@ call-function: (
 // Check that search input correctly decodes form encoding.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a+b"
 wait-for: "#search-tabs" // Waiting for the search.js to load.
+wait-for-false: "#search-tabs .count.loading"
 assert-property: (".search-input", { "value": "a b" })
 // Check that literal + is not treated as space.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a%2Bb"
 wait-for: "#search-tabs" // Waiting for the search.js to load.
+wait-for-false: "#search-tabs .count.loading"
 assert-property: (".search-input", { "value": "a+b" })
diff --git a/tests/rustdoc-gui/search-input-mobile.goml b/tests/rustdoc-gui/search-input-mobile.goml
index adcb3658a27..a383d92d288 100644
--- a/tests/rustdoc-gui/search-input-mobile.goml
+++ b/tests/rustdoc-gui/search-input-mobile.goml
@@ -2,10 +2,13 @@
 // The PR which fixed it is: https://github.com/rust-lang/rust/pull/81592
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 set-window-size: (463, 700)
-// We first check that the search input isn't already focused.
-assert-false: ("input.search-input:focus")
-click: "input.search-input"
+click: "#search-button"
+wait-for: ".search-input"
+assert: "input.search-input:focus"
+
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 reload:
 set-window-size: (750, 700)
-click: "input.search-input"
-assert: ("input.search-input:focus")
+click: "#search-button"
+wait-for: ".search-input"
+assert: "input.search-input:focus"
diff --git a/tests/rustdoc-gui/search-keyboard.goml b/tests/rustdoc-gui/search-keyboard.goml
index 707bb8f5faa..4adaaa106ea 100644
--- a/tests/rustdoc-gui/search-keyboard.goml
+++ b/tests/rustdoc-gui/search-keyboard.goml
@@ -1,28 +1,25 @@
 // Checks that the search tab results work correctly with function signature syntax
 // First, try a search-by-name
+include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write-into: (".search-input", "Foo")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "Foo"})
 
 // Now use the keyboard commands to switch to the third result.
 press-key: "ArrowDown"
 press-key: "ArrowDown"
 press-key: "ArrowDown"
-assert: ".search-results.active > a:focus:nth-of-type(3)"
+wait-for: ".search-results.active > a:focus:nth-of-type(3)"
 
 // Now switch to the second tab, then back to the first one, then arrow back up.
 press-key: "ArrowRight"
-assert: ".search-results.active:nth-of-type(2) > a:focus:nth-of-type(1)"
+wait-for: ".search-results.active:nth-of-type(2) > a:focus:nth-of-type(1)"
 press-key: "ArrowLeft"
-assert: ".search-results.active:nth-of-type(1) > a:focus:nth-of-type(3)"
+wait-for: ".search-results.active:nth-of-type(1) > a:focus:nth-of-type(3)"
 press-key: "ArrowUp"
-assert: ".search-results.active > a:focus:nth-of-type(2)"
+wait-for: ".search-results.active > a:focus:nth-of-type(2)"
 press-key: "ArrowUp"
-assert: ".search-results.active > a:focus:nth-of-type(1)"
+wait-for: ".search-results.active > a:focus:nth-of-type(1)"
 press-key: "ArrowUp"
-assert: ".search-input:focus"
+wait-for: ".search-input:focus"
 press-key: "ArrowDown"
-assert: ".search-results.active > a:focus:nth-of-type(1)"
+wait-for: ".search-results.active > a:focus:nth-of-type(1)"
diff --git a/tests/rustdoc-gui/search-reexport.goml b/tests/rustdoc-gui/search-reexport.goml
index fa9eedeceac..c69464f8bd9 100644
--- a/tests/rustdoc-gui/search-reexport.goml
+++ b/tests/rustdoc-gui/search-reexport.goml
@@ -6,10 +6,8 @@ call-function: ("switch-theme", {"theme": "dark"})
 // First we check that the reexport has the correct ID and no background color.
 assert-text: ("//*[@id='reexport.TheStdReexport']", "pub use ::std as TheStdReexport;")
 assert-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgba(0, 0, 0, 0)"})
-write-into: (".search-input", "TheStdReexport")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-wait-for: "//a[@class='result-import']"
+call-function: ("perform-search", {"query": "TheStdReexport"})
+assert: "//a[@class='result-import']"
 assert-attribute: (
     "//a[@class='result-import']",
     {"href": "../test_docs/index.html#reexport.TheStdReexport"},
@@ -21,9 +19,8 @@ wait-for-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "#494a
 
 // We now check that the alias is working as well on the reexport.
 // To be SURE that the search will be run.
-press-key: 'Enter'
-write-into: (".search-input", "AliasForTheStdReexport")
-wait-for: "//a[@class='result-import']"
+call-function: ("perform-search", {"query": "AliasForTheStdReexport"})
+assert: "//a[@class='result-import']"
 assert-text: (
     "a.result-import .result-name",
     "re-export AliasForTheStdReexport - see test_docs::TheStdReexport",
diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml
index e6dd504d703..e136eab6a7d 100644
--- a/tests/rustdoc-gui/search-result-color.goml
+++ b/tests/rustdoc-gui/search-result-color.goml
@@ -14,6 +14,7 @@ define-function: (
 
         // Waiting for the search results to appear...
         wait-for: "#search-tabs"
+        wait-for-false: "#search-tabs .count.loading"
         assert-css: (
             "#search-tabs > button > .count",
             {"color": |count_color|},
@@ -212,11 +213,7 @@ call-function: ("check-search-color", {
 // Check the alias.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 
-write-into: (".search-input", "thisisanalias")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "thisisanalias"})
 
 define-function: (
     "check-alias",
diff --git a/tests/rustdoc-gui/search-result-description.goml b/tests/rustdoc-gui/search-result-description.goml
index 745ef31e6cb..4ab250b472d 100644
--- a/tests/rustdoc-gui/search-result-description.goml
+++ b/tests/rustdoc-gui/search-result-description.goml
@@ -2,4 +2,5 @@
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=some_more_function"
 // Waiting for the search results to appear...
 wait-for: "#search-tabs"
+wait-for-false: "#search-tabs .count.loading"
 assert-text: (".search-results .desc code", "format!")
diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml
index 1521267956a..345e08cd578 100644
--- a/tests/rustdoc-gui/search-result-display.goml
+++ b/tests/rustdoc-gui/search-result-display.goml
@@ -7,6 +7,7 @@ write-into: (".search-input", "test")
 // To be SURE that the search will be run.
 press-key: 'Enter'
 wait-for: "#crate-search"
+wait-for-false: "#search-tabs .count.loading"
 // The width is returned by "getComputedStyle" which returns the exact number instead of the
 // CSS rule which is "50%"...
 assert-size: (".search-results div.desc", {"width": 248})
@@ -34,6 +35,7 @@ assert: |new_width| < |width| - 10
 // Check that if the search is too long on mobile, it'll go under the "typename".
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName"
 wait-for: "#crate-search"
+wait-for-false: "#search-tabs .count.loading"
 compare-elements-position-near: (
     ".search-results .result-name .typename",
     ".search-results .result-name .path",
@@ -51,7 +53,7 @@ set-window-size: (900, 900)
 
 // First we check the current width, height and position.
 assert-css: ("#crate-search", {"width": "159px"})
-store-size: (".search-results-title", {
+store-size: (".search-switcher", {
     "height": search_results_title_height,
     "width": search_results_title_width,
 })
@@ -64,8 +66,8 @@ set-text: (
 )
 
 // Then we compare again to confirm the height didn't change.
-assert-size: ("#crate-search", {"width": 370})
-assert-size: (".search-results-title", {
+assert-size: ("#crate-search", {"width": 185})
+assert-size: (".search-switcher", {
     "height": |search_results_title_height|,
 })
 assert-css: ("#search", {"width": "640px"})
@@ -79,6 +81,7 @@ define-function: (
     block {
         call-function: ("switch-theme", {"theme": |theme|})
         wait-for: "#crate-search"
+        wait-for-false: "#search-tabs .count.loading"
         assert-css: ("#crate-search", {"border": "1px solid " + |border|})
         assert-css: ("#crate-search-div::after", {"filter": |filter|})
         move-cursor-to: "#crate-search"
diff --git a/tests/rustdoc-gui/search-result-go-to-first.goml b/tests/rustdoc-gui/search-result-go-to-first.goml
index 136213c517e..acb25453171 100644
--- a/tests/rustdoc-gui/search-result-go-to-first.goml
+++ b/tests/rustdoc-gui/search-result-go-to-first.goml
@@ -9,6 +9,7 @@ assert-text-false: (".main-heading h1", "Struct test_docs::FooCopy item path")
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo"
 // Waiting for the search results to appear...
 wait-for: "#search-tabs"
+wait-for-false: "#search-tabs .count.loading"
 assert-text-false: (".main-heading h1", "Struct test_docs::FooCopy item path")
 // Ensure that the search results are displayed, not the "normal" content.
 assert-css: ("#main-content", {"display": "none"})
@@ -17,4 +18,4 @@ assert-css: ("#main-content", {"display": "none"})
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo&go_to_first=true"
 // Waiting for the page to load...
 wait-for-text: (".main-heading .rustdoc-breadcrumbs", "test_docs")
-wait-for-text: (".main-heading h1", "Struct FooCopy item path")
+wait-for-text: (".main-heading h1", "Struct Foo Copy item path")
diff --git a/tests/rustdoc-gui/search-result-impl-disambiguation.goml b/tests/rustdoc-gui/search-result-impl-disambiguation.goml
index bca52b46498..e39b90a735e 100644
--- a/tests/rustdoc-gui/search-result-impl-disambiguation.goml
+++ b/tests/rustdoc-gui/search-result-impl-disambiguation.goml
@@ -1,15 +1,12 @@
 // ignore-tidy-linelength
+include: "utils.goml"
 
 // Checks that, if a type has two methods with the same name, they both get
 // linked correctly.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 
 // This should link to the inherent impl
-write-into: (".search-input", "ZyxwvutMethodDisambiguation -> bool")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "ZyxwvutMethodDisambiguation -> bool"})
 // Check the disambiguated link.
 assert-count: ("a.result-method", 1)
 assert-attribute: ("a.result-method", {
@@ -25,11 +22,7 @@ assert: "section:target"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 
 // This should link to the trait impl
-write-into: (".search-input", "ZyxwvutMethodDisambiguation, usize -> usize")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "ZyxwvutMethodDisambiguation, usize -> usize"})
 // Check the disambiguated link.
 assert-count: ("a.result-method", 1)
 assert-attribute: ("a.result-method", {
@@ -47,6 +40,7 @@ assert: "section:target"
 // impl block's disambiguator is also acted upon.
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=MultiImplBlockStruct->bool"
 wait-for: "#search-tabs"
+wait-for-false: "#search-tabs .count.loading"
 assert-count: ("a.result-method", 1)
 assert-attribute: ("a.result-method", {
     "href": "../lib2/another_mod/struct.MultiImplBlockStruct.html#impl-MultiImplBlockStruct/method.second_fn"
@@ -56,6 +50,7 @@ wait-for: "details:has(summary > #impl-MultiImplBlockStruct-1) > div section[id=
 
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=MultiImplBlockStruct->u32"
 wait-for: "#search-tabs"
+wait-for-false: "#search-tabs .count.loading"
 assert-count: ("a.result-method", 1)
 assert-attribute: ("a.result-method", {
     "href": "../lib2/another_mod/struct.MultiImplBlockStruct.html#impl-MultiImplBlockTrait-for-MultiImplBlockStruct/method.second_fn"
diff --git a/tests/rustdoc-gui/search-result-keyword.goml b/tests/rustdoc-gui/search-result-keyword.goml
index 02305f2587c..d9bdf6d0135 100644
--- a/tests/rustdoc-gui/search-result-keyword.goml
+++ b/tests/rustdoc-gui/search-result-keyword.goml
@@ -1,8 +1,5 @@
 // Checks that the "keyword" results have the expected text alongside them.
+include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write-into: (".search-input", "for")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "for"})
 assert-text: (".result-keyword .result-name", "keyword for")
diff --git a/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml b/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml
index 7e26229ec6e..7bd283c5739 100644
--- a/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml
+++ b/tests/rustdoc-gui/search-tab-change-title-fn-sig.goml
@@ -1,11 +1,9 @@
 // Checks that the search tab results work correctly with function signature syntax
 // First, try a search-by-name
+include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write-into: (".search-input", "Foo")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "Foo"})
+
 assert-attribute: ("#search-tabs > button:nth-of-type(1)", {"class": "selected"})
 assert-text: ("#search-tabs > button:nth-of-type(1)", "In Names", STARTS_WITH)
 assert: "input.search-input:focus"
@@ -23,11 +21,7 @@ wait-for-attribute: ("#search-tabs > button:nth-of-type(3)", {"class": "selected
 
 // Now try search-by-return
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write-into: (".search-input", "-> String")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "-> String"})
 assert-attribute: ("#search-tabs > button:nth-of-type(1)", {"class": "selected"})
 assert-text: ("#search-tabs > button:nth-of-type(1)", "In Function Return Types", STARTS_WITH)
 assert: "input.search-input:focus"
@@ -45,30 +39,18 @@ wait-for-attribute: ("#search-tabs > button:nth-of-type(1)", {"class": "selected
 
 // Try with a search-by-return with no results
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write-into: (".search-input", "-> Something")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "-> Something"})
 assert-attribute: ("#search-tabs > button:nth-of-type(1)", {"class": "selected"})
 assert-text: ("#search-tabs > button:nth-of-type(1)", "In Function Return Types", STARTS_WITH)
 
 // Try with a search-by-parameter
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write-into: (".search-input", "usize,pattern")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "usize,pattern"})
 assert-attribute: ("#search-tabs > button:nth-of-type(1)", {"class": "selected"})
 assert-text: ("#search-tabs > button:nth-of-type(1)", "In Function Parameters", STARTS_WITH)
 
 // Try with a search-by-parameter-and-return
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-write-into: (".search-input", "pattern -> str")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-// Waiting for the search results to appear...
-wait-for: "#search-tabs"
+call-function: ("perform-search", {"query": "pattern -> str"})
 assert-attribute: ("#search-tabs > button:nth-of-type(1)", {"class": "selected"})
 assert-text: ("#search-tabs > button:nth-of-type(1)", "In Function Signatures", STARTS_WITH)
diff --git a/tests/rustdoc-gui/search-tab.goml b/tests/rustdoc-gui/search-tab.goml
index 826e272e508..00ca952033d 100644
--- a/tests/rustdoc-gui/search-tab.goml
+++ b/tests/rustdoc-gui/search-tab.goml
@@ -15,7 +15,8 @@ define-function: (
         focus: ".search-input"
         press-key: "Enter"
 
-        wait-for: "#search-tabs"
+        wait-for: "#search-tabs .count"
+        wait-for-false: "#search-tabs .count.loading"
         assert-css: ("#search-tabs > button:not(.selected)", {
             "background-color": |background|,
             "border-bottom": |border_bottom|,
diff --git a/tests/rustdoc-gui/search-title.goml b/tests/rustdoc-gui/search-title.goml
index 95bc36af449..83321a05f2b 100644
--- a/tests/rustdoc-gui/search-title.goml
+++ b/tests/rustdoc-gui/search-title.goml
@@ -5,10 +5,7 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 store-value: (title, "test_docs - Rust")
 assert-document-property: {"title": |title|}
 
-write-into: (".search-input", "test")
-// To be SURE that the search will be run.
-press-key: 'Enter'
-wait-for: "#crate-search"
+call-function: ("perform-search", {"query": "test"})
 
 assert-document-property: {"title": '"test" Search - Rust'}
 
@@ -16,6 +13,7 @@ set-property: (".search-input", {"value": "another one"})
 // To be SURE that the search will be run.
 press-key: 'Enter'
 wait-for: "#crate-search"
+wait-for-false: "#search-tabs .count.loading"
 
 assert-document-property: {"title": '"another one" Search - Rust'}
 
diff --git a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
index 9afde7c61da..342bd726694 100644
--- a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
+++ b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
@@ -9,7 +9,7 @@ define-function: (
     [storage_value, setting_attribute_value, toggle_attribute_value],
     block {
         assert-local-storage: {"rustdoc-auto-hide-large-items": |storage_value|}
-        click: "#settings-menu"
+        click: "rustdoc-toolbar .settings-menu"
         wait-for: "#settings"
         assert-property: ("#auto-hide-large-items", {"checked": |setting_attribute_value|})
         assert-attribute: (".item-decl .type-contents-toggle", {"open": |toggle_attribute_value|})
diff --git a/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml b/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
index 644396ed578..02d4ce8855f 100644
--- a/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
+++ b/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
@@ -6,7 +6,7 @@ define-function: (
     [storage_value, setting_attribute_value, toggle_attribute_value],
     block {
         assert-local-storage: {"rustdoc-auto-hide-method-docs": |storage_value|}
-        click: "#settings-menu"
+        click: "rustdoc-toolbar .settings-menu"
         wait-for: "#settings"
         assert-property: ("#auto-hide-method-docs", {"checked": |setting_attribute_value|})
         assert-attribute: (".toggle.method-toggle", {"open": |toggle_attribute_value|})
diff --git a/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml b/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml
index 3c09198dae5..4af1e829b31 100644
--- a/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml
+++ b/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml
@@ -5,7 +5,7 @@ define-function: (
     [storage_value, setting_attribute_value, toggle_attribute_value],
     block {
         assert-local-storage: {"rustdoc-auto-hide-trait-implementations": |storage_value|}
-        click: "#settings-menu"
+        click: "rustdoc-toolbar .settings-menu"
         wait-for: "#settings"
         assert-property: ("#auto-hide-trait-implementations", {"checked": |setting_attribute_value|})
         assert-attribute: ("#trait-implementations-list > details", {"open": |toggle_attribute_value|}, ALL)
diff --git a/tests/rustdoc-gui/setting-go-to-only-result.goml b/tests/rustdoc-gui/setting-go-to-only-result.goml
index f8535477c22..5a9c81e0b83 100644
--- a/tests/rustdoc-gui/setting-go-to-only-result.goml
+++ b/tests/rustdoc-gui/setting-go-to-only-result.goml
@@ -5,7 +5,7 @@ define-function: (
     [storage_value, setting_attribute_value],
     block {
         assert-local-storage: {"rustdoc-go-to-only-result": |storage_value|}
-        click: "#settings-menu"
+        click: "rustdoc-toolbar .settings-menu"
         wait-for: "#settings"
         assert-property: ("#go-to-only-result", {"checked": |setting_attribute_value|})
     }
@@ -25,7 +25,7 @@ wait-for: "#search"
 assert-document-property: ({"URL": "/lib2/index.html"}, CONTAINS)
 
 // Now we change its value.
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#settings"
 click: "#go-to-only-result"
 assert-local-storage: {"rustdoc-go-to-only-result": "true"}
diff --git a/tests/rustdoc-gui/settings-button.goml b/tests/rustdoc-gui/settings-button.goml
index d78034769e2..28ce06207aa 100644
--- a/tests/rustdoc-gui/settings-button.goml
+++ b/tests/rustdoc-gui/settings-button.goml
@@ -9,7 +9,7 @@ define-function: (
     [theme, filter],
     block {
         call-function: ("switch-theme", {"theme": |theme|})
-        assert-css: ("#settings-menu > a::before", {
+        assert-css: ("rustdoc-toolbar .settings-menu > a::before", {
             "filter": |filter|,
             "width": "18px",
             "height": "18px",
diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml
index 11d3696ccf6..7a163103b5a 100644
--- a/tests/rustdoc-gui/settings.goml
+++ b/tests/rustdoc-gui/settings.goml
@@ -5,7 +5,7 @@ show-text: true // needed when we check for colors below.
 // First, we check that the settings page doesn't exist.
 assert-false: "#settings"
 // We now click on the settings button.
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#settings"
 assert-css: ("#settings", {"display": "block"})
 
@@ -13,11 +13,11 @@ assert-css: ("#settings", {"display": "block"})
 store-css: (".setting-line", {"margin": setting_line_margin})
 
 // Let's close it by clicking on the same button.
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for-css: ("#settings", {"display": "none"})
 
 // Let's check that pressing "ESCAPE" is closing it.
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for-css: ("#settings", {"display": "block"})
 press-key: "Escape"
 wait-for-css: ("#settings", {"display": "none"})
@@ -28,7 +28,7 @@ write: "test"
 // To be SURE that the search will be run.
 press-key: 'Enter'
 wait-for: "#alternative-display #search"
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for-css: ("#settings", {"display": "block"})
 // Ensure that the search is still displayed.
 wait-for: "#alternative-display #search"
@@ -41,7 +41,7 @@ set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"
 // We reload the page so the local storage settings are being used.
 reload:
 
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#settings"
 
 // We check that the "Use system theme" is disabled.
@@ -55,7 +55,7 @@ assert: "#preferred-light-theme.setting-line.hidden"
 assert-property: ("#theme .setting-radio-choices #theme-dark", {"checked": "true"})
 
 // Some style checks...
-move-cursor-to: "#settings-menu > a"
+move-cursor-to: "rustdoc-toolbar .settings-menu > a"
 // First we check the "default" display for radio buttons.
 assert-css: (
     "#theme-dark",
@@ -194,7 +194,7 @@ assert-css: (
         "border-width": "2px",
     },
 )
-move-cursor-to: "#settings-menu > a"
+move-cursor-to: "rustdoc-toolbar .settings-menu > a"
 // Let's now check with the focus for toggles.
 focus: "#auto-hide-large-items"
 assert-css: (
@@ -273,43 +273,43 @@ assert-local-storage: {"rustdoc-disable-shortcuts": "true"}
 press-key: "Escape"
 press-key: "?"
 assert-false: "#help-button .popover"
-wait-for-css: ("#settings-menu .popover", {"display": "block"})
+wait-for-css: ("rustdoc-toolbar .settings-menu .popover", {"display": "block"})
 
 // Now turn keyboard shortcuts back on, and see if they work.
 click: "#disable-shortcuts"
 assert-local-storage: {"rustdoc-disable-shortcuts": "false"}
 press-key: "Escape"
 press-key: "?"
-wait-for-css: ("#help-button .popover", {"display": "block"})
-assert-css: ("#settings-menu .popover", {"display": "none"})
+wait-for-css: ("rustdoc-toolbar .help-menu .popover", {"display": "block"})
+assert-css: ("rustdoc-toolbar .settings-menu .popover", {"display": "none"})
 
 // Now switch back to the settings popover, and make sure the keyboard
 // shortcut works when a check box is selected.
-click: "#settings-menu > a"
-wait-for-css: ("#settings-menu .popover", {"display": "block"})
+click: "rustdoc-toolbar .settings-menu > a"
+wait-for-css: ("rustdoc-toolbar .settings-menu .popover", {"display": "block"})
 focus: "#auto-hide-large-items"
 press-key: "?"
-wait-for-css: ("#settings-menu .popover", {"display": "none"})
-wait-for-css: ("#help-button .popover", {"display": "block"})
+wait-for-css: ("rustdoc-toolbar .settings-menu .popover", {"display": "none"})
+wait-for-css: ("rustdoc-toolbar .help-menu .popover", {"display": "block"})
 
 // Now switch back to the settings popover, and make sure the keyboard
 // shortcut works when a check box is selected.
-click: "#settings-menu > a"
-wait-for-css: ("#settings-menu .popover", {"display": "block"})
-wait-for-css: ("#help-button .popover", {"display": "none"})
+click: "rustdoc-toolbar .settings-menu > a"
+wait-for-css: ("rustdoc-toolbar .settings-menu .popover", {"display": "block"})
+assert-false: "rustdoc-toolbar .help-menu .popover"
 focus: "#theme-system-preference"
 press-key: "?"
-wait-for-css: ("#settings-menu .popover", {"display": "none"})
-wait-for-css: ("#help-button .popover", {"display": "block"})
+wait-for-css: ("rustdoc-toolbar .settings-menu .popover", {"display": "none"})
+wait-for-css: ("rustdoc-toolbar .help-menu .popover", {"display": "block"})
 
 // Now we go to the settings page to check that the CSS is loaded as expected.
 go-to: "file://" + |DOC_PATH| + "/settings.html"
 wait-for: "#settings"
-assert-false: "#settings-menu"
+assert-false: "rustdoc-toolbar .settings-menu"
 assert-css: (".setting-radio", {"cursor": "pointer"})
 
 assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
-compare-elements-position: (".sub form", "#settings", ["x"])
+compare-elements-position: (".main-heading", "#settings", ["x"])
 
 // Check that setting-line has the same margin in this mode as in the popover.
 assert-css: (".setting-line", {"margin": |setting_line_margin|})
diff --git a/tests/rustdoc-gui/shortcuts.goml b/tests/rustdoc-gui/shortcuts.goml
index 5a6171d6f76..b27cf8c407d 100644
--- a/tests/rustdoc-gui/shortcuts.goml
+++ b/tests/rustdoc-gui/shortcuts.goml
@@ -8,9 +8,9 @@ press-key: "Escape"
 assert-false: "input.search-input:focus"
 // We now check for the help popup.
 press-key: "?"
-assert-css: ("#help-button .popover", {"display": "block"})
+assert-css: ("rustdoc-toolbar .help-menu .popover", {"display": "block"})
 press-key: "Escape"
-assert-css: ("#help-button .popover", {"display": "none"})
+assert-false: "rustdoc-toolbar .help-menu .popover"
 // Checking doc collapse and expand.
 // It should be displaying a "-":
 assert-text: ("#toggle-all-docs", "Summary")
diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml
index 6ddc07c6481..f828516d762 100644
--- a/tests/rustdoc-gui/sidebar-mobile.goml
+++ b/tests/rustdoc-gui/sidebar-mobile.goml
@@ -17,7 +17,7 @@ assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 focus: ".sidebar-elems h3 a"
 assert-css: (".sidebar", {"display": "block", "left": "0px"})
 // When we tab out of the sidebar, close it.
-focus: ".search-input"
+focus: "#search-button"
 assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 
 // Open the sidebar menu.
@@ -43,7 +43,7 @@ press-key: "Escape"
 assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 
 // Check that the topbar is visible
-assert-property: (".mobile-topbar", {"clientHeight": "45"})
+assert-property: ("rustdoc-topbar", {"clientHeight": "45"})
 
 // Check that clicking an element from the sidebar scrolls to the right place
 // so the target is not obscured by the topbar.
@@ -54,7 +54,7 @@ assert-position: ("#method\.must_use", {"y": 46})
 // Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
 click: ".sidebar-menu-toggle"
 scroll-to: ".block.keyword li:nth-child(1)"
-compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 544})
+compare-elements-position-near: (".block.keyword li:nth-child(1)", "rustdoc-topbar", {"y": 544})
 
 // Now checking the background color of the sidebar.
 // Close the sidebar menu.
@@ -65,7 +65,7 @@ define-function: (
     "check-colors",
     [theme, color, background],
     block {
-        call-function: ("switch-theme", {"theme": |theme|})
+        call-function: ("switch-theme-mobile", {"theme": |theme|})
         reload:
 
         // Open the sidebar menu.
diff --git a/tests/rustdoc-gui/sidebar-resize-close-popover.goml b/tests/rustdoc-gui/sidebar-resize-close-popover.goml
index 2d26caf1a39..d3fea9b0f40 100644
--- a/tests/rustdoc-gui/sidebar-resize-close-popover.goml
+++ b/tests/rustdoc-gui/sidebar-resize-close-popover.goml
@@ -2,7 +2,7 @@
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 assert-property: (".sidebar", {"clientWidth": "199"})
 show-text: true
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#settings"
 assert-css: ("#settings", {"display": "block"})
 // normal resizing
@@ -12,7 +12,7 @@ assert-css: ("#settings", {"display": "none"})
 
 // Now same thing, but for source code
 go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#settings"
 assert-css: ("#settings", {"display": "block"})
 assert-property: (".sidebar", {"clientWidth": "49"})
diff --git a/tests/rustdoc-gui/sidebar-resize-setting.goml b/tests/rustdoc-gui/sidebar-resize-setting.goml
index e346fe6aeac..a4572c670f8 100644
--- a/tests/rustdoc-gui/sidebar-resize-setting.goml
+++ b/tests/rustdoc-gui/sidebar-resize-setting.goml
@@ -4,7 +4,7 @@ assert-property: (".sidebar", {"clientWidth": "199"})
 show-text: true
 
 // Verify that the "hide" option is unchecked
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#settings"
 assert-css: ("#settings", {"display": "block"})
 assert-property: ("#hide-sidebar", {"checked": "false"})
@@ -15,7 +15,7 @@ drag-and-drop: ((205, 100), (5, 100))
 assert-css: (".sidebar", {"display": "none"})
 
 // Verify that the "hide" option is checked
-focus: "#settings-menu a"
+focus: "rustdoc-toolbar .settings-menu a"
 press-key: "Enter"
 wait-for-css: ("#settings", {"display": "block"})
 assert-property: ("#hide-sidebar", {"checked": "true"})
@@ -24,28 +24,28 @@ wait-for-css: (".sidebar", {"display": "block"})
 
 // Verify that hiding the sidebar hides the source sidebar
 // and puts the button in static position mode on mobile
-go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 set-window-size: (600, 600)
-focus: "#settings-menu a"
+focus: "rustdoc-topbar .settings-menu a"
 press-key: "Enter"
 wait-for-css: ("#settings", {"display": "block"})
+wait-for-css: ("#sidebar-button", {"position": "static"})
+assert-property: ("#hide-sidebar", {"checked": "false"})
+click: "#hide-sidebar"
+wait-for-css: (".sidebar", {"display": "none"})
 wait-for-css: ("#sidebar-button", {"position": "fixed"})
 store-position: ("#sidebar-button", {
     "y": sidebar_button_y,
     "x": sidebar_button_x,
 })
-assert-property: ("#hide-sidebar", {"checked": "false"})
-click: "#hide-sidebar"
-wait-for-css: (".sidebar", {"display": "none"})
-wait-for-css: ("#sidebar-button", {"position": "static"})
-assert-position: ("#sidebar-button", {
-    "y": |sidebar_button_y|,
-    "x": |sidebar_button_x|,
-})
 assert-property: ("#hide-sidebar", {"checked": "true"})
 press-key: "Escape"
 // Clicking the sidebar button should work, and implicitly re-enable
 // the persistent navigation bar
 wait-for-css: ("#settings", {"display": "none"})
+assert-position: ("#sidebar-button", {
+    "y": |sidebar_button_y|,
+    "x": |sidebar_button_x|,
+})
 click: "#sidebar-button"
 wait-for-css: (".sidebar", {"display": "block"})
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index 1e77bcc2273..99810cd7863 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -141,7 +141,7 @@ click: "#sidebar-button"
 wait-for-css: (".src .sidebar > *", {"visibility": "hidden"})
 // We scroll to line 117 to change the scroll position.
 scroll-to: '//*[@id="117"]'
-store-value: (y_offset, "2578")
+store-value: (y_offset, "2567")
 assert-window-property: {"pageYOffset": |y_offset|}
 // Expanding the sidebar...
 click: "#sidebar-button"
diff --git a/tests/rustdoc-gui/sidebar-source-code.goml b/tests/rustdoc-gui/sidebar-source-code.goml
index 6afccf6a95f..0ac88612cef 100644
--- a/tests/rustdoc-gui/sidebar-source-code.goml
+++ b/tests/rustdoc-gui/sidebar-source-code.goml
@@ -85,4 +85,4 @@ assert-false: ".src-sidebar-expanded"
 assert: "nav.sidebar"
 
 // Check that the topbar is not visible
-assert-false: ".mobile-topbar"
+assert-false: "rustdoc-topbar"
diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml
index c0fe240e2be..5ec0008ad8a 100644
--- a/tests/rustdoc-gui/sidebar.goml
+++ b/tests/rustdoc-gui/sidebar.goml
@@ -200,7 +200,7 @@ drag-and-drop: ((205, 100), (108, 100))
 assert-position: (".sidebar-crate > h2 > a", {"x": -3})
 
 // Check that the mobile sidebar and the source sidebar use the same icon.
-store-css: (".mobile-topbar .sidebar-menu-toggle::before", {"content": image_url})
+store-css: ("rustdoc-topbar .sidebar-menu-toggle::before", {"content": image_url})
 // Then we go to a source page.
 click: ".main-heading .src"
 assert-css: ("#sidebar-button a::before", {"content": |image_url|})
@@ -212,7 +212,7 @@ assert: |sidebar_background| != |sidebar_background_hover|
 click: "#sidebar-button a"
 wait-for: "html.src-sidebar-expanded"
 assert-css: ("#sidebar-button a:hover", {"background-color": |sidebar_background_hover|})
-move-cursor-to: "#settings-menu"
+move-cursor-to: "#search-button"
 assert-css: ("#sidebar-button a:not(:hover)", {"background-color": |sidebar_background|})
 // Closing sidebar.
 click: "#sidebar-button a"
@@ -220,7 +220,7 @@ wait-for: "html:not(.src-sidebar-expanded)"
 // Now we check the same when the sidebar button is moved alongside the search.
 set-window-size: (500, 500)
 store-css: ("#sidebar-button a:hover", {"background-color": not_sidebar_background_hover})
-move-cursor-to: "#settings-menu"
+move-cursor-to: "rustdoc-toolbar #search-button"
 store-css: ("#sidebar-button a:not(:hover)", {"background-color": not_sidebar_background})
 // The sidebar background is supposed to be the same as the main background.
 assert-css: ("body", {"background-color": |not_sidebar_background|})
diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml
index c005af1e7a1..b1cbd02ef04 100644
--- a/tests/rustdoc-gui/source-anchor-scroll.goml
+++ b/tests/rustdoc-gui/source-anchor-scroll.goml
@@ -8,13 +8,13 @@ set-window-size: (600, 800)
 assert-property: ("html", {"scrollTop": "0"})
 
 click: '//a[text() = "barbar" and @href="#5-7"]'
-assert-property: ("html", {"scrollTop": "206"})
+assert-property: ("html", {"scrollTop": "195"})
 click: '//a[text() = "bar" and @href="#28-36"]'
-assert-property: ("html", {"scrollTop": "239"})
+assert-property: ("html", {"scrollTop": "228"})
 click: '//a[normalize-space() = "sub_fn" and @href="#2-4"]'
-assert-property: ("html", {"scrollTop": "134"})
+assert-property: ("html", {"scrollTop": "123"})
 
 // We now check that clicking on lines doesn't change the scroll
 // Extra information: the "sub_fn" function header is on line 1.
 click: '//*[@id="6"]'
-assert-property: ("html", {"scrollTop": "134"})
+assert-property: ("html", {"scrollTop": "123"})
diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml
index aa5a16aac70..5e3470dca20 100644
--- a/tests/rustdoc-gui/source-code-page.goml
+++ b/tests/rustdoc-gui/source-code-page.goml
@@ -89,9 +89,9 @@ assert-css: ("a[data-nosnippet]", {"text-align": "right"}, ALL)
 // do anything (and certainly not add a `#NaN` to the URL!).
 go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 // We use this assert-position to know where we will click.
-assert-position: ("//*[@id='1']", {"x": 81, "y": 169})
-// We click on the left of the "1" anchor but still in the `a[data-nosnippet]`.
-click: (77, 163)
+assert-position: ("//*[@id='1']", {"x": 81, "y": 141})
+// We click on the left of the "1" anchor but still in the "src-line-number" `<pre>`.
+click: (135, 77)
 assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
 
 // Checking the source code sidebar.
@@ -156,27 +156,8 @@ call-function: ("check-sidebar-dir-entry", {
     "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 7,
 })
 
-// Check the search form
-assert-css: ("nav.sub", {"flex-direction": "row"})
-// The goal of this test is to ensure the search input is perfectly centered
-// between the top of the page and the header.
-// To check this, we maintain the invariant:
-//
-// offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form]
-assert-position: ("nav.sub form", {"y": 15})
-assert-property: ("nav.sub form", {"offsetHeight": 34})
-assert-position: ("h1", {"y": 68})
-// 15 = 64 - 34 - 15
-
-// Now do the same check on moderately-sized, tablet mobile.
-set-window-size: (700, 700)
-assert-css: ("nav.sub", {"flex-direction": "row"})
-assert-position: ("nav.sub form", {"y": 8})
-assert-property: ("nav.sub form", {"offsetHeight": 34})
-assert-position: ("h1", {"y": 54})
-// 8 = 50 - 34 - 8
-
 // Check the sidebar directory entries have a marker and spacing (tablet).
+set-window-size: (700, 700)
 store-property: (".src-sidebar-title", {
     "offsetHeight": source_sidebar_title_height,
     "offsetTop": source_sidebar_title_y,
@@ -187,11 +168,8 @@ call-function: ("check-sidebar-dir-entry", {
     "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 7,
 })
 
-// Tiny, phone mobile gets a different display where the logo is stacked on top.
-set-window-size: (450, 700)
-assert-css: ("nav.sub", {"flex-direction": "column"})
-
 // Check the sidebar directory entries have a marker and spacing (phone).
+set-window-size: (450, 700)
 store-property: (".src-sidebar-title", {
     "offsetHeight": source_sidebar_title_height,
     "offsetTop": source_sidebar_title_y,
diff --git a/tests/rustdoc-gui/source-code-wrapping.goml b/tests/rustdoc-gui/source-code-wrapping.goml
index 0dab9c72ea9..c1fc2835c89 100644
--- a/tests/rustdoc-gui/source-code-wrapping.goml
+++ b/tests/rustdoc-gui/source-code-wrapping.goml
@@ -13,7 +13,7 @@ define-function: (
 )
 
 store-size: (".rust code", {"width": width, "height": height})
-click: "#settings-menu"
+click: "main .settings-menu"
 wait-for: "#settings"
 call-function: ("click-code-wrapping", {"expected": "true"})
 wait-for-size-false: (".rust code", {"width": |width|, "height": |height|})
@@ -28,7 +28,7 @@ assert-size: (".rust code", {"width": |width|, "height": |height|})
 
 // Now let's check in docs code examples.
 go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/index.html"
-click: "#settings-menu"
+click: "main .settings-menu"
 wait-for: "#settings"
 
 store-property: (".example-wrap .rust code", {"scrollWidth": rust_width, "scrollHeight": rust_height})
diff --git a/tests/rustdoc-gui/theme-change.goml b/tests/rustdoc-gui/theme-change.goml
index 58987110509..3860596e343 100644
--- a/tests/rustdoc-gui/theme-change.goml
+++ b/tests/rustdoc-gui/theme-change.goml
@@ -7,7 +7,7 @@ store-value: (background_light, "white")
 store-value: (background_dark, "#353535")
 store-value: (background_ayu, "#0f1419")
 
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#theme-ayu"
 click: "#theme-ayu"
 // should be the ayu theme so let's check the color.
@@ -75,7 +75,7 @@ store-value: (background_dark, "#353535")
 store-value: (background_ayu, "#0f1419")
 store-value: (background_custom_theme, "red")
 
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#theme-ayu"
 click: "#theme-ayu"
 // should be the ayu theme so let's check the color.
diff --git a/tests/rustdoc-gui/theme-defaults.goml b/tests/rustdoc-gui/theme-defaults.goml
index 2cc5d716cfe..12c17166e87 100644
--- a/tests/rustdoc-gui/theme-defaults.goml
+++ b/tests/rustdoc-gui/theme-defaults.goml
@@ -1,6 +1,6 @@
 // Ensure that the theme picker always starts with the actual defaults.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#theme-system-preference"
 assert: "#theme-system-preference:checked"
 assert: "#preferred-light-theme-light:checked"
@@ -16,7 +16,7 @@ set-local-storage: {
     "rustdoc-theme": "ayu"
 }
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-click: "#settings-menu"
+click: "rustdoc-toolbar .settings-menu"
 wait-for: "#theme-system-preference"
 assert: "#theme-system-preference:checked"
 assert: "#preferred-light-theme-light:checked"
diff --git a/tests/rustdoc-gui/toggle-click-deadspace.goml b/tests/rustdoc-gui/toggle-click-deadspace.goml
index caca1b61493..c6d13973087 100644
--- a/tests/rustdoc-gui/toggle-click-deadspace.goml
+++ b/tests/rustdoc-gui/toggle-click-deadspace.goml
@@ -13,4 +13,4 @@ assert-attribute-false: (".impl-items .toggle", {"open": ""})
 // Click the "Trait" part of "impl Trait" and verify it navigates.
 click: "#impl-Trait-for-Foo h3 a:first-of-type"
 assert-text: (".main-heading .rustdoc-breadcrumbs", "lib2")
-assert-text: (".main-heading h1", "Trait TraitCopy item path")
+assert-text: (".main-heading h1", "Trait Trait Copy item path")
diff --git a/tests/rustdoc-gui/toggle-docs-mobile.goml b/tests/rustdoc-gui/toggle-docs-mobile.goml
index 6a40ba83b84..d038ebcdd6f 100644
--- a/tests/rustdoc-gui/toggle-docs-mobile.goml
+++ b/tests/rustdoc-gui/toggle-docs-mobile.goml
@@ -3,12 +3,12 @@
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 set-window-size: (433, 600)
 assert-attribute: (".top-doc", {"open": ""})
-click: (4, 270) // This is the position of the top doc comment toggle
+click: (4, 230) // This is the position of the top doc comment toggle
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 270)
+click: (4, 230)
 assert-attribute: (".top-doc", {"open": ""})
 // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
-click: (3, 270)
+click: (3, 230)
 assert-attribute: (".top-doc", {"open": ""})
 
 // Assert the position of the toggle on the top doc block.
@@ -24,12 +24,12 @@ assert-position: (
 // Now we do the same but with a little bigger width
 set-window-size: (600, 600)
 assert-attribute: (".top-doc", {"open": ""})
-click: (4, 270) // New Y position since all search elements are back on one line.
+click: (4, 230) // New Y position since all search elements are back on one line.
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 270)
+click: (4, 230)
 assert-attribute: (".top-doc", {"open": ""})
 // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
-click: (3, 270)
+click: (3, 230)
 assert-attribute: (".top-doc", {"open": ""})
 
 // Same check on trait items.
diff --git a/tests/rustdoc-gui/toggle-docs.goml b/tests/rustdoc-gui/toggle-docs.goml
index 4607c604eeb..9eea687f74e 100644
--- a/tests/rustdoc-gui/toggle-docs.goml
+++ b/tests/rustdoc-gui/toggle-docs.goml
@@ -64,7 +64,7 @@ define-function: (
             "filter": |filter|,
         })
         // moving the cursor somewhere else to not mess with next function calls.
-        move-cursor-to: ".search-input"
+        move-cursor-to: "#search-button"
     },
 )
 
diff --git a/tests/rustdoc-gui/type-declation-overflow.goml b/tests/rustdoc-gui/type-declation-overflow.goml
index 4f8fe78ea4d..e53d7f00d93 100644
--- a/tests/rustdoc-gui/type-declation-overflow.goml
+++ b/tests/rustdoc-gui/type-declation-overflow.goml
@@ -47,27 +47,27 @@ assert-property: ("pre.item-decl", {"scrollWidth": "950"})
 set-window-size: (600, 600)
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
 // It shouldn't have an overflow in the topbar either.
-store-property: (".mobile-topbar", {"scrollWidth": scrollWidth})
-assert-property: (".mobile-topbar", {"clientWidth": |scrollWidth|})
-assert-css: (".mobile-topbar h2", {"overflow-x": "hidden"})
+store-property: ("rustdoc-topbar", {"scrollWidth": scrollWidth})
+assert-property: ("rustdoc-topbar", {"clientWidth": |scrollWidth|}, NEAR)
+assert-css: ("rustdoc-topbar h2", {"overflow-x": "hidden"})
 
 // Check that main heading and toolbar go side-by-side, both on desktop and on mobile.
 set-window-size: (1100, 800)
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
-compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
-compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 550})
+compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar #search-button", ["y"])
+compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar #search-button", {"x": 300})
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
-compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
-compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 550})
+compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar #search-button", ["y"])
+compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar #search-button", {"x": 300})
 
 // On mobile, they always wrap.
 set-window-size: (600, 600)
 go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
-compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
-compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 200})
+compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar #search-button", ["y"])
+compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar #search-button", {"x": 200})
 go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
-compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
-compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 200})
+compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar #search-button", ["y"])
+compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar #search-button", {"x": 200})
 
 // Now we will check that the scrolling is working.
 // First on an item with "hidden methods".
diff --git a/tests/rustdoc-gui/utils.goml b/tests/rustdoc-gui/utils.goml
index 844dc98a537..10439309402 100644
--- a/tests/rustdoc-gui/utils.goml
+++ b/tests/rustdoc-gui/utils.goml
@@ -5,14 +5,47 @@ define-function: (
     block {
         // Set the theme.
         // Open the settings menu.
-        click: "#settings-menu"
+        click: "rustdoc-toolbar .settings-menu"
         // Wait for the popover to appear...
         wait-for: "#settings"
         // Change the setting.
         click: "#theme-"+ |theme|
         // Close the popover.
-        click: "#settings-menu"
+        click: "rustdoc-toolbar .settings-menu"
         // Ensure that the local storage was correctly updated.
         assert-local-storage: {"rustdoc-theme": |theme|}
     },
 )
+
+define-function: (
+    "switch-theme-mobile",
+    [theme],
+    block {
+        // Set the theme.
+        // Open the settings menu.
+        click: "rustdoc-topbar .settings-menu"
+        // Wait for the popover to appear...
+        wait-for: "#settings"
+        // Change the setting.
+        click: "#theme-"+ |theme|
+        // Close the popover.
+        click: "rustdoc-topbar .settings-menu"
+        // Ensure that the local storage was correctly updated.
+        assert-local-storage: {"rustdoc-theme": |theme|}
+    },
+)
+
+define-function: (
+    "perform-search",
+    [query],
+    block {
+        click: "#search-button"
+        wait-for: ".search-input"
+        write-into: (".search-input", |query|)
+        press-key: 'Enter'
+        // wait for the search to start
+        wait-for: "#search-tabs"
+        // then wait for it to finish
+        wait-for-false: "#search-tabs .count.loading"
+    }
+)
diff --git a/tests/rustdoc-js-std/alias-1.js b/tests/rustdoc-js-std/alias-1.js
index c31d1a3b1ad..b8f8db1f629 100644
--- a/tests/rustdoc-js-std/alias-1.js
+++ b/tests/rustdoc-js-std/alias-1.js
@@ -6,5 +6,10 @@ const EXPECTED = {
             'name': 'reference',
             'desc': "References, <code>&amp;T</code> and <code>&amp;mut T</code>.",
         },
+        {
+            'path': 'std::ops',
+            'name': 'BitAnd',
+            'desc': "The bitwise AND operator <code>&amp;</code>.",
+        },
     ],
 };
diff --git a/tests/rustdoc-js-std/alias-2.js b/tests/rustdoc-js-std/alias-2.js
index 5735b573bcb..9e97501e443 100644
--- a/tests/rustdoc-js-std/alias-2.js
+++ b/tests/rustdoc-js-std/alias-2.js
@@ -1,9 +1,7 @@
 const EXPECTED = {
     'query': '+',
     'others': [
-        { 'path': 'std::ops', 'name': 'AddAssign' },
         { 'path': 'std::ops', 'name': 'Add' },
-        { 'path': 'core::ops', 'name': 'AddAssign' },
-        { 'path': 'core::ops', 'name': 'Add' },
+        { 'path': 'std::ops', 'name': 'AddAssign' },
     ],
 };
diff --git a/tests/rustdoc-js-std/basic.js b/tests/rustdoc-js-std/basic.js
index baff24b0af6..74467f0eef1 100644
--- a/tests/rustdoc-js-std/basic.js
+++ b/tests/rustdoc-js-std/basic.js
@@ -9,6 +9,6 @@ const EXPECTED = {
         { 'path': 'std::str', 'name': 'eq' },
     ],
     'returned': [
-        { 'path': 'std::string::String', 'name': 'add' },
+        { 'path': 'std::string::String', 'name': 'new' },
     ],
 };
diff --git a/tests/rustdoc-js-std/parser-bindings.js b/tests/rustdoc-js-std/parser-bindings.js
index bd379f139ff..e00e3088303 100644
--- a/tests/rustdoc-js-std/parser-bindings.js
+++ b/tests/rustdoc-js-std/parser-bindings.js
@@ -20,12 +20,12 @@ const PARSED = [
                                 pathLast: "c",
                                 normalizedPathLast: "c",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                         ]
                     ],
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -51,11 +51,11 @@ const PARSED = [
                             pathWithoutLast: [],
                             pathLast: "c",
                             generics: [],
-                            typeFilter: -1,
+                            typeFilter: null,
                         }]
                     ],
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -81,11 +81,11 @@ const PARSED = [
                             pathWithoutLast: [],
                             pathLast: "never",
                             generics: [],
-                            typeFilter: 1,
+                            typeFilter: "primitive",
                         }]
                     ],
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -111,11 +111,11 @@ const PARSED = [
                             pathWithoutLast: [],
                             pathLast: "[]",
                             generics: [],
-                            typeFilter: 1,
+                            typeFilter: "primitive",
                         }]
                     ],
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -147,14 +147,14 @@ const PARSED = [
                                     pathWithoutLast: [],
                                     pathLast: "never",
                                     generics: [],
-                                    typeFilter: 1,
+                                    typeFilter: "primitive",
                                 },
                             ],
-                            typeFilter: 1,
+                            typeFilter: "primitive",
                         }]
                     ],
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -213,7 +213,7 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "c",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                             {
                                 name: "X",
@@ -221,12 +221,12 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "x",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                         ],
                     ],
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js
index 8bffef61c8f..49150cbd570 100644
--- a/tests/rustdoc-js-std/parser-errors.js
+++ b/tests/rustdoc-js-std/parser-errors.js
@@ -406,10 +406,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "x",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: "y",
@@ -417,7 +417,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "y",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 2,
@@ -440,7 +440,7 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "x",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                     {
                         name: "y",
@@ -448,10 +448,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "y",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -468,7 +468,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "p",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: "x",
@@ -476,7 +476,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "x",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: "y",
@@ -484,7 +484,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "y",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 3,
diff --git a/tests/rustdoc-js-std/parser-filter.js b/tests/rustdoc-js-std/parser-filter.js
index cda950461f7..569ef9aa96c 100644
--- a/tests/rustdoc-js-std/parser-filter.js
+++ b/tests/rustdoc-js-std/parser-filter.js
@@ -7,7 +7,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "foo",
             generics: [],
-            typeFilter: 7,
+            typeFilter: "fn",
         }],
         foundElems: 1,
         userQuery: "fn:foo",
@@ -22,7 +22,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "foo",
             generics: [],
-            typeFilter: 6,
+            typeFilter: "enum",
         }],
         foundElems: 1,
         userQuery: "enum : foo",
@@ -45,7 +45,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "macro",
             generics: [],
-            typeFilter: 16,
+            typeFilter: "macro",
         }],
         foundElems: 1,
         userQuery: "macro!",
@@ -60,7 +60,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "mac",
             generics: [],
-            typeFilter: 16,
+            typeFilter: "macro",
         }],
         foundElems: 1,
         userQuery: "macro:mac!",
@@ -75,7 +75,7 @@ const PARSED = [
             pathWithoutLast: ["a"],
             pathLast: "mac",
             generics: [],
-            typeFilter: 16,
+            typeFilter: "macro",
         }],
         foundElems: 1,
         userQuery: "a::mac!",
@@ -93,7 +93,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "foo",
             generics: [],
-            typeFilter: 7,
+            typeFilter: "fn",
         }],
         error: null,
     },
@@ -114,10 +114,10 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "bar",
                     generics: [],
-                    typeFilter: 7,
+                    typeFilter: "fn",
                 }
             ],
-            typeFilter: 7,
+            typeFilter: "fn",
         }],
         error: null,
     },
@@ -138,7 +138,7 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "bar",
                     generics: [],
-                    typeFilter: 7,
+                    typeFilter: "fn",
                 },
                 {
                     name: "baz::fuzz",
@@ -146,10 +146,10 @@ const PARSED = [
                     pathWithoutLast: ["baz"],
                     pathLast: "fuzz",
                     generics: [],
-                    typeFilter: 6,
+                    typeFilter: "enum",
                 },
             ],
-            typeFilter: 7,
+            typeFilter: "fn",
         }],
         error: null,
     },
diff --git a/tests/rustdoc-js-std/parser-generics.js b/tests/rustdoc-js-std/parser-generics.js
index 8b8d95bcb88..deaa0adbc63 100644
--- a/tests/rustdoc-js-std/parser-generics.js
+++ b/tests/rustdoc-js-std/parser-generics.js
@@ -16,7 +16,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "p",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: "u8",
@@ -24,7 +24,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "u8",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 2,
@@ -49,7 +49,7 @@ const PARSED = [
                         generics: [],
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -82,7 +82,7 @@ const PARSED = [
                         ],
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -122,7 +122,7 @@ const PARSED = [
                         generics: [],
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -162,7 +162,7 @@ const PARSED = [
                         ],
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
diff --git a/tests/rustdoc-js-std/parser-hof.js b/tests/rustdoc-js-std/parser-hof.js
index ca761015412..5de232a66cd 100644
--- a/tests/rustdoc-js-std/parser-hof.js
+++ b/tests/rustdoc-js-std/parser-hof.js
@@ -25,11 +25,11 @@ const PARSED = [
                                 generics: [],
                             },
                         ],
-                        typeFilter: -1,
+                        typeFilter: null,
                     }],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "(-> F<P>)",
@@ -53,11 +53,11 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "p",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     }],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "(-> P)",
@@ -81,11 +81,11 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "a",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     }],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "(->,a)",
@@ -113,7 +113,7 @@ const PARSED = [
                         generics: [],
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             }],
             bindings: [
                 [
@@ -121,7 +121,7 @@ const PARSED = [
                     [],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "(F<P> ->)",
@@ -141,7 +141,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "p",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             }],
             bindings: [
                 [
@@ -149,7 +149,7 @@ const PARSED = [
                     [],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "(P ->)",
@@ -169,7 +169,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "a",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             }],
             bindings: [
                 [
@@ -177,7 +177,7 @@ const PARSED = [
                     [],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "(,a->)",
@@ -197,7 +197,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "aaaaa",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             }],
             bindings: [
                 [
@@ -208,11 +208,11 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "a",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     }],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "(aaaaa->a)",
@@ -233,7 +233,7 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "aaaaa",
                     generics: [],
-                    typeFilter: -1,
+                    typeFilter: null,
                 },
                 {
                     name: "b",
@@ -241,7 +241,7 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "b",
                     generics: [],
-                    typeFilter: -1,
+                    typeFilter: null,
                 },
             ],
             bindings: [
@@ -253,11 +253,11 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "a",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     }],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "(aaaaa, b -> a)",
@@ -278,7 +278,7 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "aaaaa",
                     generics: [],
-                    typeFilter: -1,
+                    typeFilter: null,
                 },
                 {
                     name: "b",
@@ -286,7 +286,7 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "b",
                     generics: [],
-                    typeFilter: -1,
+                    typeFilter: null,
                 },
             ],
             bindings: [
@@ -298,11 +298,11 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "a",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     }],
                 ],
             ],
-            typeFilter: 1,
+            typeFilter: "primitive",
         }],
         foundElems: 1,
         userQuery: "primitive:(aaaaa, b -> a)",
@@ -318,7 +318,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "x",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: "->",
@@ -332,7 +332,7 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "aaaaa",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                     {
                         name: "b",
@@ -340,7 +340,7 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "b",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
                 bindings: [
@@ -352,11 +352,11 @@ const PARSED = [
                             pathWithoutLast: [],
                             pathLast: "a",
                             generics: [],
-                            typeFilter: -1,
+                            typeFilter: null,
                         }],
                     ],
                 ],
-                typeFilter: 10,
+                typeFilter: "trait",
             }
         ],
         foundElems: 2,
@@ -390,11 +390,11 @@ const PARSED = [
                                 generics: [],
                             },
                         ],
-                        typeFilter: -1,
+                        typeFilter: null,
                     }],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "Fn () -> F<P>",
@@ -418,11 +418,11 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "p",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     }],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "FnMut() -> P",
@@ -446,11 +446,11 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "p",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     }],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "(FnMut() -> P)",
@@ -478,7 +478,7 @@ const PARSED = [
                         generics: [],
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             }],
             bindings: [
                 [
@@ -486,7 +486,7 @@ const PARSED = [
                     [],
                 ],
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "Fn(F<P>)",
@@ -507,7 +507,7 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "aaaaa",
                     generics: [],
-                    typeFilter: -1,
+                    typeFilter: null,
                 },
                 {
                     name: "b",
@@ -515,7 +515,7 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "b",
                     generics: [],
-                    typeFilter: -1,
+                    typeFilter: null,
                 },
             ],
             bindings: [
@@ -527,11 +527,11 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "a",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     }],
                 ],
             ],
-            typeFilter: 1,
+            typeFilter: "primitive",
         }],
         foundElems: 1,
         userQuery: "primitive:fnonce(aaaaa, b) -> a",
@@ -552,7 +552,7 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "aaaaa",
                     generics: [],
-                    typeFilter: -1,
+                    typeFilter: null,
                 },
                 {
                     name: "b",
@@ -560,7 +560,7 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "b",
                     generics: [],
-                    typeFilter: 0,
+                    typeFilter: "keyword",
                 },
             ],
             bindings: [
@@ -572,11 +572,11 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "a",
                         generics: [],
-                        typeFilter: 10,
+                        typeFilter: "trait",
                     }],
                 ],
             ],
-            typeFilter: 1,
+            typeFilter: "primitive",
         }],
         foundElems: 1,
         userQuery: "primitive:fnonce(aaaaa, keyword:b) -> trait:a",
@@ -592,7 +592,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "x",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: "fn",
@@ -612,7 +612,7 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "aaaaa",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                             {
                                 name: "b",
@@ -620,7 +620,7 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "b",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                         ],
                         bindings: [
@@ -632,11 +632,11 @@ const PARSED = [
                                     pathWithoutLast: [],
                                     pathLast: "a",
                                     generics: [],
-                                    typeFilter: -1,
+                                    typeFilter: null,
                                 }],
                             ],
                         ],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
                 bindings: [
@@ -645,7 +645,7 @@ const PARSED = [
                         [],
                     ]
                 ],
-                typeFilter: 10,
+                typeFilter: "trait",
             }
         ],
         foundElems: 2,
@@ -662,7 +662,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "a",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: "b",
@@ -675,7 +675,7 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "c",
                     generics: [],
-                    typeFilter: -1,
+                    typeFilter: null,
                 }],
                 bindings: [
                     [
@@ -683,7 +683,7 @@ const PARSED = [
                         [],
                     ]
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             }
         ],
         foundElems: 2,
diff --git a/tests/rustdoc-js-std/parser-ident.js b/tests/rustdoc-js-std/parser-ident.js
index f65391b1571..5366ac847b0 100644
--- a/tests/rustdoc-js-std/parser-ident.js
+++ b/tests/rustdoc-js-std/parser-ident.js
@@ -13,10 +13,10 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "never",
                     generics: [],
-                    typeFilter: 1,
+                    typeFilter: "primitive",
                 },
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "R<!>",
@@ -31,7 +31,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "never",
             generics: [],
-            typeFilter: 1,
+            typeFilter: "primitive",
         }],
         foundElems: 1,
         userQuery: "!",
@@ -46,7 +46,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "a",
             generics: [],
-            typeFilter: 16,
+            typeFilter: "macro",
         }],
         foundElems: 1,
         userQuery: "a!",
@@ -77,7 +77,7 @@ const PARSED = [
             pathWithoutLast: ["never"],
             pathLast: "b",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "!::b",
@@ -122,10 +122,10 @@ const PARSED = [
                     pathWithoutLast: [],
                     pathLast: "t",
                     generics: [],
-                    typeFilter: -1,
+                    typeFilter: null,
                 }
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "!::b<T>",
diff --git a/tests/rustdoc-js-std/parser-literal.js b/tests/rustdoc-js-std/parser-literal.js
index 63e07a246a1..803929b74fd 100644
--- a/tests/rustdoc-js-std/parser-literal.js
+++ b/tests/rustdoc-js-std/parser-literal.js
@@ -15,7 +15,7 @@ const PARSED = [
                     generics: [],
                 },
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "R<P>",
diff --git a/tests/rustdoc-js-std/parser-paths.js b/tests/rustdoc-js-std/parser-paths.js
index bb34e22e518..3ddd6572277 100644
--- a/tests/rustdoc-js-std/parser-paths.js
+++ b/tests/rustdoc-js-std/parser-paths.js
@@ -7,7 +7,7 @@ const PARSED = [
             pathWithoutLast: ["a"],
             pathLast: "b",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "A::B",
@@ -22,7 +22,7 @@ const PARSED = [
             pathWithoutLast: ["a"],
             pathLast: "a",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: 'a:: a',
@@ -37,7 +37,7 @@ const PARSED = [
             pathWithoutLast: ["a"],
             pathLast: "a",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: 'a ::a',
@@ -52,7 +52,7 @@ const PARSED = [
             pathWithoutLast: ["a"],
             pathLast: "a",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: 'a  ::  a',
@@ -68,7 +68,7 @@ const PARSED = [
                 pathWithoutLast: ["a"],
                 pathLast: "b",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: "C",
@@ -76,7 +76,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "c",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 2,
@@ -101,7 +101,7 @@ const PARSED = [
                         generics: [],
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: "C",
@@ -109,7 +109,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "c",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 2,
@@ -125,7 +125,7 @@ const PARSED = [
             pathWithoutLast: ["mod"],
             pathLast: "a",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "mod::a",
diff --git a/tests/rustdoc-js-std/parser-quote.js b/tests/rustdoc-js-std/parser-quote.js
index b485047e385..d5a9863367f 100644
--- a/tests/rustdoc-js-std/parser-quote.js
+++ b/tests/rustdoc-js-std/parser-quote.js
@@ -10,7 +10,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "p",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         error: null,
     },
@@ -22,7 +22,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "p",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: '"p",',
diff --git a/tests/rustdoc-js-std/parser-reference.js b/tests/rustdoc-js-std/parser-reference.js
index 0fa07ae9895..b17dad5fb1f 100644
--- a/tests/rustdoc-js-std/parser-reference.js
+++ b/tests/rustdoc-js-std/parser-reference.js
@@ -42,16 +42,16 @@ const PARSED = [
                                         pathWithoutLast: [],
                                         pathLast: "d",
                                         generics: [],
-                                        typeFilter: -1,
+                                        typeFilter: null,
                                     },
                                 ],
-                                typeFilter: 1,
+                                typeFilter: "primitive",
                             },
                         ],
-                        typeFilter: 1,
+                        typeFilter: "primitive",
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
             {
                 name: "[]",
@@ -59,7 +59,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "[]",
                 generics: [],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 2,
@@ -100,19 +100,19 @@ const PARSED = [
                                                 pathWithoutLast: [],
                                                 pathLast: "d",
                                                 generics: [],
-                                                typeFilter: -1,
+                                                typeFilter: null,
                                             },
                                         ],
-                                        typeFilter: 1,
+                                        typeFilter: "primitive",
                                     },
                                 ],
-                                typeFilter: 1,
+                                typeFilter: "primitive",
                             },
                         ],
-                        typeFilter: 1,
+                        typeFilter: "primitive",
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -129,7 +129,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "reference",
                 generics: [],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -152,10 +152,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "mut",
                         generics: [],
-                        typeFilter: 0,
+                        typeFilter: "keyword",
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -172,7 +172,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "reference",
                 generics: [],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
             {
                 name: "u8",
@@ -180,7 +180,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "u8",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 2,
@@ -203,10 +203,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "mut",
                         generics: [],
-                        typeFilter: 0,
+                        typeFilter: "keyword",
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
             {
                 name: "u8",
@@ -214,7 +214,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "u8",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 2,
@@ -237,10 +237,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -269,13 +269,13 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "u8",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                         ],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -304,13 +304,13 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "u8",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                         ],
-                        typeFilter: 1,
+                        typeFilter: "primitive",
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -339,10 +339,10 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "u8",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                         ],
-                        typeFilter: 1,
+                        typeFilter: "primitive",
                     },
                     {
                         name: "u8",
@@ -350,10 +350,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -382,13 +382,13 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "u8",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                         ],
-                        typeFilter: 1,
+                        typeFilter: "primitive",
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -417,7 +417,7 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "mut",
                                 generics: [],
-                                typeFilter: 0,
+                                typeFilter: "keyword",
                             },
                             {
                                 name: "u8",
@@ -425,10 +425,10 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "u8",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                         ],
-                        typeFilter: 1,
+                        typeFilter: "primitive",
                     },
                     {
                         name: "u8",
@@ -436,10 +436,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -462,10 +462,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -496,10 +496,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: 16,
+                        typeFilter: "macro",
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
diff --git a/tests/rustdoc-js-std/parser-returned.js b/tests/rustdoc-js-std/parser-returned.js
index 30ce26a8920..67aabdacb04 100644
--- a/tests/rustdoc-js-std/parser-returned.js
+++ b/tests/rustdoc-js-std/parser-returned.js
@@ -18,7 +18,7 @@ const PARSED = [
                     generics: [],
                 },
             ],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         error: null,
     },
@@ -33,7 +33,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "p",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         error: null,
     },
@@ -48,7 +48,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "a",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         error: null,
     },
@@ -60,7 +60,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "aaaaa",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 2,
         userQuery: "aaaaa->a",
@@ -70,7 +70,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "a",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         error: null,
     },
@@ -85,7 +85,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "never",
             generics: [],
-            typeFilter: 1,
+            typeFilter: "primitive",
         }],
         error: null,
     },
@@ -97,7 +97,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "a",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "a->",
@@ -113,7 +113,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "never",
             generics: [],
-            typeFilter: 1,
+            typeFilter: "primitive",
         }],
         foundElems: 1,
         userQuery: "!->",
@@ -129,7 +129,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "never",
             generics: [],
-            typeFilter: 1,
+            typeFilter: "primitive",
         }],
         foundElems: 1,
         userQuery: "! ->",
@@ -145,7 +145,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "never",
             generics: [],
-            typeFilter: 1,
+            typeFilter: "primitive",
         }],
         foundElems: 1,
         userQuery: "primitive:!->",
diff --git a/tests/rustdoc-js-std/parser-separators.js b/tests/rustdoc-js-std/parser-separators.js
index cf271c80cdc..2f41211d783 100644
--- a/tests/rustdoc-js-std/parser-separators.js
+++ b/tests/rustdoc-js-std/parser-separators.js
@@ -10,7 +10,7 @@ const PARSED = [
                 pathWithoutLast: ['aaaaaa'],
                 pathLast: 'b',
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -27,7 +27,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'aaaaaa',
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: 'b',
@@ -35,7 +35,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'b',
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 2,
@@ -52,7 +52,7 @@ const PARSED = [
                 pathWithoutLast: ['a'],
                 pathLast: 'b',
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -69,7 +69,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'a',
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
             {
                 name: 'b',
@@ -77,7 +77,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: 'b',
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 2,
@@ -94,7 +94,7 @@ const PARSED = [
                 pathWithoutLast: ['a'],
                 pathLast: 'b',
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -119,7 +119,7 @@ const PARSED = [
                         generics: [],
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -151,7 +151,7 @@ const PARSED = [
                         generics: [],
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -176,7 +176,7 @@ const PARSED = [
                         generics: [],
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
diff --git a/tests/rustdoc-js-std/parser-slice-array.js b/tests/rustdoc-js-std/parser-slice-array.js
index 65797945535..c587eb9001f 100644
--- a/tests/rustdoc-js-std/parser-slice-array.js
+++ b/tests/rustdoc-js-std/parser-slice-array.js
@@ -34,7 +34,7 @@ const PARSED = [
                                         pathWithoutLast: [],
                                         pathLast: "d",
                                         generics: [],
-                                        typeFilter: -1,
+                                        typeFilter: null,
                                     },
                                     {
                                         name: "[]",
@@ -42,16 +42,16 @@ const PARSED = [
                                         pathWithoutLast: [],
                                         pathLast: "[]",
                                         generics: [],
-                                        typeFilter: 1,
+                                        typeFilter: "primitive",
                                     },
                                 ],
-                                typeFilter: 1,
+                                typeFilter: "primitive",
                             },
                         ],
-                        typeFilter: 1,
+                        typeFilter: "primitive",
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -68,7 +68,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "[]",
                 generics: [],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
             {
                 name: "u8",
@@ -76,7 +76,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "u8",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 2,
@@ -99,10 +99,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -125,7 +125,7 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                     {
                         name: "u8",
@@ -133,10 +133,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -165,13 +165,13 @@ const PARSED = [
                                 pathWithoutLast: [],
                                 pathLast: "u8",
                                 generics: [],
-                                typeFilter: -1,
+                                typeFilter: null,
                             },
                         ],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -188,7 +188,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "[]",
                 generics: [],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -283,10 +283,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
diff --git a/tests/rustdoc-js-std/parser-tuple.js b/tests/rustdoc-js-std/parser-tuple.js
index 61925068387..dfe9fdc98e3 100644
--- a/tests/rustdoc-js-std/parser-tuple.js
+++ b/tests/rustdoc-js-std/parser-tuple.js
@@ -22,7 +22,7 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "d",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                     {
                         name: "()",
@@ -30,10 +30,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "()",
                         generics: [],
-                        typeFilter: 1,
+                        typeFilter: "primitive",
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             }
         ],
         foundElems: 1,
@@ -50,7 +50,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "()",
                 generics: [],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
             {
                 name: "u8",
@@ -58,7 +58,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "u8",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 2,
@@ -81,7 +81,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "u8",
                 generics: [],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -104,10 +104,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -130,10 +130,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -156,10 +156,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -176,7 +176,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "u8",
                 generics: [],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -199,7 +199,7 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                     {
                         name: "u8",
@@ -207,10 +207,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
@@ -233,10 +233,10 @@ const PARSED = [
                         pathWithoutLast: [],
                         pathLast: "u8",
                         generics: [],
-                        typeFilter: -1,
+                        typeFilter: null,
                     },
                 ],
-                typeFilter: -1,
+                typeFilter: null,
             },
         ],
         foundElems: 1,
@@ -253,7 +253,7 @@ const PARSED = [
                 pathWithoutLast: [],
                 pathLast: "()",
                 generics: [],
-                typeFilter: 1,
+                typeFilter: "primitive",
             },
         ],
         foundElems: 1,
diff --git a/tests/rustdoc-js-std/path-end-empty.js b/tests/rustdoc-js-std/path-end-empty.js
index 6e853c61b4d..17b8cac8a66 100644
--- a/tests/rustdoc-js-std/path-end-empty.js
+++ b/tests/rustdoc-js-std/path-end-empty.js
@@ -1,6 +1,7 @@
+const FILTER_CRATE = "std";
 const EXPECTED = {
     'query': 'Option::',
     'others': [
-        { 'path': 'std::option::Option', 'name': 'get_or_insert_default' },
+        { 'path': 'std::option::Option', 'name': 'eq' },
     ],
 }
diff --git a/tests/rustdoc-js-std/path-maxeditdistance.js b/tests/rustdoc-js-std/path-maxeditdistance.js
index 6989e7d6488..b22a506eee5 100644
--- a/tests/rustdoc-js-std/path-maxeditdistance.js
+++ b/tests/rustdoc-js-std/path-maxeditdistance.js
@@ -10,15 +10,15 @@ const EXPECTED = [
         query: 'vec::iter',
         others: [
             // std::net::ToSocketAttrs::iter should not show up here
-            { 'path': 'std::vec', 'name': 'IntoIter' },
+            { 'path': 'std::collections::VecDeque', 'name': 'iter' },
+            { 'path': 'std::collections::VecDeque', 'name': 'iter_mut' },
             { 'path': 'std::vec::Vec', 'name': 'from_iter' },
+            { 'path': 'std::vec', 'name': 'IntoIter' },
             { 'path': 'std::vec::Vec', 'name': 'into_iter' },
             { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
             { 'path': 'std::vec::Drain', 'name': 'into_iter' },
             { 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
             { 'path': 'std::vec::Splice', 'name': 'into_iter' },
-            { 'path': 'std::collections::VecDeque', 'name': 'iter' },
-            { 'path': 'std::collections::VecDeque', 'name': 'iter_mut' },
             { 'path': 'std::collections::VecDeque', 'name': 'from_iter' },
             { 'path': 'std::collections::VecDeque', 'name': 'into_iter' },
         ],
diff --git a/tests/rustdoc-js-std/return-specific-literal.js b/tests/rustdoc-js-std/return-specific-literal.js
index 86ed3aceb4e..1efdb776ad7 100644
--- a/tests/rustdoc-js-std/return-specific-literal.js
+++ b/tests/rustdoc-js-std/return-specific-literal.js
@@ -4,6 +4,6 @@ const EXPECTED = {
         { 'path': 'std::string::String', 'name': 'ne' },
     ],
     'returned': [
-        { 'path': 'std::string::String', 'name': 'add' },
+        { 'path': 'std::string::String', 'name': 'new' },
     ],
 };
diff --git a/tests/rustdoc-js-std/return-specific.js b/tests/rustdoc-js-std/return-specific.js
index be54a1c9772..abf243bf6ab 100644
--- a/tests/rustdoc-js-std/return-specific.js
+++ b/tests/rustdoc-js-std/return-specific.js
@@ -4,6 +4,6 @@ const EXPECTED = {
         { 'path': 'std::string::String', 'name': 'ne' },
     ],
     'returned': [
-        { 'path': 'std::string::String', 'name': 'add' },
+        { 'path': 'std::string::String', 'name': 'new' },
     ],
 };
diff --git a/tests/rustdoc-js/doc-alias.js b/tests/rustdoc-js/doc-alias.js
index e57bd71419d..74f1665f74a 100644
--- a/tests/rustdoc-js/doc-alias.js
+++ b/tests/rustdoc-js/doc-alias.js
@@ -232,6 +232,12 @@ const EXPECTED = [
         'query': 'UnionItem',
         'others': [
             {
+                'path': 'doc_alias::Union',
+                'name': 'union_item',
+                'desc': 'Doc for <code>Union::union_item</code>',
+                'href': '../doc_alias/union.Union.html#structfield.union_item'
+            },
+            {
                 'path': 'doc_alias',
                 'name': 'Union',
                 'desc': 'Doc for <code>Union</code>',
@@ -239,13 +245,6 @@ const EXPECTED = [
                 'href': '../doc_alias/union.Union.html',
                 'is_alias': true
             },
-            // Not an alias!
-            {
-                'path': 'doc_alias::Union',
-                'name': 'union_item',
-                'desc': 'Doc for <code>Union::union_item</code>',
-                'href': '../doc_alias/union.Union.html#structfield.union_item'
-            },
         ],
     },
     {
diff --git a/tests/rustdoc-js/generics-trait.js b/tests/rustdoc-js/generics-trait.js
index 8da9c67050e..cd100463e9a 100644
--- a/tests/rustdoc-js/generics-trait.js
+++ b/tests/rustdoc-js/generics-trait.js
@@ -25,8 +25,25 @@ const EXPECTED = [
     },
     {
         'query': 'Resulx<SomeTrait>',
-        'in_args': [],
-        'returned': [],
+        'correction': 'Result',
+        'in_args': [
+            {
+                'path': 'generics_trait',
+                'name': 'beta',
+                'displayType': '`Result`<`T`, ()> -> ()',
+                'displayMappedNames': '',
+                'displayWhereClause': 'T: `SomeTrait`',
+            },
+        ],
+        'returned': [
+            {
+                'path': 'generics_trait',
+                'name': 'bet',
+                'displayType': ' -> `Result`<`T`, ()>',
+                'displayMappedNames': '',
+                'displayWhereClause': 'T: `SomeTrait`',
+            },
+        ],
     },
     {
         'query': 'Result<SomeTraiz>',
diff --git a/tests/rustdoc-js/non-english-identifier.js b/tests/rustdoc-js/non-english-identifier.js
index 3d50bd3ee90..0f9ffe7c038 100644
--- a/tests/rustdoc-js/non-english-identifier.js
+++ b/tests/rustdoc-js/non-english-identifier.js
@@ -7,7 +7,7 @@ const PARSED = [
             pathWithoutLast: [],
             pathLast: "中文",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         returned: [],
         foundElems: 1,
@@ -23,7 +23,7 @@ const PARSED = [
             pathLast: "_0mixed中英文",
             normalizedPathLast: "0mixed中英文",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "_0Mixed中英文",
@@ -38,7 +38,7 @@ const PARSED = [
             pathWithoutLast: ["my_crate"],
             pathLast: "中文api",
             generics: [],
-            typeFilter: -1,
+            typeFilter: null,
         }],
         foundElems: 1,
         userQuery: "my_crate::中文API",
@@ -94,7 +94,7 @@ const PARSED = [
             pathWithoutLast: ["my_crate"],
             pathLast: "中文宏",
             generics: [],
-            typeFilter: 16,
+            typeFilter: "macro",
         }],
         foundElems: 1,
         userQuery: "my_crate 中文宏!",
diff --git a/tests/rustdoc-js/ordering.js b/tests/rustdoc-js/ordering.js
new file mode 100644
index 00000000000..a7c10900da6
--- /dev/null
+++ b/tests/rustdoc-js/ordering.js
@@ -0,0 +1,9 @@
+const EXPECTED = [
+    {
+        'query': 'Entry',
+        'others': [
+            { 'path': 'ordering', 'name': 'Entry1a' },
+            { 'path': 'ordering', 'name': 'Entry2ab' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/ordering.rs b/tests/rustdoc-js/ordering.rs
new file mode 100644
index 00000000000..18ca06ab5ec
--- /dev/null
+++ b/tests/rustdoc-js/ordering.rs
@@ -0,0 +1,3 @@
+pub struct Entry1a;
+pub struct Entry1b;
+pub struct Entry2ab;
diff --git a/tests/rustdoc-js/type-parameters.js b/tests/rustdoc-js/type-parameters.js
index fa2b8d2ebfd..b1f1ee951c6 100644
--- a/tests/rustdoc-js/type-parameters.js
+++ b/tests/rustdoc-js/type-parameters.js
@@ -4,8 +4,8 @@ const EXPECTED = [
     {
         query: '-> trait:Some',
         others: [
-            { path: 'foo', name: 'alpha' },
             { path: 'foo', name: 'alef' },
+            { path: 'foo', name: 'alpha' },
         ],
     },
     {
@@ -75,10 +75,8 @@ const EXPECTED = [
     {
         query: 'Other',
         in_args: [
-            // because function is called "other", it's sorted first
-            // even though it has higher type distance
-            { path: 'foo', name: 'other' },
             { path: 'foo', name: 'alternate' },
+            { path: 'foo', name: 'other' },
         ],
     },
     {
diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs b/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs
index 85c460ace64..088ab242d27 100644
--- a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs
+++ b/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs
@@ -5,9 +5,9 @@
 //@ has t/trait.Tango.html
 //@ hasraw s/struct.Sierra.html 'Tango'
 //@ hasraw trait.impl/t/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Tango'
-//@ hasraw search-index.js 'Sierra'
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Tango'
+//@ hasraw search.index/name/*.js 'Sierra'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // We document multiple crates into the same output directory, which
 // merges the cross-crate information. Everything is available.
diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive/s.rs b/tests/rustdoc/cross-crate-info/cargo-transitive/s.rs
index 68bfc34883b..fb6eef0bf69 100644
--- a/tests/rustdoc/cross-crate-info/cargo-transitive/s.rs
+++ b/tests/rustdoc/cross-crate-info/cargo-transitive/s.rs
@@ -13,9 +13,9 @@
 //@ has t/trait.Tango.html
 //@ hasraw s/struct.Sierra.html 'Tango'
 //@ hasraw trait.impl/t/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Tango'
-//@ hasraw search-index.js 'Sierra'
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Tango'
+//@ hasraw search.index/name/*.js 'Sierra'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // We document multiple crates into the same output directory, which
 // merges the cross-crate information. Everything is available.
diff --git a/tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs b/tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs
index c93298f969e..53375670552 100644
--- a/tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs
+++ b/tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs
@@ -4,8 +4,8 @@
 //@ has f/trait.Foxtrot.html
 //@ hasraw e/enum.Echo.html 'Foxtrot'
 //@ hasraw trait.impl/f/trait.Foxtrot.js 'enum.Echo.html'
-//@ hasraw search-index.js 'Foxtrot'
-//@ hasraw search-index.js 'Echo'
+//@ hasraw search.index/name/*.js 'Foxtrot'
+//@ hasraw search.index/name/*.js 'Echo'
 
 // document two crates in the same way that cargo does. do not provide
 // --enable-index-page
diff --git a/tests/rustdoc/cross-crate-info/cargo-two/e.rs b/tests/rustdoc/cross-crate-info/cargo-two/e.rs
index 00f86cbc348..936e75c97af 100644
--- a/tests/rustdoc/cross-crate-info/cargo-two/e.rs
+++ b/tests/rustdoc/cross-crate-info/cargo-two/e.rs
@@ -11,8 +11,8 @@
 //@ has f/trait.Foxtrot.html
 //@ hasraw e/enum.Echo.html 'Foxtrot'
 //@ hasraw trait.impl/f/trait.Foxtrot.js 'enum.Echo.html'
-//@ hasraw search-index.js 'Foxtrot'
-//@ hasraw search-index.js 'Echo'
+//@ hasraw search.index/name/*.js 'Foxtrot'
+//@ hasraw search.index/name/*.js 'Echo'
 
 // document two crates in the same way that cargo does, writing them both
 // into the same output directory
diff --git a/tests/rustdoc/cross-crate-info/index-on-last/e.rs b/tests/rustdoc/cross-crate-info/index-on-last/e.rs
index ffee898cd96..dbaeaf5b725 100644
--- a/tests/rustdoc/cross-crate-info/index-on-last/e.rs
+++ b/tests/rustdoc/cross-crate-info/index-on-last/e.rs
@@ -11,8 +11,8 @@
 //@ has f/trait.Foxtrot.html
 //@ hasraw e/enum.Echo.html 'Foxtrot'
 //@ hasraw trait.impl/f/trait.Foxtrot.js 'enum.Echo.html'
-//@ hasraw search-index.js 'Foxtrot'
-//@ hasraw search-index.js 'Echo'
+//@ hasraw search.index/name/*.js 'Foxtrot'
+//@ hasraw search.index/name/*.js 'Echo'
 
 // only declare --enable-index-page to the last rustdoc invocation
 extern crate f;
diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/i.rs b/tests/rustdoc/cross-crate-info/kitchen-sink/i.rs
index bcb9464795a..979d77d8c42 100644
--- a/tests/rustdoc/cross-crate-info/kitchen-sink/i.rs
+++ b/tests/rustdoc/cross-crate-info/kitchen-sink/i.rs
@@ -19,10 +19,10 @@
 //@ has t/trait.Tango.html
 //@ hasraw s/struct.Sierra.html 'Tango'
 //@ hasraw trait.impl/t/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Quebec'
-//@ hasraw search-index.js 'Romeo'
-//@ hasraw search-index.js 'Sierra'
-//@ hasraw search-index.js 'Tango'
+//@ hasraw search.index/name/*.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Romeo'
+//@ hasraw search.index/name/*.js 'Sierra'
+//@ hasraw search.index/name/*.js 'Tango'
 //@ has type.impl/s/struct.Sierra.js
 //@ hasraw type.impl/s/struct.Sierra.js 'Tango'
 //@ hasraw type.impl/s/struct.Sierra.js 'Romeo'
diff --git a/tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs b/tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs
index c5e3dc0a0f4..439ab23de18 100644
--- a/tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs
+++ b/tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs
@@ -6,7 +6,7 @@
 //@ has index.html '//h1' 'List of all crates'
 //@ has index.html '//ul[@class="all-items"]//a[@href="q/index.html"]' 'q'
 //@ has q/struct.Quebec.html
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // there's nothing cross-crate going on here
 pub struct Quebec;
diff --git a/tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs b/tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs
index d3e71fa0ce3..b3703658465 100644
--- a/tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs
+++ b/tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs
@@ -1,6 +1,6 @@
 //@ build-aux-docs
 //@ has q/struct.Quebec.html
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // there's nothing cross-crate going on here
 pub struct Quebec;
diff --git a/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs b/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs
index 9dcec211e17..6ded19546b8 100644
--- a/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs
+++ b/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs
@@ -4,8 +4,8 @@
 //@ !has f/trait.Foxtrot.html
 //@ hasraw e/enum.Echo.html 'Foxtrot'
 //@ hasraw trait.impl/f/trait.Foxtrot.js 'enum.Echo.html'
-//@ !hasraw search-index.js 'Foxtrot'
-//@ hasraw search-index.js 'Echo'
+//@ !hasraw search.index/name/*.js 'Foxtrot'
+//@ hasraw search.index/name/*.js 'Echo'
 
 // test the fact that our test runner will document this crate somewhere
 // else
diff --git a/tests/rustdoc/masked.rs b/tests/rustdoc/masked.rs
index 4f361ca881e..bc0a5f57cef 100644
--- a/tests/rustdoc/masked.rs
+++ b/tests/rustdoc/masked.rs
@@ -7,7 +7,7 @@
 #[doc(masked)]
 extern crate masked;
 
-//@ !hasraw 'search-index.js' 'masked_method'
+//@ !hasraw 'search.index/name/*.js' 'masked_method'
 
 //@ !hasraw 'foo/struct.String.html' 'MaskedTrait'
 //@ !hasraw 'foo/struct.String.html' 'MaskedBlanketTrait'
diff --git a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs b/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs
index 665f9567ba2..26292c50d35 100644
--- a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs
+++ b/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs
@@ -14,9 +14,9 @@
 //@ has tango/trait.Tango.html
 //@ hasraw sierra/struct.Sierra.html 'Tango'
 //@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Tango'
-//@ hasraw search-index.js 'Sierra'
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Tango'
+//@ hasraw search.index/name/*.js 'Sierra'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // similar to cargo-workflow-transitive, but we use --merge=read-write,
 // which is the default.
diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs
index f03f6bd6026..fd6ee0cbf24 100644
--- a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs
+++ b/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs
@@ -23,10 +23,10 @@
 //@ !has sierra/struct.Sierra.html
 //@ !has tango/trait.Tango.html
 //@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Quebec'
-//@ hasraw search-index.js 'Romeo'
-//@ hasraw search-index.js 'Sierra'
-//@ hasraw search-index.js 'Tango'
+//@ hasraw search.index/name/*.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Romeo'
+//@ hasraw search.index/name/*.js 'Sierra'
+//@ hasraw search.index/name/*.js 'Tango'
 //@ has type.impl/sierra/struct.Sierra.js
 //@ hasraw type.impl/sierra/struct.Sierra.js 'Tango'
 //@ hasraw type.impl/sierra/struct.Sierra.js 'Romeo'
diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs b/tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs
index 7eac207e518..c3b8200f151 100644
--- a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs
+++ b/tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs
@@ -8,7 +8,7 @@
 //@ has sierra/struct.Sierra.html
 //@ hasraw sierra/struct.Sierra.html 'Tango'
 //@ !has trait.impl/tango/trait.Tango.js
-//@ !has search-index.js
+//@ !has search.index/name/*.js
 
 // we don't generate any cross-crate info if --merge=none, even if we
 // document crates separately
diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs b/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs
index f3340a80c84..2e47d42daff 100644
--- a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs
+++ b/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs
@@ -10,7 +10,7 @@
 //@ has tango/trait.Tango.html
 //@ hasraw sierra/struct.Sierra.html 'Tango'
 //@ !has trait.impl/tango/trait.Tango.js
-//@ !has search-index.js
+//@ !has search.index/name/*.js
 
 // we --merge=none, so --parts-out-dir doesn't do anything
 extern crate tango;
diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs b/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs
index 8eb0f1d0498..337dc558f35 100644
--- a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs
+++ b/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs
@@ -10,9 +10,9 @@
 //@ has tango/trait.Tango.html
 //@ hasraw sierra/struct.Sierra.html 'Tango'
 //@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Tango'
-//@ hasraw search-index.js 'Sierra'
-//@ !hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Tango'
+//@ hasraw search.index/name/*.js 'Sierra'
+//@ !hasraw search.index/name/*.js 'Quebec'
 
 // we overwrite quebec and tango's cross-crate information, but we
 // include the info from tango meaning that it should appear in the out
diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs b/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs
index 4ee036238b4..c07b30d2aa0 100644
--- a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs
+++ b/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs
@@ -13,9 +13,9 @@
 //@ has index.html '//ul[@class="all-items"]//a[@href="tango/index.html"]' 'tango'
 //@ has sierra/struct.Sierra.html
 //@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Tango'
-//@ hasraw search-index.js 'Sierra'
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Tango'
+//@ hasraw search.index/name/*.js 'Sierra'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // If these were documeted into the same directory, the info would be
 // overwritten. However, since they are merged, we can still recover all
diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs b/tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs
index 11e61dd2744..cac978f3bb2 100644
--- a/tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs
+++ b/tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs
@@ -9,9 +9,9 @@
 //@ has tango/trait.Tango.html
 //@ hasraw sierra/struct.Sierra.html 'Tango'
 //@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Tango'
-//@ hasraw search-index.js 'Sierra'
-//@ !hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Tango'
+//@ hasraw search.index/name/*.js 'Sierra'
+//@ !hasraw search.index/name/*.js 'Quebec'
 
 // since tango is documented with --merge=finalize, we overwrite q's
 // cross-crate information
diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs b/tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs
index 09bb78c06f1..2ab08c112a1 100644
--- a/tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs
+++ b/tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs
@@ -6,7 +6,7 @@
 //@ has index.html '//h1' 'List of all crates'
 //@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec'
 //@ has quebec/struct.Quebec.html
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // there is nothing to read from the output directory if we use a single
 // crate
diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs b/tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs
index 72475426f6e..1b9e8a3db08 100644
--- a/tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs
+++ b/tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs
@@ -6,7 +6,7 @@
 //@ has index.html '//h1' 'List of all crates'
 //@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec'
 //@ has quebec/struct.Quebec.html
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // read-write is the default and this does the same as `single-crate`
 pub struct Quebec;
diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs b/tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs
index b20e173a830..6b72615eb9d 100644
--- a/tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs
+++ b/tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs
@@ -6,7 +6,7 @@
 //@ has index.html '//h1' 'List of all crates'
 //@ has index.html '//ul[@class="all-items"]//a[@href="quebec/index.html"]' 'quebec'
 //@ has quebec/struct.Quebec.html
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // we can --parts-out-dir, but that doesn't do anything other than create
 // the file
diff --git a/tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs b/tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs
index e888a43c460..bfde21c9ed3 100644
--- a/tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs
+++ b/tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs
@@ -5,7 +5,7 @@
 
 //@ !has index.html
 //@ has quebec/struct.Quebec.html
-//@ !has search-index.js
+//@ !has search.index/name/*.js
 
 // --merge=none doesn't write anything, despite --parts-out-dir
 pub struct Quebec;
diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs b/tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs
index 68fc4b13fa8..b45895a40a1 100644
--- a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs
+++ b/tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs
@@ -12,7 +12,7 @@
 //@ has tango/trait.Tango.html
 //@ hasraw sierra/struct.Sierra.html 'Tango'
 //@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Sierra'
+//@ hasraw search.index/name/*.js 'Sierra'
 
 // write only overwrites stuff in the output directory
 extern crate tango;
diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs b/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs
index b407228085e..be371376179 100644
--- a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs
+++ b/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs
@@ -16,9 +16,9 @@
 //@ has tango/trait.Tango.html
 //@ hasraw sierra/struct.Sierra.html 'Tango'
 //@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Tango'
-//@ hasraw search-index.js 'Sierra'
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Tango'
+//@ hasraw search.index/name/*.js 'Sierra'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // We avoid writing any cross-crate information, preferring to include it
 // with --include-parts-dir.
diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs b/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs
index 15e32d5941f..dc10ec3de35 100644
--- a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs
+++ b/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs
@@ -14,9 +14,9 @@
 //@ has tango/trait.Tango.html
 //@ hasraw sierra/struct.Sierra.html 'Tango'
 //@ hasraw trait.impl/tango/trait.Tango.js 'struct.Sierra.html'
-//@ hasraw search-index.js 'Tango'
-//@ hasraw search-index.js 'Sierra'
-//@ hasraw search-index.js 'Quebec'
+//@ hasraw search.index/name/*.js 'Tango'
+//@ hasraw search.index/name/*.js 'Sierra'
+//@ hasraw search.index/name/*.js 'Quebec'
 
 // We can use read-write to emulate the default behavior of rustdoc, when
 // --merge is left out.
diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs b/tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs
index 3eb2cebd743..9eaa627419b 100644
--- a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs
+++ b/tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs
@@ -9,7 +9,7 @@
 //@ has tango/trait.Tango.html
 //@ hasraw sierra/struct.Sierra.html 'Tango'
 //@ !has trait.impl/tango/trait.Tango.js
-//@ !has search-index.js
+//@ !has search.index/name/*.js
 
 // --merge=none on all crates does not generate any cross-crate info
 extern crate tango;
diff --git a/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs b/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs
index ee2b646e43c..d79302e62cd 100644
--- a/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs
+++ b/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs
@@ -6,8 +6,8 @@
 //@ has echo/enum.Echo.html
 //@ hasraw echo/enum.Echo.html 'Foxtrot'
 //@ hasraw trait.impl/foxtrot/trait.Foxtrot.js 'enum.Echo.html'
-//@ hasraw search-index.js 'Foxtrot'
-//@ hasraw search-index.js 'Echo'
+//@ hasraw search.index/name/*.js 'Foxtrot'
+//@ hasraw search.index/name/*.js 'Echo'
 
 // document two crates in different places, and merge their docs after
 // they are generated
diff --git a/tests/rustdoc/no-unit-struct-field.rs b/tests/rustdoc/no-unit-struct-field.rs
index 6ac44037cea..cb74a9d19ad 100644
--- a/tests/rustdoc/no-unit-struct-field.rs
+++ b/tests/rustdoc/no-unit-struct-field.rs
@@ -1,10 +1,11 @@
 // This test ensures that the tuple struct fields are not generated in the
 // search index.
 
-//@ !hasraw search-index.js '"0"'
-//@ !hasraw search-index.js '"1"'
-//@ hasraw search-index.js '"foo_a"'
-//@ hasraw search-index.js '"bar_a"'
+// vlqhex encoding ` = 0, a = 1, e = 5
+//@ !hasraw search.index/name/*.js 'a0'
+//@ !hasraw search.index/name/*.js 'a1'
+//@ hasraw search.index/name/*.js 'efoo_a'
+//@ hasraw search.index/name/*.js 'ebar_a'
 
 pub struct Bar(pub u32, pub u8);
 pub struct Foo {
diff --git a/tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs b/tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs
index 6054d8f12f5..ea828e08d82 100644
--- a/tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs
+++ b/tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs
@@ -9,7 +9,7 @@ pub mod str {
     #![rustc_doc_primitive = "str"]
 
     impl str {
-        //@ hasraw search-index.js foo
+        //@ hasraw search.index/name/*.js foo
         #[rustc_allow_incoherent_impl]
         pub fn foo(&self) {}
     }
diff --git a/tests/rustdoc/search-index-summaries.rs b/tests/rustdoc/search-index-summaries.rs
index 55db04340a6..e680a9d57c1 100644
--- a/tests/rustdoc/search-index-summaries.rs
+++ b/tests/rustdoc/search-index-summaries.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-//@ hasraw 'search.desc/foo/foo-desc-0-.js' 'Foo short link.'
+//@ hasraw 'search.index/desc/*.js' 'Foo short link.'
 //@ !hasraw - 'www.example.com'
 //@ !hasraw - 'More Foo.'
 
diff --git a/tests/rustdoc/search-index.rs b/tests/rustdoc/search-index.rs
index f53862ede38..49ccacd0a5c 100644
--- a/tests/rustdoc/search-index.rs
+++ b/tests/rustdoc/search-index.rs
@@ -2,7 +2,7 @@
 
 use std::ops::Deref;
 
-//@ hasraw search-index.js Foo
+//@ hasraw search.index/name/*.js Foo
 pub use private::Foo;
 
 mod private {
@@ -20,7 +20,7 @@ mod private {
 pub struct Bar;
 
 impl Deref for Bar {
-    //@ !hasraw search-index.js Target
+    //@ !hasraw search.index/name/*.js Target
     type Target = Bar;
     fn deref(&self) -> &Bar { self }
 }
diff --git a/tests/ui-fulldeps/internal-lints/query_stability.rs b/tests/ui-fulldeps/internal-lints/query_stability.rs
index 7b897fabd2d..92c1d6bf7f8 100644
--- a/tests/ui-fulldeps/internal-lints/query_stability.rs
+++ b/tests/ui-fulldeps/internal-lints/query_stability.rs
@@ -1,4 +1,5 @@
 //@ compile-flags: -Z unstable-options
+//@ ignore-stage1
 
 #![feature(rustc_private)]
 #![deny(rustc::potential_query_instability)]
@@ -34,4 +35,16 @@ fn main() {
         //~^ ERROR using `values_mut` can result in unstable query results
         *val = *val + 10;
     }
+
+    FxHashMap::<u32, i32>::default().extend(x);
+    //~^ ERROR using `into_iter` can result in unstable query results
+}
+
+fn hide_into_iter<T>(x: impl IntoIterator<Item = T>) -> impl Iterator<Item = T> {
+    x.into_iter()
+}
+
+fn take(map: std::collections::HashMap<i32, i32>) {
+    _ = hide_into_iter(map);
+    //~^ ERROR using `into_iter` can result in unstable query results
 }
diff --git a/tests/ui-fulldeps/internal-lints/query_stability.stderr b/tests/ui-fulldeps/internal-lints/query_stability.stderr
index 43b156dc20a..e5bb0453f90 100644
--- a/tests/ui-fulldeps/internal-lints/query_stability.stderr
+++ b/tests/ui-fulldeps/internal-lints/query_stability.stderr
@@ -1,18 +1,18 @@
 error: using `drain` can result in unstable query results
-  --> $DIR/query_stability.rs:13:16
+  --> $DIR/query_stability.rs:14:16
    |
 LL |     for _ in x.drain() {}
    |                ^^^^^
    |
    = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 note: the lint level is defined here
-  --> $DIR/query_stability.rs:4:9
+  --> $DIR/query_stability.rs:5:9
    |
 LL | #![deny(rustc::potential_query_instability)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: using `iter` can result in unstable query results
-  --> $DIR/query_stability.rs:16:16
+  --> $DIR/query_stability.rs:17:16
    |
 LL |     for _ in x.iter() {}
    |                ^^^^
@@ -20,7 +20,7 @@ LL |     for _ in x.iter() {}
    = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 
 error: using `iter_mut` can result in unstable query results
-  --> $DIR/query_stability.rs:19:36
+  --> $DIR/query_stability.rs:20:36
    |
 LL |     for _ in Some(&mut x).unwrap().iter_mut() {}
    |                                    ^^^^^^^^
@@ -28,7 +28,7 @@ LL |     for _ in Some(&mut x).unwrap().iter_mut() {}
    = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 
 error: using `into_iter` can result in unstable query results
-  --> $DIR/query_stability.rs:22:14
+  --> $DIR/query_stability.rs:23:14
    |
 LL |     for _ in x {}
    |              ^
@@ -36,7 +36,7 @@ LL |     for _ in x {}
    = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 
 error: using `keys` can result in unstable query results
-  --> $DIR/query_stability.rs:26:15
+  --> $DIR/query_stability.rs:27:15
    |
 LL |     let _ = x.keys();
    |               ^^^^
@@ -44,7 +44,7 @@ LL |     let _ = x.keys();
    = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 
 error: using `values` can result in unstable query results
-  --> $DIR/query_stability.rs:29:15
+  --> $DIR/query_stability.rs:30:15
    |
 LL |     let _ = x.values();
    |               ^^^^^^
@@ -52,12 +52,28 @@ LL |     let _ = x.values();
    = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 
 error: using `values_mut` can result in unstable query results
-  --> $DIR/query_stability.rs:33:18
+  --> $DIR/query_stability.rs:34:18
    |
 LL |     for val in x.values_mut() {
    |                  ^^^^^^^^^^
    |
    = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 
-error: aborting due to 7 previous errors
+error: using `into_iter` can result in unstable query results
+  --> $DIR/query_stability.rs:39:38
+   |
+LL |     FxHashMap::<u32, i32>::default().extend(x);
+   |                                      ^^^^^^^^^
+   |
+   = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
+
+error: using `into_iter` can result in unstable query results
+  --> $DIR/query_stability.rs:48:9
+   |
+LL |     _ = hide_into_iter(map);
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
+
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 001699b2bc7..396abb001ce 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -559,6 +559,12 @@ error: cannot find attribute `error` in this scope
    |
 LL | #[error(no_crate_example, code = E0123)]
    |   ^^^^^
+   |
+help: `error` is an attribute that can be used by the derive macro `Error`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Error)]
+LL | struct ErrorAttribute {}
+   |
 
 error: cannot find attribute `warn_` in this scope
   --> $DIR/diagnostic-derive.rs:590:3
diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr
index 3b29efc8102..8375de3e817 100644
--- a/tests/ui/abi/debug.generic.stderr
+++ b/tests/ui/abi/debug.generic.stderr
@@ -939,7 +939,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
                    },
                    mode: Direct(
                        ArgAttributes {
-                           regular: NoAlias | NonNull | ReadOnly | NoUndef,
+                           regular: NoAlias | NonNull | ReadOnly | NoUndef | CapturesReadOnly,
                            arg_ext: None,
                            pointee_size: Size(2 bytes),
                            pointee_align: Some(
diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr
index 2417396de2f..bddf0aea3d7 100644
--- a/tests/ui/abi/debug.riscv64.stderr
+++ b/tests/ui/abi/debug.riscv64.stderr
@@ -939,7 +939,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
                    },
                    mode: Direct(
                        ArgAttributes {
-                           regular: NoAlias | NonNull | ReadOnly | NoUndef,
+                           regular: NoAlias | NonNull | ReadOnly | NoUndef | CapturesReadOnly,
                            arg_ext: None,
                            pointee_size: Size(2 bytes),
                            pointee_align: Some(
diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr
index 61d07f29fd7..f2b14e0707b 100644
--- a/tests/ui/abi/unsupported.aarch64.stderr
+++ b/tests/ui/abi/unsupported.aarch64.stderr
@@ -165,7 +165,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
+   = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: "cdecl" is not a supported ABI for the current target
   --> $DIR/unsupported.rs:104:1
diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr
index 37b6e2316b0..bc666b7ced1 100644
--- a/tests/ui/abi/unsupported.arm.stderr
+++ b/tests/ui/abi/unsupported.arm.stderr
@@ -147,7 +147,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
+   = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: "cdecl" is not a supported ABI for the current target
   --> $DIR/unsupported.rs:104:1
diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr
index d7eb222eb76..722b1ec7713 100644
--- a/tests/ui/abi/unsupported.riscv32.stderr
+++ b/tests/ui/abi/unsupported.riscv32.stderr
@@ -159,7 +159,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
+   = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: "cdecl" is not a supported ABI for the current target
   --> $DIR/unsupported.rs:104:1
diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr
index d7eb222eb76..722b1ec7713 100644
--- a/tests/ui/abi/unsupported.riscv64.stderr
+++ b/tests/ui/abi/unsupported.riscv64.stderr
@@ -159,7 +159,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
+   = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: "cdecl" is not a supported ABI for the current target
   --> $DIR/unsupported.rs:104:1
diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr
index cf04680b587..3bf19f9f19d 100644
--- a/tests/ui/abi/unsupported.x64.stderr
+++ b/tests/ui/abi/unsupported.x64.stderr
@@ -141,7 +141,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
+   = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: "cdecl" is not a supported ABI for the current target
   --> $DIR/unsupported.rs:104:1
diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr
index d383a4df732..70f63a14d76 100644
--- a/tests/ui/abi/unsupported.x64_win.stderr
+++ b/tests/ui/abi/unsupported.x64_win.stderr
@@ -109,7 +109,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
+   = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: "stdcall" is not a supported ABI for the current target
   --> $DIR/unsupported.rs:87:1
diff --git a/tests/ui/issues/issue-8498.rs b/tests/ui/array-slice-vec/matching-on-vector-slice-option-8498.rs
index 92904e2198f..e243a247ed5 100644
--- a/tests/ui/issues/issue-8498.rs
+++ b/tests/ui/array-slice-vec/matching-on-vector-slice-option-8498.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8498
 //@ run-pass
 
 pub fn main() {
diff --git a/tests/ui/issues/issue-7784.rs b/tests/ui/array-slice-vec/pattern-matching-fixed-length-vectors-7784.rs
index 90b88ae5727..7d987e92b63 100644
--- a/tests/ui/issues/issue-7784.rs
+++ b/tests/ui/array-slice-vec/pattern-matching-fixed-length-vectors-7784.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/7784
 //@ run-pass
 
 use std::ops::Add;
diff --git a/tests/ui/array-slice-vec/slice-mut-2.stderr b/tests/ui/array-slice-vec/slice-mut-2.stderr
index 8cc2c6e0397..228417c873d 100644
--- a/tests/ui/array-slice-vec/slice-mut-2.stderr
+++ b/tests/ui/array-slice-vec/slice-mut-2.stderr
@@ -4,10 +4,10 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
 LL |     let _ = &mut x[2..4];
    |                  ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
    |
-help: consider changing this to be a mutable reference
+help: consider changing this binding's type
    |
-LL |     let x: &[isize] = &mut [1, 2, 3, 4, 5];
-   |                        +++
+LL |     let x: &mut [isize] = &[1, 2, 3, 4, 5];
+   |             +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-78622.rs b/tests/ui/associated-consts/ambiguous-associated-type-error-78622.rs
index c00fd266063..9763be1ecb2 100644
--- a/tests/ui/issues/issue-78622.rs
+++ b/tests/ui/associated-consts/ambiguous-associated-type-error-78622.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/78622
 #![crate_type = "lib"]
 
 struct S;
diff --git a/tests/ui/issues/issue-78622.stderr b/tests/ui/associated-consts/ambiguous-associated-type-error-78622.stderr
index 432913a0fc9..4dff1364af7 100644
--- a/tests/ui/issues/issue-78622.stderr
+++ b/tests/ui/associated-consts/ambiguous-associated-type-error-78622.stderr
@@ -1,5 +1,5 @@
 error[E0223]: ambiguous associated type
-  --> $DIR/issue-78622.rs:5:5
+  --> $DIR/ambiguous-associated-type-error-78622.rs:6:5
    |
 LL |     S::A::<f> {}
    |     ^^^^
diff --git a/tests/ui/associated-consts/associated-const-type-parameters.stderr b/tests/ui/associated-consts/associated-const-type-parameters.stderr
index 6ee2a5de1b6..c94cffd69c1 100644
--- a/tests/ui/associated-consts/associated-const-type-parameters.stderr
+++ b/tests/ui/associated-consts/associated-const-type-parameters.stderr
@@ -4,7 +4,7 @@ warning: trait `Bar` is never used
 LL | trait Bar: Foo {
    |       ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/associated-type-bounds/rpit.stderr b/tests/ui/associated-type-bounds/rpit.stderr
index 1091a4c573b..4c959456932 100644
--- a/tests/ui/associated-type-bounds/rpit.stderr
+++ b/tests/ui/associated-type-bounds/rpit.stderr
@@ -6,7 +6,7 @@ LL | trait Tr2<'a> { fn tr2(self) -> &'a Self; }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/associated-types/associated-types-issue-20220.stderr b/tests/ui/associated-types/associated-types-issue-20220.stderr
index c682f46e140..572889bbe74 100644
--- a/tests/ui/associated-types/associated-types-issue-20220.stderr
+++ b/tests/ui/associated-types/associated-types-issue-20220.stderr
@@ -4,7 +4,7 @@ warning: trait `IntoIteratorX` is never used
 LL | trait IntoIteratorX {
    |       ^^^^^^^^^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/associated-types/associated-types-nested-projections.stderr b/tests/ui/associated-types/associated-types-nested-projections.stderr
index 1b69fcfacf5..e360d337639 100644
--- a/tests/ui/associated-types/associated-types-nested-projections.stderr
+++ b/tests/ui/associated-types/associated-types-nested-projections.stderr
@@ -7,7 +7,7 @@ LL | trait IntoIterator {
 LL |     fn into_iter(self) -> Self::Iter;
    |        ^^^^^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr
index c26ed79a026..ddfe9eb6967 100644
--- a/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr
+++ b/tests/ui/associated-types/associated-types-projection-from-known-type-in-impl.stderr
@@ -7,7 +7,7 @@ LL | trait Int
 LL |     fn dummy(&self) { }
    |        ^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/async-await/async-closures/type-name.rs b/tests/ui/async-await/async-closures/type-name.rs
new file mode 100644
index 00000000000..12daad5a609
--- /dev/null
+++ b/tests/ui/async-await/async-closures/type-name.rs
@@ -0,0 +1,18 @@
+//@ run-pass
+//@ edition: 2024
+
+fn once<F: FnOnce() -> T, T>(f: F) -> T {
+    f()
+}
+
+fn main() {
+    let closure = async || {};
+
+    // Name of future when called normally.
+    let name = std::any::type_name_of_val(&closure());
+    assert_eq!(name, "type_name::main::{{closure}}::{{closure}}");
+
+    // Name of future when closure is called via its FnOnce shim.
+    let name = std::any::type_name_of_val(&once(closure));
+    assert_eq!(name, "type_name::main::{{closure}}::{{closure}}::{{call_once}}");
+}
diff --git a/tests/ui/async-await/recursive-async-auto-trait-overflow-only-parent-args.rs b/tests/ui/async-await/recursive-async-auto-trait-overflow-only-parent-args.rs
new file mode 100644
index 00000000000..9681f66412a
--- /dev/null
+++ b/tests/ui/async-await/recursive-async-auto-trait-overflow-only-parent-args.rs
@@ -0,0 +1,17 @@
+// Regression test for #145288. This is the same issue as #145151
+// which we fixed in #145194. However in that PR we accidentally created
+// a `CoroutineWitness` which referenced all generic arguments of the
+// coroutine, including upvars and the signature.
+
+//@ edition: 2024
+//@ check-pass
+
+async fn process<'a>(x: &'a u32) {
+    Box::pin(process(x)).await;
+}
+
+fn require_send(_: impl Send) {}
+
+fn main() {
+    require_send(process(&1));
+}
diff --git a/tests/ui/issues/issue-78957.rs b/tests/ui/attributes/invalid-attributes-on-const-params-78957.rs
index 2ff92612e18..106b9ae2690 100644
--- a/tests/ui/issues/issue-78957.rs
+++ b/tests/ui/attributes/invalid-attributes-on-const-params-78957.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/78957
 #![deny(unused_attributes)]
 
 use std::marker::PhantomData;
diff --git a/tests/ui/issues/issue-78957.stderr b/tests/ui/attributes/invalid-attributes-on-const-params-78957.stderr
index d271b1840fb..f8010b4ea68 100644
--- a/tests/ui/issues/issue-78957.stderr
+++ b/tests/ui/attributes/invalid-attributes-on-const-params-78957.stderr
@@ -1,5 +1,5 @@
 error: `#[inline]` attribute cannot be used on function params
-  --> $DIR/issue-78957.rs:5:16
+  --> $DIR/invalid-attributes-on-const-params-78957.rs:6:16
    |
 LL | pub struct Foo<#[inline] const N: usize>;
    |                ^^^^^^^^^
@@ -7,7 +7,7 @@ LL | pub struct Foo<#[inline] const N: usize>;
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on function params
-  --> $DIR/issue-78957.rs:13:17
+  --> $DIR/invalid-attributes-on-const-params-78957.rs:14:17
    |
 LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>);
    |                 ^^^^^^^^^
@@ -15,7 +15,7 @@ LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>);
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on function params
-  --> $DIR/issue-78957.rs:21:17
+  --> $DIR/invalid-attributes-on-const-params-78957.rs:22:17
    |
 LL | pub struct Foo3<#[inline] T>(PhantomData<T>);
    |                 ^^^^^^^^^
@@ -23,25 +23,25 @@ LL | pub struct Foo3<#[inline] T>(PhantomData<T>);
    = help: `#[inline]` can only be applied to functions
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-78957.rs:10:23
+  --> $DIR/invalid-attributes-on-const-params-78957.rs:11:23
    |
 LL | pub struct Baz<#[repr(C)] const N: usize>;
    |                       ^   -------------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-78957.rs:18:24
+  --> $DIR/invalid-attributes-on-const-params-78957.rs:19:24
    |
 LL | pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>);
    |                        ^   -- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-78957.rs:26:24
+  --> $DIR/invalid-attributes-on-const-params-78957.rs:27:24
    |
 LL | pub struct Baz3<#[repr(C)] T>(PhantomData<T>);
    |                        ^   - not a struct, enum, or union
 
 error: `#[cold]` attribute cannot be used on function params
-  --> $DIR/issue-78957.rs:7:16
+  --> $DIR/invalid-attributes-on-const-params-78957.rs:8:16
    |
 LL | pub struct Bar<#[cold] const N: usize>;
    |                ^^^^^^^
@@ -49,13 +49,13 @@ LL | pub struct Bar<#[cold] const N: usize>;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = help: `#[cold]` can only be applied to functions
 note: the lint level is defined here
-  --> $DIR/issue-78957.rs:1:9
+  --> $DIR/invalid-attributes-on-const-params-78957.rs:2:9
    |
 LL | #![deny(unused_attributes)]
    |         ^^^^^^^^^^^^^^^^^
 
 error: `#[cold]` attribute cannot be used on function params
-  --> $DIR/issue-78957.rs:15:17
+  --> $DIR/invalid-attributes-on-const-params-78957.rs:16:17
    |
 LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>);
    |                 ^^^^^^^
@@ -64,7 +64,7 @@ LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>);
    = help: `#[cold]` can only be applied to functions
 
 error: `#[cold]` attribute cannot be used on function params
-  --> $DIR/issue-78957.rs:23:17
+  --> $DIR/invalid-attributes-on-const-params-78957.rs:24:17
    |
 LL | pub struct Bar3<#[cold] T>(PhantomData<T>);
    |                 ^^^^^^^
diff --git a/tests/ui/attributes/key-value-expansion-scope.stderr b/tests/ui/attributes/key-value-expansion-scope.stderr
index 29b48ca4ce6..71a83d80617 100644
--- a/tests/ui/attributes/key-value-expansion-scope.stderr
+++ b/tests/ui/attributes/key-value-expansion-scope.stderr
@@ -135,7 +135,7 @@ LL | #![doc = in_root!()]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535>
    = help: import `macro_rules` with `use` to make it callable above its definition
-   = note: `#[deny(out_of_scope_macro_calls)]` on by default
+   = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: cannot find macro `in_mod_escape` in the current scope when looking from the crate root
   --> $DIR/key-value-expansion-scope.rs:4:10
@@ -199,7 +199,7 @@ LL | #![doc = in_root!()]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535>
    = help: import `macro_rules` with `use` to make it callable above its definition
-   = note: `#[deny(out_of_scope_macro_calls)]` on by default
+   = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: cannot find macro `in_mod_escape` in the current scope when looking from the crate root
@@ -211,7 +211,7 @@ LL | #![doc = in_mod_escape!()]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535>
    = help: import `macro_rules` with `use` to make it callable above its definition
-   = note: `#[deny(out_of_scope_macro_calls)]` on by default
+   = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay`
@@ -223,7 +223,7 @@ LL | #[doc = in_mod!()]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535>
    = help: import `macro_rules` with `use` to make it callable above its definition
-   = note: `#[deny(out_of_scope_macro_calls)]` on by default
+   = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: cannot find macro `in_mod` in the current scope when looking from module `macros_stay`
@@ -235,7 +235,7 @@ LL |     #![doc = in_mod!()]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535>
    = help: import `macro_rules` with `use` to make it callable above its definition
-   = note: `#[deny(out_of_scope_macro_calls)]` on by default
+   = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape`
@@ -247,7 +247,7 @@ LL | #[doc = in_mod_escape!()]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535>
    = help: import `macro_rules` with `use` to make it callable above its definition
-   = note: `#[deny(out_of_scope_macro_calls)]` on by default
+   = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: cannot find macro `in_mod_escape` in the current scope when looking from module `macros_escape`
@@ -259,5 +259,5 @@ LL |     #![doc = in_mod_escape!()]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #124535 <https://github.com/rust-lang/rust/issues/124535>
    = help: import `macro_rules` with `use` to make it callable above its definition
-   = note: `#[deny(out_of_scope_macro_calls)]` on by default
+   = note: `#[deny(out_of_scope_macro_calls)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/attributes/lint_on_root.rs b/tests/ui/attributes/lint_on_root.rs
index bafdb46883f..6cec7508560 100644
--- a/tests/ui/attributes/lint_on_root.rs
+++ b/tests/ui/attributes/lint_on_root.rs
@@ -1,7 +1,7 @@
 // NOTE: this used to panic in debug builds (by a sanity assertion)
 // and not emit any lint on release builds. See https://github.com/rust-lang/rust/issues/142891.
 #![inline = ""]
-//~^ ERROR: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` [ill_formed_attribute_input]
+//~^ ERROR: valid forms for the attribute are `#![inline(always)]`, `#![inline(never)]`, and `#![inline]` [ill_formed_attribute_input]
 //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 //~| ERROR attribute cannot be used on
 
diff --git a/tests/ui/attributes/lint_on_root.stderr b/tests/ui/attributes/lint_on_root.stderr
index 9d8d1495c1b..46b0b613a2f 100644
--- a/tests/ui/attributes/lint_on_root.stderr
+++ b/tests/ui/attributes/lint_on_root.stderr
@@ -6,7 +6,7 @@ LL | #![inline = ""]
    |
    = help: `#[inline]` can only be applied to functions
 
-error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
+error: valid forms for the attribute are `#![inline(always)]`, `#![inline(never)]`, and `#![inline]`
   --> $DIR/lint_on_root.rs:3:1
    |
 LL | #![inline = ""]
@@ -14,12 +14,12 @@ LL | #![inline = ""]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 2 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
-error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
+error: valid forms for the attribute are `#![inline(always)]`, `#![inline(never)]`, and `#![inline]`
   --> $DIR/lint_on_root.rs:3:1
    |
 LL | #![inline = ""]
@@ -27,5 +27,5 @@ LL | #![inline = ""]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs
index 3293f75fba9..90ca007451e 100644
--- a/tests/ui/attributes/malformed-attrs.rs
+++ b/tests/ui/attributes/malformed-attrs.rs
@@ -12,7 +12,7 @@
 #![feature(min_generic_const_args)]
 #![feature(ffi_const, ffi_pure)]
 #![feature(coverage_attribute)]
-#![feature(no_sanitize)]
+#![feature(sanitize)]
 #![feature(marker_trait_attr)]
 #![feature(thread_local)]
 #![feature(must_not_suspend)]
@@ -89,7 +89,7 @@
 //~^ ERROR malformed
 #[coverage]
 //~^ ERROR malformed `coverage` attribute input
-#[no_sanitize]
+#[sanitize]
 //~^ ERROR malformed
 #[ignore()]
 //~^ ERROR valid forms for the attribute are
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 9c31765149b..98ff578918b 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -49,11 +49,23 @@ LL | #[crate_name]
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute>
 
-error: malformed `no_sanitize` attribute input
+error: malformed `sanitize` attribute input
   --> $DIR/malformed-attrs.rs:92:1
    |
-LL | #[no_sanitize]
-   | ^^^^^^^^^^^^^^ help: must be of the form: `#[no_sanitize(address, kcfi, memory, thread)]`
+LL | #[sanitize]
+   | ^^^^^^^^^^^
+   |
+help: the following are the possible correct uses
+   |
+LL | #[sanitize(address = "on|off")]
+   |           ++++++++++++++++++++
+LL | #[sanitize(cfi = "on|off")]
+   |           ++++++++++++++++
+LL | #[sanitize(hwaddress = "on|off")]
+   |           ++++++++++++++++++++++
+LL | #[sanitize(kcfi = "on|off")]
+   |           +++++++++++++++++
+   = and 5 other candidates
 
 error: malformed `instruction_set` attribute input
   --> $DIR/malformed-attrs.rs:106:1
@@ -244,7 +256,7 @@ LL | #[doc]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]`
   --> $DIR/malformed-attrs.rs:76:1
@@ -754,7 +766,7 @@ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
 LL | #[diagnostic::do_not_recommend()]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(malformed_diagnostic_attributes)]` on by default
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: missing options for `on_unimplemented` attribute
   --> $DIR/malformed-attrs.rs:138:1
@@ -824,7 +836,7 @@ LL | #[doc]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]`
@@ -836,7 +848,7 @@ LL | #[doc]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
@@ -848,7 +860,7 @@ LL | #[link]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
@@ -859,7 +871,7 @@ LL | #[inline = 5]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
@@ -870,7 +882,7 @@ LL | #[ignore()]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
@@ -881,5 +893,5 @@ LL | #[ignore = 1]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/attributes/malformed-reprs.stderr b/tests/ui/attributes/malformed-reprs.stderr
index 43085b9c341..3a788999542 100644
--- a/tests/ui/attributes/malformed-reprs.stderr
+++ b/tests/ui/attributes/malformed-reprs.stderr
@@ -7,18 +7,14 @@ LL | #![repr]
    = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
 help: try changing it to one of the following valid forms of the attribute
    |
-LL - #![repr]
-LL + #[repr(<integer type>)]
-   |
-LL - #![repr]
-LL + #[repr(C)]
-   |
-LL - #![repr]
-LL + #[repr(Rust)]
-   |
-LL - #![repr]
-LL + #[repr(align(...))]
-   |
+LL | #![repr(<integer type>)]
+   |        ++++++++++++++++
+LL | #![repr(C)]
+   |        +++
+LL | #![repr(Rust)]
+   |        ++++++
+LL | #![repr(align(...))]
+   |        ++++++++++++
    = and 2 other candidates
 
 error[E0589]: invalid `repr(align)` attribute: not a power of two
diff --git a/tests/ui/attributes/no-sanitize.rs b/tests/ui/attributes/no-sanitize.rs
deleted file mode 100644
index ddf909be63a..00000000000
--- a/tests/ui/attributes/no-sanitize.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-#![feature(no_sanitize)]
-#![feature(stmt_expr_attributes)]
-#![deny(unused_attributes)]
-#![allow(dead_code)]
-
-fn invalid() {
-    #[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
-    {
-        1
-    };
-}
-
-#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
-type InvalidTy = ();
-
-#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
-mod invalid_module {}
-
-fn main() {
-    let _ = #[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
-    (|| 1);
-}
-
-#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
-struct F;
-
-#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
-impl F {
-    #[no_sanitize(memory)]
-    fn valid(&self) {}
-}
-
-#[no_sanitize(address, memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
-static INVALID : i32 = 0;
-
-#[no_sanitize(memory)]
-fn valid() {}
-
-#[no_sanitize(address)]
-static VALID : i32 = 0;
-
-#[no_sanitize("address")]
-//~^ ERROR `#[no_sanitize(...)]` should be applied to a function
-//~| ERROR invalid argument for `no_sanitize`
-static VALID2 : i32 = 0;
diff --git a/tests/ui/attributes/no-sanitize.stderr b/tests/ui/attributes/no-sanitize.stderr
deleted file mode 100644
index 8d5fbb109ea..00000000000
--- a/tests/ui/attributes/no-sanitize.stderr
+++ /dev/null
@@ -1,80 +0,0 @@
-error: `#[no_sanitize(memory)]` should be applied to a function
-  --> $DIR/no-sanitize.rs:7:19
-   |
-LL |       #[no_sanitize(memory)]
-   |                     ^^^^^^
-LL | /     {
-LL | |         1
-LL | |     };
-   | |_____- not a function
-
-error: `#[no_sanitize(memory)]` should be applied to a function
-  --> $DIR/no-sanitize.rs:13:15
-   |
-LL | #[no_sanitize(memory)]
-   |               ^^^^^^
-LL | type InvalidTy = ();
-   | -------------------- not a function
-
-error: `#[no_sanitize(memory)]` should be applied to a function
-  --> $DIR/no-sanitize.rs:16:15
-   |
-LL | #[no_sanitize(memory)]
-   |               ^^^^^^
-LL | mod invalid_module {}
-   | --------------------- not a function
-
-error: `#[no_sanitize(memory)]` should be applied to a function
-  --> $DIR/no-sanitize.rs:20:27
-   |
-LL |     let _ = #[no_sanitize(memory)]
-   |                           ^^^^^^
-LL |     (|| 1);
-   |     ------ not a function
-
-error: `#[no_sanitize(memory)]` should be applied to a function
-  --> $DIR/no-sanitize.rs:24:15
-   |
-LL | #[no_sanitize(memory)]
-   |               ^^^^^^
-LL | struct F;
-   | --------- not a function
-
-error: `#[no_sanitize(memory)]` should be applied to a function
-  --> $DIR/no-sanitize.rs:27:15
-   |
-LL |   #[no_sanitize(memory)]
-   |                 ^^^^^^
-LL | / impl F {
-LL | |     #[no_sanitize(memory)]
-LL | |     fn valid(&self) {}
-LL | | }
-   | |_- not a function
-
-error: `#[no_sanitize(memory)]` should be applied to a function
-  --> $DIR/no-sanitize.rs:33:24
-   |
-LL | #[no_sanitize(address, memory)]
-   |                        ^^^^^^
-LL | static INVALID : i32 = 0;
-   | ------------------------- not a function
-
-error: `#[no_sanitize(...)]` should be applied to a function
-  --> $DIR/no-sanitize.rs:42:15
-   |
-LL | #[no_sanitize("address")]
-   |               ^^^^^^^^^
-...
-LL | static VALID2 : i32 = 0;
-   | ------------------------ not a function
-
-error: invalid argument for `no_sanitize`
-  --> $DIR/no-sanitize.rs:42:15
-   |
-LL | #[no_sanitize("address")]
-   |               ^^^^^^^^^
-   |
-   = note: expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
-
-error: aborting due to 9 previous errors
-
diff --git a/tests/ui/attributes/rustc_confusables.rs b/tests/ui/attributes/rustc_confusables.rs
index 91c66a75cc3..14aed092694 100644
--- a/tests/ui/attributes/rustc_confusables.rs
+++ b/tests/ui/attributes/rustc_confusables.rs
@@ -45,4 +45,5 @@ impl Bar {
 #[rustc_confusables("blah")]
 //~^ ERROR attribute cannot be used on
 //~| HELP can only be applied to
+//~| HELP remove the attribute
 fn not_inherent_impl_method() {}
diff --git a/tests/ui/auto-traits/auto-traits.stderr b/tests/ui/auto-traits/auto-traits.stderr
index 34be8d3f67b..1ac1a992200 100644
--- a/tests/ui/auto-traits/auto-traits.stderr
+++ b/tests/ui/auto-traits/auto-traits.stderr
@@ -4,7 +4,7 @@ warning: trait `AutoInner` is never used
 LL |     auto trait AutoInner {}
    |                ^^^^^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: trait `AutoUnsafeInner` is never used
   --> $DIR/auto-traits.rs:23:23
diff --git a/tests/ui/issues/issue-77218/issue-77218.fixed b/tests/ui/binding/invalid-assignment-in-while-loop-77218.fixed
index 6ce9dd1c2c5..aa662ead21a 100644
--- a/tests/ui/issues/issue-77218/issue-77218.fixed
+++ b/tests/ui/binding/invalid-assignment-in-while-loop-77218.fixed
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/77218
 //@ run-rustfix
 fn main() {
     let value = [7u8];
diff --git a/tests/ui/issues/issue-77218/issue-77218.rs b/tests/ui/binding/invalid-assignment-in-while-loop-77218.rs
index 14edc065d0e..9f249180e83 100644
--- a/tests/ui/issues/issue-77218/issue-77218.rs
+++ b/tests/ui/binding/invalid-assignment-in-while-loop-77218.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/77218
 //@ run-rustfix
 fn main() {
     let value = [7u8];
diff --git a/tests/ui/issues/issue-77218/issue-77218.stderr b/tests/ui/binding/invalid-assignment-in-while-loop-77218.stderr
index e98e69314d9..e6baf349d28 100644
--- a/tests/ui/issues/issue-77218/issue-77218.stderr
+++ b/tests/ui/binding/invalid-assignment-in-while-loop-77218.stderr
@@ -1,5 +1,5 @@
 error[E0070]: invalid left-hand side of assignment
-  --> $DIR/issue-77218.rs:4:19
+  --> $DIR/invalid-assignment-in-while-loop-77218.rs:5:19
    |
 LL |     while Some(0) = value.get(0) {}
    |                -  ^
diff --git a/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr
index ac0241cf9a7..0a32cccff1d 100644
--- a/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr
+++ b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr
@@ -15,10 +15,10 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer
 LL |     let q = &raw mut *x;
    |             ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
    |
-help: consider changing this to be a mutable pointer
+help: consider specifying this binding's type
    |
-LL |     let x = &mut 0 as *const i32;
-   |              +++
+LL |     let x: *mut i32 = &0 as *const i32;
+   |          ++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr
index ade10dbbfbd..87717a53290 100644
--- a/tests/ui/borrowck/borrowck-access-permissions.stderr
+++ b/tests/ui/borrowck/borrowck-access-permissions.stderr
@@ -43,10 +43,11 @@ error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` poin
 LL |             let _y1 = &mut *ptr_x;
    |                       ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
    |
-help: consider changing this to be a mutable pointer
+help: consider changing this binding's type
+   |
+LL -         let ptr_x: *const _ = &x;
+LL +         let ptr_x: *mut i32 = &x;
    |
-LL |         let ptr_x: *const _ = &mut x;
-   |                                +++
 
 error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-access-permissions.rs:59:18
diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
index c55923097fc..709cf76b444 100644
--- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
+++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
@@ -6,7 +6,7 @@ LL |         let sfoo: *mut Foo = &mut SFOO;
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
-   = note: `#[warn(static_mut_refs)]` on by default
+   = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `&raw mut` instead to create a raw pointer
    |
 LL |         let sfoo: *mut Foo = &raw mut SFOO;
diff --git a/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr b/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr
index 02d5231f713..8e1cd800b37 100644
--- a/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr
+++ b/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr
@@ -21,7 +21,7 @@ LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
-   = note: `#[warn(anonymous_parameters)]` on by default
+   = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default
 
 error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait
   --> $DIR/ice-mutability-error-slicing-121807.rs:17:5
diff --git a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr
index 4ec4d2138db..5389226f7a7 100644
--- a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr
+++ b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr
@@ -22,12 +22,6 @@ LL |         force_send(async_load(&not_static));
 ...
 LL |     }
    |     - `not_static` dropped here while still borrowed
-   |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
-  --> $DIR/implementation-not-general-enough-ice-133252.rs:16:18
-   |
-LL | fn force_send<T: Send>(_: T) {}
-   |                  ^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-78192.rs b/tests/ui/borrowck/incorrect-use-after-storage-end-78192.rs
index bec2a82910c..99a1d37eb4d 100644
--- a/tests/ui/issues/issue-78192.rs
+++ b/tests/ui/borrowck/incorrect-use-after-storage-end-78192.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/78192
 //@ run-pass
 
 #![allow(unused_assignments)]
diff --git a/tests/ui/issues/issue-7660.rs b/tests/ui/borrowck/rvalue-lifetime-match-equivalence-7660.rs
index 104cdad8f7b..90526de14e7 100644
--- a/tests/ui/issues/issue-7660.rs
+++ b/tests/ui/borrowck/rvalue-lifetime-match-equivalence-7660.rs
@@ -1,9 +1,9 @@
+// https://github.com/rust-lang/rust/issues/7660
 //@ run-pass
 #![allow(unused_variables)]
 // Regression test for issue 7660
 // rvalue lifetime too short when equivalent `match` works
 
-
 use std::collections::HashMap;
 
 struct A(isize, isize);
diff --git a/tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.fixed b/tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.fixed
new file mode 100644
index 00000000000..6303733967b
--- /dev/null
+++ b/tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.fixed
@@ -0,0 +1,21 @@
+//@ run-rustfix
+fn main() {
+    let mut map = std::collections::BTreeMap::new();
+    map.insert(0, "string".to_owned());
+
+    let string = map.get_mut(&0).unwrap();
+    string.push_str("test");
+    //~^ ERROR cannot borrow `*string` as mutable, as it is behind a `&` reference
+
+    let mut map = std::collections::HashMap::new();
+    map.insert(0, "string".to_owned());
+
+    let string = map.get_mut(&0).unwrap();
+    string.push_str("test");
+    //~^ ERROR cannot borrow `*string` as mutable, as it is behind a `&` reference
+
+    let mut vec = vec![String::new(), String::new()];
+    let string = &mut vec[0];
+    string.push_str("test");
+    //~^ ERROR cannot borrow `*string` as mutable, as it is behind a `&` reference
+}
diff --git a/tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.rs b/tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.rs
new file mode 100644
index 00000000000..be1a63a5e69
--- /dev/null
+++ b/tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.rs
@@ -0,0 +1,21 @@
+//@ run-rustfix
+fn main() {
+    let mut map = std::collections::BTreeMap::new();
+    map.insert(0, "string".to_owned());
+
+    let string = &map[&0];
+    string.push_str("test");
+    //~^ ERROR cannot borrow `*string` as mutable, as it is behind a `&` reference
+
+    let mut map = std::collections::HashMap::new();
+    map.insert(0, "string".to_owned());
+
+    let string = &map[&0];
+    string.push_str("test");
+    //~^ ERROR cannot borrow `*string` as mutable, as it is behind a `&` reference
+
+    let mut vec = vec![String::new(), String::new()];
+    let string = &vec[0];
+    string.push_str("test");
+    //~^ ERROR cannot borrow `*string` as mutable, as it is behind a `&` reference
+}
diff --git a/tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.stderr b/tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.stderr
new file mode 100644
index 00000000000..44cc9aefcf1
--- /dev/null
+++ b/tests/ui/borrowck/suggestions/overloaded-index-not-mut-but-should-be-mut.stderr
@@ -0,0 +1,38 @@
+error[E0596]: cannot borrow `*string` as mutable, as it is behind a `&` reference
+  --> $DIR/overloaded-index-not-mut-but-should-be-mut.rs:7:5
+   |
+LL |     string.push_str("test");
+   |     ^^^^^^ `string` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider using `get_mut`
+   |
+LL -     let string = &map[&0];
+LL +     let string = map.get_mut(&0).unwrap();
+   |
+
+error[E0596]: cannot borrow `*string` as mutable, as it is behind a `&` reference
+  --> $DIR/overloaded-index-not-mut-but-should-be-mut.rs:14:5
+   |
+LL |     string.push_str("test");
+   |     ^^^^^^ `string` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider using `get_mut`
+   |
+LL -     let string = &map[&0];
+LL +     let string = map.get_mut(&0).unwrap();
+   |
+
+error[E0596]: cannot borrow `*string` as mutable, as it is behind a `&` reference
+  --> $DIR/overloaded-index-not-mut-but-should-be-mut.rs:19:5
+   |
+LL |     string.push_str("test");
+   |     ^^^^^^ `string` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     let string = &mut vec[0];
+   |                   +++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/suggestions/overloaded-index-without-indexmut.rs b/tests/ui/borrowck/suggestions/overloaded-index-without-indexmut.rs
new file mode 100644
index 00000000000..06eb5b52e5f
--- /dev/null
+++ b/tests/ui/borrowck/suggestions/overloaded-index-without-indexmut.rs
@@ -0,0 +1,16 @@
+use std::ops::Index;
+
+struct MyType;
+impl Index<usize> for MyType {
+    type Output = String;
+    fn index(&self, _idx: usize) -> &String {
+        const { &String::new() }
+    }
+}
+
+fn main() {
+    let x = MyType;
+    let y = &x[0];
+    y.push_str("");
+    //~^ ERROR cannot borrow `*y` as mutable, as it is behind a `&` reference
+}
diff --git a/tests/ui/borrowck/suggestions/overloaded-index-without-indexmut.stderr b/tests/ui/borrowck/suggestions/overloaded-index-without-indexmut.stderr
new file mode 100644
index 00000000000..6a46332a5d7
--- /dev/null
+++ b/tests/ui/borrowck/suggestions/overloaded-index-without-indexmut.stderr
@@ -0,0 +1,9 @@
+error[E0596]: cannot borrow `*y` as mutable, as it is behind a `&` reference
+  --> $DIR/overloaded-index-without-indexmut.rs:14:5
+   |
+LL |     y.push_str("");
+   |     ^ `y` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
index a656bb67bcb..3d54d5269ae 100644
--- a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
+++ b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
@@ -6,7 +6,7 @@ LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
-   = note: `#[warn(anonymous_parameters)]` on by default
+   = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default
 
 error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait
   --> $DIR/trait-impl-argument-difference-ice.rs:14:5
diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr b/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr
index 01277fd632e..5f5238dd891 100644
--- a/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr
+++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr
@@ -4,7 +4,7 @@ warning: trait `Bar` is never used
 LL | trait Bar {
    |       ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/cast/coercion-as-explicit-cast.stderr b/tests/ui/cast/coercion-as-explicit-cast.stderr
index d66298c7d44..9553ddd6567 100644
--- a/tests/ui/cast/coercion-as-explicit-cast.stderr
+++ b/tests/ui/cast/coercion-as-explicit-cast.stderr
@@ -6,7 +6,7 @@ LL | trait Foo {
 LL |     fn foo(&self) {}
    |        ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/cast/fat-ptr-cast-rpass.stderr b/tests/ui/cast/fat-ptr-cast-rpass.stderr
index d01688e0cc3..b314f397c4f 100644
--- a/tests/ui/cast/fat-ptr-cast-rpass.stderr
+++ b/tests/ui/cast/fat-ptr-cast-rpass.stderr
@@ -6,7 +6,7 @@ LL | trait Foo {
 LL |     fn foo(&self) {}
    |        ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr
index 5dd81f486c8..f6448147392 100644
--- a/tests/ui/check-cfg/target_feature.stderr
+++ b/tests/ui/check-cfg/target_feature.stderr
@@ -6,6 +6,7 @@ LL |     cfg!(target_feature = "_UNEXPECTED_VALUE");
    |
    = note: expected values for `target_feature` are: `10e60`
 `2e3`
+`32s`
 `3e3r1`
 `3e3r2`
 `3e3r3`
diff --git a/tests/ui/closures/2229_closure_analysis/match/issue-87097.stderr b/tests/ui/closures/2229_closure_analysis/match/issue-87097.stderr
index 39ec71ba22a..df6e84c0f65 100644
--- a/tests/ui/closures/2229_closure_analysis/match/issue-87097.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/issue-87097.stderr
@@ -7,7 +7,7 @@ LL |     A,
 LL |     B,
    |     ^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: unused closure that must be used
   --> $DIR/issue-87097.rs:17:5
@@ -19,7 +19,7 @@ LL | |     };
    | |_____^
    |
    = note: closures are lazy and do nothing unless called
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: unused closure that must be used
   --> $DIR/issue-87097.rs:26:5
diff --git a/tests/ui/closures/issue-1460.stderr b/tests/ui/closures/issue-1460.stderr
index 15eaf7a9a11..8d6851640f9 100644
--- a/tests/ui/closures/issue-1460.stderr
+++ b/tests/ui/closures/issue-1460.stderr
@@ -5,7 +5,7 @@ LL |     {|i: u32| if 1 == i { }};
    |      ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/closures/moved-upvar-mut-rebind-11958.stderr b/tests/ui/closures/moved-upvar-mut-rebind-11958.stderr
index b12bbcad925..1bf8a8b23a1 100644
--- a/tests/ui/closures/moved-upvar-mut-rebind-11958.stderr
+++ b/tests/ui/closures/moved-upvar-mut-rebind-11958.stderr
@@ -5,7 +5,7 @@ LL |     let _thunk = Box::new(move|| { x = 2; });
    |                                    ^
    |
    = help: maybe it is overwritten before being read?
-   = note: `#[warn(unused_assignments)]` on by default
+   = note: `#[warn(unused_assignments)]` (part of `#[warn(unused)]`) on by default
 
 warning: unused variable: `x`
   --> $DIR/moved-upvar-mut-rebind-11958.rs:10:36
@@ -14,7 +14,7 @@ LL |     let _thunk = Box::new(move|| { x = 2; });
    |                                    ^
    |
    = help: did you mean to capture by reference instead?
-   = note: `#[warn(unused_variables)]` on by default
+   = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/closures/old-closure-expr-precedence.stderr b/tests/ui/closures/old-closure-expr-precedence.stderr
index fabece1ad4a..2ab1995075f 100644
--- a/tests/ui/closures/old-closure-expr-precedence.stderr
+++ b/tests/ui/closures/old-closure-expr-precedence.stderr
@@ -4,7 +4,7 @@ warning: unnecessary trailing semicolons
 LL |   if (true) { 12; };;; -num;
    |                     ^^ help: remove these semicolons
    |
-   = note: `#[warn(redundant_semicolons)]` on by default
+   = note: `#[warn(redundant_semicolons)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/closures/unused-closure-ice-16256.stderr b/tests/ui/closures/unused-closure-ice-16256.stderr
index 9df433add5d..a00b9fbac8e 100644
--- a/tests/ui/closures/unused-closure-ice-16256.stderr
+++ b/tests/ui/closures/unused-closure-ice-16256.stderr
@@ -5,7 +5,7 @@ LL |     |c: u8| buf.push(c);
    |     ^^^^^^^^^^^^^^^^^^^
    |
    = note: closures are lazy and do nothing unless called
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs
index 70cbb9a52f7..c69565a81f2 100644
--- a/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs
@@ -55,6 +55,7 @@ fn main() {
     // The `Box` has been deallocated by now, so this is a dangling reference!
     let r: &u8 = &*r;
     println!("{:p}", r);
+    println!("{}", i);
 
     // The following might segfault. Or it might not.
     // Depends on the platform semantics
diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs
index ad1d7b56c8c..b74f85290a7 100644
--- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs
@@ -58,6 +58,7 @@ fn main() {
     // The `Box` has been deallocated by now, so this is a dangling reference!
     let r: &u8 = &*r;
     println!("{:p}", r);
+    println!("{}", i);
 
     // The following might segfault. Or it might not.
     // Depends on the platform semantics
diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
index 637f0042ada..18d5bd33355 100644
--- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
+++ b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
@@ -58,6 +58,7 @@ fn main() {
     // The `Box` has been deallocated by now, so this is a dangling reference!
     let r: &u8 = &*r;
     println!("{:p}", r);
+    println!("{}", i);
 
     // The following might segfault. Or it might not.
     // Depends on the platform semantics
diff --git a/tests/ui/issues/issue-76042.rs b/tests/ui/codegen/i128-shift-overflow-check-76042.rs
index 279e860459d..7ae0806216c 100644
--- a/tests/ui/issues/issue-76042.rs
+++ b/tests/ui/codegen/i128-shift-overflow-check-76042.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/76042
 //@ run-pass
 //@ compile-flags: -Coverflow-checks=off -Ccodegen-units=1 -Copt-level=0
 
diff --git a/tests/ui/coercion/issue-14589.stderr b/tests/ui/coercion/issue-14589.stderr
index 5d7b840a8d7..b98444ab7e4 100644
--- a/tests/ui/coercion/issue-14589.stderr
+++ b/tests/ui/coercion/issue-14589.stderr
@@ -6,7 +6,7 @@ LL | trait Foo { fn dummy(&self) { }}
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coercion/method-return-trait-object-14399.stderr b/tests/ui/coercion/method-return-trait-object-14399.stderr
index 1aa87f53ff8..283358cb77d 100644
--- a/tests/ui/coercion/method-return-trait-object-14399.stderr
+++ b/tests/ui/coercion/method-return-trait-object-14399.stderr
@@ -6,7 +6,7 @@ LL | trait A { fn foo(&self) {} }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-8248.rs b/tests/ui/coercion/mut-trait-coercion-8248.rs
index 95f626658cc..a45a4d94315 100644
--- a/tests/ui/issues/issue-8248.rs
+++ b/tests/ui/coercion/mut-trait-coercion-8248.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8248
 //@ run-pass
 
 trait A {
diff --git a/tests/ui/issues/issue-8248.stderr b/tests/ui/coercion/mut-trait-coercion-8248.stderr
index 8570bfaefad..0c7d5f9dc45 100644
--- a/tests/ui/issues/issue-8248.stderr
+++ b/tests/ui/coercion/mut-trait-coercion-8248.stderr
@@ -1,12 +1,12 @@
 warning: method `dummy` is never used
-  --> $DIR/issue-8248.rs:4:8
+  --> $DIR/mut-trait-coercion-8248.rs:5:8
    |
 LL | trait A {
    |       - method in this trait
 LL |     fn dummy(&self) { }
    |        ^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-8398.rs b/tests/ui/coercion/mut-trait-object-coercion-8398.rs
index 7d100b855fd..d87d27582ba 100644
--- a/tests/ui/issues/issue-8398.rs
+++ b/tests/ui/coercion/mut-trait-object-coercion-8398.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8398
 //@ check-pass
 #![allow(dead_code)]
 
diff --git a/tests/ui/coercion/trait-object-coercion-distribution-9951.stderr b/tests/ui/coercion/trait-object-coercion-distribution-9951.stderr
index 0c672aa9b33..04e05ed8d6b 100644
--- a/tests/ui/coercion/trait-object-coercion-distribution-9951.stderr
+++ b/tests/ui/coercion/trait-object-coercion-distribution-9951.stderr
@@ -6,7 +6,7 @@ LL | trait Bar {
 LL |   fn noop(&self);
    |      ^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr b/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
index 01694eaf5d1..41164e99e6d 100644
--- a/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
+++ b/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
@@ -9,7 +9,7 @@ LL | impl<'a> Trait for fn(fn(&'a ())) {}
    = warning: the behavior may change in a future release
    = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
    = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
-   = note: `#[warn(coherence_leak_check)]` on by default
+   = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coherence/coherence-fn-inputs.stderr b/tests/ui/coherence/coherence-fn-inputs.stderr
index 56f3a14833e..75df33913a9 100644
--- a/tests/ui/coherence/coherence-fn-inputs.stderr
+++ b/tests/ui/coherence/coherence-fn-inputs.stderr
@@ -9,7 +9,7 @@ LL | impl Trait for for<'c> fn(&'c u32, &'c u32) {
    = warning: the behavior may change in a future release
    = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
    = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
-   = note: `#[warn(coherence_leak_check)]` on by default
+   = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coherence/coherence-subtyping.stderr b/tests/ui/coherence/coherence-subtyping.stderr
index 42f256ace78..f380ea87829 100644
--- a/tests/ui/coherence/coherence-subtyping.stderr
+++ b/tests/ui/coherence/coherence-subtyping.stderr
@@ -10,7 +10,7 @@ LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
    = warning: the behavior may change in a future release
    = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
    = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
-   = note: `#[warn(coherence_leak_check)]` on by default
+   = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coherence/orphan-check-alias.classic.stderr b/tests/ui/coherence/orphan-check-alias.classic.stderr
index 3fd62b05b4d..25fde6ee1d2 100644
--- a/tests/ui/coherence/orphan-check-alias.classic.stderr
+++ b/tests/ui/coherence/orphan-check-alias.classic.stderr
@@ -8,7 +8,7 @@ LL | impl<T> foreign::Trait2<B, T> for <T as Id>::Assoc {
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
-   = note: `#[warn(uncovered_param_in_projection)]` on by default
+   = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coherence/orphan-check-alias.next.stderr b/tests/ui/coherence/orphan-check-alias.next.stderr
index 3fd62b05b4d..25fde6ee1d2 100644
--- a/tests/ui/coherence/orphan-check-alias.next.stderr
+++ b/tests/ui/coherence/orphan-check-alias.next.stderr
@@ -8,7 +8,7 @@ LL | impl<T> foreign::Trait2<B, T> for <T as Id>::Assoc {
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
-   = note: `#[warn(uncovered_param_in_projection)]` on by default
+   = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr
index d83a56c0bd0..464413e9f38 100644
--- a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr
+++ b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr
@@ -8,7 +8,7 @@ LL | impl<T> foreign::Trait1<Local, T> for <T as Project>::Output {}
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
-   = note: `#[warn(uncovered_param_in_projection)]` on by default
+   = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr
index d83a56c0bd0..464413e9f38 100644
--- a/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr
+++ b/tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr
@@ -8,7 +8,7 @@ LL | impl<T> foreign::Trait1<Local, T> for <T as Project>::Output {}
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
-   = note: `#[warn(uncovered_param_in_projection)]` on by default
+   = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr
index 8964fefedd4..0465fad2119 100644
--- a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr
+++ b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr
@@ -8,7 +8,7 @@ LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
-   = note: `#[warn(uncovered_param_in_projection)]` on by default
+   = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning[E0210]: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`)
   --> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:9
diff --git a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr
index 8964fefedd4..0465fad2119 100644
--- a/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr
+++ b/tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr
@@ -8,7 +8,7 @@ LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
-   = note: `#[warn(uncovered_param_in_projection)]` on by default
+   = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning[E0210]: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`)
   --> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:9
diff --git a/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr b/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr
index 28b8c3f4a94..de34ef7cfd3 100644
--- a/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr
+++ b/tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr
@@ -8,7 +8,7 @@ LL | impl<T> foreign::Trait0<Local, T, ()> for <T as Identity>::Output {}
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
-   = note: `#[warn(uncovered_param_in_projection)]` on by default
+   = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
   --> $DIR/orphan-check-projections-not-covering.rs:27:6
diff --git a/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr b/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr
index 28b8c3f4a94..de34ef7cfd3 100644
--- a/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr
+++ b/tests/ui/coherence/orphan-check-projections-not-covering.next.stderr
@@ -8,7 +8,7 @@ LL | impl<T> foreign::Trait0<Local, T, ()> for <T as Identity>::Output {}
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
-   = note: `#[warn(uncovered_param_in_projection)]` on by default
+   = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
   --> $DIR/orphan-check-projections-not-covering.rs:27:6
diff --git a/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr b/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr
index 0346a9d665c..e729bcf225e 100644
--- a/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr
+++ b/tests/ui/coherence/orphan-check-projections-unsat-bounds.classic.stderr
@@ -8,7 +8,7 @@ LL | impl<T> foreign::Trait1<LocalTy, T> for <Wrapper<T> as Discard>::Output
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
-   = note: `#[warn(uncovered_param_in_projection)]` on by default
+   = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr b/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr
index 0346a9d665c..e729bcf225e 100644
--- a/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr
+++ b/tests/ui/coherence/orphan-check-projections-unsat-bounds.next.stderr
@@ -8,7 +8,7 @@ LL | impl<T> foreign::Trait1<LocalTy, T> for <Wrapper<T> as Discard>::Output
    = note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
-   = note: `#[warn(uncovered_param_in_projection)]` on by default
+   = note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/const-generics/dyn-supertraits.stderr b/tests/ui/const-generics/dyn-supertraits.stderr
index 38b67ef4403..2b59cdb9418 100644
--- a/tests/ui/const-generics/dyn-supertraits.stderr
+++ b/tests/ui/const-generics/dyn-supertraits.stderr
@@ -4,7 +4,7 @@ warning: trait `Baz` is never used
 LL | trait Baz: Foo<3> {}
    |       ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: trait `Boz` is never used
   --> $DIR/dyn-supertraits.rs:26:7
diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
index 6b095f3818a..23e126d8702 100644
--- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
@@ -24,7 +24,7 @@ LL |     [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
-   = note: `#[warn(const_evaluatable_unchecked)]` on by default
+   = note: `#[warn(const_evaluatable_unchecked)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: cannot use constants which depend on generic parameters in types
   --> $DIR/dependence_lint.rs:18:9
diff --git a/tests/ui/const-generics/generic_const_exprs/function-call.stderr b/tests/ui/const-generics/generic_const_exprs/function-call.stderr
index 84abfe57876..806bc3e89a9 100644
--- a/tests/ui/const-generics/generic_const_exprs/function-call.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/function-call.stderr
@@ -6,7 +6,7 @@ LL |     let _ = [0; foo::<T>()];
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
-   = note: `#[warn(const_evaluatable_unchecked)]` on by default
+   = note: `#[warn(const_evaluatable_unchecked)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
index cf0bdd0e9a1..453079e3c15 100644
--- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr
@@ -46,7 +46,7 @@ warning: type `v11` should have an upper camel case name
 LL |     pub type v11 = [[usize; v4]; v4];
    |              ^^^ help: convert the identifier to upper camel case (notice the capitalization): `V11`
    |
-   = note: `#[warn(non_camel_case_types)]` on by default
+   = note: `#[warn(non_camel_case_types)]` (part of `#[warn(nonstandard_style)]`) on by default
 
 warning: type `v17` should have an upper camel case name
   --> $DIR/unevaluated-const-ice-119731.rs:16:16
diff --git a/tests/ui/const-generics/invariant.stderr b/tests/ui/const-generics/invariant.stderr
index b4e46e55268..095219f6e5f 100644
--- a/tests/ui/const-generics/invariant.stderr
+++ b/tests/ui/const-generics/invariant.stderr
@@ -10,7 +10,7 @@ LL | impl SadBee for fn(&'static ()) {
    = warning: the behavior may change in a future release
    = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
    = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
-   = note: `#[warn(coherence_leak_check)]` on by default
+   = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default
 
 error[E0308]: mismatched types
   --> $DIR/invariant.rs:25:5
diff --git a/tests/ui/const-generics/issues/issue-69654-run-pass.stderr b/tests/ui/const-generics/issues/issue-69654-run-pass.stderr
index 7b3cd4f375f..abde9a95f89 100644
--- a/tests/ui/const-generics/issues/issue-69654-run-pass.stderr
+++ b/tests/ui/const-generics/issues/issue-69654-run-pass.stderr
@@ -4,7 +4,7 @@ warning: trait `Bar` is never used
 LL | trait Bar<T> {}
    |       ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/const-generics/issues/issue-83466.stderr b/tests/ui/const-generics/issues/issue-83466.stderr
index 91451a799b0..5a0f5cbd131 100644
--- a/tests/ui/const-generics/issues/issue-83466.stderr
+++ b/tests/ui/const-generics/issues/issue-83466.stderr
@@ -9,7 +9,7 @@ LL |     S.func::<'a, 10_u32>()
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
-   = note: `#[warn(late_bound_lifetime_arguments)]` on by default
+   = note: `#[warn(late_bound_lifetime_arguments)]` (part of `#[warn(future_incompatible)]`) on by default
 
 error[E0747]: constant provided when a type was expected
   --> $DIR/issue-83466.rs:11:18
diff --git a/tests/ui/const-generics/issues/issue-86535-2.stderr b/tests/ui/const-generics/issues/issue-86535-2.stderr
index 0ba74836575..870d97d7d2e 100644
--- a/tests/ui/const-generics/issues/issue-86535-2.stderr
+++ b/tests/ui/const-generics/issues/issue-86535-2.stderr
@@ -4,7 +4,7 @@ warning: struct `Bar` is never constructed
 LL | struct Bar<const N: &'static ()>;
    |        ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/const-generics/issues/issue-86535.stderr b/tests/ui/const-generics/issues/issue-86535.stderr
index 84d6c1c11ff..6bb362de261 100644
--- a/tests/ui/const-generics/issues/issue-86535.stderr
+++ b/tests/ui/const-generics/issues/issue-86535.stderr
@@ -4,7 +4,7 @@ warning: struct `F` is never constructed
 LL | struct F<const S: &'static str>;
    |        ^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/const-generics/min_const_generics/complex-expression.stderr b/tests/ui/const-generics/min_const_generics/complex-expression.stderr
index 35039bb4109..ed3fa840cdf 100644
--- a/tests/ui/const-generics/min_const_generics/complex-expression.stderr
+++ b/tests/ui/const-generics/min_const_generics/complex-expression.stderr
@@ -69,7 +69,7 @@ LL |     let _ = [0; size_of::<*mut T>() + 1];
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
-   = note: `#[warn(const_evaluatable_unchecked)]` on by default
+   = note: `#[warn(const_evaluatable_unchecked)]` (part of `#[warn(future_incompatible)]`) on by default
 
 error: aborting due to 7 previous errors; 1 warning emitted
 
diff --git a/tests/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr b/tests/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr
index 8003dfa4071..cf72c0aa0df 100644
--- a/tests/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr
+++ b/tests/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr
@@ -6,7 +6,7 @@ LL |     [0; std::mem::size_of::<*mut T>()];
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
-   = note: `#[warn(const_evaluatable_unchecked)]` on by default
+   = note: `#[warn(const_evaluatable_unchecked)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: cannot use constants which depend on generic parameters in types
   --> $DIR/const-evaluatable-unchecked.rs:17:21
diff --git a/tests/ui/consts/const-block-item.stderr b/tests/ui/consts/const-block-item.stderr
index 04658742b56..b325976a60b 100644
--- a/tests/ui/consts/const-block-item.stderr
+++ b/tests/ui/consts/const-block-item.stderr
@@ -4,7 +4,7 @@ warning: trait `Value` is never used
 LL |     pub trait Value {
    |               ^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr
index b3ccd2459aa..943695d75fc 100644
--- a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr
+++ b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr
@@ -6,7 +6,7 @@ LL |     panic!({ "foo" });
    |
    = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>
-   = note: `#[warn(non_fmt_panics)]` on by default
+   = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: add a "{}" format string to `Display` the message
    |
 LL |     panic!("{}", { "foo" });
diff --git a/tests/ui/issues/issue-76191.rs b/tests/ui/consts/const-range-matching-76191.rs
index d2de44380c3..b579a4b3258 100644
--- a/tests/ui/issues/issue-76191.rs
+++ b/tests/ui/consts/const-range-matching-76191.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/76191
 // Regression test for diagnostic issue #76191
 #![allow(non_snake_case)]
 
diff --git a/tests/ui/issues/issue-76191.stderr b/tests/ui/consts/const-range-matching-76191.stderr
index d8b54be88f4..5c358d0fa1c 100644
--- a/tests/ui/issues/issue-76191.stderr
+++ b/tests/ui/consts/const-range-matching-76191.stderr
@@ -1,11 +1,11 @@
 error[E0080]: evaluation panicked: explicit panic
-  --> $DIR/issue-76191.rs:8:37
+  --> $DIR/const-range-matching-76191.rs:9:37
    |
 LL | const RANGE2: RangeInclusive<i32> = panic!();
    |                                     ^^^^^^^^ evaluation of `RANGE2` failed here
 
 error[E0308]: mismatched types
-  --> $DIR/issue-76191.rs:14:9
+  --> $DIR/const-range-matching-76191.rs:15:9
    |
 LL | const RANGE: RangeInclusive<i32> = 0..=255;
    | -------------------------------- constant defined here
@@ -27,7 +27,7 @@ LL +         0..=255 => {}
    |
 
 error[E0308]: mismatched types
-  --> $DIR/issue-76191.rs:16:9
+  --> $DIR/const-range-matching-76191.rs:17:9
    |
 LL | const RANGE2: RangeInclusive<i32> = panic!();
    | --------------------------------- constant defined here
diff --git a/tests/ui/consts/const_let_assign2.stderr b/tests/ui/consts/const_let_assign2.stderr
index e8bed6d0724..ad3587b7134 100644
--- a/tests/ui/consts/const_let_assign2.stderr
+++ b/tests/ui/consts/const_let_assign2.stderr
@@ -6,7 +6,7 @@ LL |     let ptr = unsafe { &mut BB };
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
-   = note: `#[warn(static_mut_refs)]` on by default
+   = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `&raw mut` instead to create a raw pointer
    |
 LL |     let ptr = unsafe { &raw mut BB };
diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.stderr b/tests/ui/consts/const_refs_to_static-ice-121413.stderr
index e354110f293..ea3daca51ef 100644
--- a/tests/ui/consts/const_refs_to_static-ice-121413.stderr
+++ b/tests/ui/consts/const_refs_to_static-ice-121413.stderr
@@ -17,7 +17,7 @@ LL |     static FOO: Sync = AtomicUsize::new(0);
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL |     static FOO: dyn Sync = AtomicUsize::new(0);
diff --git a/tests/ui/consts/packed_pattern.stderr b/tests/ui/consts/packed_pattern.stderr
index dc26078fb63..83bb3e5b6a7 100644
--- a/tests/ui/consts/packed_pattern.stderr
+++ b/tests/ui/consts/packed_pattern.stderr
@@ -6,7 +6,7 @@ LL |         Foo { field: (5, 6, 7, 8) } => {},
 LL |         FOO => unreachable!(),
    |         ^^^ no value can reach this
    |
-   = note: `#[warn(unreachable_patterns)]` on by default
+   = note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/consts/packed_pattern2.stderr b/tests/ui/consts/packed_pattern2.stderr
index 013f61f733c..8a09e708cb7 100644
--- a/tests/ui/consts/packed_pattern2.stderr
+++ b/tests/ui/consts/packed_pattern2.stderr
@@ -6,7 +6,7 @@ LL |         Bar { a: Foo { field: (5, 6) } } => {},
 LL |         FOO => unreachable!(),
    |         ^^^ no value can reach this
    |
-   = note: `#[warn(unreachable_patterns)]` on by default
+   = note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coroutine/gen_block_panic.stderr b/tests/ui/coroutine/gen_block_panic.stderr
index a0a6d1063c4..a43c9e03691 100644
--- a/tests/ui/coroutine/gen_block_panic.stderr
+++ b/tests/ui/coroutine/gen_block_panic.stderr
@@ -6,7 +6,7 @@ LL |         panic!("foo");
 LL |         yield 69;
    |         ^^^^^^^^^ unreachable statement
    |
-   = note: `#[warn(unreachable_code)]` on by default
+   = note: `#[warn(unreachable_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coroutine/issue-52398.stderr b/tests/ui/coroutine/issue-52398.stderr
index 806690cc332..b3bf2e4a4e6 100644
--- a/tests/ui/coroutine/issue-52398.stderr
+++ b/tests/ui/coroutine/issue-52398.stderr
@@ -8,7 +8,7 @@ LL | |     };
    | |_____^
    |
    = note: coroutines are lazy and do nothing unless resumed
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: unused coroutine that must be used
   --> $DIR/issue-52398.rs:24:18
diff --git a/tests/ui/coroutine/issue-57084.stderr b/tests/ui/coroutine/issue-57084.stderr
index 81bd27da919..0e2359f2f81 100644
--- a/tests/ui/coroutine/issue-57084.stderr
+++ b/tests/ui/coroutine/issue-57084.stderr
@@ -11,7 +11,7 @@ LL | |     };
    | |_____^
    |
    = note: coroutines are lazy and do nothing unless resumed
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coroutine/match-bindings.stderr b/tests/ui/coroutine/match-bindings.stderr
index 1318e6931f5..98877bbcba5 100644
--- a/tests/ui/coroutine/match-bindings.stderr
+++ b/tests/ui/coroutine/match-bindings.stderr
@@ -11,7 +11,7 @@ LL | |     };
    | |_____^
    |
    = note: coroutines are lazy and do nothing unless resumed
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coroutine/reborrow-mut-upvar.stderr b/tests/ui/coroutine/reborrow-mut-upvar.stderr
index a05e84c5f3e..a77121a25dc 100644
--- a/tests/ui/coroutine/reborrow-mut-upvar.stderr
+++ b/tests/ui/coroutine/reborrow-mut-upvar.stderr
@@ -12,7 +12,7 @@ LL | |     };
    | |_____^
    |
    = note: coroutines are lazy and do nothing unless resumed
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr b/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr
index 4fad4036300..0bc6cb60370 100644
--- a/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr
+++ b/tests/ui/coroutine/too-live-local-in-immovable-gen.stderr
@@ -9,7 +9,7 @@ LL | |         };
    | |_________^
    |
    = note: coroutines are lazy and do nothing unless resumed
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coroutine/yield-in-args-rev.stderr b/tests/ui/coroutine/yield-in-args-rev.stderr
index 10829d66185..d1650cee6cb 100644
--- a/tests/ui/coroutine/yield-in-args-rev.stderr
+++ b/tests/ui/coroutine/yield-in-args-rev.stderr
@@ -9,7 +9,7 @@ LL | |     };
    | |_____^
    |
    = note: coroutines are lazy and do nothing unless resumed
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coroutine/yield-in-initializer.stderr b/tests/ui/coroutine/yield-in-initializer.stderr
index eff5a0fdccf..a01be9e8e73 100644
--- a/tests/ui/coroutine/yield-in-initializer.stderr
+++ b/tests/ui/coroutine/yield-in-initializer.stderr
@@ -9,7 +9,7 @@ LL | |     };
    | |_____^
    |
    = note: coroutines are lazy and do nothing unless resumed
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coroutine/yield-subtype.stderr b/tests/ui/coroutine/yield-subtype.stderr
index 973415327a5..b2bf219822b 100644
--- a/tests/ui/coroutine/yield-subtype.stderr
+++ b/tests/ui/coroutine/yield-subtype.stderr
@@ -9,7 +9,7 @@ LL | |     };
    | |_____^
    |
    = note: coroutines are lazy and do nothing unless resumed
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr
index 2dac2401e3c..d1527ec810c 100644
--- a/tests/ui/coverage-attr/name-value.stderr
+++ b/tests/ui/coverage-attr/name-value.stderr
@@ -22,10 +22,10 @@ LL |     #![coverage = "off"]
 help: try changing it to one of the following valid forms of the attribute
    |
 LL -     #![coverage = "off"]
-LL +     #[coverage(off)]
+LL +     #![coverage(off)]
    |
 LL -     #![coverage = "off"]
-LL +     #[coverage(on)]
+LL +     #![coverage(on)]
    |
 
 error[E0539]: malformed `coverage` attribute input
diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr
index e916a817e36..880ad080953 100644
--- a/tests/ui/coverage-attr/word-only.stderr
+++ b/tests/ui/coverage-attr/word-only.stderr
@@ -19,12 +19,10 @@ LL |     #![coverage]
    |
 help: try changing it to one of the following valid forms of the attribute
    |
-LL -     #![coverage]
-LL +     #[coverage(off)]
-   |
-LL -     #![coverage]
-LL +     #[coverage(on)]
-   |
+LL |     #![coverage(off)]
+   |                +++++
+LL |     #![coverage(on)]
+   |                ++++
 
 error[E0539]: malformed `coverage` attribute input
   --> $DIR/word-only.rs:21:1
diff --git a/tests/ui/issues/auxiliary/issue-7899.rs b/tests/ui/cross-crate/auxiliary/aux-7899.rs
index 3af6e871661..3af6e871661 100644
--- a/tests/ui/issues/auxiliary/issue-7899.rs
+++ b/tests/ui/cross-crate/auxiliary/aux-7899.rs
diff --git a/tests/ui/issues/auxiliary/issue-8259.rs b/tests/ui/cross-crate/auxiliary/aux-8259.rs
index 891aee099dc..891aee099dc 100644
--- a/tests/ui/issues/auxiliary/issue-8259.rs
+++ b/tests/ui/cross-crate/auxiliary/aux-8259.rs
diff --git a/tests/ui/issues/issue-8259.rs b/tests/ui/cross-crate/static-regions-in-cross-crate-8259.rs
index e843f7f9c50..347cfa2aee1 100644
--- a/tests/ui/issues/issue-8259.rs
+++ b/tests/ui/cross-crate/static-regions-in-cross-crate-8259.rs
@@ -1,11 +1,11 @@
+// https://github.com/rust-lang/rust/issues/8259
 //@ run-pass
 #![allow(dead_code)]
 #![allow(non_upper_case_globals)]
 
-//@ aux-build:issue-8259.rs
+//@ aux-build:aux-8259.rs
 
-
-extern crate issue_8259 as other;
+extern crate aux_8259 as other;
 static a: other::Foo<'static> = other::Foo::A;
 
 pub fn main() {}
diff --git a/tests/ui/cross-crate/tuple-like-structs-cross-crate-7899.rs b/tests/ui/cross-crate/tuple-like-structs-cross-crate-7899.rs
new file mode 100644
index 00000000000..ce3ea7dd579
--- /dev/null
+++ b/tests/ui/cross-crate/tuple-like-structs-cross-crate-7899.rs
@@ -0,0 +1,10 @@
+// https://github.com/rust-lang/rust/issues/7899
+//@ run-pass
+#![allow(unused_variables)]
+//@ aux-build:aux-7899.rs
+
+extern crate aux_7899 as testcrate;
+
+fn main() {
+    let f = testcrate::V2(1.0f32, 2.0f32);
+}
diff --git a/tests/ui/delegation/target-expr-pass.stderr b/tests/ui/delegation/target-expr-pass.stderr
index c8d73ec6e5a..4924d95208a 100644
--- a/tests/ui/delegation/target-expr-pass.stderr
+++ b/tests/ui/delegation/target-expr-pass.stderr
@@ -4,7 +4,7 @@ warning: trait `Trait` is never used
 LL | trait Trait {
    |       ^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: struct `F` is never constructed
   --> $DIR/target-expr-pass.rs:21:8
diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs
index 9698a376025..45ee91741e5 100644
--- a/tests/ui/deprecation/deprecation-sanity.rs
+++ b/tests/ui/deprecation/deprecation-sanity.rs
@@ -42,4 +42,9 @@ impl Default for X {
     }
 }
 
+unsafe extern "C" {
+    #[deprecated]
+    static FOO: std::ffi::c_int;
+}
+
 fn main() { }
diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr
index 1d44215731d..57af76d8f24 100644
--- a/tests/ui/deprecation/deprecation-sanity.stderr
+++ b/tests/ui/deprecation/deprecation-sanity.stderr
@@ -177,7 +177,7 @@ LL | #[deprecated = "hello"]
    | ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates
+   = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates
    = note: `#[deny(useless_deprecated)]` on by default
 
 error: aborting due to 10 previous errors
diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs
index 00a269ccb5c..db58f12d60c 100644
--- a/tests/ui/deriving/deriving-all-codegen.rs
+++ b/tests/ui/deriving/deriving-all-codegen.rs
@@ -18,6 +18,8 @@
 #![allow(deprecated)]
 #![feature(derive_from)]
 
+use std::from::From;
+
 // Empty struct.
 #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
 struct Empty;
@@ -51,7 +53,14 @@ struct SingleField {
 // `clone` implemention that just does `*self`.
 #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
 struct Big {
-    b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8: u32,
+    b1: u32,
+    b2: u32,
+    b3: u32,
+    b4: u32,
+    b5: u32,
+    b6: u32,
+    b7: u32,
+    b8: u32,
 }
 
 // It is more efficient to compare scalar types before non-scalar types.
@@ -126,7 +135,7 @@ enum Enum0 {}
 // A single-variant enum.
 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
 enum Enum1 {
-    Single { x: u32 }
+    Single { x: u32 },
 }
 
 // A C-like, fieldless enum with a single variant.
@@ -152,7 +161,10 @@ enum Mixed {
     P,
     Q,
     R(u32),
-    S { d1: Option<u32>, d2: Option<i32> },
+    S {
+        d1: Option<u32>,
+        d2: Option<i32>,
+    },
 }
 
 // When comparing enum variant it is more efficient to compare scalar types before non-scalar types.
diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout
index 78b93f39b9e..4c60b1cf427 100644
--- a/tests/ui/deriving/deriving-all-codegen.stdout
+++ b/tests/ui/deriving/deriving-all-codegen.stdout
@@ -23,6 +23,8 @@ extern crate std;
 #[prelude_import]
 use std::prelude::rust_2021::*;
 
+use std::from::From;
+
 // Empty struct.
 struct Empty;
 #[automatically_derived]
diff --git a/tests/ui/deriving/deriving-from-wrong-target.rs b/tests/ui/deriving/deriving-from-wrong-target.rs
index 57e009cae69..d0cab937b5d 100644
--- a/tests/ui/deriving/deriving-from-wrong-target.rs
+++ b/tests/ui/deriving/deriving-from-wrong-target.rs
@@ -1,9 +1,10 @@
-//@ edition: 2021
 //@ check-fail
 
 #![feature(derive_from)]
 #![allow(dead_code)]
 
+use std::from::From;
+
 #[derive(From)]
 //~^ ERROR `#[derive(From)]` used on a struct with no fields
 struct S1;
@@ -28,8 +29,6 @@ struct S4 {
 enum E1 {}
 
 #[derive(From)]
-//~^ ERROR the size for values of type `T` cannot be known at compilation time [E0277]
-//~| ERROR the size for values of type `T` cannot be known at compilation time [E0277]
 struct SUnsizedField<T: ?Sized> {
     last: T,
     //~^ ERROR the size for values of type `T` cannot be known at compilation time [E0277]
diff --git a/tests/ui/deriving/deriving-from-wrong-target.stderr b/tests/ui/deriving/deriving-from-wrong-target.stderr
index 13593c95973..4547cea5ba6 100644
--- a/tests/ui/deriving/deriving-from-wrong-target.stderr
+++ b/tests/ui/deriving/deriving-from-wrong-target.stderr
@@ -1,5 +1,5 @@
 error: `#[derive(From)]` used on a struct with no fields
-  --> $DIR/deriving-from-wrong-target.rs:7:10
+  --> $DIR/deriving-from-wrong-target.rs:8:10
    |
 LL | #[derive(From)]
    |          ^^^^
@@ -10,7 +10,7 @@ LL | struct S1;
    = note: `#[derive(From)]` can only be used on structs with exactly one field
 
 error: `#[derive(From)]` used on a struct with no fields
-  --> $DIR/deriving-from-wrong-target.rs:11:10
+  --> $DIR/deriving-from-wrong-target.rs:12:10
    |
 LL | #[derive(From)]
    |          ^^^^
@@ -21,7 +21,7 @@ LL | struct S2 {}
    = note: `#[derive(From)]` can only be used on structs with exactly one field
 
 error: `#[derive(From)]` used on a struct with multiple fields
-  --> $DIR/deriving-from-wrong-target.rs:15:10
+  --> $DIR/deriving-from-wrong-target.rs:16:10
    |
 LL | #[derive(From)]
    |          ^^^^
@@ -32,7 +32,7 @@ LL | struct S3(u32, bool);
    = note: `#[derive(From)]` can only be used on structs with exactly one field
 
 error: `#[derive(From)]` used on a struct with multiple fields
-  --> $DIR/deriving-from-wrong-target.rs:19:10
+  --> $DIR/deriving-from-wrong-target.rs:20:10
    |
 LL | #[derive(From)]
    |          ^^^^
@@ -43,7 +43,7 @@ LL | struct S4 {
    = note: `#[derive(From)]` can only be used on structs with exactly one field
 
 error: `#[derive(From)]` used on an enum
-  --> $DIR/deriving-from-wrong-target.rs:26:10
+  --> $DIR/deriving-from-wrong-target.rs:27:10
    |
 LL | #[derive(From)]
    |          ^^^^
@@ -54,45 +54,7 @@ LL | enum E1 {}
    = note: `#[derive(From)]` can only be used on structs with exactly one field
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/deriving-from-wrong-target.rs:30:10
-   |
-LL | #[derive(From)]
-   |          ^^^^ doesn't have a size known at compile-time
-...
-LL | struct SUnsizedField<T: ?Sized> {
-   |                      - this type parameter needs to be `Sized`
-   |
-note: required by an implicit `Sized` bound in `From`
-  --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
-help: consider removing the `?Sized` bound to make the type parameter `Sized`
-   |
-LL - struct SUnsizedField<T: ?Sized> {
-LL + struct SUnsizedField<T> {
-   |
-
-error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/deriving-from-wrong-target.rs:30:10
-   |
-LL | #[derive(From)]
-   |          ^^^^ doesn't have a size known at compile-time
-...
-LL | struct SUnsizedField<T: ?Sized> {
-   |                      - this type parameter needs to be `Sized`
-   |
-note: required because it appears within the type `SUnsizedField<T>`
-  --> $DIR/deriving-from-wrong-target.rs:33:8
-   |
-LL | struct SUnsizedField<T: ?Sized> {
-   |        ^^^^^^^^^^^^^
-   = note: the return type of a function must have a statically known size
-help: consider removing the `?Sized` bound to make the type parameter `Sized`
-   |
-LL - struct SUnsizedField<T: ?Sized> {
-LL + struct SUnsizedField<T> {
-   |
-
-error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/deriving-from-wrong-target.rs:34:11
+  --> $DIR/deriving-from-wrong-target.rs:33:11
    |
 LL | struct SUnsizedField<T: ?Sized> {
    |                      - this type parameter needs to be `Sized`
@@ -110,6 +72,6 @@ help: function arguments must have a statically known size, borrowed types alway
 LL |     last: &T,
    |           +
 
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/deriving/deriving-from.rs b/tests/ui/deriving/deriving-from.rs
index ff4c5b4c426..75988ba974d 100644
--- a/tests/ui/deriving/deriving-from.rs
+++ b/tests/ui/deriving/deriving-from.rs
@@ -3,6 +3,8 @@
 
 #![feature(derive_from)]
 
+use core::from::From;
+
 #[derive(From)]
 struct TupleSimple(u32);
 
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr
index 9d1556ee0c1..2af24130a1e 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr
@@ -4,7 +4,7 @@ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
 LL | #[diagnostic::do_not_recommend(not_accepted)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(malformed_diagnostic_attributes)]` on by default
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
   --> $DIR/does_not_acccept_args.rs:15:1
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr
index 9d1556ee0c1..2af24130a1e 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr
@@ -4,7 +4,7 @@ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
 LL | #[diagnostic::do_not_recommend(not_accepted)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(malformed_diagnostic_attributes)]` on by default
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
   --> $DIR/does_not_acccept_args.rs:15:1
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr
index 29ffbb5bf18..d2ad65b3c79 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr
@@ -4,7 +4,7 @@ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implement
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(misplaced_diagnostic_attributes)]` on by default
+   = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
   --> $DIR/incorrect-locations.rs:11:1
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr
index 29ffbb5bf18..d2ad65b3c79 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr
@@ -4,7 +4,7 @@ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implement
 LL | #[diagnostic::do_not_recommend]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(misplaced_diagnostic_attributes)]` on by default
+   = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
   --> $DIR/incorrect-locations.rs:11:1
diff --git a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr
index 4f9b7ba2bcf..acaa1ac0c56 100644
--- a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr
+++ b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr
@@ -4,7 +4,7 @@ warning: unknown diagnostic attribute
 LL | #[diagnostic::non_existing_attribute]
    |               ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(unknown_diagnostic_attributes)]` on by default
+   = note: `#[warn(unknown_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: unknown diagnostic attribute
   --> $DIR/non_existing_attributes_accepted.rs:8:15
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
index 5002122f8b7..2138d591ca2 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
@@ -4,7 +4,7 @@ warning: unmatched `}` found
 LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
    |                                          ^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(malformed_diagnostic_format_literals)]` on by default
+   = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: positional format arguments are not allowed here
   --> $DIR/broken_format.rs:7:49
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
index 42f4bc0d8b0..6493a8cf2e1 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
@@ -4,7 +4,7 @@ warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definiti
 LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(misplaced_diagnostic_attributes)]` on by default
+   = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5
@@ -13,7 +13,7 @@ LL |     on(Self = "&str"),
    |     ^^^^^^^^^^^^^^^^^ invalid option found here
    |
    = help: only `message`, `note` and `label` are allowed as options
-   = note: `#[warn(malformed_diagnostic_attributes)]` on by default
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:12:5
@@ -46,7 +46,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
    |                 ^^^^^^^^^^^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
-   = note: `#[warn(malformed_diagnostic_format_literals)]` on by default
+   = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: there is no parameter `direct` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:34
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
index 85d74fb8955..df5d0d6dccb 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
@@ -4,7 +4,7 @@ warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definiti
 LL | #[diagnostic::on_unimplemented(message = "Baz")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(misplaced_diagnostic_attributes)]` on by default
+   = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
@@ -13,7 +13,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
    |                                ^^^^^^^^^^^^^^^^^^^ invalid option found here
    |
    = help: only `message`, `note` and `label` are allowed as options
-   = note: `#[warn(malformed_diagnostic_attributes)]` on by default
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
@@ -62,7 +62,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
    |                                            ^^^^^^^^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
-   = note: `#[warn(malformed_diagnostic_format_literals)]` on by default
+   = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
index 86fe75a62de..24b3a9c3405 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr
@@ -5,7 +5,7 @@ LL |     if(Self = "()"),
    |     ^^^^^^^^^^^^^^^ invalid option found here
    |
    = help: only `message`, `note` and `label` are allowed as options
-   = note: `#[warn(malformed_diagnostic_attributes)]` on by default
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: `message` is ignored due to previous definition of `message`
   --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:10:32
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.stderr
index 69433f91543..e9d0c6e5daf 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_impl_trait.stderr
@@ -4,7 +4,7 @@ warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definiti
 LL | #[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(misplaced_diagnostic_attributes)]` on by default
+   = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 error[E0277]: the trait bound `{integer}: Alias` is not satisfied
   --> $DIR/on_impl_trait.rs:16:9
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr
index d2e121b61a6..de43656ff08 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr
@@ -7,7 +7,7 @@ LL |     message = "first message",
 LL |     message = "second message",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `message` is already declared here
    |
-   = note: `#[warn(malformed_diagnostic_attributes)]` on by default
+   = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
 
 warning: `label` is ignored due to previous definition of `label`
   --> $DIR/report_warning_on_duplicated_options.rs:11:5
diff --git a/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr b/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr
index 416ff358d53..af0a9d064d5 100644
--- a/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr
+++ b/tests/ui/did_you_mean/bad-assoc-ty.edition2015.stderr
@@ -187,7 +187,7 @@ LL | type H = Fn(u8) -> (u8)::Output;
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL | type H = <dyn Fn(u8) -> (u8)>::Output;
diff --git a/tests/ui/drop/drop-struct-as-object.stderr b/tests/ui/drop/drop-struct-as-object.stderr
index 16f6d1110ba..bde4e6074f3 100644
--- a/tests/ui/drop/drop-struct-as-object.stderr
+++ b/tests/ui/drop/drop-struct-as-object.stderr
@@ -6,7 +6,7 @@ LL | trait Dummy {
 LL |     fn get(&self) -> usize;
    |        ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/drop/generic-drop-trait-bound-15858.stderr b/tests/ui/drop/generic-drop-trait-bound-15858.stderr
index 86cd6cb6026..92bcdc1eda8 100644
--- a/tests/ui/drop/generic-drop-trait-bound-15858.stderr
+++ b/tests/ui/drop/generic-drop-trait-bound-15858.stderr
@@ -6,7 +6,7 @@ LL | trait Bar {
 LL |     fn do_something(&mut self);
    |        ^^^^^^^^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
index 687799c6688..265bfb01de1 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
@@ -6,7 +6,7 @@ LL | fn id<F>(f: Copy) -> usize {
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL | fn id<F>(f: dyn Copy) -> usize {
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
index 4cfac943375..7b299fa3cab 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
@@ -6,7 +6,7 @@ LL | trait B { fn f(a: A) -> A; }
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL | trait B { fn f(a: dyn A) -> A; }
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr
index 4645b35f8f1..849f2a2ecc4 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning.old.stderr
@@ -24,7 +24,7 @@ LL | fn call_this<F>(f: F) : Fn(&str) + call_that {}
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL | fn call_this<F>(f: F) : dyn Fn(&str) + call_that {}
diff --git a/tests/ui/issues/auxiliary/issue-8401.rs b/tests/ui/dyn-keyword/auxiliary/aux-8401.rs
index 7d0eb5cd876..7d0eb5cd876 100644
--- a/tests/ui/issues/auxiliary/issue-8401.rs
+++ b/tests/ui/dyn-keyword/auxiliary/aux-8401.rs
diff --git a/tests/ui/dyn-keyword/methods-with-mut-trait-and-polymorphic-objects-issue-8401.rs b/tests/ui/dyn-keyword/methods-with-mut-trait-and-polymorphic-objects-issue-8401.rs
new file mode 100644
index 00000000000..313c6891720
--- /dev/null
+++ b/tests/ui/dyn-keyword/methods-with-mut-trait-and-polymorphic-objects-issue-8401.rs
@@ -0,0 +1,7 @@
+//@ run-pass
+//@ aux-build:aux-8401.rs
+// https://github.com/rust-lang/rust/issues/8401
+
+extern crate aux_8401;
+
+pub fn main() {}
diff --git a/tests/ui/dynamically-sized-types/dst-coercions.stderr b/tests/ui/dynamically-sized-types/dst-coercions.stderr
index e7c48783df0..ebc025a98cc 100644
--- a/tests/ui/dynamically-sized-types/dst-coercions.stderr
+++ b/tests/ui/dynamically-sized-types/dst-coercions.stderr
@@ -6,7 +6,7 @@ LL | trait T { fn dummy(&self) { } }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr
index e30c0adb79d..3d4a10aeaaf 100644
--- a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr
+++ b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr
@@ -12,7 +12,7 @@ note: in edition 2024, the requirement `!: Default` will fail
    |
 LL |         true => Default::default(),
    |                 ^^^^^^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     let x: () = match true {
@@ -111,7 +111,7 @@ note: in edition 2024, the requirement `!: Default` will fail
    |
 LL |         true => Default::default(),
    |                 ^^^^^^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     let x: () = match true {
@@ -132,7 +132,7 @@ note: in edition 2024, the requirement `!: Default` will fail
    |
 LL |     deserialize()?;
    |     ^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     deserialize::<()>()?;
@@ -153,7 +153,7 @@ note: in edition 2024, the requirement `(): From<!>` will fail
    |
 LL |     help(1)?;
    |     ^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     help::<(), _>(1)?;
@@ -174,7 +174,7 @@ note: in edition 2024, the requirement `!: Default` will fail
    |
 LL |     takes_apit(|| Default::default())?;
    |                   ^^^^^^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     takes_apit::<()>(|| Default::default())?;
@@ -195,7 +195,7 @@ note: in edition 2024, the requirement `!: Default` will fail
    |
 LL |     takes_apit2(mk()?);
    |                 ^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     takes_apit2(mk::<()>()?);
diff --git a/tests/ui/issues/issue-8761.rs b/tests/ui/enum/enum-discriminant-type-mismatch-8761.rs
index 5883bb96695..ae09b919dc1 100644
--- a/tests/ui/issues/issue-8761.rs
+++ b/tests/ui/enum/enum-discriminant-type-mismatch-8761.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8761
 enum Foo {
     A = 1i64,
     //~^ ERROR mismatched types
diff --git a/tests/ui/issues/issue-8761.stderr b/tests/ui/enum/enum-discriminant-type-mismatch-8761.stderr
index 4a9db568913..f1645183e17 100644
--- a/tests/ui/issues/issue-8761.stderr
+++ b/tests/ui/enum/enum-discriminant-type-mismatch-8761.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-8761.rs:2:9
+  --> $DIR/enum-discriminant-type-mismatch-8761.rs:3:9
    |
 LL |     A = 1i64,
    |         ^^^^ expected `isize`, found `i64`
@@ -11,7 +11,7 @@ LL +     A = 1isize,
    |
 
 error[E0308]: mismatched types
-  --> $DIR/issue-8761.rs:5:9
+  --> $DIR/enum-discriminant-type-mismatch-8761.rs:6:9
    |
 LL |     B = 2u8
    |         ^^^ expected `isize`, found `u8`
diff --git a/tests/ui/issues/issue-80607.rs b/tests/ui/enum/enum-variant-field-error-80607.rs
index 63f4df359b8..aa3f2f7c526 100644
--- a/tests/ui/issues/issue-80607.rs
+++ b/tests/ui/enum/enum-variant-field-error-80607.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/80607
 // This tests makes sure the diagnostics print the offending enum variant, not just the type.
 pub enum Enum {
     V1(i32),
diff --git a/tests/ui/issues/issue-80607.stderr b/tests/ui/enum/enum-variant-field-error-80607.stderr
index 8f9f494c8b7..8d088ef04bb 100644
--- a/tests/ui/issues/issue-80607.stderr
+++ b/tests/ui/enum/enum-variant-field-error-80607.stderr
@@ -1,5 +1,5 @@
 error[E0559]: variant `Enum::V1` has no field named `x`
-  --> $DIR/issue-80607.rs:7:16
+  --> $DIR/enum-variant-field-error-80607.rs:8:16
    |
 LL |     V1(i32),
    |     -- `Enum::V1` defined here
diff --git a/tests/ui/issues/issue-8506.rs b/tests/ui/enum/simple-enum-usage-8506.rs
index 30a789a3e27..ebe095d84e4 100644
--- a/tests/ui/issues/issue-8506.rs
+++ b/tests/ui/enum/simple-enum-usage-8506.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8506
 //@ run-pass
 #![allow(non_upper_case_globals)]
 
diff --git a/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr b/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr
index 0004ea82fac..c1584e66e33 100644
--- a/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr
+++ b/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr
@@ -6,7 +6,7 @@ LL |     let _ = MyIterator::next;
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL |     let _ = <dyn MyIterator>::next;
diff --git a/tests/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr b/tests/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr
index d9acdbea3fc..462819c138f 100644
--- a/tests/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr
+++ b/tests/ui/errors/issue-89280-emitter-overflow-splice-lines.stderr
@@ -9,7 +9,7 @@ LL | |     )) {}
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
-   = note: `#[warn(anonymous_parameters)]` on by default
+   = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default
 help: try naming the parameter or explicitly ignoring it
    |
 LL |     fn test(x: u32, _: (
diff --git a/tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.rs b/tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.rs
new file mode 100644
index 00000000000..8ad244568a3
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.rs
@@ -0,0 +1,15 @@
+#![feature(explicit_tail_calls)]
+#![expect(incomplete_features)]
+
+fn foo() -> for<'a> fn(&'a i32) {
+    become bar();
+    //~^ ERROR mismatched signatures
+}
+
+fn bar() -> fn(&'static i32) {
+    dummy
+}
+
+fn dummy(_: &i32) {}
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.stderr b/tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.stderr
new file mode 100644
index 00000000000..f6594580ba5
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.stderr
@@ -0,0 +1,12 @@
+error: mismatched signatures
+  --> $DIR/ret-ty-hr-mismatch.rs:5:5
+   |
+LL |     become bar();
+   |     ^^^^^^^^^^^^
+   |
+   = note: `become` requires caller and callee to have matching signatures
+   = note: caller signature: `fn() -> for<'a> fn(&'a i32)`
+   = note: callee signature: `fn() -> fn(&'static i32)`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/explicit-tail-calls/ret-ty-modulo-anonymization.rs b/tests/ui/explicit-tail-calls/ret-ty-modulo-anonymization.rs
new file mode 100644
index 00000000000..0cd4e204278
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ret-ty-modulo-anonymization.rs
@@ -0,0 +1,16 @@
+// Ensure that we anonymize the output of a function for tail call signature compatibility.
+
+//@ check-pass
+
+#![feature(explicit_tail_calls)]
+#![expect(incomplete_features)]
+
+fn foo() -> for<'a> fn(&'a ()) {
+    become bar();
+}
+
+fn bar() -> for<'b> fn(&'b ()) {
+    todo!()
+}
+
+fn main() {}
diff --git a/tests/ui/expr/if/if-ret.stderr b/tests/ui/expr/if/if-ret.stderr
index e5464affd2f..e53a1e3b081 100644
--- a/tests/ui/expr/if/if-ret.stderr
+++ b/tests/ui/expr/if/if-ret.stderr
@@ -6,7 +6,7 @@ LL | fn foo() { if (return) { } }
    |               |
    |               any code following this expression is unreachable
    |
-   = note: `#[warn(unreachable_code)]` on by default
+   = note: `#[warn(unreachable_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-75283.rs b/tests/ui/extern/function-definition-in-extern-block-75283.rs
index d556132e47f..e2b7358743b 100644
--- a/tests/ui/issues/issue-75283.rs
+++ b/tests/ui/extern/function-definition-in-extern-block-75283.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/75283
 extern "C" {
     fn lol() { //~ ERROR incorrect function inside `extern` block
         println!("");
diff --git a/tests/ui/issues/issue-75283.stderr b/tests/ui/extern/function-definition-in-extern-block-75283.stderr
index 240d9716a55..67be1c29599 100644
--- a/tests/ui/issues/issue-75283.stderr
+++ b/tests/ui/extern/function-definition-in-extern-block-75283.stderr
@@ -1,5 +1,5 @@
 error: incorrect function inside `extern` block
-  --> $DIR/issue-75283.rs:2:8
+  --> $DIR/function-definition-in-extern-block-75283.rs:3:8
    |
 LL |   extern "C" {
    |   ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
diff --git a/tests/ui/extern/issue-47725.rs b/tests/ui/extern/issue-47725.rs
index b0a0af930de..6b4d0dd30e0 100644
--- a/tests/ui/extern/issue-47725.rs
+++ b/tests/ui/extern/issue-47725.rs
@@ -4,12 +4,14 @@
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can be applied to
+//~| HELP remove the attribute
 struct Foo;
 
 #[link_name = "foobar"]
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can be applied to
+//~| HELP remove the attribute
 extern "C" {
     fn foo() -> u32;
 }
@@ -19,6 +21,7 @@ extern "C" {
 //~| HELP must be of the form
 //~| WARN attribute cannot be used on
 //~| WARN previously accepted
+//~| HELP remove the attribute
 //~| HELP can be applied to
 //~| NOTE for more information, visit
 extern "C" {
diff --git a/tests/ui/extern/issue-47725.stderr b/tests/ui/extern/issue-47725.stderr
index 704b1d81b63..43362ea655b 100644
--- a/tests/ui/extern/issue-47725.stderr
+++ b/tests/ui/extern/issue-47725.stderr
@@ -1,5 +1,5 @@
 error[E0539]: malformed `link_name` attribute input
-  --> $DIR/issue-47725.rs:17:1
+  --> $DIR/issue-47725.rs:19:1
    |
 LL | #[link_name]
    | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]`
@@ -21,7 +21,7 @@ LL | #![warn(unused_attributes)]
    |         ^^^^^^^^^^^^^^^^^
 
 warning: `#[link_name]` attribute cannot be used on foreign modules
-  --> $DIR/issue-47725.rs:9:1
+  --> $DIR/issue-47725.rs:10:1
    |
 LL | #[link_name = "foobar"]
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -30,7 +30,7 @@ LL | #[link_name = "foobar"]
    = help: `#[link_name]` can be applied to foreign functions, foreign statics
 
 warning: `#[link_name]` attribute cannot be used on foreign modules
-  --> $DIR/issue-47725.rs:17:1
+  --> $DIR/issue-47725.rs:19:1
    |
 LL | #[link_name]
    | ^^^^^^^^^^^^
diff --git a/tests/ui/extern/no-mangle-associated-fn.stderr b/tests/ui/extern/no-mangle-associated-fn.stderr
index 772cbf6cf7d..79d8144448f 100644
--- a/tests/ui/extern/no-mangle-associated-fn.stderr
+++ b/tests/ui/extern/no-mangle-associated-fn.stderr
@@ -4,7 +4,7 @@ warning: trait `Bar` is never used
 LL | trait Bar {
    |       ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/feature-gates/feature-gate-derive-from.rs b/tests/ui/feature-gates/feature-gate-derive-from.rs
index 12440356ddf..0e8c5e4af37 100644
--- a/tests/ui/feature-gates/feature-gate-derive-from.rs
+++ b/tests/ui/feature-gates/feature-gate-derive-from.rs
@@ -1,4 +1,4 @@
-//@ edition: 2021
+use std::from::From; //~ ERROR use of unstable library feature `derive_from
 
 #[derive(From)] //~ ERROR use of unstable library feature `derive_from`
 struct Foo(u32);
diff --git a/tests/ui/feature-gates/feature-gate-derive-from.stderr b/tests/ui/feature-gates/feature-gate-derive-from.stderr
index d58dcdd7541..63216a4cccd 100644
--- a/tests/ui/feature-gates/feature-gate-derive-from.stderr
+++ b/tests/ui/feature-gates/feature-gate-derive-from.stderr
@@ -8,6 +8,16 @@ LL | #[derive(From)]
    = help: add `#![feature(derive_from)]` 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 1 previous error
+error[E0658]: use of unstable library feature `derive_from`
+  --> $DIR/feature-gate-derive-from.rs:1:5
+   |
+LL | use std::from::From;
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #144889 <https://github.com/rust-lang/rust/issues/144889> for more information
+   = help: add `#![feature(derive_from)]` 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/feature-gates/feature-gate-macro-derive.rs b/tests/ui/feature-gates/feature-gate-macro-derive.rs
new file mode 100644
index 00000000000..b9d63423061
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-macro-derive.rs
@@ -0,0 +1,4 @@
+#![crate_type = "lib"]
+
+macro_rules! MyDerive { derive() {} => {} }
+//~^ ERROR `macro_rules!` derives are unstable
diff --git a/tests/ui/feature-gates/feature-gate-macro-derive.stderr b/tests/ui/feature-gates/feature-gate-macro-derive.stderr
new file mode 100644
index 00000000000..b7ca6717bd5
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-macro-derive.stderr
@@ -0,0 +1,13 @@
+error[E0658]: `macro_rules!` derives are unstable
+  --> $DIR/feature-gate-macro-derive.rs:3:1
+   |
+LL | macro_rules! MyDerive { derive() {} => {} }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_attr)]` 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 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-no_sanitize.rs b/tests/ui/feature-gates/feature-gate-no_sanitize.rs
deleted file mode 100644
index 5ac014f1c5b..00000000000
--- a/tests/ui/feature-gates/feature-gate-no_sanitize.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#[no_sanitize(address)]
-//~^ ERROR the `#[no_sanitize]` attribute is an experimental feature
-fn main() {
-}
diff --git a/tests/ui/feature-gates/feature-gate-no_sanitize.stderr b/tests/ui/feature-gates/feature-gate-no_sanitize.stderr
deleted file mode 100644
index a33bf6a9e40..00000000000
--- a/tests/ui/feature-gates/feature-gate-no_sanitize.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: the `#[no_sanitize]` attribute is an experimental feature
-  --> $DIR/feature-gate-no_sanitize.rs:1:1
-   |
-LL | #[no_sanitize(address)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #39699 <https://github.com/rust-lang/rust/issues/39699> for more information
-   = help: add `#![feature(no_sanitize)]` 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 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-repr-simd.stderr b/tests/ui/feature-gates/feature-gate-repr-simd.stderr
index 3bf8ec61705..0f1929038fe 100644
--- a/tests/ui/feature-gates/feature-gate-repr-simd.stderr
+++ b/tests/ui/feature-gates/feature-gate-repr-simd.stderr
@@ -49,7 +49,7 @@ LL | #[repr(simd)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
-   = note: `#[deny(conflicting_repr_hints)]` on by default
+   = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error[E0517]: attribute should be applied to a struct
   --> $DIR/feature-gate-repr-simd.rs:9:8
@@ -85,5 +85,5 @@ LL | #[repr(simd)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
-   = note: `#[deny(conflicting_repr_hints)]` on by default
+   = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/feature-gates/feature-gate-sanitize.rs b/tests/ui/feature-gates/feature-gate-sanitize.rs
new file mode 100644
index 00000000000..40098d93272
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-sanitize.rs
@@ -0,0 +1,7 @@
+//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
+#![feature(no_sanitize)] //~ ERROR feature has been removed
+
+#[sanitize(address = "on")]
+//~^ ERROR the `#[sanitize]` attribute is an experimental feature
+fn main() {
+}
diff --git a/tests/ui/feature-gates/feature-gate-sanitize.stderr b/tests/ui/feature-gates/feature-gate-sanitize.stderr
new file mode 100644
index 00000000000..7c38b351916
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-sanitize.stderr
@@ -0,0 +1,23 @@
+error[E0557]: feature has been removed
+  --> $DIR/feature-gate-sanitize.rs:2:12
+   |
+LL | #![feature(no_sanitize)]
+   |            ^^^^^^^^^^^ feature has been removed
+   |
+   = note: removed in CURRENT_RUSTC_VERSION; see <https://github.com/rust-lang/rust/pull/142681> for more information
+   = note: renamed to sanitize(xyz = "on|off")
+
+error[E0658]: the `#[sanitize]` attribute is an experimental feature
+  --> $DIR/feature-gate-sanitize.rs:4:1
+   |
+LL | #[sanitize(address = "on")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #39699 <https://github.com/rust-lang/rust/issues/39699> for more information
+   = help: add `#![feature(sanitize)]` 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
+
+Some errors have detailed explanations: E0557, E0658.
+For more information about an error, try `rustc --explain E0557`.
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
index 130dd48b0fe..f391cf92fb6 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
@@ -40,7 +40,7 @@ mod inline {
     #[inline = "2100"] fn f() { }
     //~^ ERROR valid forms for the attribute are
     //~| WARN this was previously accepted
-    //~| NOTE #[deny(ill_formed_attribute_input)]` on by default
+    //~| NOTE `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
     //~| NOTE for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
     #[inline] struct S;
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index 13dce72a882..14122d466c4 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -305,7 +305,7 @@ LL |     #[inline = "2100"] fn f() { }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 37 previous errors
 
@@ -320,5 +320,5 @@ LL |     #[inline = "2100"] fn f() { }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
index 8702d852a89..60666481bec 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
@@ -50,9 +50,11 @@
 #![should_panic] //~ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can only be applied to
+//~| HELP remove the attribute
 #![ignore] //~ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can only be applied to
+//~| HELP remove the attribute
 #![no_implicit_prelude]
 #![reexport_test_harness_main = "2900"]
 // see gated-link-args.rs
@@ -61,22 +63,28 @@
 #![proc_macro_derive(Test)] //~ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can only be applied to
+//~| HELP remove the attribute
 #![doc = "2400"]
 #![cold] //~ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can only be applied to
+//~| HELP remove the attribute
 #![link()] //~ WARN attribute should be applied to an `extern` block
 //~^ WARN this was previously accepted
 #![link_name = "1900"]
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can be applied to
+//~| HELP remove the attribute
 #![link_section = "1800"]
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can be applied to
+//~| HELP remove the attribute
 #![must_use]
-//~^ WARN `#[must_use]` has no effect
+//~^ WARN attribute cannot be used on
+//~| WARN previously accepted
+//~| HELP can be applied to
 //~| HELP remove the attribute
 // see issue-43106-gating-of-stable.rs
 // see issue-43106-gating-of-unstable.rs
@@ -184,21 +192,25 @@ mod macro_use {
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[macro_use] struct S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[macro_use] type T = S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[macro_use] impl S { }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 }
 
 #[macro_export]
@@ -260,57 +272,68 @@ mod path {
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[path = "3800"]  struct S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[path = "3800"] type T = S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[path = "3800"] impl S { }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 }
 
 #[automatically_derived]
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can only be applied to
+//~| HELP remove the attribute
 mod automatically_derived {
     mod inner { #![automatically_derived] }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[automatically_derived] fn f() { }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[automatically_derived] struct S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[automatically_derived] type T = S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[automatically_derived] trait W { }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[automatically_derived] impl S { }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[automatically_derived] impl W for S { }
 }
@@ -319,11 +342,13 @@ mod automatically_derived {
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can be applied to
+//~| HELP remove the attribute
 mod no_mangle {
     mod inner { #![no_mangle] }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[no_mangle] fn f() { }
 
@@ -331,27 +356,32 @@ mod no_mangle {
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[no_mangle] type T = S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[no_mangle] impl S { }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     trait Tr {
         #[no_mangle] fn foo();
         //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
         //~| HELP can be applied to
+        //~| HELP remove the attribute
 
         #[no_mangle] fn bar() {}
         //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
         //~| HELP can be applied to
+        //~| HELP remove the attribute
     }
 }
 
@@ -359,11 +389,13 @@ mod no_mangle {
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can only be applied to
+//~| HELP remove the attribute
 mod should_panic {
     mod inner { #![should_panic] }
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[should_panic] fn f() { }
 
@@ -371,27 +403,32 @@ mod should_panic {
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[should_panic] type T = S;
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[should_panic] impl S { }
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 }
 
 #[ignore]
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can only be applied to
+//~| HELP remove the attribute
 mod ignore {
     mod inner { #![ignore] }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[ignore] fn f() { }
 
@@ -399,16 +436,19 @@ mod ignore {
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[ignore] type T = S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[ignore] impl S { }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 }
 
 #[no_implicit_prelude]
@@ -419,21 +459,25 @@ mod no_implicit_prelude {
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[no_implicit_prelude] struct S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[no_implicit_prelude] type T = S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[no_implicit_prelude] impl S { }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 }
 
 #[reexport_test_harness_main = "2900"]
@@ -467,21 +511,25 @@ mod macro_escape {
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[macro_escape] struct S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[macro_escape] type T = S;
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[macro_escape] impl S { }
     //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 }
 
 #[no_std]
@@ -524,12 +572,14 @@ mod doc {
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can only be applied to
+//~| HELP remove the attribute
 mod cold {
 
     mod inner { #![cold] }
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[cold] fn f() { }
 
@@ -537,64 +587,76 @@ mod cold {
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[cold] type T = S;
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[cold] impl S { }
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can only be applied to
+    //~| HELP remove the attribute
 }
 
 #[link_name = "1900"]
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can be applied to
+//~| HELP remove the attribute
 mod link_name {
     #[link_name = "1900"]
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
     extern "C" { }
 
     mod inner { #![link_name="1900"] }
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[link_name = "1900"] fn f() { }
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[link_name = "1900"] struct S;
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[link_name = "1900"] type T = S;
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[link_name = "1900"] impl S { }
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 }
 
 #[link_section = "1800"]
 //~^ WARN attribute cannot be used on
 //~| WARN previously accepted
 //~| HELP can be applied to
+//~| HELP remove the attribute
 mod link_section {
     mod inner { #![link_section="1800"] }
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[link_section = "1800"] fn f() { }
 
@@ -602,16 +664,19 @@ mod link_section {
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[link_section = "1800"] type T = S;
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[link_section = "1800"] impl S { }
     //~^ WARN attribute cannot be used on
     //~| WARN previously accepted
     //~| HELP can be applied to
+    //~| HELP remove the attribute
 }
 
 
@@ -668,21 +733,29 @@ mod deprecated {
     #[deprecated] impl super::StructForDeprecated { }
 }
 
-#[must_use] //~ WARN `#[must_use]` has no effect
-//~^ HELP remove the attribute
+#[must_use] //~ WARN attribute cannot be used on
+//~| WARN previously accepted
+//~| HELP can be applied to
+//~| HELP remove the attribute
 mod must_use {
-    mod inner { #![must_use] } //~ WARN `#[must_use]` has no effect
-    //~^ HELP remove the attribute
+    mod inner { #![must_use] } //~ WARN attribute cannot be used on
+    //~| WARN previously accepted
+    //~| HELP can be applied to
+    //~| HELP remove the attribute
 
     #[must_use] fn f() { }
 
     #[must_use] struct S;
 
-    #[must_use] type T = S; //~ WARN `#[must_use]` has no effect
-    //~^ HELP remove the attribute
+    #[must_use] type T = S; //~ WARN attribute cannot be used on
+    //~| WARN previously accepted
+    //~| HELP can be applied to
+    //~| HELP remove the attribute
 
-    #[must_use] impl S { } //~ WARN `#[must_use]` has no effect
-    //~^ HELP remove the attribute
+    #[must_use] impl S { } //~ WARN attribute cannot be used on
+    //~| WARN previously accepted
+    //~| HELP can be applied to
+    //~| HELP remove the attribute
 }
 
 #[windows_subsystem = "windows"]
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index 8e2bffb91ca..a633ac0aadb 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -1,5 +1,5 @@
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:506:17
    |
 LL |     mod inner { #![macro_escape] }
    |                 ^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     mod inner { #![macro_escape] }
    = help: try an outer attribute: `#[macro_use]`
 
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:1
    |
 LL | #[macro_escape]
    | ^^^^^^^^^^^^^^^
@@ -43,151 +43,151 @@ LL | #![deny(x5100)]
    |         ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:103:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:8
    |
 LL | #[warn(x5400)]
    |        ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:106:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:114:25
    |
 LL |     mod inner { #![warn(x5400)] }
    |                         ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:117:12
    |
 LL |     #[warn(x5400)] fn f() { }
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:12
    |
 LL |     #[warn(x5400)] struct S;
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:115:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:123:12
    |
 LL |     #[warn(x5400)] type T = S;
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:118:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:126:12
    |
 LL |     #[warn(x5400)] impl S { }
    |            ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:9
    |
 LL | #[allow(x5300)]
    |         ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:26
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:133:26
    |
 LL |     mod inner { #![allow(x5300)] }
    |                          ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:136:13
    |
 LL |     #[allow(x5300)] fn f() { }
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:13
    |
 LL |     #[allow(x5300)] struct S;
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:134:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:142:13
    |
 LL |     #[allow(x5300)] type T = S;
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:137:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:145:13
    |
 LL |     #[allow(x5300)] impl S { }
    |             ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:10
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:10
    |
 LL | #[forbid(x5200)]
    |          ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:27
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:152:27
    |
 LL |     mod inner { #![forbid(x5200)] }
    |                           ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:155:14
    |
 LL |     #[forbid(x5200)] fn f() { }
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:14
    |
 LL |     #[forbid(x5200)] struct S;
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:153:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:161:14
    |
 LL |     #[forbid(x5200)] type T = S;
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:156:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:164:14
    |
 LL |     #[forbid(x5200)] impl S { }
    |              ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:8
    |
 LL | #[deny(x5100)]
    |        ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:171:25
    |
 LL |     mod inner { #![deny(x5100)] }
    |                         ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:174:12
    |
 LL |     #[deny(x5100)] fn f() { }
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:12
    |
 LL |     #[deny(x5100)] struct S;
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:172:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:180:12
    |
 LL |     #[deny(x5100)] type T = S;
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:175:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:183:12
    |
 LL |     #[deny(x5100)] impl S { }
    |            ^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:1
    |
 LL | #[macro_export]
    | ^^^^^^^^^^^^^^^
@@ -199,19 +199,19 @@ LL | #![warn(unused_attributes, unknown_lints)]
    |         ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:1
    |
 LL | #[reexport_test_harness_main = "2900"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:535:1
    |
 LL | #[no_std]
    | ^^^^^^^^^
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:1
    |
 LL |   #[link()]
    |   ^^^^^^^^^
@@ -226,76 +226,64 @@ LL | | }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: `#[must_use]` has no effect when applied to modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:1
-   |
-LL | #[must_use]
-   | ^^^^^^^^^^^
-
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:1
    |
 LL | #[windows_subsystem = "windows"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:1
    |
 LL | #[crate_name = "0900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:1
    |
 LL | #[crate_type = "0800"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:820:1
    |
 LL | #[feature(x0600)]
    | ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:1
    |
 LL | #[no_main]
    | ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:859:1
    |
 LL | #[no_builtins]
    | ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:878:1
    |
 LL | #[recursion_limit="0200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:897:1
    |
 LL | #[type_length_limit="0100"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:68:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1
    |
 LL | #![link()]
    | ^^^^^^^^^^ not an `extern` block
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: `#[must_use]` has no effect when applied to modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:78:1
-   |
-LL | #![must_use]
-   | ^^^^^^^^^^^^
-
 warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:92:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:100:12
    |
 LL | #![feature(rust1)]
    |            ^^^^^
@@ -303,97 +291,97 @@ LL | #![feature(rust1)]
    = note: `#[warn(stable_features)]` on by default
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:17
    |
 LL |     mod inner { #![macro_export] }
    |                 ^^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:210:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:222:5
    |
 LL |     #[macro_export] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:225:5
    |
 LL |     #[macro_export] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:5
    |
 LL |     #[macro_export] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5
    |
 LL |     #[macro_export] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:17
    |
 LL |     mod inner { #![reexport_test_harness_main="2900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:445:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:5
    |
 LL |     #[reexport_test_harness_main = "2900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:448:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5
    |
 LL |     #[reexport_test_harness_main = "2900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:451:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5
    |
 LL |     #[reexport_test_harness_main = "2900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:454:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:498:5
    |
 LL |     #[reexport_test_harness_main = "2900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:490:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:538:17
    |
 LL |     mod inner { #![no_std] }
    |                 ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5
    |
 LL |     #[no_std] fn f() { }
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5
    |
 LL |     #[no_std] struct S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:5
    |
 LL |     #[no_std] type T = S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:550:5
    |
 LL |     #[no_std] impl S { }
    |     ^^^^^^^^^
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17
    |
 LL |     mod inner { #![link()] }
    |     ------------^^^^^^^^^^-- not an `extern` block
@@ -401,7 +389,7 @@ LL |     mod inner { #![link()] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
    |
 LL |     #[link()] fn f() { }
    |     ^^^^^^^^^ ---------- not an `extern` block
@@ -409,7 +397,7 @@ LL |     #[link()] fn f() { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:636:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5
    |
 LL |     #[link()] struct S;
    |     ^^^^^^^^^ --------- not an `extern` block
@@ -417,7 +405,7 @@ LL |     #[link()] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5
    |
 LL |     #[link()] type T = S;
    |     ^^^^^^^^^ ----------- not an `extern` block
@@ -425,7 +413,7 @@ LL |     #[link()] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:5
    |
 LL |     #[link()] impl S { }
    |     ^^^^^^^^^ ---------- not an `extern` block
@@ -433,273 +421,255 @@ LL |     #[link()] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5
    |
 LL |     #[link()] extern "Rust" {}
    |     ^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: `#[must_use]` has no effect when applied to modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:674:17
-   |
-LL |     mod inner { #![must_use] }
-   |                 ^^^^^^^^^^^^
-
-warning: `#[must_use]` has no effect when applied to type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5
-   |
-LL |     #[must_use] type T = S;
-   |     ^^^^^^^^^^^
-
-warning: `#[must_use]` has no effect when applied to inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5
-   |
-LL |     #[must_use] impl S { }
-   |     ^^^^^^^^^^^
-
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:17
    |
 LL |     mod inner { #![windows_subsystem="windows"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:694:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:5
    |
 LL |     #[windows_subsystem = "windows"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5
    |
 LL |     #[windows_subsystem = "windows"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:5
    |
 LL |     #[windows_subsystem = "windows"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5
    |
 LL |     #[windows_subsystem = "windows"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:17
    |
 LL |     mod inner { #![crate_name="0900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:5
    |
 LL |     #[crate_name = "0900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:5
    |
 LL |     #[crate_name = "0900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5
    |
 LL |     #[crate_name = "0900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:804:17
    |
 LL |     mod inner { #![crate_type="0800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:807:5
    |
 LL |     #[crate_type = "0800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:5
    |
 LL |     #[crate_type = "0800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:5
    |
 LL |     #[crate_type = "0800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:5
    |
 LL |     #[crate_type = "0800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:17
    |
 LL |     mod inner { #![feature(x0600)] }
    |                 ^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5
    |
 LL |     #[feature(x0600)] fn f() { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:829:5
    |
 LL |     #[feature(x0600)] struct S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:5
    |
 LL |     #[feature(x0600)] type T = S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:835:5
    |
 LL |     #[feature(x0600)] impl S { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17
    |
 LL |     mod inner { #![no_main] }
    |                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:5
    |
 LL |     #[no_main] fn f() { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:849:5
    |
 LL |     #[no_main] struct S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:852:5
    |
 LL |     #[no_main] type T = S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5
    |
 LL |     #[no_main] impl S { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:862:17
    |
 LL |     mod inner { #![no_builtins] }
    |                 ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:792:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:865:5
    |
 LL |     #[no_builtins] fn f() { }
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:868:5
    |
 LL |     #[no_builtins] struct S;
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5
    |
 LL |     #[no_builtins] type T = S;
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:874:5
    |
 LL |     #[no_builtins] impl S { }
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:881:17
    |
 LL |     mod inner { #![recursion_limit="0200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:884:5
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:887:5
    |
 LL |     #[recursion_limit="0200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:890:5
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:820:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:893:5
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:17
    |
 LL |     mod inner { #![type_length_limit="0100"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:903:5
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:833:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:906:5
    |
 LL |     #[type_length_limit="0100"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:5
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:912:5
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[macro_use]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:183:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5
    |
 LL |     #[macro_use] fn f() { }
    |     ^^^^^^^^^^^^
@@ -708,7 +678,7 @@ LL |     #[macro_use] fn f() { }
    = help: `#[macro_use]` can be applied to modules, extern crates, crates
 
 warning: `#[macro_use]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:197:5
    |
 LL |     #[macro_use] struct S;
    |     ^^^^^^^^^^^^
@@ -717,7 +687,7 @@ LL |     #[macro_use] struct S;
    = help: `#[macro_use]` can be applied to modules, extern crates, crates
 
 warning: `#[macro_use]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:203:5
    |
 LL |     #[macro_use] type T = S;
    |     ^^^^^^^^^^^^
@@ -726,7 +696,7 @@ LL |     #[macro_use] type T = S;
    = help: `#[macro_use]` can be applied to modules, extern crates, crates
 
 warning: `#[macro_use]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:5
    |
 LL |     #[macro_use] impl S { }
    |     ^^^^^^^^^^^^
@@ -735,7 +705,7 @@ LL |     #[macro_use] impl S { }
    = help: `#[macro_use]` can be applied to modules, extern crates, crates
 
 warning: `#[path]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:259:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5
    |
 LL |     #[path = "3800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^
@@ -744,7 +714,7 @@ LL |     #[path = "3800"] fn f() { }
    = help: `#[path]` can only be applied to modules
 
 warning: `#[path]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:264:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:277:5
    |
 LL |     #[path = "3800"]  struct S;
    |     ^^^^^^^^^^^^^^^^
@@ -753,7 +723,7 @@ LL |     #[path = "3800"]  struct S;
    = help: `#[path]` can only be applied to modules
 
 warning: `#[path]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:283:5
    |
 LL |     #[path = "3800"] type T = S;
    |     ^^^^^^^^^^^^^^^^
@@ -762,7 +732,7 @@ LL |     #[path = "3800"] type T = S;
    = help: `#[path]` can only be applied to modules
 
 warning: `#[path]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:274:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:289:5
    |
 LL |     #[path = "3800"] impl S { }
    |     ^^^^^^^^^^^^^^^^
@@ -771,7 +741,7 @@ LL |     #[path = "3800"] impl S { }
    = help: `#[path]` can only be applied to modules
 
 warning: `#[automatically_derived]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:280:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:296:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -780,7 +750,7 @@ LL | #[automatically_derived]
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:285:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:302:17
    |
 LL |     mod inner { #![automatically_derived] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -789,7 +759,7 @@ LL |     mod inner { #![automatically_derived] }
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:290:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:308:5
    |
 LL |     #[automatically_derived] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -798,7 +768,7 @@ LL |     #[automatically_derived] fn f() { }
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:295:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:5
    |
 LL |     #[automatically_derived] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -807,7 +777,7 @@ LL |     #[automatically_derived] struct S;
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:300:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:320:5
    |
 LL |     #[automatically_derived] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -816,7 +786,7 @@ LL |     #[automatically_derived] type T = S;
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on traits
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:305:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:5
    |
 LL |     #[automatically_derived] trait W { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -825,7 +795,7 @@ LL |     #[automatically_derived] trait W { }
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:310:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5
    |
 LL |     #[automatically_derived] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -834,7 +804,7 @@ LL |     #[automatically_derived] impl S { }
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[no_mangle]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:318:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:1
    |
 LL | #[no_mangle]
    | ^^^^^^^^^^^^
@@ -843,7 +813,7 @@ LL | #[no_mangle]
    = help: `#[no_mangle]` can be applied to functions, statics
 
 warning: `#[no_mangle]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:323:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:17
    |
 LL |     mod inner { #![no_mangle] }
    |                 ^^^^^^^^^^^^^
@@ -852,7 +822,7 @@ LL |     mod inner { #![no_mangle] }
    = help: `#[no_mangle]` can be applied to functions, statics
 
 warning: `#[no_mangle]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:330:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5
    |
 LL |     #[no_mangle] struct S;
    |     ^^^^^^^^^^^^
@@ -861,7 +831,7 @@ LL |     #[no_mangle] struct S;
    = help: `#[no_mangle]` can be applied to functions, statics
 
 warning: `#[no_mangle]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5
    |
 LL |     #[no_mangle] type T = S;
    |     ^^^^^^^^^^^^
@@ -870,7 +840,7 @@ LL |     #[no_mangle] type T = S;
    = help: `#[no_mangle]` can be applied to functions, statics
 
 warning: `#[no_mangle]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:340:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5
    |
 LL |     #[no_mangle] impl S { }
    |     ^^^^^^^^^^^^
@@ -879,7 +849,7 @@ LL |     #[no_mangle] impl S { }
    = help: `#[no_mangle]` can be applied to functions, statics
 
 warning: `#[no_mangle]` attribute cannot be used on required trait methods
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:346:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:9
    |
 LL |         #[no_mangle] fn foo();
    |         ^^^^^^^^^^^^
@@ -888,7 +858,7 @@ LL |         #[no_mangle] fn foo();
    = help: `#[no_mangle]` can be applied to functions, statics, inherent methods, trait methods in impl blocks
 
 warning: `#[no_mangle]` attribute cannot be used on provided trait methods
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:9
    |
 LL |         #[no_mangle] fn bar() {}
    |         ^^^^^^^^^^^^
@@ -897,7 +867,7 @@ LL |         #[no_mangle] fn bar() {}
    = help: `#[no_mangle]` can be applied to functions, statics, inherent methods, trait methods in impl blocks
 
 warning: `#[should_panic]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:1
    |
 LL | #[should_panic]
    | ^^^^^^^^^^^^^^^
@@ -906,7 +876,7 @@ LL | #[should_panic]
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[should_panic]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:363:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:17
    |
 LL |     mod inner { #![should_panic] }
    |                 ^^^^^^^^^^^^^^^^
@@ -915,7 +885,7 @@ LL |     mod inner { #![should_panic] }
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[should_panic]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:5
    |
 LL |     #[should_panic] struct S;
    |     ^^^^^^^^^^^^^^^
@@ -924,7 +894,7 @@ LL |     #[should_panic] struct S;
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[should_panic]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:375:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5
    |
 LL |     #[should_panic] type T = S;
    |     ^^^^^^^^^^^^^^^
@@ -933,7 +903,7 @@ LL |     #[should_panic] type T = S;
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[should_panic]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5
    |
 LL |     #[should_panic] impl S { }
    |     ^^^^^^^^^^^^^^^
@@ -942,7 +912,7 @@ LL |     #[should_panic] impl S { }
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:1
    |
 LL | #[ignore]
    | ^^^^^^^^^
@@ -951,7 +921,7 @@ LL | #[ignore]
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:17
    |
 LL |     mod inner { #![ignore] }
    |                 ^^^^^^^^^^
@@ -960,7 +930,7 @@ LL |     mod inner { #![ignore] }
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:435:5
    |
 LL |     #[ignore] struct S;
    |     ^^^^^^^^^
@@ -969,7 +939,7 @@ LL |     #[ignore] struct S;
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:403:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:441:5
    |
 LL |     #[ignore] type T = S;
    |     ^^^^^^^^^
@@ -978,7 +948,7 @@ LL |     #[ignore] type T = S;
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:447:5
    |
 LL |     #[ignore] impl S { }
    |     ^^^^^^^^^
@@ -987,7 +957,7 @@ LL |     #[ignore] impl S { }
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[no_implicit_prelude]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:418:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:5
    |
 LL |     #[no_implicit_prelude] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -996,7 +966,7 @@ LL |     #[no_implicit_prelude] fn f() { }
    = help: `#[no_implicit_prelude]` can be applied to modules, crates
 
 warning: `#[no_implicit_prelude]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:5
    |
 LL |     #[no_implicit_prelude] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -1005,7 +975,7 @@ LL |     #[no_implicit_prelude] struct S;
    = help: `#[no_implicit_prelude]` can be applied to modules, crates
 
 warning: `#[no_implicit_prelude]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:428:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:5
    |
 LL |     #[no_implicit_prelude] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -1014,7 +984,7 @@ LL |     #[no_implicit_prelude] type T = S;
    = help: `#[no_implicit_prelude]` can be applied to modules, crates
 
 warning: `#[no_implicit_prelude]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5
    |
 LL |     #[no_implicit_prelude] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -1023,7 +993,7 @@ LL |     #[no_implicit_prelude] impl S { }
    = help: `#[no_implicit_prelude]` can be applied to modules, crates
 
 warning: `#[macro_escape]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:510:5
    |
 LL |     #[macro_escape] fn f() { }
    |     ^^^^^^^^^^^^^^^
@@ -1032,7 +1002,7 @@ LL |     #[macro_escape] fn f() { }
    = help: `#[macro_escape]` can be applied to modules, extern crates, crates
 
 warning: `#[macro_escape]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:5
    |
 LL |     #[macro_escape] struct S;
    |     ^^^^^^^^^^^^^^^
@@ -1041,7 +1011,7 @@ LL |     #[macro_escape] struct S;
    = help: `#[macro_escape]` can be applied to modules, extern crates, crates
 
 warning: `#[macro_escape]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:522:5
    |
 LL |     #[macro_escape] type T = S;
    |     ^^^^^^^^^^^^^^^
@@ -1050,7 +1020,7 @@ LL |     #[macro_escape] type T = S;
    = help: `#[macro_escape]` can be applied to modules, extern crates, crates
 
 warning: `#[macro_escape]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:481:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:5
    |
 LL |     #[macro_escape] impl S { }
    |     ^^^^^^^^^^^^^^^
@@ -1059,7 +1029,7 @@ LL |     #[macro_escape] impl S { }
    = help: `#[macro_escape]` can be applied to modules, extern crates, crates
 
 warning: `#[cold]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:523:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:571:1
    |
 LL | #[cold]
    | ^^^^^^^
@@ -1068,7 +1038,7 @@ LL | #[cold]
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[cold]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:529:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:578:17
    |
 LL |     mod inner { #![cold] }
    |                 ^^^^^^^^
@@ -1077,7 +1047,7 @@ LL |     mod inner { #![cold] }
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[cold]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:586:5
    |
 LL |     #[cold] struct S;
    |     ^^^^^^^
@@ -1086,7 +1056,7 @@ LL |     #[cold] struct S;
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[cold]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:592:5
    |
 LL |     #[cold] type T = S;
    |     ^^^^^^^
@@ -1095,7 +1065,7 @@ LL |     #[cold] type T = S;
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[cold]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:546:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:598:5
    |
 LL |     #[cold] impl S { }
    |     ^^^^^^^
@@ -1104,7 +1074,7 @@ LL |     #[cold] impl S { }
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[link_name]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:552:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:605:1
    |
 LL | #[link_name = "1900"]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -1113,7 +1083,7 @@ LL | #[link_name = "1900"]
    = help: `#[link_name]` can be applied to foreign functions, foreign statics
 
 warning: `#[link_name]` attribute cannot be used on foreign modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:557:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -1122,7 +1092,7 @@ LL |     #[link_name = "1900"]
    = help: `#[link_name]` can be applied to foreign functions, foreign statics
 
 warning: `#[link_name]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:563:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:618:17
    |
 LL |     mod inner { #![link_name="1900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^
@@ -1131,7 +1101,7 @@ LL |     mod inner { #![link_name="1900"] }
    = help: `#[link_name]` can be applied to foreign functions, foreign statics
 
 warning: `#[link_name]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:568:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:624:5
    |
 LL |     #[link_name = "1900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -1140,7 +1110,7 @@ LL |     #[link_name = "1900"] fn f() { }
    = help: `#[link_name]` can be applied to foreign functions, foreign statics
 
 warning: `#[link_name]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:5
    |
 LL |     #[link_name = "1900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -1149,7 +1119,7 @@ LL |     #[link_name = "1900"] struct S;
    = help: `#[link_name]` can be applied to foreign functions, foreign statics
 
 warning: `#[link_name]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:578:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:636:5
    |
 LL |     #[link_name = "1900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -1158,7 +1128,7 @@ LL |     #[link_name = "1900"] type T = S;
    = help: `#[link_name]` can be applied to foreign functions, foreign statics
 
 warning: `#[link_name]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:583:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5
    |
 LL |     #[link_name = "1900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -1167,7 +1137,7 @@ LL |     #[link_name = "1900"] impl S { }
    = help: `#[link_name]` can be applied to foreign functions, foreign statics
 
 warning: `#[link_section]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:589:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:1
    |
 LL | #[link_section = "1800"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1176,7 +1146,7 @@ LL | #[link_section = "1800"]
    = help: `#[link_section]` can be applied to statics, functions
 
 warning: `#[link_section]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:17
    |
 LL |     mod inner { #![link_section="1800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
@@ -1185,7 +1155,7 @@ LL |     mod inner { #![link_section="1800"] }
    = help: `#[link_section]` can be applied to statics, functions
 
 warning: `#[link_section]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5
    |
 LL |     #[link_section = "1800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1194,7 +1164,7 @@ LL |     #[link_section = "1800"] struct S;
    = help: `#[link_section]` can be applied to statics, functions
 
 warning: `#[link_section]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:606:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:5
    |
 LL |     #[link_section = "1800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1203,7 +1173,7 @@ LL |     #[link_section = "1800"] type T = S;
    = help: `#[link_section]` can be applied to statics, functions
 
 warning: `#[link_section]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5
    |
 LL |     #[link_section = "1800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1211,6 +1181,42 @@ LL |     #[link_section = "1800"] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = help: `#[link_section]` can be applied to statics, functions
 
+warning: `#[must_use]` attribute cannot be used on modules
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:1
+   |
+LL | #[must_use]
+   | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
+
+warning: `#[must_use]` attribute cannot be used on modules
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:17
+   |
+LL |     mod inner { #![must_use] }
+   |                 ^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
+
+warning: `#[must_use]` attribute cannot be used on type aliases
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5
+   |
+LL |     #[must_use] type T = S;
+   |     ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
+
+warning: `#[must_use]` attribute cannot be used on inherent impl blocks
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5
+   |
+LL |     #[must_use] impl S { }
+   |     ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
+
 warning: `#[should_panic]` attribute cannot be used on crates
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1
    |
@@ -1221,7 +1227,7 @@ LL | #![should_panic]
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1
    |
 LL | #![ignore]
    | ^^^^^^^^^^
@@ -1230,7 +1236,7 @@ LL | #![ignore]
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[proc_macro_derive]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:61:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:63:1
    |
 LL | #![proc_macro_derive(Test)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1239,7 +1245,7 @@ LL | #![proc_macro_derive(Test)]
    = help: `#[proc_macro_derive]` can only be applied to functions
 
 warning: `#[cold]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:68:1
    |
 LL | #![cold]
    | ^^^^^^^^
@@ -1248,7 +1254,7 @@ LL | #![cold]
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[link_name]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:74:1
    |
 LL | #![link_name = "1900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -1257,7 +1263,7 @@ LL | #![link_name = "1900"]
    = help: `#[link_name]` can be applied to foreign functions, foreign statics
 
 warning: `#[link_section]` attribute cannot be used on crates
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:74:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:79:1
    |
 LL | #![link_section = "1800"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1265,5 +1271,14 @@ LL | #![link_section = "1800"]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = help: `#[link_section]` can be applied to statics, functions
 
+warning: `#[must_use]` attribute cannot be used on crates
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:84:1
+   |
+LL | #![must_use]
+   | ^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
+
 warning: 173 warnings emitted
 
diff --git a/tests/ui/fn/error-recovery-mismatch.stderr b/tests/ui/fn/error-recovery-mismatch.stderr
index 10dab3052be..b4293500b3b 100644
--- a/tests/ui/fn/error-recovery-mismatch.stderr
+++ b/tests/ui/fn/error-recovery-mismatch.stderr
@@ -27,7 +27,7 @@ LL |     fn fold<T>(&self, _: T, &self._) {}
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
-   = note: `#[warn(anonymous_parameters)]` on by default
+   = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for methods
   --> $DIR/error-recovery-mismatch.rs:11:35
diff --git a/tests/ui/frontmatter/auxiliary/makro.rs b/tests/ui/frontmatter/auxiliary/makro.rs
index 78e7417afb5..70707b27bff 100644
--- a/tests/ui/frontmatter/auxiliary/makro.rs
+++ b/tests/ui/frontmatter/auxiliary/makro.rs
@@ -3,6 +3,6 @@ use proc_macro::TokenStream;
 
 #[proc_macro]
 pub fn check(_: TokenStream) -> TokenStream {
-    assert!("---\n---".parse::<TokenStream>().unwrap().is_empty());
+    assert_eq!(6, "---\n---".parse::<TokenStream>().unwrap().into_iter().count());
     Default::default()
 }
diff --git a/tests/ui/frontmatter/proc-macro-observer.rs b/tests/ui/frontmatter/proc-macro-observer.rs
index bafbe912032..b1cc1460933 100644
--- a/tests/ui/frontmatter/proc-macro-observer.rs
+++ b/tests/ui/frontmatter/proc-macro-observer.rs
@@ -2,11 +2,10 @@
 //@ proc-macro: makro.rs
 //@ edition: 2021
 
-#![feature(frontmatter)]
-
 makro::check!();
 
-// checks that a proc-macro cannot observe frontmatter tokens.
+// checks that a proc-macro doesn't know or parse frontmatters at all and instead treats
+// it as normal Rust code.
 // see auxiliary/makro.rs for how it is tested.
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr
index 5dfc42bc873..8bb72833e30 100644
--- a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr
+++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr
@@ -9,11 +9,11 @@ LL |     print_items::<WindowsMut<'_>>(windows);
 LL | }
    | - temporary value is freed at the end of this statement
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
-  --> $DIR/hrtb-implied-1.rs:26:26
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/hrtb-implied-1.rs:26:5
    |
 LL |     for<'a> I::Item<'a>: Debug,
-   |                          ^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr
index 9a1a09b29df..1a397f6cdb2 100644
--- a/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr
+++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr
@@ -15,7 +15,11 @@ LL |     let _next = iter2.next();
    = note: requirement occurs because of a mutable reference to `Eat<&mut I, F>`
    = note: mutable references are invariant over their type parameter
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
-   = note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/hrtb-implied-2.rs:31:8
+   |
+LL |     F: FnMut(I::Item<'_>),
+   |        ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr
index 77f363ee87d..aaafcb3b7af 100644
--- a/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr
+++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr
@@ -11,11 +11,11 @@ LL |     trivial_bound(iter);
    |     `iter` escapes the function body here
    |     argument requires that `'1` must outlive `'static`
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
-  --> $DIR/hrtb-implied-3.rs:14:26
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/hrtb-implied-3.rs:14:5
    |
 LL |     for<'a> I::Item<'a>: Sized,
-   |                          ^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/generic-associated-types/collectivity-regression.stderr b/tests/ui/generic-associated-types/collectivity-regression.stderr
index 1c081ac644a..31349c8eb27 100644
--- a/tests/ui/generic-associated-types/collectivity-regression.stderr
+++ b/tests/ui/generic-associated-types/collectivity-regression.stderr
@@ -7,7 +7,7 @@ LL | |         let _x = x;
 LL | |     };
    | |_____^
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+note: due to a current limitation of the type system, this implies a `'static` lifetime
   --> $DIR/collectivity-regression.rs:11:16
    |
 LL |     for<'a> T: Get<Value<'a> = ()>,
diff --git a/tests/ui/generic-associated-types/extended/lending_iterator.stderr b/tests/ui/generic-associated-types/extended/lending_iterator.stderr
index 84f5ed07bda..7af95dc96a1 100644
--- a/tests/ui/generic-associated-types/extended/lending_iterator.stderr
+++ b/tests/ui/generic-associated-types/extended/lending_iterator.stderr
@@ -12,6 +12,12 @@ error: `Self` does not live long enough
    |
 LL |         <B as FromLendingIterator<A>>::from_iter(self)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/lending_iterator.rs:4:21
+   |
+LL |     fn from_iter<T: for<'x> LendingIterator<Item<'x> = A>>(iter: T) -> Self;
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-86756.rs b/tests/ui/generics/duplicate-generic-parameter-error-86756.rs
index 55a6c144839..acc281cb8c4 100644
--- a/tests/ui/issues/issue-86756.rs
+++ b/tests/ui/generics/duplicate-generic-parameter-error-86756.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/86756
 //@ edition: 2015
 trait Foo<T, T = T> {}
 //~^ ERROR the name `T` is already used for a generic parameter in this item's generic parameters
diff --git a/tests/ui/issues/issue-86756.stderr b/tests/ui/generics/duplicate-generic-parameter-error-86756.stderr
index b650b32c2a3..e761d15ff67 100644
--- a/tests/ui/issues/issue-86756.stderr
+++ b/tests/ui/generics/duplicate-generic-parameter-error-86756.stderr
@@ -1,5 +1,5 @@
 error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/issue-86756.rs:2:14
+  --> $DIR/duplicate-generic-parameter-error-86756.rs:3:14
    |
 LL | trait Foo<T, T = T> {}
    |           -  ^ already used
@@ -7,33 +7,33 @@ LL | trait Foo<T, T = T> {}
    |           first use of `T`
 
 error[E0412]: cannot find type `dyn` in this scope
-  --> $DIR/issue-86756.rs:6:10
+  --> $DIR/duplicate-generic-parameter-error-86756.rs:7:10
    |
 LL |     eq::<dyn, Foo>
    |          ^^^ not found in this scope
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-86756.rs:6:15
+  --> $DIR/duplicate-generic-parameter-error-86756.rs:7:15
    |
 LL |     eq::<dyn, Foo>
    |               ^^^
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL |     eq::<dyn, dyn Foo>
    |               +++
 
 error[E0107]: missing generics for trait `Foo`
-  --> $DIR/issue-86756.rs:6:15
+  --> $DIR/duplicate-generic-parameter-error-86756.rs:7:15
    |
 LL |     eq::<dyn, Foo>
    |               ^^^ expected at least 1 generic argument
    |
 note: trait defined here, with at least 1 generic parameter: `T`
-  --> $DIR/issue-86756.rs:2:7
+  --> $DIR/duplicate-generic-parameter-error-86756.rs:3:7
    |
 LL | trait Foo<T, T = T> {}
    |       ^^^ -
diff --git a/tests/ui/generics/empty-generic-brackets-equiv.stderr b/tests/ui/generics/empty-generic-brackets-equiv.stderr
index 151ee4697b4..aef4aa7cbf1 100644
--- a/tests/ui/generics/empty-generic-brackets-equiv.stderr
+++ b/tests/ui/generics/empty-generic-brackets-equiv.stderr
@@ -4,7 +4,7 @@ warning: trait `T` is never used
 LL | trait T<> {}
    |       ^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/generics/invalid-type-param-default.stderr b/tests/ui/generics/invalid-type-param-default.stderr
index 1c8fdd8ab5c..3bec7542ad0 100644
--- a/tests/ui/generics/invalid-type-param-default.stderr
+++ b/tests/ui/generics/invalid-type-param-default.stderr
@@ -12,7 +12,7 @@ LL | fn avg<T = i32>(_: T) {}
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-   = note: `#[deny(invalid_type_param_default)]` on by default
+   = note: `#[deny(invalid_type_param_default)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: defaults for generic parameters are not allowed here
   --> $DIR/invalid-type-param-default.rs:12:8
@@ -44,7 +44,7 @@ LL | fn avg<T = i32>(_: T) {}
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-   = note: `#[deny(invalid_type_param_default)]` on by default
+   = note: `#[deny(invalid_type_param_default)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: defaults for generic parameters are not allowed here
@@ -55,7 +55,7 @@ LL | fn mdn<T = T::Item>(_: T) {}
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-   = note: `#[deny(invalid_type_param_default)]` on by default
+   = note: `#[deny(invalid_type_param_default)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: defaults for generic parameters are not allowed here
@@ -66,5 +66,5 @@ LL | impl<T = i32> S<T> {}
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-   = note: `#[deny(invalid_type_param_default)]` on by default
+   = note: `#[deny(invalid_type_param_default)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/generics/overlapping-errors-span-issue-123861.stderr b/tests/ui/generics/overlapping-errors-span-issue-123861.stderr
index 44e8b4a01e7..f9dfb00723e 100644
--- a/tests/ui/generics/overlapping-errors-span-issue-123861.stderr
+++ b/tests/ui/generics/overlapping-errors-span-issue-123861.stderr
@@ -23,7 +23,7 @@ LL | fn mainIterator<_ = _> {}
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-   = note: `#[deny(invalid_type_param_default)]` on by default
+   = note: `#[deny(invalid_type_param_default)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/overlapping-errors-span-issue-123861.rs:1:21
@@ -43,5 +43,5 @@ LL | fn mainIterator<_ = _> {}
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-   = note: `#[deny(invalid_type_param_default)]` on by default
+   = note: `#[deny(invalid_type_param_default)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr
index 1c077a9b906..697e85dc8c3 100644
--- a/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr
@@ -15,7 +15,7 @@ LL | fn give_some<'a>() {
 LL |     want_hrtb::<&'a u32>()
    |     ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+note: due to a current limitation of the type system, this implies a `'static` lifetime
   --> $DIR/hrtb-just-for-static.rs:9:15
    |
 LL |     where T : for<'a> Foo<&'a isize>
diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr
index 727b9e6bec8..327c0faa482 100644
--- a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr
@@ -47,7 +47,7 @@ LL | fn foo_hrtb_bar_not<'b, T>(mut t: T)
 LL |     foo_hrtb_bar_not(&mut t);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+note: due to a current limitation of the type system, this implies a `'static` lifetime
   --> $DIR/hrtb-perfect-forwarding.rs:37:8
    |
 LL |     T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
diff --git a/tests/ui/impl-trait/example-st.stderr b/tests/ui/impl-trait/example-st.stderr
index f722d7f6582..eb998bf3bb3 100644
--- a/tests/ui/impl-trait/example-st.stderr
+++ b/tests/ui/impl-trait/example-st.stderr
@@ -4,7 +4,7 @@ warning: trait `Bind` is never used
 LL | trait Bind<F> {
    |       ^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
index 46b677202ef..447f236def3 100644
--- a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
+++ b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
@@ -6,7 +6,7 @@ LL | fn ice() -> impl AsRef<Fn(&())> {
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL | fn ice() -> impl AsRef<dyn Fn(&())> {
diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr
index d3729b6c973..8bc3c8b647c 100644
--- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr
+++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr
@@ -25,7 +25,7 @@ LL |     fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> {
    |
    = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
    = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
-   = note: `#[warn(refining_impl_trait_reachable)]` on by default
+   = note: `#[warn(refining_impl_trait_reachable)]` (part of `#[warn(refining_impl_trait)]`) on by default
 help: replace the return type so that it matches the trait
    |
 LL -     fn iter(&self) -> impl 'a + Iterator<Item = I::Item<'a>> {
diff --git a/tests/ui/impl-trait/in-trait/expeced-refree-to-map-to-reearlybound-ice-108580.stderr b/tests/ui/impl-trait/in-trait/expeced-refree-to-map-to-reearlybound-ice-108580.stderr
index 7c064cc7176..0a73a363786 100644
--- a/tests/ui/impl-trait/in-trait/expeced-refree-to-map-to-reearlybound-ice-108580.stderr
+++ b/tests/ui/impl-trait/in-trait/expeced-refree-to-map-to-reearlybound-ice-108580.stderr
@@ -9,7 +9,7 @@ LL |     fn bar(&self) -> impl Iterator + '_ {
    |
    = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
    = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
-   = note: `#[warn(refining_impl_trait_internal)]` on by default
+   = note: `#[warn(refining_impl_trait_internal)]` (part of `#[warn(refining_impl_trait)]`) on by default
 help: replace the return type so that it matches the trait
    |
 LL |     fn bar(&self) -> impl Iterator<Item = impl Sized> + '_ {
diff --git a/tests/ui/impl-trait/in-trait/refine-captures.stderr b/tests/ui/impl-trait/in-trait/refine-captures.stderr
index 6f213f16144..f7ba99c0763 100644
--- a/tests/ui/impl-trait/in-trait/refine-captures.stderr
+++ b/tests/ui/impl-trait/in-trait/refine-captures.stderr
@@ -6,7 +6,7 @@ LL |     fn test() -> impl Sized + use<> {}
    |
    = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
    = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
-   = note: `#[warn(refining_impl_trait_internal)]` on by default
+   = note: `#[warn(refining_impl_trait_internal)]` (part of `#[warn(refining_impl_trait)]`) on by default
 help: modify the `use<..>` bound to capture the same lifetimes that the trait does
    |
 LL |     fn test() -> impl Sized + use<'a> {}
diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.stderr b/tests/ui/impl-trait/in-trait/unconstrained-lt.stderr
index 27340c5b362..3a4d90dfd4e 100644
--- a/tests/ui/impl-trait/in-trait/unconstrained-lt.stderr
+++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.stderr
@@ -9,7 +9,7 @@ LL |     fn test() -> &'a () {
    |
    = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
    = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
-   = note: `#[warn(refining_impl_trait_internal)]` on by default
+   = note: `#[warn(refining_impl_trait_internal)]` (part of `#[warn(refining_impl_trait)]`) on by default
 help: replace the return type so that it matches the trait
    |
 LL -     fn test() -> &'a () {
diff --git a/tests/ui/impl-trait/precise-capturing/parenthesized.rs b/tests/ui/impl-trait/precise-capturing/parenthesized.rs
new file mode 100644
index 00000000000..e3f80fc1d9f
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/parenthesized.rs
@@ -0,0 +1,8 @@
+// Ensure that we forbid parenthesized use-bounds. In the future we might want
+// to lift this restriction but for now they bear no use whatsoever.
+
+fn f() -> impl Sized + (use<>) {}
+//~^ ERROR precise capturing lists may not be parenthesized
+//~| HELP remove the parentheses
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/parenthesized.stderr b/tests/ui/impl-trait/precise-capturing/parenthesized.stderr
new file mode 100644
index 00000000000..c97fa9972ef
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/parenthesized.stderr
@@ -0,0 +1,14 @@
+error: precise capturing lists may not be parenthesized
+  --> $DIR/parenthesized.rs:4:24
+   |
+LL | fn f() -> impl Sized + (use<>) {}
+   |                        ^^^^^^^
+   |
+help: remove the parentheses
+   |
+LL - fn f() -> impl Sized + (use<>) {}
+LL + fn f() -> impl Sized + use<> {}
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/impl-trait/type-alias-generic-param.stderr b/tests/ui/impl-trait/type-alias-generic-param.stderr
index e4115dc1319..0a063eed257 100644
--- a/tests/ui/impl-trait/type-alias-generic-param.stderr
+++ b/tests/ui/impl-trait/type-alias-generic-param.stderr
@@ -4,7 +4,7 @@ warning: trait `Meow` is never used
 LL | trait Meow {
    |       ^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr b/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr
index 8919919d04e..be8b44b1bde 100644
--- a/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr
+++ b/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr
@@ -30,6 +30,12 @@ LL |     fn test_lifetime<'lt, T: Trait>(_: Foo<&'lt u8>) {}
    |     |                |
    |     |                lifetime `'lt` defined here
    |     requires that `'lt` must outlive `'static`
+   |
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/normalization-placeholder-leak.rs:19:5
+   |
+LL |     for<'x> T::Ty<'x>: Sized;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lifetime may not live long enough
   --> $DIR/normalization-placeholder-leak.rs:38:5
@@ -39,6 +45,12 @@ LL |     fn test_alias<'lt, T: AnotherTrait>(_: Foo<T::Ty2::<'lt>>) {}
    |     |             |
    |     |             lifetime `'lt` defined here
    |     requires that `'lt` must outlive `'static`
+   |
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/normalization-placeholder-leak.rs:19:5
+   |
+LL |     for<'x> T::Ty<'x>: Sized;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/imports/ambiguous-10.stderr b/tests/ui/imports/ambiguous-10.stderr
index cd36795b3c0..f175d27c99e 100644
--- a/tests/ui/imports/ambiguous-10.stderr
+++ b/tests/ui/imports/ambiguous-10.stderr
@@ -19,7 +19,7 @@ note: `Token` could also refer to the enum imported here
 LL | use crate::b::*;
    |     ^^^^^^^^^^^
    = help: consider adding an explicit import of `Token` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error
 
@@ -45,5 +45,5 @@ note: `Token` could also refer to the enum imported here
 LL | use crate::b::*;
    |     ^^^^^^^^^^^
    = help: consider adding an explicit import of `Token` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/ambiguous-12.stderr b/tests/ui/imports/ambiguous-12.stderr
index 273a4ed3c0f..5f92eae0dbc 100644
--- a/tests/ui/imports/ambiguous-12.stderr
+++ b/tests/ui/imports/ambiguous-12.stderr
@@ -19,7 +19,7 @@ note: `b` could also refer to the function imported here
 LL | use crate::public::*;
    |     ^^^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `b` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error
 
@@ -45,5 +45,5 @@ note: `b` could also refer to the function imported here
 LL | use crate::public::*;
    |     ^^^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `b` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/ambiguous-13.stderr b/tests/ui/imports/ambiguous-13.stderr
index c4a42c01c91..279b4e8f142 100644
--- a/tests/ui/imports/ambiguous-13.stderr
+++ b/tests/ui/imports/ambiguous-13.stderr
@@ -19,7 +19,7 @@ note: `Rect` could also refer to the struct imported here
 LL | use crate::content::*;
    |     ^^^^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `Rect` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error
 
@@ -45,5 +45,5 @@ note: `Rect` could also refer to the struct imported here
 LL | use crate::content::*;
    |     ^^^^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `Rect` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/ambiguous-14.stderr b/tests/ui/imports/ambiguous-14.stderr
index f3115f8c8b5..ef7e2669bae 100644
--- a/tests/ui/imports/ambiguous-14.stderr
+++ b/tests/ui/imports/ambiguous-14.stderr
@@ -19,7 +19,7 @@ note: `foo` could also refer to the function imported here
 LL |     pub use b::*;
    |             ^^^^
    = help: consider adding an explicit import of `foo` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error
 
@@ -45,5 +45,5 @@ note: `foo` could also refer to the function imported here
 LL |     pub use b::*;
    |             ^^^^
    = help: consider adding an explicit import of `foo` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/ambiguous-15.stderr b/tests/ui/imports/ambiguous-15.stderr
index 1312f2c63c4..15f83546532 100644
--- a/tests/ui/imports/ambiguous-15.stderr
+++ b/tests/ui/imports/ambiguous-15.stderr
@@ -19,7 +19,7 @@ note: `Error` could also refer to the enum imported here
 LL | pub use t2::*;
    |         ^^^^^
    = help: consider adding an explicit import of `Error` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error
 
@@ -45,5 +45,5 @@ note: `Error` could also refer to the enum imported here
 LL | pub use t2::*;
    |         ^^^^^
    = help: consider adding an explicit import of `Error` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/ambiguous-16.stderr b/tests/ui/imports/ambiguous-16.stderr
index ae65f9a84fc..7c80dee17f0 100644
--- a/tests/ui/imports/ambiguous-16.stderr
+++ b/tests/ui/imports/ambiguous-16.stderr
@@ -19,7 +19,7 @@ note: `ConfirmedTranscriptHashInput` could also refer to the struct imported her
 LL |     pub use self::public_message_in::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `ConfirmedTranscriptHashInput` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error
 
@@ -45,5 +45,5 @@ note: `ConfirmedTranscriptHashInput` could also refer to the struct imported her
 LL |     pub use self::public_message_in::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `ConfirmedTranscriptHashInput` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/ambiguous-17.stderr b/tests/ui/imports/ambiguous-17.stderr
index a87e2572d63..38491ce1062 100644
--- a/tests/ui/imports/ambiguous-17.stderr
+++ b/tests/ui/imports/ambiguous-17.stderr
@@ -29,7 +29,7 @@ note: `id` could also refer to the function imported here
 LL | pub use handwritten::*;
    |         ^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `id` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error; 1 warning emitted
 
@@ -55,5 +55,5 @@ note: `id` could also refer to the function imported here
 LL | pub use handwritten::*;
    |         ^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `id` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/ambiguous-3.stderr b/tests/ui/imports/ambiguous-3.stderr
index 8766db5654a..27fa05a195b 100644
--- a/tests/ui/imports/ambiguous-3.stderr
+++ b/tests/ui/imports/ambiguous-3.stderr
@@ -19,7 +19,7 @@ note: `x` could also refer to the function imported here
 LL |     pub use self::c::*;
    |             ^^^^^^^^^^
    = help: consider adding an explicit import of `x` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error
 
@@ -45,5 +45,5 @@ note: `x` could also refer to the function imported here
 LL |     pub use self::c::*;
    |             ^^^^^^^^^^
    = help: consider adding an explicit import of `x` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/ambiguous-5.stderr b/tests/ui/imports/ambiguous-5.stderr
index 41c15809351..1fc5f4543f3 100644
--- a/tests/ui/imports/ambiguous-5.stderr
+++ b/tests/ui/imports/ambiguous-5.stderr
@@ -19,7 +19,7 @@ note: `Class` could also refer to the struct imported here
 LL |     use super::gsubgpos::*;
    |         ^^^^^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `Class` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error
 
@@ -45,5 +45,5 @@ note: `Class` could also refer to the struct imported here
 LL |     use super::gsubgpos::*;
    |         ^^^^^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `Class` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/ambiguous-6.stderr b/tests/ui/imports/ambiguous-6.stderr
index d988126dbfb..681bc40931f 100644
--- a/tests/ui/imports/ambiguous-6.stderr
+++ b/tests/ui/imports/ambiguous-6.stderr
@@ -19,7 +19,7 @@ note: `C` could also refer to the constant imported here
 LL |     pub use mod2::*;
    |             ^^^^^^^
    = help: consider adding an explicit import of `C` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error
 
@@ -45,5 +45,5 @@ note: `C` could also refer to the constant imported here
 LL |     pub use mod2::*;
    |             ^^^^^^^
    = help: consider adding an explicit import of `C` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/ambiguous-9.stderr b/tests/ui/imports/ambiguous-9.stderr
index 1c4768da827..800a2e10c9d 100644
--- a/tests/ui/imports/ambiguous-9.stderr
+++ b/tests/ui/imports/ambiguous-9.stderr
@@ -29,7 +29,7 @@ note: `date_range` could also refer to the function imported here
 LL |     use super::prelude::*;
    |         ^^^^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `date_range` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 warning: ambiguous glob re-exports
   --> $DIR/ambiguous-9.rs:15:13
@@ -85,7 +85,7 @@ note: `date_range` could also refer to the function imported here
 LL |     use super::prelude::*;
    |         ^^^^^^^^^^^^^^^^^
    = help: consider adding an explicit import of `date_range` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: `date_range` is ambiguous
@@ -109,5 +109,5 @@ note: `date_range` could also refer to the function imported here
 LL | use prelude::*;
    |     ^^^^^^^^^^
    = help: consider adding an explicit import of `date_range` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/duplicate.stderr b/tests/ui/imports/duplicate.stderr
index ef987d07c04..5cd3b0c2c8a 100644
--- a/tests/ui/imports/duplicate.stderr
+++ b/tests/ui/imports/duplicate.stderr
@@ -89,7 +89,7 @@ note: `foo` could also refer to the function imported here
 LL |     pub use crate::b::*;
    |             ^^^^^^^^^^^
    = help: consider adding an explicit import of `foo` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 5 previous errors
 
@@ -117,5 +117,5 @@ note: `foo` could also refer to the function imported here
 LL |     pub use crate::b::*;
    |             ^^^^^^^^^^^
    = help: consider adding an explicit import of `foo` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/imports/local-modularized-tricky-fail-2.stderr b/tests/ui/imports/local-modularized-tricky-fail-2.stderr
index ea4056b3d75..e5b48d2efdd 100644
--- a/tests/ui/imports/local-modularized-tricky-fail-2.stderr
+++ b/tests/ui/imports/local-modularized-tricky-fail-2.stderr
@@ -16,7 +16,7 @@ LL | |     }
 ...
 LL |   define_exported!();
    |   ------------------ in this macro invocation
-   = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default
+   = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
@@ -60,7 +60,7 @@ LL | |     }
 ...
 LL |   define_exported!();
    |   ------------------ in this macro invocation
-   = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default
+   = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
@@ -82,6 +82,6 @@ LL | |     }
 ...
 LL |   define_exported!();
    |   ------------------ in this macro invocation
-   = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default
+   = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/imports/unresolved-seg-after-ambiguous.stderr b/tests/ui/imports/unresolved-seg-after-ambiguous.stderr
index 3b50ae32683..67316462a27 100644
--- a/tests/ui/imports/unresolved-seg-after-ambiguous.stderr
+++ b/tests/ui/imports/unresolved-seg-after-ambiguous.stderr
@@ -25,7 +25,7 @@ note: `E` could also refer to the struct imported here
 LL |         pub use self::d::*;
    |                 ^^^^^^^^^^
    = help: consider adding an explicit import of `E` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 2 previous errors
 
@@ -52,5 +52,5 @@ note: `E` could also refer to the struct imported here
 LL |         pub use self::d::*;
    |                 ^^^^^^^^^^
    = help: consider adding an explicit import of `E` to disambiguate
-   = note: `#[deny(ambiguous_glob_imports)]` on by default
+   = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/inference/inference-variable-behind-raw-pointer.stderr b/tests/ui/inference/inference-variable-behind-raw-pointer.stderr
index 3dea09e7f52..fe4e16c3328 100644
--- a/tests/ui/inference/inference-variable-behind-raw-pointer.stderr
+++ b/tests/ui/inference/inference-variable-behind-raw-pointer.stderr
@@ -6,7 +6,7 @@ LL |     if data.is_null() {}
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
-   = note: `#[warn(tyvar_behind_raw_pointer)]` on by default
+   = note: `#[warn(tyvar_behind_raw_pointer)]` (part of `#[warn(rust_2018_compatibility)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/inference/inference_unstable.stderr b/tests/ui/inference/inference_unstable.stderr
index 395dcb2661f..0072175d514 100644
--- a/tests/ui/inference/inference_unstable.stderr
+++ b/tests/ui/inference/inference_unstable.stderr
@@ -7,7 +7,7 @@ LL |     assert_eq!('x'.ipu_flatten(), 1);
    = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior!
    = note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919>
    = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_flatten(...)` to keep using the current method
-   = note: `#[warn(unstable_name_collisions)]` on by default
+   = note: `#[warn(unstable_name_collisions)]` (part of `#[warn(future_incompatible)]`) on by default
 help: add `#![feature(ipu_flatten)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_flatten`
    |
 LL + #![feature(ipu_flatten)]
diff --git a/tests/ui/inference/issue-72616.stderr b/tests/ui/inference/issue-72616.stderr
index 31a0586301d..a271639996f 100644
--- a/tests/ui/inference/issue-72616.stderr
+++ b/tests/ui/inference/issue-72616.stderr
@@ -6,14 +6,10 @@ LL |         if String::from("a") == "a".try_into().unwrap() {}
    |                              |
    |                              type must be known at this point
    |
-   = note: cannot satisfy `String: PartialEq<_>`
-   = help: the following types implement trait `PartialEq<Rhs>`:
-             `String` implements `PartialEq<&str>`
-             `String` implements `PartialEq<ByteStr>`
-             `String` implements `PartialEq<ByteString>`
-             `String` implements `PartialEq<Cow<'_, str>>`
-             `String` implements `PartialEq<str>`
-             `String` implements `PartialEq`
+   = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the following crates: `alloc`, `std`:
+           - impl PartialEq for String;
+           - impl PartialEq<Path> for String;
+           - impl PartialEq<PathBuf> for String;
 help: try using a fully qualified path to specify the expected types
    |
 LL -         if String::from("a") == "a".try_into().unwrap() {}
diff --git a/tests/ui/issues/issue-85461.rs b/tests/ui/instrument-coverage/link-regex-crate-with-instrument-coverage-85461.rs
index 72538081ccb..ffb535e69ee 100644
--- a/tests/ui/issues/issue-85461.rs
+++ b/tests/ui/instrument-coverage/link-regex-crate-with-instrument-coverage-85461.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/85461
 //@ compile-flags: -Cinstrument-coverage -Ccodegen-units=4 --crate-type dylib -Copt-level=0
 //@ build-pass
 //@ needs-profiler-runtime
diff --git a/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr
new file mode 100644
index 00000000000..e3f7871da35
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr
@@ -0,0 +1,4 @@
+error: `-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs
new file mode 100644
index 00000000000..bc81c993d26
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs
@@ -0,0 +1,21 @@
+//@ revisions: x86 x86_64 aarch64
+
+//@ compile-flags: -Zindirect-branch-cs-prefix
+
+//@[x86] check-pass
+//@[x86] needs-llvm-components: x86
+//@[x86] compile-flags: --target i686-unknown-linux-gnu
+
+//@[x86_64] check-pass
+//@[x86_64] needs-llvm-components: x86
+//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
+
+//@[aarch64] check-fail
+//@[aarch64] needs-llvm-components: aarch64
+//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
+
+//[aarch64]~? ERROR `-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64
diff --git a/tests/ui/invalid/invalid-no-sanitize.rs b/tests/ui/invalid/invalid-no-sanitize.rs
deleted file mode 100644
index b52e3cc83fa..00000000000
--- a/tests/ui/invalid/invalid-no-sanitize.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![feature(no_sanitize)]
-
-#[no_sanitize(brontosaurus)] //~ ERROR invalid argument
-fn main() {
-}
diff --git a/tests/ui/invalid/invalid-no-sanitize.stderr b/tests/ui/invalid/invalid-no-sanitize.stderr
deleted file mode 100644
index b1c80438b31..00000000000
--- a/tests/ui/invalid/invalid-no-sanitize.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: invalid argument for `no_sanitize`
-  --> $DIR/invalid-no-sanitize.rs:3:15
-   |
-LL | #[no_sanitize(brontosaurus)]
-   |               ^^^^^^^^^^^^
-   |
-   = note: expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/issues/issue-17351.stderr b/tests/ui/issues/issue-17351.stderr
index e4c84ab9315..043d4ffc780 100644
--- a/tests/ui/issues/issue-17351.stderr
+++ b/tests/ui/issues/issue-17351.stderr
@@ -6,7 +6,7 @@ LL | trait Str { fn foo(&self) {} }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-20055-box-trait.stderr b/tests/ui/issues/issue-20055-box-trait.stderr
index db9d359e225..b1cbb2a5717 100644
--- a/tests/ui/issues/issue-20055-box-trait.stderr
+++ b/tests/ui/issues/issue-20055-box-trait.stderr
@@ -6,7 +6,7 @@ LL | trait Boo {
 LL |     fn dummy(&self) { }
    |        ^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-23485.stderr b/tests/ui/issues/issue-23485.stderr
index ed2d2400d0d..7ad518e449b 100644
--- a/tests/ui/issues/issue-23485.stderr
+++ b/tests/ui/issues/issue-23485.stderr
@@ -7,7 +7,7 @@ LL | trait Iterator {
 LL |     fn clone_first(mut self) -> Option<<Self::Item as Deref>::Target> where
    |        ^^^^^^^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-26217.stderr b/tests/ui/issues/issue-26217.stderr
index 0b153ad7490..a8750567819 100644
--- a/tests/ui/issues/issue-26217.stderr
+++ b/tests/ui/issues/issue-26217.stderr
@@ -6,11 +6,11 @@ LL | fn bar<'a>() {
 LL |     foo::<&'a i32>();
    |     ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
-  --> $DIR/issue-26217.rs:1:30
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/issue-26217.rs:1:19
    |
 LL | fn foo<T>() where for<'a> T: 'a {}
-   |                              ^^
+   |                   ^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-28344.stderr b/tests/ui/issues/issue-28344.stderr
index dfd4951f172..c23b5767302 100644
--- a/tests/ui/issues/issue-28344.stderr
+++ b/tests/ui/issues/issue-28344.stderr
@@ -6,7 +6,7 @@ LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL |     let x: u8 = <dyn BitXor>::bitor(0 as u8, 0 as u8);
diff --git a/tests/ui/issues/issue-2989.stderr b/tests/ui/issues/issue-2989.stderr
index 57181607cec..500ace8f275 100644
--- a/tests/ui/issues/issue-2989.stderr
+++ b/tests/ui/issues/issue-2989.stderr
@@ -4,7 +4,7 @@ warning: trait `methods` is never used
 LL | trait methods {
    |       ^^^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-34503.stderr b/tests/ui/issues/issue-34503.stderr
index 60d8d76a619..1877e20bbc1 100644
--- a/tests/ui/issues/issue-34503.stderr
+++ b/tests/ui/issues/issue-34503.stderr
@@ -8,7 +8,7 @@ LL |         fn foo(&self) where (T, Option<T>): Ord {}
 LL |         fn bar(&self, x: &Option<T>) -> bool
    |            ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-39367.stderr b/tests/ui/issues/issue-39367.stderr
index 65076375e96..1592b8b6672 100644
--- a/tests/ui/issues/issue-39367.stderr
+++ b/tests/ui/issues/issue-39367.stderr
@@ -11,7 +11,7 @@ LL | |             });
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
-   = note: `#[warn(static_mut_refs)]` on by default
+   = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-47094.stderr b/tests/ui/issues/issue-47094.stderr
index 1c6693403b8..da414d68214 100644
--- a/tests/ui/issues/issue-47094.stderr
+++ b/tests/ui/issues/issue-47094.stderr
@@ -6,7 +6,7 @@ LL | #[repr(C, u8)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
-   = note: `#[deny(conflicting_repr_hints)]` on by default
+   = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error[E0566]: conflicting representation hints
   --> $DIR/issue-47094.rs:8:8
@@ -32,7 +32,7 @@ LL | #[repr(C, u8)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
-   = note: `#[deny(conflicting_repr_hints)]` on by default
+   = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error[E0566]: conflicting representation hints
@@ -46,5 +46,5 @@ LL | #[repr(u8)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
-   = note: `#[deny(conflicting_repr_hints)]` on by default
+   = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/issues/issue-58734.stderr b/tests/ui/issues/issue-58734.stderr
index c246d1fc111..2336a94f150 100644
--- a/tests/ui/issues/issue-58734.stderr
+++ b/tests/ui/issues/issue-58734.stderr
@@ -6,7 +6,7 @@ LL |     Trait::nonexistent(());
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL |     <dyn Trait>::nonexistent(());
diff --git a/tests/ui/issues/issue-72278.stderr b/tests/ui/issues/issue-72278.stderr
index 5468837a305..91efada3d8d 100644
--- a/tests/ui/issues/issue-72278.stderr
+++ b/tests/ui/issues/issue-72278.stderr
@@ -9,7 +9,7 @@ LL |     S.func::<'a, U>()
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
-   = note: `#[warn(late_bound_lifetime_arguments)]` on by default
+   = note: `#[warn(late_bound_lifetime_arguments)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-7575.stderr b/tests/ui/issues/issue-7575.stderr
deleted file mode 100644
index 2f987d19c80..00000000000
--- a/tests/ui/issues/issue-7575.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-warning: trait `Foo` is never used
-  --> $DIR/issue-7575.rs:3:7
-   |
-LL | trait Foo {
-   |       ^^^
-   |
-   = note: `#[warn(dead_code)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/issues/issue-77218/issue-77218-2.fixed b/tests/ui/issues/issue-77218/issue-77218-2.fixed
deleted file mode 100644
index 98d79b5da65..00000000000
--- a/tests/ui/issues/issue-77218/issue-77218-2.fixed
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ run-rustfix
-fn main() {
-    let value = [7u8];
-    while let Some(0) = value.get(0) { //~ ERROR invalid left-hand side of assignment
-    }
-}
diff --git a/tests/ui/issues/issue-77218/issue-77218-2.rs b/tests/ui/issues/issue-77218/issue-77218-2.rs
deleted file mode 100644
index 3be38f8f721..00000000000
--- a/tests/ui/issues/issue-77218/issue-77218-2.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ run-rustfix
-fn main() {
-    let value = [7u8];
-    while Some(0) = value.get(0) { //~ ERROR invalid left-hand side of assignment
-    }
-}
diff --git a/tests/ui/issues/issue-77218/issue-77218-2.stderr b/tests/ui/issues/issue-77218/issue-77218-2.stderr
deleted file mode 100644
index dfed0b6e67e..00000000000
--- a/tests/ui/issues/issue-77218/issue-77218-2.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0070]: invalid left-hand side of assignment
-  --> $DIR/issue-77218-2.rs:4:19
-   |
-LL |     while Some(0) = value.get(0) {
-   |                -  ^
-   |                |
-   |                cannot assign to this expression
-   |
-help: you might have meant to use pattern destructuring
-   |
-LL |     while let Some(0) = value.get(0) {
-   |           +++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0070`.
diff --git a/tests/ui/issues/issue-7899.rs b/tests/ui/issues/issue-7899.rs
deleted file mode 100644
index 4b69f3e3d89..00000000000
--- a/tests/ui/issues/issue-7899.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-#![allow(unused_variables)]
-//@ aux-build:issue-7899.rs
-
-
-extern crate issue_7899 as testcrate;
-
-fn main() {
-    let f = testcrate::V2(1.0f32, 2.0f32);
-}
diff --git a/tests/ui/issues/issue-8044.rs b/tests/ui/issues/issue-8044.rs
deleted file mode 100644
index 3c10bbca634..00000000000
--- a/tests/ui/issues/issue-8044.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-//@ aux-build:issue-8044.rs
-
-
-extern crate issue_8044 as minimal;
-use minimal::{BTree, leaf};
-
-pub fn main() {
-    BTree::<isize> { node: leaf(1) };
-}
diff --git a/tests/ui/issues/issue-8401.rs b/tests/ui/issues/issue-8401.rs
deleted file mode 100644
index 1df63516fb0..00000000000
--- a/tests/ui/issues/issue-8401.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ run-pass
-//@ aux-build:issue-8401.rs
-
-
-extern crate issue_8401;
-
-pub fn main() {}
diff --git a/tests/ui/issues/issue-9123.rs b/tests/ui/issues/issue-9123.rs
deleted file mode 100644
index bbf6c13341c..00000000000
--- a/tests/ui/issues/issue-9123.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ run-pass
-//@ aux-build:issue-9123.rs
-
-
-extern crate issue_9123;
-
-pub fn main() {}
diff --git a/tests/ui/iterators/into-iter-on-arrays-2018.stderr b/tests/ui/iterators/into-iter-on-arrays-2018.stderr
index 8818ef80f76..6419d779b4f 100644
--- a/tests/ui/iterators/into-iter-on-arrays-2018.stderr
+++ b/tests/ui/iterators/into-iter-on-arrays-2018.stderr
@@ -6,7 +6,7 @@ LL |     let _: Iter<'_, i32> = array.into_iter();
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-   = note: `#[warn(array_into_iter)]` on by default
+   = note: `#[warn(array_into_iter)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
    |
 LL -     let _: Iter<'_, i32> = array.into_iter();
diff --git a/tests/ui/iterators/into-iter-on-arrays-lint.stderr b/tests/ui/iterators/into-iter-on-arrays-lint.stderr
index a9dfa5819c1..a3eb3133a00 100644
--- a/tests/ui/iterators/into-iter-on-arrays-lint.stderr
+++ b/tests/ui/iterators/into-iter-on-arrays-lint.stderr
@@ -6,7 +6,7 @@ LL |     small.into_iter();
    |
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html>
-   = note: `#[warn(array_into_iter)]` on by default
+   = note: `#[warn(array_into_iter)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
    |
 LL -     small.into_iter();
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr b/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr
index a0c1432756d..d2df6a2f40c 100644
--- a/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr
@@ -6,7 +6,7 @@ LL |     let _: Iter<'_, i32> = boxed_slice.into_iter();
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
-   = note: `#[warn(boxed_slice_into_iter)]` on by default
+   = note: `#[warn(boxed_slice_into_iter)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
    |
 LL -     let _: Iter<'_, i32> = boxed_slice.into_iter();
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr b/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr
index 377455d6a26..670a741ab8b 100644
--- a/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr
@@ -6,7 +6,7 @@ LL |     boxed.into_iter();
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/intoiterator-box-slice.html>
-   = note: `#[warn(boxed_slice_into_iter)]` on by default
+   = note: `#[warn(boxed_slice_into_iter)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
    |
 LL -     boxed.into_iter();
diff --git a/tests/ui/issues/issue-81584.fixed b/tests/ui/iterators/iterator-scope-collect-suggestion-81584.fixed
index c3d33a1b4f8..0e3d48fe27d 100644
--- a/tests/ui/issues/issue-81584.fixed
+++ b/tests/ui/iterators/iterator-scope-collect-suggestion-81584.fixed
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/81584
 //@ run-rustfix
 fn main() {
         let _ = vec![vec![0, 1], vec![2]]
diff --git a/tests/ui/issues/issue-81584.rs b/tests/ui/iterators/iterator-scope-collect-suggestion-81584.rs
index 27db73aaa2c..3fba39517fc 100644
--- a/tests/ui/issues/issue-81584.rs
+++ b/tests/ui/iterators/iterator-scope-collect-suggestion-81584.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/81584
 //@ run-rustfix
 fn main() {
         let _ = vec![vec![0, 1], vec![2]]
diff --git a/tests/ui/issues/issue-81584.stderr b/tests/ui/iterators/iterator-scope-collect-suggestion-81584.stderr
index eb97916ad75..e180183e7e3 100644
--- a/tests/ui/issues/issue-81584.stderr
+++ b/tests/ui/iterators/iterator-scope-collect-suggestion-81584.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return value referencing function parameter `y`
-  --> $DIR/issue-81584.rs:5:22
+  --> $DIR/iterator-scope-collect-suggestion-81584.rs:6:22
    |
 LL |             .map(|y| y.iter().map(|x| x + 1))
    |                      -^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lang-items/issue-83471.stderr b/tests/ui/lang-items/issue-83471.stderr
index e913c0bf10f..28fa552fbeb 100644
--- a/tests/ui/lang-items/issue-83471.stderr
+++ b/tests/ui/lang-items/issue-83471.stderr
@@ -48,7 +48,7 @@ LL |     fn call(export_name);
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
-   = note: `#[warn(anonymous_parameters)]` on by default
+   = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default
 
 error[E0718]: `fn` lang item must be applied to a trait with 1 generic argument
   --> $DIR/issue-83471.rs:19:1
diff --git a/tests/ui/lifetimes/issue-105507.fixed b/tests/ui/lifetimes/issue-105507.fixed
index 177da01b154..46d4f14a245 100644
--- a/tests/ui/lifetimes/issue-105507.fixed
+++ b/tests/ui/lifetimes/issue-105507.fixed
@@ -25,8 +25,8 @@ impl<T> ProjectedMyTrait for T
     where
         T: Project,
         for<'a> T::Projected<'a>: MyTrait,
-        //~^ NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime
-        //~| NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime
+        //~^ NOTE due to a current limitation of the type system, this implies a `'static` lifetime
+        //~| NOTE due to a current limitation of the type system, this implies a `'static` lifetime
 {}
 
 fn require_trait<T: MyTrait>(_: T) {}
diff --git a/tests/ui/lifetimes/issue-105507.rs b/tests/ui/lifetimes/issue-105507.rs
index 858fa19a029..f1721fee5b4 100644
--- a/tests/ui/lifetimes/issue-105507.rs
+++ b/tests/ui/lifetimes/issue-105507.rs
@@ -25,8 +25,8 @@ impl<T> ProjectedMyTrait for T
     where
         T: Project,
         for<'a> T::Projected<'a>: MyTrait,
-        //~^ NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime
-        //~| NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime
+        //~^ NOTE due to a current limitation of the type system, this implies a `'static` lifetime
+        //~| NOTE due to a current limitation of the type system, this implies a `'static` lifetime
 {}
 
 fn require_trait<T: MyTrait>(_: T) {}
diff --git a/tests/ui/lifetimes/issue-105507.stderr b/tests/ui/lifetimes/issue-105507.stderr
index 44d3a7eb9a4..7fccba7cc44 100644
--- a/tests/ui/lifetimes/issue-105507.stderr
+++ b/tests/ui/lifetimes/issue-105507.stderr
@@ -4,7 +4,7 @@ error: `T` does not live long enough
 LL |     require_trait(wrap);
    |     ^^^^^^^^^^^^^^^^^^^
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+note: due to a current limitation of the type system, this implies a `'static` lifetime
   --> $DIR/issue-105507.rs:27:35
    |
 LL |         for<'a> T::Projected<'a>: MyTrait,
@@ -20,7 +20,7 @@ error: `U` does not live long enough
 LL |     require_trait(wrap1);
    |     ^^^^^^^^^^^^^^^^^^^^
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+note: due to a current limitation of the type system, this implies a `'static` lifetime
   --> $DIR/issue-105507.rs:27:35
    |
 LL |         for<'a> T::Projected<'a>: MyTrait,
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr
index bd68479c58c..7f44ab2ed6b 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.stderr
+++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr
@@ -30,7 +30,7 @@ LL | fn c<T = u8()>() {}
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-   = note: `#[deny(invalid_type_param_default)]` on by default
+   = note: `#[deny(invalid_type_param_default)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error[E0308]: mismatched types
   --> $DIR/unusual-rib-combinations.rs:5:16
@@ -51,5 +51,5 @@ LL | fn c<T = u8()>() {}
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-   = note: `#[deny(invalid_type_param_default)]` on by default
+   = note: `#[deny(invalid_type_param_default)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/link-native-libs/link-attr-validation-early.stderr b/tests/ui/link-native-libs/link-attr-validation-early.stderr
index 36cca6f27ef..d4fc2e272f8 100644
--- a/tests/ui/link-native-libs/link-attr-validation-early.stderr
+++ b/tests/ui/link-native-libs/link-attr-validation-early.stderr
@@ -7,7 +7,7 @@ LL | #[link]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/link-attr-validation-early.rs:4:1
@@ -31,7 +31,7 @@ LL | #[link]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
@@ -43,5 +43,5 @@ LL | #[link = "foo"]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr
index 91e42f2909e..8727e55f4ce 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr
+++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr
@@ -12,7 +12,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
+   = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default
 
 error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
   --> $DIR/unsupported-abi.rs:16:5
diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr
index 8da63a9c546..5d756db2319 100644
--- a/tests/ui/lint/bare-trait-objects-path.stderr
+++ b/tests/ui/lint/bare-trait-objects-path.stderr
@@ -6,7 +6,7 @@ LL |     Dyn::func();
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL |     <dyn Dyn>::func();
diff --git a/tests/ui/lint/forbid-group-member.stderr b/tests/ui/lint/forbid-group-member.stderr
index 2e0147693f3..54f56ecbe64 100644
--- a/tests/ui/lint/forbid-group-member.stderr
+++ b/tests/ui/lint/forbid-group-member.stderr
@@ -9,7 +9,7 @@ LL | #[allow(unused_variables)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: `#[warn(forbidden_lint_groups)]` on by default
+   = note: `#[warn(forbidden_lint_groups)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
 
@@ -25,5 +25,5 @@ LL | #[allow(unused_variables)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: `#[warn(forbidden_lint_groups)]` on by default
+   = note: `#[warn(forbidden_lint_groups)]` (part of `#[warn(future_incompatible)]`) on by default
 
diff --git a/tests/ui/lint/future-incompatible-lint-group.stderr b/tests/ui/lint/future-incompatible-lint-group.stderr
index 87b9ebec08b..4157cd0c77d 100644
--- a/tests/ui/lint/future-incompatible-lint-group.stderr
+++ b/tests/ui/lint/future-incompatible-lint-group.stderr
@@ -6,7 +6,7 @@ LL |     fn f(u8) {}
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
-   = note: `#[warn(anonymous_parameters)]` on by default
+   = note: `#[warn(anonymous_parameters)]` (part of `#[warn(rust_2018_compatibility)]`) on by default
 
 error: ambiguous associated item
   --> $DIR/future-incompatible-lint-group.rs:18:17
diff --git a/tests/ui/lint/let_underscore/let_underscore_lock.stderr b/tests/ui/lint/let_underscore/let_underscore_lock.stderr
index a54a23e364b..d70dab32e3e 100644
--- a/tests/ui/lint/let_underscore/let_underscore_lock.stderr
+++ b/tests/ui/lint/let_underscore/let_underscore_lock.stderr
@@ -4,7 +4,7 @@ error: non-binding let on a synchronization lock
 LL |     let _ = data.lock().unwrap();
    |         ^ this lock is not assigned to a binding and is immediately dropped
    |
-   = note: `#[deny(let_underscore_lock)]` on by default
+   = note: `#[deny(let_underscore_lock)]` (part of `#[deny(let_underscore)]`) on by default
 help: consider binding to an unused variable to avoid immediately dropping the value
    |
 LL |     let _unused = data.lock().unwrap();
diff --git a/tests/ui/lint/lint-non-uppercase-usages.stderr b/tests/ui/lint/lint-non-uppercase-usages.stderr
index b34be31216d..5dde4d4c89d 100644
--- a/tests/ui/lint/lint-non-uppercase-usages.stderr
+++ b/tests/ui/lint/lint-non-uppercase-usages.stderr
@@ -4,7 +4,7 @@ warning: constant `my_static` should have an upper case name
 LL | const my_static: u32 = 0;
    |       ^^^^^^^^^
    |
-   = note: `#[warn(non_upper_case_globals)]` on by default
+   = note: `#[warn(non_upper_case_globals)]` (part of `#[warn(nonstandard_style)]`) on by default
 help: convert the identifier to upper case
    |
 LL - const my_static: u32 = 0;
diff --git a/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.rs b/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.rs
new file mode 100644
index 00000000000..5db7cc02baa
--- /dev/null
+++ b/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.rs
@@ -0,0 +1,22 @@
+//@ check-pass
+
+// Verify information about membership to builtin lint group is included in the lint message when
+// explaining lint level and source for builtin lints with default settings.
+//
+// Ideally, we'd like to use lints that are part of `unused` group as shown in the issue.
+// This is not possible in a ui test, because `unused` lints are enabled with `-A unused`
+// in such tests, and the we're testing a scenario with no modification to the default settings.
+
+fn main() {
+    // additional context is provided only if the level is not explicitly set
+    let WrongCase = 1;
+    //~^ WARN [non_snake_case]
+    //~| NOTE `#[warn(non_snake_case)]` (part of `#[warn(nonstandard_style)]`) on by default
+
+    // unchanged message if the level is explicitly set
+    // even if the level is the same as the default
+    #[warn(nonstandard_style)] //~ NOTE the lint level is defined here
+    let WrongCase = 2;
+    //~^ WARN [non_snake_case]
+    //~| NOTE `#[warn(non_snake_case)]` implied by `#[warn(nonstandard_style)]`
+}
diff --git a/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.stderr b/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.stderr
new file mode 100644
index 00000000000..86ec59220f0
--- /dev/null
+++ b/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.stderr
@@ -0,0 +1,23 @@
+warning: variable `WrongCase` should have a snake case name
+  --> $DIR/mention-lint-group-in-default-level-lint-note-issue-65464.rs:12:9
+   |
+LL |     let WrongCase = 1;
+   |         ^^^^^^^^^ help: convert the identifier to snake case: `wrong_case`
+   |
+   = note: `#[warn(non_snake_case)]` (part of `#[warn(nonstandard_style)]`) on by default
+
+warning: variable `WrongCase` should have a snake case name
+  --> $DIR/mention-lint-group-in-default-level-lint-note-issue-65464.rs:19:9
+   |
+LL |     let WrongCase = 2;
+   |         ^^^^^^^^^ help: convert the identifier to snake case: `wrong_case`
+   |
+note: the lint level is defined here
+  --> $DIR/mention-lint-group-in-default-level-lint-note-issue-65464.rs:18:12
+   |
+LL |     #[warn(nonstandard_style)]
+   |            ^^^^^^^^^^^^^^^^^
+   = note: `#[warn(non_snake_case)]` implied by `#[warn(nonstandard_style)]`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr
index 000545a0600..1ba4deded46 100644
--- a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr
+++ b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr
@@ -33,7 +33,7 @@ warning: constant `µ` should have an upper case name
 LL | const µ: f64 = 0.000001;
    |       ^ help: convert the identifier to upper case: `Μ`
    |
-   = note: `#[warn(non_upper_case_globals)]` on by default
+   = note: `#[warn(non_upper_case_globals)]` (part of `#[warn(nonstandard_style)]`) on by default
 
 error: aborting due to 3 previous errors; 1 warning emitted
 
diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr b/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr
index 99cdcafab39..9506d702f51 100644
--- a/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr
+++ b/tests/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr
@@ -9,7 +9,7 @@ LL |         _ => foo!()
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
-   = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default
+   = note: `#[deny(semicolon_in_expressions_from_macros)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
@@ -26,6 +26,6 @@ LL |         _ => foo!()
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
-   = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default
+   = note: `#[deny(semicolon_in_expressions_from_macros)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/lint/special-upper-lower-cases.stderr b/tests/ui/lint/special-upper-lower-cases.stderr
index 2aa13c33be3..0f5cf336aec 100644
--- a/tests/ui/lint/special-upper-lower-cases.stderr
+++ b/tests/ui/lint/special-upper-lower-cases.stderr
@@ -4,7 +4,7 @@ warning: type `𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝` should have an upper camel
 LL | struct 𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝;
    |        ^^^^^^^^^ should have an UpperCamelCase name
    |
-   = note: `#[warn(non_camel_case_types)]` on by default
+   = note: `#[warn(non_camel_case_types)]` (part of `#[warn(nonstandard_style)]`) on by default
 
 warning: type `𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝` should have an upper camel case name
   --> $DIR/special-upper-lower-cases.rs:14:8
@@ -18,7 +18,7 @@ warning: static variable `𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲` shou
 LL | static 𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲: i32 = 1;
    |        ^^^^^^^^^^^^ should have an UPPER_CASE name
    |
-   = note: `#[warn(non_upper_case_globals)]` on by default
+   = note: `#[warn(non_upper_case_globals)]` (part of `#[warn(nonstandard_style)]`) on by default
 
 warning: variable `𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢` should have a snake case name
   --> $DIR/special-upper-lower-cases.rs:21:9
@@ -26,7 +26,7 @@ warning: variable `𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢` should have a snake cas
 LL |     let 𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢 = 1;
    |         ^^^^^^^^^ should have a snake_case name
    |
-   = note: `#[warn(non_snake_case)]` on by default
+   = note: `#[warn(non_snake_case)]` (part of `#[warn(nonstandard_style)]`) on by default
 
 warning: 4 warnings emitted
 
diff --git a/tests/ui/lint/static-mut-refs.e2021.stderr b/tests/ui/lint/static-mut-refs.e2021.stderr
index 75a7e60690c..86854ab2dda 100644
--- a/tests/ui/lint/static-mut-refs.e2021.stderr
+++ b/tests/ui/lint/static-mut-refs.e2021.stderr
@@ -6,7 +6,7 @@ LL |         let _y = &X;
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
-   = note: `#[warn(static_mut_refs)]` on by default
+   = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `&raw const` instead to create a raw pointer
    |
 LL |         let _y = &raw const X;
diff --git a/tests/ui/lint/static-mut-refs.e2024.stderr b/tests/ui/lint/static-mut-refs.e2024.stderr
index 42a96bafc88..5c21c5b0dd9 100644
--- a/tests/ui/lint/static-mut-refs.e2024.stderr
+++ b/tests/ui/lint/static-mut-refs.e2024.stderr
@@ -6,7 +6,7 @@ LL |         let _y = &X;
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
-   = note: `#[deny(static_mut_refs)]` on by default
+   = note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 help: use `&raw const` instead to create a raw pointer
    |
 LL |         let _y = &raw const X;
diff --git a/tests/ui/lint/unused/issue-70041.stderr b/tests/ui/lint/unused/issue-70041.stderr
index b2e6d1aeb3f..4a2c4b8b907 100644
--- a/tests/ui/lint/unused/issue-70041.stderr
+++ b/tests/ui/lint/unused/issue-70041.stderr
@@ -4,7 +4,7 @@ warning: unused macro definition: `regex`
 LL | macro_rules! regex {
    |              ^^^^^
    |
-   = note: `#[warn(unused_macros)]` on by default
+   = note: `#[warn(unused_macros)]` (part of `#[warn(unused)]`) on by default
 
 warning: unused import: `regex`
   --> $DIR/issue-70041.rs:10:5
@@ -12,7 +12,7 @@ warning: unused import: `regex`
 LL | use regex;
    |     ^^^^^
    |
-   = note: `#[warn(unused_imports)]` on by default
+   = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/lint/unused/unused_attributes-must_use.fixed b/tests/ui/lint/unused/unused_attributes-must_use.fixed
index 80d488296ea..2e800cbff3f 100644
--- a/tests/ui/lint/unused/unused_attributes-must_use.fixed
+++ b/tests/ui/lint/unused/unused_attributes-must_use.fixed
@@ -4,18 +4,23 @@
 #![deny(unused_attributes, unused_must_use)]
 #![feature(asm_experimental_arch, stmt_expr_attributes, trait_alias)]
 
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 extern crate std as std2;
 
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 mod test_mod {}
 
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 use std::arch::global_asm;
 
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 const CONST: usize = 4;
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 #[no_mangle]
 static STATIC: usize = 4;
 
@@ -32,7 +37,8 @@ union U {
     unit: (),
 }
 
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 impl U {
     #[must_use]
     fn method() -> i32 {
@@ -46,10 +52,12 @@ fn foo() -> i64 {
     4
 }
 
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 extern "Rust" {
     #[link_name = "STATIC"]
-     //~ ERROR `#[must_use]` has no effect
+     //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     static FOREIGN_STATIC: usize;
 
     #[link_name = "foo"]
@@ -60,16 +68,20 @@ extern "Rust" {
  //~ ERROR unused attribute
 global_asm!("");
 
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 type UseMe = ();
 
-fn qux< T>(_: T) {} //~ ERROR `#[must_use]` has no effect
+fn qux< T>(_: T) {} //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 
 #[must_use]
 trait Use {
-     //~ ERROR `#[must_use]` has no effect
+     //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     const ASSOC_CONST: usize = 4;
-     //~ ERROR `#[must_use]` has no effect
+     //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     type AssocTy;
 
     #[must_use]
@@ -78,20 +90,24 @@ trait Use {
     }
 }
 
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 impl Use for () {
     type AssocTy = ();
 
-     //~ ERROR `#[must_use]` has no effect
+     //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     fn get_four(&self) -> usize {
         4
     }
 }
 
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 trait Alias = Use;
 
- //~ ERROR `#[must_use]` has no effect
+ //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 macro_rules! cool_macro {
     () => {
         4
@@ -99,11 +115,13 @@ macro_rules! cool_macro {
 }
 
 fn main() {
-     //~ ERROR `#[must_use]` has no effect
+     //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     let x = || {};
     x();
 
-    let x =  //~ ERROR `#[must_use]` has no effect
+    let x =  //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     || {};
     x();
 
@@ -125,7 +143,8 @@ fn main() {
     let _ = ().get_four(); //~ ERROR that must be used
 
     match Some(4) {
-         //~ ERROR `#[must_use]` has no effect
+         //~ ERROR attribute cannot be used on
+        //~| WARN previously accepted
         Some(res) => res,
         None => 0,
     };
@@ -133,7 +152,9 @@ fn main() {
     struct PatternField {
         foo: i32,
     }
-    let s = PatternField {   foo: 123 }; //~ ERROR `#[must_use]` has no effect
-    let PatternField {  foo } = s; //~ ERROR `#[must_use]` has no effect
+    let s = PatternField {   foo: 123 }; //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
+    let PatternField {  foo } = s; //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     let _ = foo;
 }
diff --git a/tests/ui/lint/unused/unused_attributes-must_use.rs b/tests/ui/lint/unused/unused_attributes-must_use.rs
index edefe8ed65e..c41c6c1d706 100644
--- a/tests/ui/lint/unused/unused_attributes-must_use.rs
+++ b/tests/ui/lint/unused/unused_attributes-must_use.rs
@@ -4,18 +4,23 @@
 #![deny(unused_attributes, unused_must_use)]
 #![feature(asm_experimental_arch, stmt_expr_attributes, trait_alias)]
 
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 extern crate std as std2;
 
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 mod test_mod {}
 
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 use std::arch::global_asm;
 
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 const CONST: usize = 4;
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 #[no_mangle]
 static STATIC: usize = 4;
 
@@ -32,7 +37,8 @@ union U {
     unit: (),
 }
 
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 impl U {
     #[must_use]
     fn method() -> i32 {
@@ -46,10 +52,12 @@ fn foo() -> i64 {
     4
 }
 
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 extern "Rust" {
     #[link_name = "STATIC"]
-    #[must_use] //~ ERROR `#[must_use]` has no effect
+    #[must_use] //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     static FOREIGN_STATIC: usize;
 
     #[link_name = "foo"]
@@ -60,16 +68,20 @@ extern "Rust" {
 #[must_use] //~ ERROR unused attribute
 global_asm!("");
 
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 type UseMe = ();
 
-fn qux<#[must_use] T>(_: T) {} //~ ERROR `#[must_use]` has no effect
+fn qux<#[must_use] T>(_: T) {} //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 
 #[must_use]
 trait Use {
-    #[must_use] //~ ERROR `#[must_use]` has no effect
+    #[must_use] //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     const ASSOC_CONST: usize = 4;
-    #[must_use] //~ ERROR `#[must_use]` has no effect
+    #[must_use] //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     type AssocTy;
 
     #[must_use]
@@ -78,20 +90,24 @@ trait Use {
     }
 }
 
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 impl Use for () {
     type AssocTy = ();
 
-    #[must_use] //~ ERROR `#[must_use]` has no effect
+    #[must_use] //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     fn get_four(&self) -> usize {
         4
     }
 }
 
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 trait Alias = Use;
 
-#[must_use] //~ ERROR `#[must_use]` has no effect
+#[must_use] //~ ERROR attribute cannot be used on
+//~| WARN previously accepted
 macro_rules! cool_macro {
     () => {
         4
@@ -99,11 +115,13 @@ macro_rules! cool_macro {
 }
 
 fn main() {
-    #[must_use] //~ ERROR `#[must_use]` has no effect
+    #[must_use] //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     let x = || {};
     x();
 
-    let x = #[must_use] //~ ERROR `#[must_use]` has no effect
+    let x = #[must_use] //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     || {};
     x();
 
@@ -125,7 +143,8 @@ fn main() {
     ().get_four(); //~ ERROR that must be used
 
     match Some(4) {
-        #[must_use] //~ ERROR `#[must_use]` has no effect
+        #[must_use] //~ ERROR attribute cannot be used on
+        //~| WARN previously accepted
         Some(res) => res,
         None => 0,
     };
@@ -133,7 +152,9 @@ fn main() {
     struct PatternField {
         foo: i32,
     }
-    let s = PatternField { #[must_use]  foo: 123 }; //~ ERROR `#[must_use]` has no effect
-    let PatternField { #[must_use] foo } = s; //~ ERROR `#[must_use]` has no effect
+    let s = PatternField { #[must_use]  foo: 123 }; //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
+    let PatternField { #[must_use] foo } = s; //~ ERROR attribute cannot be used on
+    //~| WARN previously accepted
     let _ = foo;
 }
diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr
index 9e37f6504cc..12cc2ea56be 100644
--- a/tests/ui/lint/unused/unused_attributes-must_use.stderr
+++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr
@@ -1,11 +1,11 @@
 error: unused attribute `must_use`
-  --> $DIR/unused_attributes-must_use.rs:60:1
+  --> $DIR/unused_attributes-must_use.rs:68:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
    |
 note: the built-in attribute `must_use` will be ignored, since it's applied to the macro invocation `global_asm`
-  --> $DIR/unused_attributes-must_use.rs:61:1
+  --> $DIR/unused_attributes-must_use.rs:69:1
    |
 LL | global_asm!("");
    | ^^^^^^^^^^
@@ -15,134 +15,197 @@ note: the lint level is defined here
 LL | #![deny(unused_attributes, unused_must_use)]
    |         ^^^^^^^^^^^^^^^^^
 
-error: `#[must_use]` has no effect when applied to extern crates
+error: `#[must_use]` attribute cannot be used on extern crates
   --> $DIR/unused_attributes-must_use.rs:7:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to modules
-  --> $DIR/unused_attributes-must_use.rs:10:1
+error: `#[must_use]` attribute cannot be used on modules
+  --> $DIR/unused_attributes-must_use.rs:11:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to use statements
-  --> $DIR/unused_attributes-must_use.rs:13:1
+error: `#[must_use]` attribute cannot be used on use statements
+  --> $DIR/unused_attributes-must_use.rs:15:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to constants
-  --> $DIR/unused_attributes-must_use.rs:16:1
+error: `#[must_use]` attribute cannot be used on constants
+  --> $DIR/unused_attributes-must_use.rs:19:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to statics
-  --> $DIR/unused_attributes-must_use.rs:18:1
+error: `#[must_use]` attribute cannot be used on statics
+  --> $DIR/unused_attributes-must_use.rs:22:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to inherent impl blocks
-  --> $DIR/unused_attributes-must_use.rs:35:1
+error: `#[must_use]` attribute cannot be used on inherent impl blocks
+  --> $DIR/unused_attributes-must_use.rs:40:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to foreign modules
-  --> $DIR/unused_attributes-must_use.rs:49:1
+error: `#[must_use]` attribute cannot be used on foreign modules
+  --> $DIR/unused_attributes-must_use.rs:55:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to type aliases
-  --> $DIR/unused_attributes-must_use.rs:63:1
+error: `#[must_use]` attribute cannot be used on foreign statics
+  --> $DIR/unused_attributes-must_use.rs:59:5
+   |
+LL |     #[must_use]
+   |     ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
+
+error: `#[must_use]` attribute cannot be used on type aliases
+  --> $DIR/unused_attributes-must_use.rs:71:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to type parameters
-  --> $DIR/unused_attributes-must_use.rs:66:8
+error: `#[must_use]` attribute cannot be used on function params
+  --> $DIR/unused_attributes-must_use.rs:75:8
    |
 LL | fn qux<#[must_use] T>(_: T) {}
    |        ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to trait impl blocks
-  --> $DIR/unused_attributes-must_use.rs:81:1
+error: `#[must_use]` attribute cannot be used on associated consts
+  --> $DIR/unused_attributes-must_use.rs:80:5
+   |
+LL |     #[must_use]
+   |     ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
+
+error: `#[must_use]` attribute cannot be used on associated types
+  --> $DIR/unused_attributes-must_use.rs:83:5
+   |
+LL |     #[must_use]
+   |     ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
+
+error: `#[must_use]` attribute cannot be used on trait impl blocks
+  --> $DIR/unused_attributes-must_use.rs:93:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to trait aliases
-  --> $DIR/unused_attributes-must_use.rs:91:1
+error: `#[must_use]` attribute cannot be used on trait methods in impl blocks
+  --> $DIR/unused_attributes-must_use.rs:98:5
+   |
+LL |     #[must_use]
+   |     ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to data types, functions, unions, required trait methods, provided trait methods, inherent methods, foreign functions, traits
+
+error: `#[must_use]` attribute cannot be used on trait aliases
+  --> $DIR/unused_attributes-must_use.rs:105:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to macro defs
-  --> $DIR/unused_attributes-must_use.rs:94:1
+error: `#[must_use]` attribute cannot be used on macro defs
+  --> $DIR/unused_attributes-must_use.rs:109:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to statements
-  --> $DIR/unused_attributes-must_use.rs:102:5
+error: `#[must_use]` attribute cannot be used on statements
+  --> $DIR/unused_attributes-must_use.rs:118:5
    |
 LL |     #[must_use]
    |     ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to closures
-  --> $DIR/unused_attributes-must_use.rs:106:13
+error: `#[must_use]` attribute cannot be used on closures
+  --> $DIR/unused_attributes-must_use.rs:123:13
    |
 LL |     let x = #[must_use]
    |             ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to methods, data types, functions, unions, foreign functions, traits
 
-error: `#[must_use]` has no effect when applied to match arms
-  --> $DIR/unused_attributes-must_use.rs:128:9
+error: `#[must_use]` attribute cannot be used on match arms
+  --> $DIR/unused_attributes-must_use.rs:146:9
    |
 LL |         #[must_use]
    |         ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to struct fields
-  --> $DIR/unused_attributes-must_use.rs:136:28
+error: `#[must_use]` attribute cannot be used on struct fields
+  --> $DIR/unused_attributes-must_use.rs:155:28
    |
 LL |     let s = PatternField { #[must_use]  foo: 123 };
    |                            ^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
-error: `#[must_use]` has no effect when applied to pattern fields
-  --> $DIR/unused_attributes-must_use.rs:137:24
+error: `#[must_use]` attribute cannot be used on pattern fields
+  --> $DIR/unused_attributes-must_use.rs:157:24
    |
 LL |     let PatternField { #[must_use] foo } = s;
    |                        ^^^^^^^^^^^
-
-error: `#[must_use]` has no effect when applied to associated consts
-  --> $DIR/unused_attributes-must_use.rs:70:5
    |
-LL |     #[must_use]
-   |     ^^^^^^^^^^^
-
-error: `#[must_use]` has no effect when applied to associated types
-  --> $DIR/unused_attributes-must_use.rs:72:5
-   |
-LL |     #[must_use]
-   |     ^^^^^^^^^^^
-
-error: `#[must_use]` has no effect when applied to provided trait methods
-  --> $DIR/unused_attributes-must_use.rs:85:5
-   |
-LL |     #[must_use]
-   |     ^^^^^^^^^^^
-
-error: `#[must_use]` has no effect when applied to foreign statics
-  --> $DIR/unused_attributes-must_use.rs:52:5
-   |
-LL |     #[must_use]
-   |     ^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[must_use]` can be applied to functions, data types, unions, traits
 
 error: unused `X` that must be used
-  --> $DIR/unused_attributes-must_use.rs:110:5
+  --> $DIR/unused_attributes-must_use.rs:128:5
    |
 LL |     X;
    |     ^
@@ -158,7 +221,7 @@ LL |     let _ = X;
    |     +++++++
 
 error: unused `Y` that must be used
-  --> $DIR/unused_attributes-must_use.rs:111:5
+  --> $DIR/unused_attributes-must_use.rs:129:5
    |
 LL |     Y::Z;
    |     ^^^^
@@ -169,7 +232,7 @@ LL |     let _ = Y::Z;
    |     +++++++
 
 error: unused `U` that must be used
-  --> $DIR/unused_attributes-must_use.rs:112:5
+  --> $DIR/unused_attributes-must_use.rs:130:5
    |
 LL |     U { unit: () };
    |     ^^^^^^^^^^^^^^
@@ -180,7 +243,7 @@ LL |     let _ = U { unit: () };
    |     +++++++
 
 error: unused return value of `U::method` that must be used
-  --> $DIR/unused_attributes-must_use.rs:113:5
+  --> $DIR/unused_attributes-must_use.rs:131:5
    |
 LL |     U::method();
    |     ^^^^^^^^^^^
@@ -191,7 +254,7 @@ LL |     let _ = U::method();
    |     +++++++
 
 error: unused return value of `foo` that must be used
-  --> $DIR/unused_attributes-must_use.rs:114:5
+  --> $DIR/unused_attributes-must_use.rs:132:5
    |
 LL |     foo();
    |     ^^^^^
@@ -202,7 +265,7 @@ LL |     let _ = foo();
    |     +++++++
 
 error: unused return value of `foreign_foo` that must be used
-  --> $DIR/unused_attributes-must_use.rs:117:9
+  --> $DIR/unused_attributes-must_use.rs:135:9
    |
 LL |         foreign_foo();
    |         ^^^^^^^^^^^^^
@@ -213,7 +276,7 @@ LL |         let _ = foreign_foo();
    |         +++++++
 
 error: unused return value of `Use::get_four` that must be used
-  --> $DIR/unused_attributes-must_use.rs:125:5
+  --> $DIR/unused_attributes-must_use.rs:143:5
    |
 LL |     ().get_four();
    |     ^^^^^^^^^^^^^
diff --git a/tests/ui/macros/issue-111749.stderr b/tests/ui/macros/issue-111749.stderr
index 884537ef531..ae953e042e0 100644
--- a/tests/ui/macros/issue-111749.stderr
+++ b/tests/ui/macros/issue-111749.stderr
@@ -12,7 +12,7 @@ LL |     cbor_map! { #[test(test)] 4};
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 2 previous errors
 
@@ -25,5 +25,5 @@ LL |     cbor_map! { #[test(test)] 4};
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/macros/lint-trailing-macro-call.stderr b/tests/ui/macros/lint-trailing-macro-call.stderr
index 3fd1ea81345..cf836abb80f 100644
--- a/tests/ui/macros/lint-trailing-macro-call.stderr
+++ b/tests/ui/macros/lint-trailing-macro-call.stderr
@@ -11,7 +11,7 @@ LL |     expand_it!()
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
    = note: macro invocations at the end of a block are treated as expressions
    = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it`
-   = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default
+   = note: `#[deny(semicolon_in_expressions_from_macros)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
@@ -30,6 +30,6 @@ LL |     expand_it!()
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
    = note: macro invocations at the end of a block are treated as expressions
    = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it`
-   = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default
+   = note: `#[deny(semicolon_in_expressions_from_macros)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr
index 6b49c05f360..2efc0b136bc 100644
--- a/tests/ui/macros/macro-context.stderr
+++ b/tests/ui/macros/macro-context.stderr
@@ -75,7 +75,7 @@ LL |     let i = m!();
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
-   = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default
+   = note: `#[deny(semicolon_in_expressions_from_macros)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 7 previous errors
@@ -94,6 +94,6 @@ LL |     let i = m!();
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
-   = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default
+   = note: `#[deny(semicolon_in_expressions_from_macros)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/macros/macro-in-expression-context.fixed b/tests/ui/macros/macro-in-expression-context.fixed
index 52e1b429e48..1d767266025 100644
--- a/tests/ui/macros/macro-in-expression-context.fixed
+++ b/tests/ui/macros/macro-in-expression-context.fixed
@@ -8,7 +8,7 @@ macro_rules! foo {
         //~| NOTE macro invocations at the end of a block
         //~| NOTE to ignore the value produced by the macro
         //~| NOTE for more information
-        //~| NOTE `#[deny(semicolon_in_expressions_from_macros)]` on by default
+        //~| NOTE `#[deny(semicolon_in_expressions_from_macros)]` (part of `#[deny(future_incompatible)]`) on by default
         assert_eq!("B", "B");
     }
     //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following
diff --git a/tests/ui/macros/macro-in-expression-context.rs b/tests/ui/macros/macro-in-expression-context.rs
index 5c560e78dad..0bdead1b480 100644
--- a/tests/ui/macros/macro-in-expression-context.rs
+++ b/tests/ui/macros/macro-in-expression-context.rs
@@ -8,7 +8,7 @@ macro_rules! foo {
         //~| NOTE macro invocations at the end of a block
         //~| NOTE to ignore the value produced by the macro
         //~| NOTE for more information
-        //~| NOTE `#[deny(semicolon_in_expressions_from_macros)]` on by default
+        //~| NOTE `#[deny(semicolon_in_expressions_from_macros)]` (part of `#[deny(future_incompatible)]`) on by default
         assert_eq!("B", "B");
     }
     //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following
diff --git a/tests/ui/macros/macro-in-expression-context.stderr b/tests/ui/macros/macro-in-expression-context.stderr
index b04348d7010..ce5abdb94b2 100644
--- a/tests/ui/macros/macro-in-expression-context.stderr
+++ b/tests/ui/macros/macro-in-expression-context.stderr
@@ -26,7 +26,7 @@ LL |     foo!()
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
    = note: macro invocations at the end of a block are treated as expressions
    = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo`
-   = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default
+   = note: `#[deny(semicolon_in_expressions_from_macros)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
@@ -45,6 +45,6 @@ LL |     foo!()
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
    = note: macro invocations at the end of a block are treated as expressions
    = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo`
-   = note: `#[deny(semicolon_in_expressions_from_macros)]` on by default
+   = note: `#[deny(semicolon_in_expressions_from_macros)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/issues/issue-7970a.rs b/tests/ui/macros/macro-invocation-span-error-7970.rs
index dae906410ed..df7e1cfea88 100644
--- a/tests/ui/issues/issue-7970a.rs
+++ b/tests/ui/macros/macro-invocation-span-error-7970.rs
@@ -1,5 +1,8 @@
+// https://github.com/rust-lang/rust/issues/7970
 macro_rules! one_arg_macro {
-    ($fmt:expr) => (print!(concat!($fmt, "\n")));
+    ($fmt:expr) => {
+        print!(concat!($fmt, "\n"))
+    };
 }
 
 fn main() {
diff --git a/tests/ui/issues/issue-7970a.stderr b/tests/ui/macros/macro-invocation-span-error-7970.stderr
index 1e6bb92ea57..beb54e05992 100644
--- a/tests/ui/issues/issue-7970a.stderr
+++ b/tests/ui/macros/macro-invocation-span-error-7970.stderr
@@ -1,5 +1,5 @@
 error: unexpected end of macro invocation
-  --> $DIR/issue-7970a.rs:6:5
+  --> $DIR/macro-invocation-span-error-7970.rs:9:5
    |
 LL | macro_rules! one_arg_macro {
    | -------------------------- when calling this macro
@@ -8,9 +8,9 @@ LL |     one_arg_macro!();
    |     ^^^^^^^^^^^^^^^^ missing tokens in macro arguments
    |
 note: while trying to match meta-variable `$fmt:expr`
-  --> $DIR/issue-7970a.rs:2:6
+  --> $DIR/macro-invocation-span-error-7970.rs:3:6
    |
-LL |     ($fmt:expr) => (print!(concat!($fmt, "\n")));
+LL |     ($fmt:expr) => {
    |      ^^^^^^^^^
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/issues/issue-8521.rs b/tests/ui/macros/macro-path-type-bounds-8521.rs
index 78ce85787d5..975d3dc402e 100644
--- a/tests/ui/issues/issue-8521.rs
+++ b/tests/ui/macros/macro-path-type-bounds-8521.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8521
 //@ check-pass
 trait Foo1 {}
 
diff --git a/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr b/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr
index 77f8bef83a4..aad4a844ec1 100644
--- a/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr
+++ b/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr
@@ -2,7 +2,7 @@ error: cannot find derive macro `sample` in this scope
   --> $DIR/macro-rules-as-derive-or-attr-issue-132928.rs:6:10
    |
 LL | macro_rules! sample { () => {} }
-   |              ------ `sample` exists, but a declarative macro cannot be used as a derive macro
+   |              ------ `sample` exists, but has no `derive` rules
 ...
 LL | #[derive(sample)]
    |          ^^^^^^
@@ -20,7 +20,7 @@ error: cannot find derive macro `sample` in this scope
   --> $DIR/macro-rules-as-derive-or-attr-issue-132928.rs:6:10
    |
 LL | macro_rules! sample { () => {} }
-   |              ------ `sample` exists, but a declarative macro cannot be used as a derive macro
+   |              ------ `sample` exists, but has no `derive` rules
 ...
 LL | #[derive(sample)]
    |          ^^^^^^
@@ -31,7 +31,7 @@ error: cannot find derive macro `sample` in this scope
   --> $DIR/macro-rules-as-derive-or-attr-issue-132928.rs:6:10
    |
 LL | macro_rules! sample { () => {} }
-   |              ------ `sample` exists, but a declarative macro cannot be used as a derive macro
+   |              ------ `sample` exists, but has no `derive` rules
 ...
 LL | #[derive(sample)]
    |          ^^^^^^
diff --git a/tests/ui/macros/macro-rules-derive-error.rs b/tests/ui/macros/macro-rules-derive-error.rs
new file mode 100644
index 00000000000..3ef0236c528
--- /dev/null
+++ b/tests/ui/macros/macro-rules-derive-error.rs
@@ -0,0 +1,51 @@
+#![feature(macro_derive)]
+
+macro_rules! MyDerive {
+    derive() { $($body:tt)* } => {
+        compile_error!(concat!("MyDerive: ", stringify!($($body)*)));
+    };
+    //~^^ ERROR: MyDerive
+}
+
+macro_rules! fn_only {
+//~^ NOTE: `fn_only` exists, but has no `derive` rules
+//~| NOTE: `fn_only` exists, but has no `derive` rules
+    {} => {}
+}
+
+//~v NOTE: `DeriveOnly` exists, but has no rules for function-like invocation
+macro_rules! DeriveOnly {
+    derive() {} => {}
+}
+
+fn main() {
+    //~v NOTE: in this expansion of #[derive(MyDerive)]
+    #[derive(MyDerive)]
+    struct S1;
+
+    //~vv ERROR: cannot find macro `MyDerive` in this scope
+    //~| NOTE: `MyDerive` is in scope, but it is a derive
+    MyDerive!(arg);
+
+    #[derive(fn_only)]
+    struct S2;
+    //~^^ ERROR: cannot find derive macro `fn_only` in this scope
+    //~| ERROR: cannot find derive macro `fn_only` in this scope
+    //~| NOTE: duplicate diagnostic emitted
+
+    DeriveOnly!(); //~ ERROR: cannot find macro `DeriveOnly` in this scope
+}
+
+#[derive(ForwardReferencedDerive)]
+struct S;
+//~^^ ERROR: cannot find derive macro `ForwardReferencedDerive` in this scope
+//~| NOTE: consider moving the definition of `ForwardReferencedDerive` before this call
+//~| ERROR: cannot find derive macro `ForwardReferencedDerive` in this scope
+//~| NOTE: consider moving the definition of `ForwardReferencedDerive` before this call
+//~| NOTE: duplicate diagnostic emitted
+
+macro_rules! ForwardReferencedDerive {
+//~^ NOTE: a macro with the same name exists, but it appears later
+//~| NOTE: a macro with the same name exists, but it appears later
+    derive() {} => {}
+}
diff --git a/tests/ui/macros/macro-rules-derive-error.stderr b/tests/ui/macros/macro-rules-derive-error.stderr
new file mode 100644
index 00000000000..bf6f58a3686
--- /dev/null
+++ b/tests/ui/macros/macro-rules-derive-error.stderr
@@ -0,0 +1,75 @@
+error: MyDerive: struct S1;
+  --> $DIR/macro-rules-derive-error.rs:5:9
+   |
+LL |         compile_error!(concat!("MyDerive: ", stringify!($($body)*)));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     #[derive(MyDerive)]
+   |              -------- in this derive macro expansion
+   |
+   = note: this error originates in the derive macro `MyDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot find macro `MyDerive` in this scope
+  --> $DIR/macro-rules-derive-error.rs:28:5
+   |
+LL |     MyDerive!(arg);
+   |     ^^^^^^^^
+   |
+   = note: `MyDerive` is in scope, but it is a derive macro: `#[derive(MyDerive)]`
+
+error: cannot find derive macro `fn_only` in this scope
+  --> $DIR/macro-rules-derive-error.rs:30:14
+   |
+LL | macro_rules! fn_only {
+   |              ------- `fn_only` exists, but has no `derive` rules
+...
+LL |     #[derive(fn_only)]
+   |              ^^^^^^^
+
+error: cannot find derive macro `fn_only` in this scope
+  --> $DIR/macro-rules-derive-error.rs:30:14
+   |
+LL | macro_rules! fn_only {
+   |              ------- `fn_only` exists, but has no `derive` rules
+...
+LL |     #[derive(fn_only)]
+   |              ^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: cannot find macro `DeriveOnly` in this scope
+  --> $DIR/macro-rules-derive-error.rs:36:5
+   |
+LL | macro_rules! DeriveOnly {
+   |              ---------- `DeriveOnly` exists, but has no rules for function-like invocation
+...
+LL |     DeriveOnly!();
+   |     ^^^^^^^^^^
+
+error: cannot find derive macro `ForwardReferencedDerive` in this scope
+  --> $DIR/macro-rules-derive-error.rs:39:10
+   |
+LL | #[derive(ForwardReferencedDerive)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^ consider moving the definition of `ForwardReferencedDerive` before this call
+   |
+note: a macro with the same name exists, but it appears later
+  --> $DIR/macro-rules-derive-error.rs:47:14
+   |
+LL | macro_rules! ForwardReferencedDerive {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cannot find derive macro `ForwardReferencedDerive` in this scope
+  --> $DIR/macro-rules-derive-error.rs:39:10
+   |
+LL | #[derive(ForwardReferencedDerive)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^ consider moving the definition of `ForwardReferencedDerive` before this call
+   |
+note: a macro with the same name exists, but it appears later
+  --> $DIR/macro-rules-derive-error.rs:47:14
+   |
+LL | macro_rules! ForwardReferencedDerive {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/macros/macro-rules-derive.rs b/tests/ui/macros/macro-rules-derive.rs
new file mode 100644
index 00000000000..d5294330fbf
--- /dev/null
+++ b/tests/ui/macros/macro-rules-derive.rs
@@ -0,0 +1,71 @@
+//@ run-pass
+//@ check-run-results
+#![feature(macro_derive)]
+
+#[macro_export]
+macro_rules! MyExportedDerive {
+    derive() { $($body:tt)* } => {
+        println!("MyExportedDerive: body={:?}", stringify!($($body)*));
+    };
+    { $($args:tt)* } => {
+        println!("MyExportedDerive!({:?})", stringify!($($args)*));
+    };
+}
+
+macro_rules! MyLocalDerive {
+    derive() { $($body:tt)* } => {
+        println!("MyLocalDerive: body={:?}", stringify!($($body)*));
+    };
+    { $($args:tt)* } => {
+        println!("MyLocalDerive!({:?})", stringify!($($args)*));
+    };
+}
+
+trait MyTrait {
+    fn name() -> &'static str;
+}
+
+macro_rules! MyTrait {
+    derive() { struct $name:ident; } => {
+        impl MyTrait for $name {
+            fn name() -> &'static str {
+                stringify!($name)
+            }
+        }
+    };
+}
+
+#[derive(MyTrait)]
+struct MyGlobalType;
+
+fn main() {
+    #[derive(crate::MyExportedDerive)]
+    struct _S1;
+    #[derive(crate::MyExportedDerive, crate::MyExportedDerive)]
+    struct _Twice1;
+
+    crate::MyExportedDerive!();
+    crate::MyExportedDerive!(invoked, arguments);
+
+    #[derive(MyExportedDerive)]
+    struct _S2;
+    #[derive(MyExportedDerive, MyExportedDerive)]
+    struct _Twice2;
+
+    MyExportedDerive!();
+    MyExportedDerive!(invoked, arguments);
+
+    #[derive(MyLocalDerive)]
+    struct _S3;
+    #[derive(MyLocalDerive, MyLocalDerive)]
+    struct _Twice3;
+
+    MyLocalDerive!();
+    MyLocalDerive!(invoked, arguments);
+
+    #[derive(MyTrait)]
+    struct MyLocalType;
+
+    println!("MyGlobalType::name(): {}", MyGlobalType::name());
+    println!("MyLocalType::name(): {}", MyLocalType::name());
+}
diff --git a/tests/ui/macros/macro-rules-derive.run.stdout b/tests/ui/macros/macro-rules-derive.run.stdout
new file mode 100644
index 00000000000..ee492873302
--- /dev/null
+++ b/tests/ui/macros/macro-rules-derive.run.stdout
@@ -0,0 +1,17 @@
+MyExportedDerive: body="struct _S1;"
+MyExportedDerive: body="struct _Twice1;"
+MyExportedDerive: body="struct _Twice1;"
+MyExportedDerive!("")
+MyExportedDerive!("invoked, arguments")
+MyExportedDerive: body="struct _S2;"
+MyExportedDerive: body="struct _Twice2;"
+MyExportedDerive: body="struct _Twice2;"
+MyExportedDerive!("")
+MyExportedDerive!("invoked, arguments")
+MyLocalDerive: body="struct _S3;"
+MyLocalDerive: body="struct _Twice3;"
+MyLocalDerive: body="struct _Twice3;"
+MyLocalDerive!("")
+MyLocalDerive!("invoked, arguments")
+MyGlobalType::name(): MyGlobalType
+MyLocalType::name(): MyLocalType
diff --git a/tests/ui/issues/issue-7911.rs b/tests/ui/macros/macro-self-mutability-7911.rs
index 11da4df5285..5313f86d97f 100644
--- a/tests/ui/issues/issue-7911.rs
+++ b/tests/ui/macros/macro-self-mutability-7911.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/7911
 //@ run-pass
 // (Closes #7911) Test that we can use the same self expression
 // with different mutability in macro in two methods
diff --git a/tests/ui/issues/issue-7911.stderr b/tests/ui/macros/macro-self-mutability-7911.stderr
index ead7ee191ac..43335aee3ea 100644
--- a/tests/ui/issues/issue-7911.stderr
+++ b/tests/ui/macros/macro-self-mutability-7911.stderr
@@ -1,12 +1,12 @@
 warning: method `dummy` is never used
-  --> $DIR/issue-7911.rs:7:8
+  --> $DIR/macro-self-mutability-7911.rs:8:8
    |
 LL | trait FooBar {
    |       ------ method in this trait
 LL |     fn dummy(&self) { }
    |        ^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/macros/missing-derive-3.stderr b/tests/ui/macros/missing-derive-3.stderr
index 0a7ed8d0876..9ece0d3ba39 100644
--- a/tests/ui/macros/missing-derive-3.stderr
+++ b/tests/ui/macros/missing-derive-3.stderr
@@ -3,6 +3,11 @@ error: cannot find attribute `sede` in this scope
    |
 LL |     #[sede(untagged)]
    |       ^^^^
+   |
+help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
+   |
+LL |     #[serde(untagged)]
+   |         +
 
 error: cannot find attribute `serde` in this scope
   --> $DIR/missing-derive-3.rs:14:7
@@ -15,6 +20,11 @@ note: `serde` is imported here, but it is a crate, not an attribute
    |
 LL | extern crate serde;
    | ^^^^^^^^^^^^^^^^^^^
+help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Deserialize, Serialize)]
+LL | enum B {
+   |
 
 error: cannot find attribute `serde` in this scope
   --> $DIR/missing-derive-3.rs:6:3
@@ -27,6 +37,11 @@ note: `serde` is imported here, but it is a crate, not an attribute
    |
 LL | extern crate serde;
    | ^^^^^^^^^^^^^^^^^^^
+help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Deserialize, Serialize)]
+LL | enum A {
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/macros/non-fmt-panic.stderr b/tests/ui/macros/non-fmt-panic.stderr
index 83410d36586..1787316b48b 100644
--- a/tests/ui/macros/non-fmt-panic.stderr
+++ b/tests/ui/macros/non-fmt-panic.stderr
@@ -5,7 +5,7 @@ LL |     panic!("here's a brace: {");
    |                             ^
    |
    = note: this message is not used as a format string, but will be in Rust 2021
-   = note: `#[warn(non_fmt_panics)]` on by default
+   = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: add a "{}" format string to use the message literally
    |
 LL |     panic!("{}", "here's a brace: {");
diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr
index 4a00c9b4a7d..cab347a8062 100644
--- a/tests/ui/malformed/malformed-regressions.stderr
+++ b/tests/ui/malformed/malformed-regressions.stderr
@@ -7,7 +7,7 @@ LL | #[doc]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/malformed-regressions.rs:7:1
@@ -59,7 +59,7 @@ LL | #[doc]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
@@ -71,7 +71,7 @@ LL | #[link]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
@@ -83,7 +83,7 @@ LL | #[link = ""]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
@@ -94,7 +94,7 @@ LL | #[ignore()]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
@@ -105,5 +105,5 @@ LL | #[inline = ""]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/issues/issue-7867.rs b/tests/ui/match/mismatched-types-in-match-pattern-7867.rs
index 87e7c831e68..9ff8755c819 100644
--- a/tests/ui/issues/issue-7867.rs
+++ b/tests/ui/match/mismatched-types-in-match-pattern-7867.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/7867
 //@ dont-require-annotations: NOTE
 
 enum A { B, C }
diff --git a/tests/ui/issues/issue-7867.stderr b/tests/ui/match/mismatched-types-in-match-pattern-7867.stderr
index fcb69d775fa..8997f36114a 100644
--- a/tests/ui/issues/issue-7867.stderr
+++ b/tests/ui/match/mismatched-types-in-match-pattern-7867.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-7867.rs:9:9
+  --> $DIR/mismatched-types-in-match-pattern-7867.rs:10:9
    |
 LL | enum A { B, C }
    |          - unit variant defined here
diff --git a/tests/ui/methods/method-call-lifetime-args-unresolved.stderr b/tests/ui/methods/method-call-lifetime-args-unresolved.stderr
index d3bd74a49fb..a87c47a9f12 100644
--- a/tests/ui/methods/method-call-lifetime-args-unresolved.stderr
+++ b/tests/ui/methods/method-call-lifetime-args-unresolved.stderr
@@ -20,7 +20,7 @@ LL |     0.clone::<'a>();
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
-   = note: `#[warn(late_bound_lifetime_arguments)]` on by default
+   = note: `#[warn(late_bound_lifetime_arguments)]` (part of `#[warn(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/methods/method-recursive-blanket-impl.stderr b/tests/ui/methods/method-recursive-blanket-impl.stderr
index e358f80d3ff..1074893744a 100644
--- a/tests/ui/methods/method-recursive-blanket-impl.stderr
+++ b/tests/ui/methods/method-recursive-blanket-impl.stderr
@@ -4,7 +4,7 @@ warning: trait `Foo` is never used
 LL | trait Foo<A> {
    |       ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/methods/method-two-trait-defer-resolution-2.stderr b/tests/ui/methods/method-two-trait-defer-resolution-2.stderr
index 4501ea5d243..17ceb745b90 100644
--- a/tests/ui/methods/method-two-trait-defer-resolution-2.stderr
+++ b/tests/ui/methods/method-two-trait-defer-resolution-2.stderr
@@ -6,7 +6,7 @@ LL | trait MyCopy { fn foo(&self) { } }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr
index fa87ce5cc49..40f91337052 100644
--- a/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr
+++ b/tests/ui/methods/method-two-traits-distinguished-via-where-clause.stderr
@@ -4,7 +4,7 @@ warning: trait `A` is never used
 LL | trait A {
    |       ^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-7575.rs b/tests/ui/methods/trait-method-self-param-error-7575.rs
index 8b1fdf6c851..9793d43cc24 100644
--- a/tests/ui/issues/issue-7575.rs
+++ b/tests/ui/methods/trait-method-self-param-error-7575.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/7575
 //@ run-pass
 
 trait Foo { //~ WARN trait `Foo` is never used
diff --git a/tests/ui/methods/trait-method-self-param-error-7575.stderr b/tests/ui/methods/trait-method-self-param-error-7575.stderr
new file mode 100644
index 00000000000..656db30352d
--- /dev/null
+++ b/tests/ui/methods/trait-method-self-param-error-7575.stderr
@@ -0,0 +1,10 @@
+warning: trait `Foo` is never used
+  --> $DIR/trait-method-self-param-error-7575.rs:4:7
+   |
+LL | trait Foo {
+   |       ^^^
+   |
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/issues/issue-81918.rs b/tests/ui/mir/mir-cfg-unpretty-check-81918.rs
index ee9721c2493..4798a654375 100644
--- a/tests/ui/issues/issue-81918.rs
+++ b/tests/ui/mir/mir-cfg-unpretty-check-81918.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/81918
 //@ check-pass
 //@ dont-check-compiler-stdout
 //@ compile-flags: -Z unpretty=mir-cfg
diff --git a/tests/ui/mir/mir_raw_fat_ptr.stderr b/tests/ui/mir/mir_raw_fat_ptr.stderr
index cd99d566654..d1f91a79acc 100644
--- a/tests/ui/mir/mir_raw_fat_ptr.stderr
+++ b/tests/ui/mir/mir_raw_fat_ptr.stderr
@@ -6,7 +6,7 @@ LL | trait Foo { fn foo(&self) -> usize; }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr
index abc5d150a3f..62e87263967 100644
--- a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr
@@ -57,7 +57,7 @@ LL |     baz(f);
    = note: requirement occurs because of a mutable pointer to `&u32`
    = note: mutable pointers are invariant over their type parameter
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+note: due to a current limitation of the type system, this implies a `'static` lifetime
   --> $DIR/closure-arg-type-mismatch.rs:8:11
    |
 LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
diff --git a/tests/ui/issues/issue-87490.rs b/tests/ui/mismatched_types/mismatched-types-in-trait-implementation-87490.rs
index 998f61a6bd3..67e16ec6ce3 100644
--- a/tests/ui/issues/issue-87490.rs
+++ b/tests/ui/mismatched_types/mismatched-types-in-trait-implementation-87490.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/87490
 fn main() {}
 trait StreamOnce {
     type Position;
diff --git a/tests/ui/issues/issue-87490.stderr b/tests/ui/mismatched_types/mismatched-types-in-trait-implementation-87490.stderr
index 5a4ec55833b..bbd73347d02 100644
--- a/tests/ui/issues/issue-87490.stderr
+++ b/tests/ui/mismatched_types/mismatched-types-in-trait-implementation-87490.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-87490.rs:9:5
+  --> $DIR/mismatched-types-in-trait-implementation-87490.rs:10:5
    |
 LL | fn follow(_: &str) -> <&str as StreamOnce>::Position {
    |                       ------------------------------ expected `usize` because of return type
diff --git a/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr b/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr
index b1fcdfa44c3..1be612af44c 100644
--- a/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr
+++ b/tests/ui/moves/issue-22536-copy-mustnt-zero.stderr
@@ -7,7 +7,7 @@ LL |     type Buffer: Copy;
 LL |     fn foo(&self) {}
    |        ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/never_type/defaulted-never-note.nofallback.stderr b/tests/ui/never_type/defaulted-never-note.nofallback.stderr
index b7df6fb7a67..b82bea0bc48 100644
--- a/tests/ui/never_type/defaulted-never-note.nofallback.stderr
+++ b/tests/ui/never_type/defaulted-never-note.nofallback.stderr
@@ -12,7 +12,7 @@ note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will f
    |
 LL |     foo(_x);
    |         ^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     let _x: () = return;
@@ -35,7 +35,7 @@ note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will f
    |
 LL |     foo(_x);
    |         ^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     let _x: () = return;
diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr
index 6ee57d531fb..6394bab8952 100644
--- a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr
+++ b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr
@@ -12,7 +12,7 @@ note: in edition 2024, the requirement `!: Default` will fail
    |
 LL |         false => <_>::default(),
    |                   ^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL -         false => <_>::default(),
@@ -55,7 +55,7 @@ note: in edition 2024, the requirement `!: Default` will fail
    |
 LL |         false => <_>::default(),
    |                   ^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL -         false => <_>::default(),
@@ -77,7 +77,7 @@ note: in edition 2024, the requirement `!: Default` will fail
    |
 LL |     deserialize()?;
    |     ^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     deserialize::<()>()?;
diff --git a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr
index 64a8ecdf546..7f857c83655 100644
--- a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr
+++ b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr
@@ -12,7 +12,7 @@ note: in edition 2024, the requirement `!: UnitDefault` will fail
    |
 LL |         x = UnitDefault::default();
    |             ^^^^^^^^^^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     let x: ();
@@ -54,7 +54,7 @@ note: in edition 2024, the requirement `!: UnitDefault` will fail
    |
 LL |         x = UnitDefault::default();
    |             ^^^^^^^^^^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     let x: ();
@@ -75,7 +75,7 @@ note: in edition 2024, the requirement `!: UnitDefault` will fail
    |
 LL |         x = UnitDefault::default();
    |             ^^^^^^^^^^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     let x: ();
diff --git a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr
index ec48c38b6d7..d4bb5f9442e 100644
--- a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr
+++ b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr
@@ -12,7 +12,7 @@ note: in edition 2024, the requirement `!: Test` will fail
    |
 LL |     unconstrained_arg(return);
    |                       ^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     unconstrained_arg::<()>(return);
@@ -35,7 +35,7 @@ note: in edition 2024, the requirement `!: Test` will fail
    |
 LL |     unconstrained_arg(return);
    |                       ^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     unconstrained_arg::<()>(return);
diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr
index 48debdd61c8..a706ad8b09b 100644
--- a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr
+++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr
@@ -12,7 +12,7 @@ note: in edition 2024, the requirement `!: UnitReturn` will fail
    |
 LL |     let _ = if true { unconstrained_return() } else { panic!() };
    |                       ^^^^^^^^^^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     let _: () = if true { unconstrained_return() } else { panic!() };
@@ -35,7 +35,7 @@ note: in edition 2024, the requirement `!: UnitReturn` will fail
    |
 LL |     let _ = if true { unconstrained_return() } else { panic!() };
    |                       ^^^^^^^^^^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     let _: () = if true { unconstrained_return() } else { panic!() };
diff --git a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr
index 5651a265888..39b40cdd76d 100644
--- a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr
+++ b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr
@@ -12,7 +12,7 @@ note: in edition 2024, the requirement `!: Bar` will fail
    |
 LL |     foo(|| panic!());
    |     ^^^^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     foo::<()>(|| panic!());
@@ -35,7 +35,7 @@ note: in edition 2024, the requirement `!: Bar` will fail
    |
 LL |     foo(|| panic!());
    |     ^^^^^^^^^^^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |     foo::<()>(|| panic!());
diff --git a/tests/ui/never_type/impl_trait_fallback.stderr b/tests/ui/never_type/impl_trait_fallback.stderr
index 36d2eae1df2..7d8624b1fe5 100644
--- a/tests/ui/never_type/impl_trait_fallback.stderr
+++ b/tests/ui/never_type/impl_trait_fallback.stderr
@@ -12,7 +12,7 @@ note: in edition 2024, the requirement `!: T` will fail
    |
 LL | fn should_ret_unit() -> impl T {
    |                         ^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 
 warning: 1 warning emitted
 
@@ -31,5 +31,5 @@ note: in edition 2024, the requirement `!: T` will fail
    |
 LL | fn should_ret_unit() -> impl T {
    |                         ^^^^^^
-   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
index 48734f3b3f8..f9d0a89eabc 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
@@ -7,7 +7,7 @@ LL |         unsafe { mem::zeroed() }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         unsafe { mem::zeroed::<()>() }
@@ -143,7 +143,7 @@ LL |         unsafe { mem::zeroed() }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         unsafe { mem::zeroed::<()>() }
@@ -159,7 +159,7 @@ LL |             core::mem::transmute(Zst)
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |             core::mem::transmute::<_, ()>(Zst)
@@ -175,7 +175,7 @@ LL |         unsafe { Union { a: () }.b }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 
 Future breakage diagnostic:
 warning: never type fallback affects this raw pointer dereference
@@ -187,7 +187,7 @@ LL |         unsafe { *ptr::from_ref(&()).cast() }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         unsafe { *ptr::from_ref(&()).cast::<()>() }
@@ -203,7 +203,7 @@ LL |         unsafe { internally_create(x) }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         unsafe { internally_create::<()>(x) }
@@ -219,7 +219,7 @@ LL |         unsafe { zeroed() }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         let zeroed = mem::zeroed::<()>;
@@ -235,7 +235,7 @@ LL |         let zeroed = mem::zeroed;
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         let zeroed = mem::zeroed::<()>;
@@ -251,7 +251,7 @@ LL |         let f = internally_create;
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         let f = internally_create::<()>;
@@ -267,7 +267,7 @@ LL |             S(marker::PhantomData).create_out_of_thin_air()
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 
 Future breakage diagnostic:
 warning: never type fallback affects this call to an `unsafe` function
@@ -282,6 +282,6 @@ LL |         msg_send!();
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
    = note: this warning originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
index 8039ef427c1..7205c13cc2a 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
@@ -7,7 +7,7 @@ LL |         unsafe { mem::zeroed() }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         unsafe { mem::zeroed::<()>() }
@@ -152,7 +152,7 @@ LL |         unsafe { mem::zeroed() }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         unsafe { mem::zeroed::<()>() }
@@ -168,7 +168,7 @@ LL |             core::mem::transmute(Zst)
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |             core::mem::transmute::<_, ()>(Zst)
@@ -184,7 +184,7 @@ LL |         unsafe { Union { a: () }.b }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 
 Future breakage diagnostic:
 error: never type fallback affects this raw pointer dereference
@@ -196,7 +196,7 @@ LL |         unsafe { *ptr::from_ref(&()).cast() }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         unsafe { *ptr::from_ref(&()).cast::<()>() }
@@ -212,7 +212,7 @@ LL |         unsafe { internally_create(x) }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         unsafe { internally_create::<()>(x) }
@@ -228,7 +228,7 @@ LL |         unsafe { zeroed() }
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         let zeroed = mem::zeroed::<()>;
@@ -244,7 +244,7 @@ LL |         let zeroed = mem::zeroed;
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         let zeroed = mem::zeroed::<()>;
@@ -260,7 +260,7 @@ LL |         let f = internally_create;
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 help: use `()` annotations to avoid fallback changes
    |
 LL |         let f = internally_create::<()>;
@@ -276,7 +276,7 @@ LL |             S(marker::PhantomData).create_out_of_thin_air()
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
 
 Future breakage diagnostic:
 error: never type fallback affects this call to an `unsafe` function
@@ -291,6 +291,6 @@ LL |         msg_send!();
    = warning: this changes meaning in Rust 2024 and in a future release in all editions!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/never-type-fallback.html>
    = help: specify the type explicitly
-   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` (part of `#[deny(rust_2024_compatibility)]`) on by default
    = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
index 331c6510ce7..63744c15fda 100644
--- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
+++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
@@ -6,7 +6,7 @@ LL |         S1 { a: unsafe { &mut X1 } }
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
-   = note: `#[warn(static_mut_refs)]` on by default
+   = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `&raw mut` instead to create a raw pointer
    |
 LL |         S1 { a: unsafe { &raw mut X1 } }
diff --git a/tests/ui/nll/issue-48623-coroutine.stderr b/tests/ui/nll/issue-48623-coroutine.stderr
index 4e4cd28ef2a..2862d7b2a2f 100644
--- a/tests/ui/nll/issue-48623-coroutine.stderr
+++ b/tests/ui/nll/issue-48623-coroutine.stderr
@@ -5,7 +5,7 @@ LL |     #[coroutine] move || { d; yield; &mut *r };
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: coroutines are lazy and do nothing unless resumed
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/nll/local-outlives-static-via-hrtb.stderr b/tests/ui/nll/local-outlives-static-via-hrtb.stderr
index a6b3328b5a2..a98f11ce513 100644
--- a/tests/ui/nll/local-outlives-static-via-hrtb.stderr
+++ b/tests/ui/nll/local-outlives-static-via-hrtb.stderr
@@ -12,11 +12,11 @@ LL |     assert_static_via_hrtb_with_assoc_type(&&local);
 LL | }
    | - `local` dropped here while still borrowed
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
-  --> $DIR/local-outlives-static-via-hrtb.rs:15:53
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/local-outlives-static-via-hrtb.rs:15:42
    |
 LL | fn assert_static_via_hrtb<G>(_: G) where for<'a> G: Outlives<'a> {}
-   |                                                     ^^^^^^^^^^^^
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0597]: `local` does not live long enough
   --> $DIR/local-outlives-static-via-hrtb.rs:25:45
@@ -32,11 +32,11 @@ LL |     assert_static_via_hrtb_with_assoc_type(&&local);
 LL | }
    | - `local` dropped here while still borrowed
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
-  --> $DIR/local-outlives-static-via-hrtb.rs:19:20
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/local-outlives-static-via-hrtb.rs:19:5
    |
 LL |     for<'a> &'a T: Reference<AssociatedType = &'a ()>,
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr
index 1d086c658df..6e47b8e59f5 100644
--- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr
+++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr
@@ -13,11 +13,11 @@ LL |     let b = |_| &a;
 LL | }
    | - `a` dropped here while still borrowed
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
-  --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/location-insensitive-scopes-issue-117146.rs:20:11
    |
 LL | fn bad<F: Fn(&()) -> &()>(_: F) {}
-   |                      ^^^
+   |           ^^^^^^^^^^^^^^
 
 error: implementation of `Fn` is not general enough
   --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5
diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr
index 1d086c658df..6e47b8e59f5 100644
--- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr
+++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr
@@ -13,11 +13,11 @@ LL |     let b = |_| &a;
 LL | }
    | - `a` dropped here while still borrowed
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
-  --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/location-insensitive-scopes-issue-117146.rs:20:11
    |
 LL | fn bad<F: Fn(&()) -> &()>(_: F) {}
-   |                      ^^^
+   |           ^^^^^^^^^^^^^^
 
 error: implementation of `Fn` is not general enough
   --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5
diff --git a/tests/ui/nll/type-test-universe.stderr b/tests/ui/nll/type-test-universe.stderr
index 31e17d64b8c..54b48c1597b 100644
--- a/tests/ui/nll/type-test-universe.stderr
+++ b/tests/ui/nll/type-test-universe.stderr
@@ -12,11 +12,11 @@ LL | fn test2<'a>() {
 LL |     outlives_forall::<Value<'a>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
-  --> $DIR/type-test-universe.rs:6:16
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/type-test-universe.rs:6:5
    |
 LL |     for<'u> T: 'u,
-   |                ^^
+   |     ^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/overloaded/issue-14958.stderr b/tests/ui/overloaded/issue-14958.stderr
index e4f527319e7..d07dba78dc3 100644
--- a/tests/ui/overloaded/issue-14958.stderr
+++ b/tests/ui/overloaded/issue-14958.stderr
@@ -6,7 +6,7 @@ LL | trait Foo { fn dummy(&self) { }}
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/overloaded/overloaded-index-in-field.stderr b/tests/ui/overloaded/overloaded-index-in-field.stderr
index 10c0a3faeb5..5ff15ba0bcb 100644
--- a/tests/ui/overloaded/overloaded-index-in-field.stderr
+++ b/tests/ui/overloaded/overloaded-index-in-field.stderr
@@ -9,7 +9,7 @@ LL |     fn get_from_ref(&self) -> isize;
 LL |     fn inc(&mut self);
    |        ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/parser/macro/macro-attr-bad.rs b/tests/ui/parser/macro/macro-attr-bad.rs
index 4313a4d04ab..9f50b057a7a 100644
--- a/tests/ui/parser/macro/macro-attr-bad.rs
+++ b/tests/ui/parser/macro/macro-attr-bad.rs
@@ -14,10 +14,10 @@ macro_rules! attr_incomplete_4 { attr() {} => }
 //~^ ERROR macro definition ended unexpectedly
 
 macro_rules! attr_noparens_1 { attr{} {} => {} }
-//~^ ERROR macro attribute argument matchers require parentheses
+//~^ ERROR `attr` rule argument matchers require parentheses
 
 macro_rules! attr_noparens_2 { attr[] {} => {} }
-//~^ ERROR macro attribute argument matchers require parentheses
+//~^ ERROR `attr` rule argument matchers require parentheses
 
 macro_rules! attr_noparens_3 { attr _ {} => {} }
 //~^ ERROR invalid macro matcher
diff --git a/tests/ui/parser/macro/macro-attr-bad.stderr b/tests/ui/parser/macro/macro-attr-bad.stderr
index 4d286b66649..bf0ed13cd55 100644
--- a/tests/ui/parser/macro/macro-attr-bad.stderr
+++ b/tests/ui/parser/macro/macro-attr-bad.stderr
@@ -22,7 +22,7 @@ error: macro definition ended unexpectedly
 LL | macro_rules! attr_incomplete_4 { attr() {} => }
    |                                              ^ expected right-hand side of macro rule
 
-error: macro attribute argument matchers require parentheses
+error: `attr` rule argument matchers require parentheses
   --> $DIR/macro-attr-bad.rs:16:36
    |
 LL | macro_rules! attr_noparens_1 { attr{} {} => {} }
@@ -34,7 +34,7 @@ LL - macro_rules! attr_noparens_1 { attr{} {} => {} }
 LL + macro_rules! attr_noparens_1 { attr() {} => {} }
    |
 
-error: macro attribute argument matchers require parentheses
+error: `attr` rule argument matchers require parentheses
   --> $DIR/macro-attr-bad.rs:19:36
    |
 LL | macro_rules! attr_noparens_2 { attr[] {} => {} }
diff --git a/tests/ui/parser/macro/macro-attr-recovery.rs b/tests/ui/parser/macro/macro-attr-recovery.rs
index dbb795f57aa..3a942973e5e 100644
--- a/tests/ui/parser/macro/macro-attr-recovery.rs
+++ b/tests/ui/parser/macro/macro-attr-recovery.rs
@@ -3,7 +3,7 @@
 
 macro_rules! attr {
     attr[$($args:tt)*] { $($body:tt)* } => {
-        //~^ ERROR: macro attribute argument matchers require parentheses
+        //~^ ERROR: `attr` rule argument matchers require parentheses
         //~v ERROR: attr:
         compile_error!(concat!(
             "attr: args=\"",
diff --git a/tests/ui/parser/macro/macro-attr-recovery.stderr b/tests/ui/parser/macro/macro-attr-recovery.stderr
index ab3a0b7c607..e1f8dccf1b8 100644
--- a/tests/ui/parser/macro/macro-attr-recovery.stderr
+++ b/tests/ui/parser/macro/macro-attr-recovery.stderr
@@ -1,4 +1,4 @@
-error: macro attribute argument matchers require parentheses
+error: `attr` rule argument matchers require parentheses
   --> $DIR/macro-attr-recovery.rs:5:9
    |
 LL |     attr[$($args:tt)*] { $($body:tt)* } => {
diff --git a/tests/ui/parser/macro/macro-derive-bad.rs b/tests/ui/parser/macro/macro-derive-bad.rs
new file mode 100644
index 00000000000..79b9eb8c113
--- /dev/null
+++ b/tests/ui/parser/macro/macro-derive-bad.rs
@@ -0,0 +1,43 @@
+#![crate_type = "lib"]
+#![feature(macro_derive)]
+
+macro_rules! derive_incomplete_1 { derive }
+//~^ ERROR macro definition ended unexpectedly
+//~| NOTE expected `()` after `derive`
+
+macro_rules! derive_incomplete_2 { derive() }
+//~^ ERROR macro definition ended unexpectedly
+//~| NOTE expected macro derive body
+
+macro_rules! derive_incomplete_3 { derive() {} }
+//~^ ERROR expected `=>`
+//~| NOTE expected `=>`
+
+macro_rules! derive_incomplete_4 { derive() {} => }
+//~^ ERROR macro definition ended unexpectedly
+//~| NOTE expected right-hand side of macro rule
+
+macro_rules! derive_noparens_1 { derive{} {} => {} }
+//~^ ERROR `derive` rule argument matchers require parentheses
+
+macro_rules! derive_noparens_2 { derive[] {} => {} }
+//~^ ERROR `derive` rule argument matchers require parentheses
+
+macro_rules! derive_noparens_3 { derive _ {} => {} }
+//~^ ERROR `derive` must be followed by `()`
+
+macro_rules! derive_args_1 { derive($x:ident) ($y:ident) => {} }
+//~^ ERROR `derive` rules do not accept arguments
+
+macro_rules! derive_args_2 { derive() => {} }
+//~^ ERROR expected macro derive body, got `=>`
+
+macro_rules! derive_args_3 { derive($x:ident) => {} }
+//~^ ERROR `derive` rules do not accept arguments
+//~| ERROR expected macro derive body, got `=>`
+//~| NOTE need `()` after this `derive`
+
+macro_rules! derive_dup_matcher { derive() {$x:ident $x:ident} => {} }
+//~^ ERROR duplicate matcher binding
+//~| NOTE duplicate binding
+//~| NOTE previous binding
diff --git a/tests/ui/parser/macro/macro-derive-bad.stderr b/tests/ui/parser/macro/macro-derive-bad.stderr
new file mode 100644
index 00000000000..ec750c9ac82
--- /dev/null
+++ b/tests/ui/parser/macro/macro-derive-bad.stderr
@@ -0,0 +1,90 @@
+error: macro definition ended unexpectedly
+  --> $DIR/macro-derive-bad.rs:4:42
+   |
+LL | macro_rules! derive_incomplete_1 { derive }
+   |                                          ^ expected `()` after `derive`
+
+error: macro definition ended unexpectedly
+  --> $DIR/macro-derive-bad.rs:8:44
+   |
+LL | macro_rules! derive_incomplete_2 { derive() }
+   |                                            ^ expected macro derive body
+
+error: expected `=>`, found end of macro arguments
+  --> $DIR/macro-derive-bad.rs:12:47
+   |
+LL | macro_rules! derive_incomplete_3 { derive() {} }
+   |                                               ^ expected `=>`
+
+error: macro definition ended unexpectedly
+  --> $DIR/macro-derive-bad.rs:16:50
+   |
+LL | macro_rules! derive_incomplete_4 { derive() {} => }
+   |                                                  ^ expected right-hand side of macro rule
+
+error: `derive` rule argument matchers require parentheses
+  --> $DIR/macro-derive-bad.rs:20:40
+   |
+LL | macro_rules! derive_noparens_1 { derive{} {} => {} }
+   |                                        ^^
+   |
+help: the delimiters should be `(` and `)`
+   |
+LL - macro_rules! derive_noparens_1 { derive{} {} => {} }
+LL + macro_rules! derive_noparens_1 { derive() {} => {} }
+   |
+
+error: `derive` rule argument matchers require parentheses
+  --> $DIR/macro-derive-bad.rs:23:40
+   |
+LL | macro_rules! derive_noparens_2 { derive[] {} => {} }
+   |                                        ^^
+   |
+help: the delimiters should be `(` and `)`
+   |
+LL - macro_rules! derive_noparens_2 { derive[] {} => {} }
+LL + macro_rules! derive_noparens_2 { derive() {} => {} }
+   |
+
+error: `derive` rules do not accept arguments; `derive` must be followed by `()`
+  --> $DIR/macro-derive-bad.rs:26:41
+   |
+LL | macro_rules! derive_noparens_3 { derive _ {} => {} }
+   |                                         ^
+
+error: `derive` rules do not accept arguments; `derive` must be followed by `()`
+  --> $DIR/macro-derive-bad.rs:29:36
+   |
+LL | macro_rules! derive_args_1 { derive($x:ident) ($y:ident) => {} }
+   |                                    ^^^^^^^^^^
+
+error: expected macro derive body, got `=>`
+  --> $DIR/macro-derive-bad.rs:32:39
+   |
+LL | macro_rules! derive_args_2 { derive() => {} }
+   |                                       ^^
+
+error: `derive` rules do not accept arguments; `derive` must be followed by `()`
+  --> $DIR/macro-derive-bad.rs:35:36
+   |
+LL | macro_rules! derive_args_3 { derive($x:ident) => {} }
+   |                                    ^^^^^^^^^^
+
+error: expected macro derive body, got `=>`
+  --> $DIR/macro-derive-bad.rs:35:47
+   |
+LL | macro_rules! derive_args_3 { derive($x:ident) => {} }
+   |                              ------           ^^
+   |                              |
+   |                              need `()` after this `derive`
+
+error: duplicate matcher binding
+  --> $DIR/macro-derive-bad.rs:40:54
+   |
+LL | macro_rules! derive_dup_matcher { derive() {$x:ident $x:ident} => {} }
+   |                                             -------- ^^^^^^^^ duplicate binding
+   |                                             |
+   |                                             previous binding
+
+error: aborting due to 12 previous errors
+
diff --git a/tests/ui/parser/recover/recover-pat-ranges.stderr b/tests/ui/parser/recover/recover-pat-ranges.stderr
index 246c704d53f..afa7f254054 100644
--- a/tests/ui/parser/recover/recover-pat-ranges.stderr
+++ b/tests/ui/parser/recover/recover-pat-ranges.stderr
@@ -192,7 +192,7 @@ LL |         (1 + 4)...1 * 2 => (),
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default
+   = note: `#[warn(ellipsis_inclusive_range_patterns)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 
 error: aborting due to 13 previous errors; 1 warning emitted
 
diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr
index 8d7938a1a46..f584197c98e 100644
--- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr
+++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr
@@ -17,7 +17,7 @@ warning: type `v` should have an upper camel case name
 LL | type v = [isize * 3];
    |      ^ help: convert the identifier to upper camel case (notice the capitalization): `V`
    |
-   = note: `#[warn(non_camel_case_types)]` on by default
+   = note: `#[warn(non_camel_case_types)]` (part of `#[warn(nonstandard_style)]`) on by default
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/parser/trait-object-lifetime-parens.e2015.stderr b/tests/ui/parser/trait-object-lifetime-parens.e2015.stderr
index cf0b3d77f5b..4f4f89de5d1 100644
--- a/tests/ui/parser/trait-object-lifetime-parens.e2015.stderr
+++ b/tests/ui/parser/trait-object-lifetime-parens.e2015.stderr
@@ -1,4 +1,4 @@
-error: parenthesized lifetime bounds are not supported
+error: lifetime bounds may not be parenthesized
   --> $DIR/trait-object-lifetime-parens.rs:9:21
    |
 LL | fn f<'a, T: Trait + ('a)>() {}
@@ -10,7 +10,7 @@ LL - fn f<'a, T: Trait + ('a)>() {}
 LL + fn f<'a, T: Trait + 'a>() {}
    |
 
-error: parenthesized lifetime bounds are not supported
+error: lifetime bounds may not be parenthesized
   --> $DIR/trait-object-lifetime-parens.rs:12:24
    |
 LL |     let _: Box<Trait + ('a)>;
diff --git a/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr b/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr
index b65c079788a..a4e2501cfdf 100644
--- a/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr
+++ b/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr
@@ -1,4 +1,4 @@
-error: parenthesized lifetime bounds are not supported
+error: lifetime bounds may not be parenthesized
   --> $DIR/trait-object-lifetime-parens.rs:9:21
    |
 LL | fn f<'a, T: Trait + ('a)>() {}
@@ -10,7 +10,7 @@ LL - fn f<'a, T: Trait + ('a)>() {}
 LL + fn f<'a, T: Trait + 'a>() {}
    |
 
-error: parenthesized lifetime bounds are not supported
+error: lifetime bounds may not be parenthesized
   --> $DIR/trait-object-lifetime-parens.rs:12:24
    |
 LL |     let _: Box<Trait + ('a)>;
diff --git a/tests/ui/parser/trait-object-lifetime-parens.rs b/tests/ui/parser/trait-object-lifetime-parens.rs
index 0ff4660bb0d..47a6884b316 100644
--- a/tests/ui/parser/trait-object-lifetime-parens.rs
+++ b/tests/ui/parser/trait-object-lifetime-parens.rs
@@ -6,10 +6,10 @@
 
 trait Trait {}
 
-fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not supported
+fn f<'a, T: Trait + ('a)>() {} //~ ERROR lifetime bounds may not be parenthesized
 
 fn check<'a>() {
-    let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
+    let _: Box<Trait + ('a)>; //~ ERROR lifetime bounds may not be parenthesized
     //[e2021]~^ ERROR expected a type, found a trait
     // FIXME: It'd be great if we could suggest removing the parentheses here too.
     //[e2015]~v ERROR lifetimes must be followed by `+` to form a trait object type
diff --git a/tests/ui/parser/trait-object-trait-parens.stderr b/tests/ui/parser/trait-object-trait-parens.stderr
index b2067547568..f498d7d36bb 100644
--- a/tests/ui/parser/trait-object-trait-parens.stderr
+++ b/tests/ui/parser/trait-object-trait-parens.stderr
@@ -24,7 +24,7 @@ LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL |     let _: Box<dyn (Obj) + (?Sized) + (for<'a> Trait<'a>)>;
diff --git a/tests/ui/issues/issue-8391.rs b/tests/ui/pattern/match-with-at-binding-8391.rs
index 20698eed18b..bc4e7be7989 100644
--- a/tests/ui/issues/issue-8391.rs
+++ b/tests/ui/pattern/match-with-at-binding-8391.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8391
 //@ run-pass
 
 fn main() {
diff --git a/tests/ui/issues/issue-8860.rs b/tests/ui/pattern/ref-in-function-parameter-patterns-8860.rs
index 3af61576fe1..1a67caf021c 100644
--- a/tests/ui/issues/issue-8860.rs
+++ b/tests/ui/pattern/ref-in-function-parameter-patterns-8860.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8860
 //@ run-pass
 // FIXME(static_mut_refs): this could use an atomic
 #![allow(static_mut_refs)]
diff --git a/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr b/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr
index f7fd4a4cc29..9580bab2b4f 100644
--- a/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr
+++ b/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr
@@ -4,7 +4,7 @@ warning: struct `Foo` is never constructed
 LL | struct Foo;
    |        ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: unused closure that must be used
   --> $DIR/skipped-ref-pats-issue-125058.rs:11:5
@@ -18,7 +18,7 @@ LL | |     };
    | |_____^
    |
    = note: closures are lazy and do nothing unless called
-   = note: `#[warn(unused_must_use)]` on by default
+   = note: `#[warn(unused_must_use)]` (part of `#[warn(unused)]`) on by default
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.fixed b/tests/ui/privacy/inaccessible-fields-pattern-matching-76077.fixed
index 6fde4e390fa..7d648543a20 100644
--- a/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.fixed
+++ b/tests/ui/privacy/inaccessible-fields-pattern-matching-76077.fixed
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/76077
 //@ run-rustfix
 #![allow(dead_code, unused_variables)]
 
diff --git a/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.rs b/tests/ui/privacy/inaccessible-fields-pattern-matching-76077.rs
index 30a8535faf5..f3b51187ae3 100644
--- a/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.rs
+++ b/tests/ui/privacy/inaccessible-fields-pattern-matching-76077.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/76077
 //@ run-rustfix
 #![allow(dead_code, unused_variables)]
 
diff --git a/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.stderr b/tests/ui/privacy/inaccessible-fields-pattern-matching-76077.stderr
index f54990d5d86..070fa1a53a5 100644
--- a/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.stderr
+++ b/tests/ui/privacy/inaccessible-fields-pattern-matching-76077.stderr
@@ -1,5 +1,5 @@
 error: pattern requires `..` due to inaccessible fields
-  --> $DIR/issue-76077-1.rs:13:9
+  --> $DIR/inaccessible-fields-pattern-matching-76077.rs:14:9
    |
 LL |     let foo::Foo {} = foo::Foo::default();
    |         ^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |     let foo::Foo { .. } = foo::Foo::default();
    |                    ++
 
 error: pattern requires `..` due to inaccessible fields
-  --> $DIR/issue-76077-1.rs:16:9
+  --> $DIR/inaccessible-fields-pattern-matching-76077.rs:17:9
    |
 LL |     let foo::Bar { visible } = foo::Bar::default();
    |         ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/privacy/macro-private-reexport.stderr b/tests/ui/privacy/macro-private-reexport.stderr
index b8768f3612e..aa02715c202 100644
--- a/tests/ui/privacy/macro-private-reexport.stderr
+++ b/tests/ui/privacy/macro-private-reexport.stderr
@@ -11,6 +11,10 @@ LL | /     macro_rules! bar {
 LL | |         () => {};
 LL | |     }
    | |_____^
+help: in case you want to use the macro within this crate only, reduce the visibility to `pub(crate)`
+   |
+LL |     pub(crate) use bar as _;
+   |        +++++++
 
 error[E0364]: `baz` is private, and cannot be re-exported
   --> $DIR/macro-private-reexport.rs:14:13
diff --git a/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077.rs b/tests/ui/privacy/private-field-struct-construction-76077.rs
index 2d29093b01b..7fc3473e8de 100644
--- a/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077.rs
+++ b/tests/ui/privacy/private-field-struct-construction-76077.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/76077
 pub mod foo {
     pub struct Foo {
         you_cant_use_this_field: bool,
diff --git a/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077.stderr b/tests/ui/privacy/private-field-struct-construction-76077.stderr
index 3fef5ffce30..5131db72fe3 100644
--- a/tests/ui/issues/issue-76077-inaccesible-private-fields/issue-76077.stderr
+++ b/tests/ui/privacy/private-field-struct-construction-76077.stderr
@@ -1,5 +1,5 @@
 error: cannot construct `Foo` with struct literal syntax due to private fields
-  --> $DIR/issue-76077.rs:8:5
+  --> $DIR/private-field-struct-construction-76077.rs:9:5
    |
 LL |     foo::Foo {};
    |     ^^^^^^^^
diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr
index 65989375ab5..2e4ddd19b7e 100644
--- a/tests/ui/proc-macro/derive-helper-shadowing.stderr
+++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr
@@ -69,7 +69,7 @@ LL | #[derive(Empty)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
-   = note: `#[deny(legacy_derive_helpers)]` on by default
+   = note: `#[deny(legacy_derive_helpers)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 5 previous errors
 
@@ -86,5 +86,5 @@ LL | #[derive(Empty)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
-   = note: `#[deny(legacy_derive_helpers)]` on by default
+   = note: `#[deny(legacy_derive_helpers)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/proc-macro/generate-mod.stderr b/tests/ui/proc-macro/generate-mod.stderr
index cbe6b14ca9a..142ff1abeed 100644
--- a/tests/ui/proc-macro/generate-mod.stderr
+++ b/tests/ui/proc-macro/generate-mod.stderr
@@ -46,7 +46,7 @@ LL | #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: cannot find type `OuterDerive` in this scope
@@ -91,7 +91,7 @@ LL | #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
@@ -103,7 +103,7 @@ LL | #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
@@ -115,7 +115,7 @@ LL |     #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
@@ -127,7 +127,7 @@ LL |     #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default
    = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
diff --git a/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr b/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr
index df7951464fb..88e829521f9 100644
--- a/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr
+++ b/tests/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr
@@ -28,7 +28,7 @@ LL | #[derive(Empty)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
-   = note: `#[deny(legacy_derive_helpers)]` on by default
+   = note: `#[deny(legacy_derive_helpers)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 2 previous errors
 
@@ -45,5 +45,5 @@ LL | #[derive(Empty)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
-   = note: `#[deny(legacy_derive_helpers)]` on by default
+   = note: `#[deny(legacy_derive_helpers)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/proc-macro/proc-macro-attributes.stderr b/tests/ui/proc-macro/proc-macro-attributes.stderr
index 892728901fb..6a1387a3b1c 100644
--- a/tests/ui/proc-macro/proc-macro-attributes.stderr
+++ b/tests/ui/proc-macro/proc-macro-attributes.stderr
@@ -93,7 +93,7 @@ LL | #[derive(B)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
-   = note: `#[deny(legacy_derive_helpers)]` on by default
+   = note: `#[deny(legacy_derive_helpers)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: derive helper attribute is used before it is introduced
   --> $DIR/proc-macro-attributes.rs:10:3
@@ -146,7 +146,7 @@ LL | #[derive(B)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
-   = note: `#[deny(legacy_derive_helpers)]` on by default
+   = note: `#[deny(legacy_derive_helpers)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: derive helper attribute is used before it is introduced
@@ -160,7 +160,7 @@ LL | #[derive(B)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
-   = note: `#[deny(legacy_derive_helpers)]` on by default
+   = note: `#[deny(legacy_derive_helpers)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: derive helper attribute is used before it is introduced
@@ -174,7 +174,7 @@ LL | #[derive(B)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
-   = note: `#[deny(legacy_derive_helpers)]` on by default
+   = note: `#[deny(legacy_derive_helpers)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error: derive helper attribute is used before it is introduced
@@ -188,5 +188,5 @@ LL | #[derive(B)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
-   = note: `#[deny(legacy_derive_helpers)]` on by default
+   = note: `#[deny(legacy_derive_helpers)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/pub/pub-reexport-priv-extern-crate.stderr b/tests/ui/pub/pub-reexport-priv-extern-crate.stderr
index 9bb64a3325b..dbb080e1b09 100644
--- a/tests/ui/pub/pub-reexport-priv-extern-crate.stderr
+++ b/tests/ui/pub/pub-reexport-priv-extern-crate.stderr
@@ -30,7 +30,7 @@ LL | pub use core as reexported_core;
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #127909 <https://github.com/rust-lang/rust/issues/127909>
-   = note: `#[deny(pub_use_of_private_extern_crate)]` on by default
+   = note: `#[deny(pub_use_of_private_extern_crate)]` (part of `#[deny(future_incompatible)]`) on by default
 help: consider making the `extern crate` item publicly accessible
    |
 LL | pub extern crate core;
@@ -49,7 +49,7 @@ LL | pub use core as reexported_core;
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #127909 <https://github.com/rust-lang/rust/issues/127909>
-   = note: `#[deny(pub_use_of_private_extern_crate)]` on by default
+   = note: `#[deny(pub_use_of_private_extern_crate)]` (part of `#[deny(future_incompatible)]`) on by default
 help: consider making the `extern crate` item publicly accessible
    |
 LL | pub extern crate core;
diff --git a/tests/ui/reachable/expr_cast.rs b/tests/ui/reachable/expr_cast.rs
index e8e477ea4f6..aa412c99b2e 100644
--- a/tests/ui/reachable/expr_cast.rs
+++ b/tests/ui/reachable/expr_cast.rs
@@ -1,13 +1,21 @@
-#![allow(unused_variables)]
-#![allow(unused_assignments)]
-#![allow(dead_code)]
+//@ check-pass
+//@ edition: 2024
+//
+// Check that we don't warn on `as` casts of never to any as unreachable.
+// While they *are* unreachable, sometimes they are required to appeal typeck.
 #![deny(unreachable_code)]
-#![feature(never_type, type_ascription)]
 
 fn a() {
-    // the cast is unreachable:
-    let x = {return} as !; //~ ERROR unreachable
-    //~| ERROR non-primitive cast
+    _ = {return} as u32;
 }
 
-fn main() { }
+fn b() {
+    (return) as u32;
+}
+
+// example that needs an explicit never-to-any `as` cast
+fn example() -> impl Iterator<Item = u8> {
+    todo!() as std::iter::Empty<_>
+}
+
+fn main() {}
diff --git a/tests/ui/reachable/expr_cast.stderr b/tests/ui/reachable/expr_cast.stderr
deleted file mode 100644
index 6643f1784a1..00000000000
--- a/tests/ui/reachable/expr_cast.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error: unreachable expression
-  --> $DIR/expr_cast.rs:9:13
-   |
-LL |     let x = {return} as !;
-   |             ^------^^^^^^
-   |             ||
-   |             |any code following this expression is unreachable
-   |             unreachable expression
-   |
-note: the lint level is defined here
-  --> $DIR/expr_cast.rs:4:9
-   |
-LL | #![deny(unreachable_code)]
-   |         ^^^^^^^^^^^^^^^^
-
-error[E0605]: non-primitive cast: `()` as `!`
-  --> $DIR/expr_cast.rs:9:13
-   |
-LL |     let x = {return} as !;
-   |             ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0605`.
diff --git a/tests/ui/reachable/unreachable-try-pattern.rs b/tests/ui/reachable/unreachable-try-pattern.rs
index 22cbfb95af0..1358722e229 100644
--- a/tests/ui/reachable/unreachable-try-pattern.rs
+++ b/tests/ui/reachable/unreachable-try-pattern.rs
@@ -18,7 +18,7 @@ fn bar(x: Result<!, i32>) -> Result<u32, i32> {
 fn foo(x: Result<!, i32>) -> Result<u32, i32> {
     let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?;
     //~^ WARN unreachable pattern
-    //~| WARN unreachable expression
+    //~| WARN unreachable call
     Ok(y)
 }
 
diff --git a/tests/ui/reachable/unreachable-try-pattern.stderr b/tests/ui/reachable/unreachable-try-pattern.stderr
index 40b11613105..468af427249 100644
--- a/tests/ui/reachable/unreachable-try-pattern.stderr
+++ b/tests/ui/reachable/unreachable-try-pattern.stderr
@@ -1,11 +1,10 @@
-warning: unreachable expression
-  --> $DIR/unreachable-try-pattern.rs:19:36
+warning: unreachable call
+  --> $DIR/unreachable-try-pattern.rs:19:33
    |
 LL |     let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?;
-   |                                    -^^^^^^^
-   |                                    |
-   |                                    unreachable expression
-   |                                    any code following this expression is unreachable
+   |                                 ^^ - any code following this expression is unreachable
+   |                                 |
+   |                                 unreachable call
    |
 note: the lint level is defined here
   --> $DIR/unreachable-try-pattern.rs:3:9
diff --git a/tests/ui/issues/issue-8727.rs b/tests/ui/recursion/infinite-function-recursion-error-8727.rs
index c1b60e8e085..a4037f76109 100644
--- a/tests/ui/issues/issue-8727.rs
+++ b/tests/ui/recursion/infinite-function-recursion-error-8727.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8727
 // Verify the compiler fails with an error on infinite function
 // recursions.
 
@@ -9,7 +10,6 @@ fn generic<T>() { //~ WARN function cannot return without recursing
 }
 //~^^ ERROR reached the recursion limit while instantiating `generic::<Option<
 
-
 fn main () {
     // Use generic<T> at least once to trigger instantiation.
     generic::<i32>();
diff --git a/tests/ui/issues/issue-8727.stderr b/tests/ui/recursion/infinite-function-recursion-error-8727.stderr
index 9fb09a7d4f4..13d57ecb3b2 100644
--- a/tests/ui/issues/issue-8727.stderr
+++ b/tests/ui/recursion/infinite-function-recursion-error-8727.stderr
@@ -1,5 +1,5 @@
 warning: function cannot return without recursing
-  --> $DIR/issue-8727.rs:7:1
+  --> $DIR/infinite-function-recursion-error-8727.rs:8:1
    |
 LL | fn generic<T>() {
    | ^^^^^^^^^^^^^^^ cannot return without recursing
@@ -10,17 +10,17 @@ LL |     generic::<Option<T>>();
    = note: `#[warn(unconditional_recursion)]` on by default
 
 error: reached the recursion limit while instantiating `generic::<Option<Option<Option<Option<...>>>>>`
-  --> $DIR/issue-8727.rs:8:5
+  --> $DIR/infinite-function-recursion-error-8727.rs:9:5
    |
 LL |     generic::<Option<T>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `generic` defined here
-  --> $DIR/issue-8727.rs:7:1
+  --> $DIR/infinite-function-recursion-error-8727.rs:8:1
    |
 LL | fn generic<T>() {
    | ^^^^^^^^^^^^^^^
-   = note: the full name for the type has been written to '$TEST_BUILD_DIR/issue-8727.long-type-$LONG_TYPE_HASH.txt'
+   = note: the full name for the type has been written to '$TEST_BUILD_DIR/infinite-function-recursion-error-8727.long-type-$LONG_TYPE_HASH.txt'
    = note: consider using `--verbose` to print the full type name to the console
 
 error: aborting due to 1 previous error; 1 warning emitted
diff --git a/tests/ui/repr/conflicting-repr-hints.stderr b/tests/ui/repr/conflicting-repr-hints.stderr
index fbfa69e7fb1..4da3d454e03 100644
--- a/tests/ui/repr/conflicting-repr-hints.stderr
+++ b/tests/ui/repr/conflicting-repr-hints.stderr
@@ -6,7 +6,7 @@ LL | #[repr(C, u64)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
-   = note: `#[deny(conflicting_repr_hints)]` on by default
+   = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error[E0566]: conflicting representation hints
   --> $DIR/conflicting-repr-hints.rs:19:8
@@ -90,7 +90,7 @@ LL | #[repr(C, u64)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
-   = note: `#[deny(conflicting_repr_hints)]` on by default
+   = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default
 
 Future breakage diagnostic:
 error[E0566]: conflicting representation hints
@@ -101,5 +101,5 @@ LL | #[repr(u32, u64)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
-   = note: `#[deny(conflicting_repr_hints)]` on by default
+   = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default
 
diff --git a/tests/ui/issues/issue-7663.rs b/tests/ui/resolve/module-import-resolution-7663.rs
index d2b2c727cab..872806594fc 100644
--- a/tests/ui/issues/issue-7663.rs
+++ b/tests/ui/resolve/module-import-resolution-7663.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/7663
 //@ run-pass
 
 #![allow(unused_imports, dead_code)]
diff --git a/tests/ui/resolve/path-attr-in-const-block.stderr b/tests/ui/resolve/path-attr-in-const-block.stderr
index f3ae5b60c4f..23f4e319c6d 100644
--- a/tests/ui/resolve/path-attr-in-const-block.stderr
+++ b/tests/ui/resolve/path-attr-in-const-block.stderr
@@ -11,7 +11,7 @@ LL |         #![path = foo!()]
    |         ^^^^^^^^^^------^
    |         |         |
    |         |         expected a string literal here
-   |         help: must be of the form: `#[path = "file"]`
+   |         help: must be of the form: `#![path = "file"]`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute>
 
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.stderr
index 24b35a2ab31..689ccb4bc9a 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/protect-precedences.stderr
@@ -6,7 +6,7 @@ LL |         if let _ = return true && false {};
    |                    |
    |                    any code following this expression is unreachable
    |
-   = note: `#[warn(unreachable_code)]` on by default
+   = note: `#[warn(unreachable_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/rust-2018/uniform-paths/macro-rules.stderr b/tests/ui/rust-2018/uniform-paths/macro-rules.stderr
index 661d667eb9a..43eacd5413f 100644
--- a/tests/ui/rust-2018/uniform-paths/macro-rules.stderr
+++ b/tests/ui/rust-2018/uniform-paths/macro-rules.stderr
@@ -9,6 +9,10 @@ help: consider adding a `#[macro_export]` to the macro in the imported module
    |
 LL |     macro_rules! legacy_macro { () => () }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: in case you want to use the macro within this crate only, reduce the visibility to `pub(crate)`
+   |
+LL |     pub(crate) use legacy_macro as _;
+   |        +++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/sanitize-attr/invalid-sanitize.rs b/tests/ui/sanitize-attr/invalid-sanitize.rs
new file mode 100644
index 00000000000..49dc01c8daa
--- /dev/null
+++ b/tests/ui/sanitize-attr/invalid-sanitize.rs
@@ -0,0 +1,22 @@
+#![feature(sanitize)]
+
+#[sanitize(brontosaurus = "off")] //~ ERROR invalid argument
+fn main() {
+}
+
+#[sanitize(address = "off")] //~ ERROR multiple `sanitize` attributes
+#[sanitize(address = "off")]
+fn multiple_consistent() {}
+
+#[sanitize(address = "on")] //~ ERROR multiple `sanitize` attributes
+#[sanitize(address = "off")]
+fn multiple_inconsistent() {}
+
+#[sanitize(address = "bogus")] //~ ERROR invalid argument for `sanitize`
+fn wrong_value() {}
+
+#[sanitize = "off"] //~ ERROR malformed `sanitize` attribute input
+fn name_value () {}
+
+#[sanitize] //~ ERROR malformed `sanitize` attribute input
+fn just_word() {}
diff --git a/tests/ui/sanitize-attr/invalid-sanitize.stderr b/tests/ui/sanitize-attr/invalid-sanitize.stderr
new file mode 100644
index 00000000000..4bf81770b89
--- /dev/null
+++ b/tests/ui/sanitize-attr/invalid-sanitize.stderr
@@ -0,0 +1,82 @@
+error: malformed `sanitize` attribute input
+  --> $DIR/invalid-sanitize.rs:18:1
+   |
+LL | #[sanitize = "off"]
+   | ^^^^^^^^^^^^^^^^^^^
+   |
+help: the following are the possible correct uses
+   |
+LL - #[sanitize = "off"]
+LL + #[sanitize(address = "on|off")]
+   |
+LL - #[sanitize = "off"]
+LL + #[sanitize(cfi = "on|off")]
+   |
+LL - #[sanitize = "off"]
+LL + #[sanitize(hwaddress = "on|off")]
+   |
+LL - #[sanitize = "off"]
+LL + #[sanitize(kcfi = "on|off")]
+   |
+   = and 5 other candidates
+
+error: malformed `sanitize` attribute input
+  --> $DIR/invalid-sanitize.rs:21:1
+   |
+LL | #[sanitize]
+   | ^^^^^^^^^^^
+   |
+help: the following are the possible correct uses
+   |
+LL | #[sanitize(address = "on|off")]
+   |           ++++++++++++++++++++
+LL | #[sanitize(cfi = "on|off")]
+   |           ++++++++++++++++
+LL | #[sanitize(hwaddress = "on|off")]
+   |           ++++++++++++++++++++++
+LL | #[sanitize(kcfi = "on|off")]
+   |           +++++++++++++++++
+   = and 5 other candidates
+
+error: multiple `sanitize` attributes
+  --> $DIR/invalid-sanitize.rs:7:1
+   |
+LL | #[sanitize(address = "off")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/invalid-sanitize.rs:8:1
+   |
+LL | #[sanitize(address = "off")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: multiple `sanitize` attributes
+  --> $DIR/invalid-sanitize.rs:11:1
+   |
+LL | #[sanitize(address = "on")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/invalid-sanitize.rs:12:1
+   |
+LL | #[sanitize(address = "off")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: invalid argument for `sanitize`
+  --> $DIR/invalid-sanitize.rs:3:1
+   |
+LL | #[sanitize(brontosaurus = "off")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: expected one of: `address`, `kernel_address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow_call_stack`, or `thread`
+
+error: invalid argument for `sanitize`
+  --> $DIR/invalid-sanitize.rs:15:1
+   |
+LL | #[sanitize(address = "bogus")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: expected one of: `address`, `kernel_address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow_call_stack`, or `thread`
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/sanitize-attr/valid-sanitize.rs b/tests/ui/sanitize-attr/valid-sanitize.rs
new file mode 100644
index 00000000000..ebe76fcba04
--- /dev/null
+++ b/tests/ui/sanitize-attr/valid-sanitize.rs
@@ -0,0 +1,115 @@
+//! Tests where the `#[sanitize(..)]` attribute can and cannot be used.
+
+#![feature(sanitize)]
+#![feature(extern_types)]
+#![feature(impl_trait_in_assoc_type)]
+#![warn(unused_attributes)]
+#![sanitize(address = "off", thread = "on")]
+
+#[sanitize(address = "off", thread = "on")]
+mod submod {}
+
+#[sanitize(address = "off")]
+static FOO: u32 = 0;
+
+#[sanitize(thread = "off")] //~ ERROR sanitize attribute not allowed here
+static BAR: u32 = 0;
+
+#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+type MyTypeAlias = ();
+
+#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+trait MyTrait {
+    #[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+    const TRAIT_ASSOC_CONST: u32;
+
+    #[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+    type TraitAssocType;
+
+    #[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+    fn trait_method(&self);
+
+    #[sanitize(address = "off", thread = "on")]
+    fn trait_method_with_default(&self) {}
+
+    #[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+    fn trait_assoc_fn();
+}
+
+#[sanitize(address = "off")]
+impl MyTrait for () {
+    const TRAIT_ASSOC_CONST: u32 = 0;
+
+    #[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+    type TraitAssocType = Self;
+
+    #[sanitize(address = "off", thread = "on")]
+    fn trait_method(&self) {}
+    #[sanitize(address = "off", thread = "on")]
+    fn trait_method_with_default(&self) {}
+    #[sanitize(address = "off", thread = "on")]
+    fn trait_assoc_fn() {}
+}
+
+trait HasAssocType {
+    type T;
+    fn constrain_assoc_type() -> Self::T;
+}
+
+impl HasAssocType for () {
+    #[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+    type T = impl Copy;
+    fn constrain_assoc_type() -> Self::T {}
+}
+
+#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+struct MyStruct {
+    #[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+    field: u32,
+}
+
+#[sanitize(address = "off", thread = "on")]
+impl MyStruct {
+    #[sanitize(address = "off", thread = "on")]
+    fn method(&self) {}
+    #[sanitize(address = "off", thread = "on")]
+    fn assoc_fn() {}
+}
+
+extern "C" {
+    #[sanitize(address = "off", thread = "on")] //~ ERROR sanitize attribute not allowed here
+    static X: u32;
+
+    #[sanitize(address = "off", thread = "on")] //~ ERROR sanitize attribute not allowed here
+    type T;
+
+    #[sanitize(address = "off", thread = "on")] //~ ERROR sanitize attribute not allowed here
+    fn foreign_fn();
+}
+
+#[sanitize(address = "off", thread = "on")]
+fn main() {
+    #[sanitize(address = "off", thread = "on")] //~ ERROR sanitize attribute not allowed here
+    let _ = ();
+
+    // Currently not allowed on let statements, even if they bind to a closure.
+    // It might be nice to support this as a special case someday, but trying
+    // to define the precise boundaries of that special case might be tricky.
+    #[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+    let _let_closure = || ();
+
+    // In situations where attributes can already be applied to expressions,
+    // the sanitize attribute is allowed on closure expressions.
+    let _closure_tail_expr = {
+        #[sanitize(address = "off", thread = "on")]
+        || ()
+    };
+
+    match () {
+        #[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+        () => (),
+    }
+
+    #[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
+    return ();
+}
diff --git a/tests/ui/sanitize-attr/valid-sanitize.stderr b/tests/ui/sanitize-attr/valid-sanitize.stderr
new file mode 100644
index 00000000000..ff9fe63eaf5
--- /dev/null
+++ b/tests/ui/sanitize-attr/valid-sanitize.stderr
@@ -0,0 +1,190 @@
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:15:1
+   |
+LL | #[sanitize(thread = "off")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | static BAR: u32 = 0;
+   | -------------------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:18:1
+   |
+LL | #[sanitize(address = "off")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | type MyTypeAlias = ();
+   | ---------------------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:21:1
+   |
+LL |   #[sanitize(address = "off")]
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait MyTrait {
+LL | |     #[sanitize(address = "off")]
+LL | |     const TRAIT_ASSOC_CONST: u32;
+...  |
+LL | |     fn trait_assoc_fn();
+LL | | }
+   | |_- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:65:1
+   |
+LL |   #[sanitize(address = "off")]
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / struct MyStruct {
+LL | |     #[sanitize(address = "off")]
+LL | |     field: u32,
+LL | | }
+   | |_- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:67:5
+   |
+LL |     #[sanitize(address = "off")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     field: u32,
+   |     ---------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:92:5
+   |
+LL |     #[sanitize(address = "off", thread = "on")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _ = ();
+   |     ----------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:98:5
+   |
+LL |     #[sanitize(address = "off")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _let_closure = || ();
+   |     ------------------------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:109:9
+   |
+LL |         #[sanitize(address = "off")]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         () => (),
+   |         -------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:113:5
+   |
+LL |     #[sanitize(address = "off")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     return ();
+   |     --------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:23:5
+   |
+LL |     #[sanitize(address = "off")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     const TRAIT_ASSOC_CONST: u32;
+   |     ----------------------------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:26:5
+   |
+LL |     #[sanitize(address = "off")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     type TraitAssocType;
+   |     -------------------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:29:5
+   |
+LL |     #[sanitize(address = "off")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fn trait_method(&self);
+   |     ----------------------- function has no body
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:35:5
+   |
+LL |     #[sanitize(address = "off")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fn trait_assoc_fn();
+   |     -------------------- function has no body
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:43:5
+   |
+LL |     #[sanitize(address = "off")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     type TraitAssocType = Self;
+   |     --------------------------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:60:5
+   |
+LL |     #[sanitize(address = "off")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     type T = impl Copy;
+   |     ------------------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:80:5
+   |
+LL |     #[sanitize(address = "off", thread = "on")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     static X: u32;
+   |     -------------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:83:5
+   |
+LL |     #[sanitize(address = "off", thread = "on")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     type T;
+   |     ------- not a function, impl block, or module
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: sanitize attribute not allowed here
+  --> $DIR/valid-sanitize.rs:86:5
+   |
+LL |     #[sanitize(address = "off", thread = "on")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fn foreign_fn();
+   |     ---------------- function has no body
+   |
+   = help: sanitize attribute can be applied to a function (with body), impl block, or module
+
+error: aborting due to 18 previous errors
+
diff --git a/tests/ui/sanitizer/inline-always.rs b/tests/ui/sanitizer/inline-always-sanitize.rs
index d92daee3026..d6ee214e9b3 100644
--- a/tests/ui/sanitizer/inline-always.rs
+++ b/tests/ui/sanitizer/inline-always-sanitize.rs
@@ -1,11 +1,11 @@
 //@ check-pass
 
-#![feature(no_sanitize)]
+#![feature(sanitize)]
 
 #[inline(always)]
 //~^ NOTE inlining requested here
-#[no_sanitize(address)]
-//~^ WARN will have no effect after inlining
+#[sanitize(address = "off")]
+//~^ WARN  setting `sanitize` off will have no effect after inlining
 //~| NOTE on by default
 fn x() {
 }
diff --git a/tests/ui/sanitizer/inline-always-sanitize.stderr b/tests/ui/sanitizer/inline-always-sanitize.stderr
new file mode 100644
index 00000000000..ed479472169
--- /dev/null
+++ b/tests/ui/sanitizer/inline-always-sanitize.stderr
@@ -0,0 +1,15 @@
+warning: setting `sanitize` off will have no effect after inlining
+  --> $DIR/inline-always-sanitize.rs:7:1
+   |
+LL | #[sanitize(address = "off")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: inlining requested here
+  --> $DIR/inline-always-sanitize.rs:5:1
+   |
+LL | #[inline(always)]
+   | ^^^^^^^^^^^^^^^^^
+   = note: `#[warn(inline_no_sanitize)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/sanitizer/inline-always.stderr b/tests/ui/sanitizer/inline-always.stderr
deleted file mode 100644
index 74fba3c0e0e..00000000000
--- a/tests/ui/sanitizer/inline-always.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: `no_sanitize` will have no effect after inlining
-  --> $DIR/inline-always.rs:7:1
-   |
-LL | #[no_sanitize(address)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: inlining requested here
-  --> $DIR/inline-always.rs:5:1
-   |
-LL | #[inline(always)]
-   | ^^^^^^^^^^^^^^^^^
-   = note: `#[warn(inline_no_sanitize)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/self/self-ctor-nongeneric.stderr b/tests/ui/self/self-ctor-nongeneric.stderr
index 6c03c6f3e38..b53ecbe55b5 100644
--- a/tests/ui/self/self-ctor-nongeneric.stderr
+++ b/tests/ui/self/self-ctor-nongeneric.stderr
@@ -9,7 +9,7 @@ LL |         const C: S0 = Self(0);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #124186 <https://github.com/rust-lang/rust/issues/124186>
-   = note: `#[warn(self_constructor_from_outer_item)]` on by default
+   = note: `#[warn(self_constructor_from_outer_item)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: can't reference `Self` constructor from outer item
   --> $DIR/self-ctor-nongeneric.rs:12:13
diff --git a/tests/ui/sized/coinductive-2.stderr b/tests/ui/sized/coinductive-2.stderr
index 1390b1f8d7b..5faec7397e2 100644
--- a/tests/ui/sized/coinductive-2.stderr
+++ b/tests/ui/sized/coinductive-2.stderr
@@ -4,7 +4,7 @@ warning: trait `Collection` is never used
 LL | trait Collection<T>: Sized {
    |       ^^^^^^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/span/issue-24690.stderr b/tests/ui/span/issue-24690.stderr
index 73e166e6403..8626108c0be 100644
--- a/tests/ui/span/issue-24690.stderr
+++ b/tests/ui/span/issue-24690.stderr
@@ -17,7 +17,7 @@ warning: variable `theTwo` should have a snake case name
 LL |     let theTwo = 2;
    |         ^^^^^^ help: convert the identifier to snake case: `the_two`
    |
-   = note: `#[warn(non_snake_case)]` on by default
+   = note: `#[warn(non_snake_case)]` (part of `#[warn(nonstandard_style)]`) on by default
 
 warning: variable `theOtherTwo` should have a snake case name
   --> $DIR/issue-24690.rs:13:9
diff --git a/tests/ui/issues/issue-8578.rs b/tests/ui/static/static-struct-with-option-8578.rs
index 9baa2f70a02..d490a3f50b4 100644
--- a/tests/ui/issues/issue-8578.rs
+++ b/tests/ui/static/static-struct-with-option-8578.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8578
 //@ check-pass
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
diff --git a/tests/ui/statics/issue-15261.stderr b/tests/ui/statics/issue-15261.stderr
index 60c5fb93dba..20ac0785245 100644
--- a/tests/ui/statics/issue-15261.stderr
+++ b/tests/ui/statics/issue-15261.stderr
@@ -6,7 +6,7 @@ LL | static n: &'static usize = unsafe { &n_mut };
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
-   = note: `#[warn(static_mut_refs)]` on by default
+   = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `&raw const` instead to create a raw pointer
    |
 LL | static n: &'static usize = unsafe { &raw const n_mut };
diff --git a/tests/ui/statics/static-impl.stderr b/tests/ui/statics/static-impl.stderr
index 83c3ffbefe1..77785d1df0e 100644
--- a/tests/ui/statics/static-impl.stderr
+++ b/tests/ui/statics/static-impl.stderr
@@ -7,7 +7,7 @@ LL |     fn length_(&self, ) -> usize;
 LL |     fn iter_<F>(&self, f: F) where F: FnMut(&T);
    |        ^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/statics/static-mut-shared-parens.stderr b/tests/ui/statics/static-mut-shared-parens.stderr
index 16daee091a8..c900fcde16f 100644
--- a/tests/ui/statics/static-mut-shared-parens.stderr
+++ b/tests/ui/statics/static-mut-shared-parens.stderr
@@ -6,7 +6,7 @@ LL |     let _ = unsafe { (&TEST) as *const usize };
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
-   = note: `#[warn(static_mut_refs)]` on by default
+   = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `&raw const` instead to create a raw pointer
    |
 LL |     let _ = unsafe { (&raw const TEST) as *const usize };
diff --git a/tests/ui/statics/static-mut-xc.stderr b/tests/ui/statics/static-mut-xc.stderr
index 2e5aa1b2645..73c4e91b8e0 100644
--- a/tests/ui/statics/static-mut-xc.stderr
+++ b/tests/ui/statics/static-mut-xc.stderr
@@ -6,7 +6,7 @@ LL |     assert_eq!(static_mut_xc::a, 3);
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
-   = note: `#[warn(static_mut_refs)]` on by default
+   = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 
 warning: creating a shared reference to mutable static
   --> $DIR/static-mut-xc.rs:22:16
diff --git a/tests/ui/statics/static-recursive.stderr b/tests/ui/statics/static-recursive.stderr
index 0c3f961372b..16d5e183ccb 100644
--- a/tests/ui/statics/static-recursive.stderr
+++ b/tests/ui/statics/static-recursive.stderr
@@ -6,7 +6,7 @@ LL | static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
    |
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html>
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
-   = note: `#[warn(static_mut_refs)]` on by default
+   = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 help: use `&raw const` instead to create a raw pointer
    |
 LL | static mut S: *const u8 = unsafe { &raw const S as *const *const u8 as *const u8 };
diff --git a/tests/ui/std/issue-3563-3.stderr b/tests/ui/std/issue-3563-3.stderr
index bd65c1e3fd5..5885bafeb99 100644
--- a/tests/ui/std/issue-3563-3.stderr
+++ b/tests/ui/std/issue-3563-3.stderr
@@ -7,7 +7,7 @@ LL | trait Canvas {
 LL |     fn add_points(&mut self, shapes: &[Point]) {
    |        ^^^^^^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr b/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr
index 670fa5bb922..8108296621c 100644
--- a/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr
+++ b/tests/ui/stdlib-unit-tests/raw-fat-ptr.stderr
@@ -6,7 +6,7 @@ LL | trait Foo { fn foo(&self) -> usize; }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/auxiliary/issue-8044.rs b/tests/ui/structs-enums/auxiliary/aux-8044.rs
index 2ec25f51cde..2ec25f51cde 100644
--- a/tests/ui/issues/auxiliary/issue-8044.rs
+++ b/tests/ui/structs-enums/auxiliary/aux-8044.rs
diff --git a/tests/ui/structs-enums/enum-null-pointer-opt.stderr b/tests/ui/structs-enums/enum-null-pointer-opt.stderr
index 64e93ffaffd..178d76cd732 100644
--- a/tests/ui/structs-enums/enum-null-pointer-opt.stderr
+++ b/tests/ui/structs-enums/enum-null-pointer-opt.stderr
@@ -6,7 +6,7 @@ LL | trait Trait { fn dummy(&self) { } }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/structs-enums/struct-and-enum-usage-8044.rs b/tests/ui/structs-enums/struct-and-enum-usage-8044.rs
new file mode 100644
index 00000000000..9b544f33f1c
--- /dev/null
+++ b/tests/ui/structs-enums/struct-and-enum-usage-8044.rs
@@ -0,0 +1,10 @@
+// https://github.com/rust-lang/rust/issues/8044
+//@ run-pass
+//@ aux-build:aux-8044.rs
+
+extern crate aux_8044 as minimal;
+use minimal::{BTree, leaf};
+
+pub fn main() {
+    BTree::<isize> { node: leaf(1) };
+}
diff --git a/tests/ui/issues/issue-8783.rs b/tests/ui/structs/destructuring-struct-type-inference-8783.rs
index d0ff79f8ac8..60bc4bf3289 100644
--- a/tests/ui/issues/issue-8783.rs
+++ b/tests/ui/structs/destructuring-struct-type-inference-8783.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8783
 //@ run-pass
 #![allow(unused_variables)]
 
diff --git a/tests/ui/suggestions/dont-try-removing-the-field.stderr b/tests/ui/suggestions/dont-try-removing-the-field.stderr
index 263171a4ac4..e327b21417a 100644
--- a/tests/ui/suggestions/dont-try-removing-the-field.stderr
+++ b/tests/ui/suggestions/dont-try-removing-the-field.stderr
@@ -4,7 +4,7 @@ warning: unused variable: `baz`
 LL |     let Foo { foo, bar, baz } = x;
    |                         ^^^ help: try ignoring the field: `baz: _`
    |
-   = note: `#[warn(unused_variables)]` on by default
+   = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr
index 696151b6ee2..8bb2bb290d3 100644
--- a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr
+++ b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr
@@ -12,7 +12,7 @@ LL |     std::ptr::from_ref(num).cast_mut().as_deref();
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
-   = note: `#[warn(tyvar_behind_raw_pointer)]` on by default
+   = note: `#[warn(tyvar_behind_raw_pointer)]` (part of `#[warn(rust_2018_compatibility)]`) on by default
 
 warning: type annotations needed
   --> $DIR/ice-unwrap-probe-many-result-125876.rs:5:40
diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr
index e7173d91438..475cc849625 100644
--- a/tests/ui/suggestions/issue-116434-2015.stderr
+++ b/tests/ui/suggestions/issue-116434-2015.stderr
@@ -6,7 +6,7 @@ LL |     fn foo() -> Clone;
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL |     fn foo() -> dyn Clone;
diff --git a/tests/ui/suggestions/partialeq_suggest_swap_on_e0277.stderr b/tests/ui/suggestions/partialeq_suggest_swap_on_e0277.stderr
index ebe103ef19a..c5984f53f68 100644
--- a/tests/ui/suggestions/partialeq_suggest_swap_on_e0277.stderr
+++ b/tests/ui/suggestions/partialeq_suggest_swap_on_e0277.stderr
@@ -10,6 +10,8 @@ LL |     String::from("Girls Band Cry") == T(String::from("Girls Band Cry"));
              `String` implements `PartialEq<ByteStr>`
              `String` implements `PartialEq<ByteString>`
              `String` implements `PartialEq<Cow<'_, str>>`
+             `String` implements `PartialEq<Path>`
+             `String` implements `PartialEq<PathBuf>`
              `String` implements `PartialEq<str>`
              `String` implements `PartialEq`
    = note: `T` implements `PartialEq<String>`
diff --git a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
index d90dd201bcf..72ac7209bdf 100644
--- a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
+++ b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
@@ -69,7 +69,7 @@ LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL | impl<'a, T> Struct<T> for dyn Trait<'a, T> {}
diff --git a/tests/ui/suggestions/try-removing-the-field.stderr b/tests/ui/suggestions/try-removing-the-field.stderr
index 7a6013d4a6e..aaf260bb86e 100644
--- a/tests/ui/suggestions/try-removing-the-field.stderr
+++ b/tests/ui/suggestions/try-removing-the-field.stderr
@@ -6,7 +6,7 @@ LL |     let Foo { foo, bar, .. } = x;
    |                    |
    |                    help: try removing the field
    |
-   = note: `#[warn(unused_variables)]` on by default
+   = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
 
 warning: unused variable: `unused`
   --> $DIR/try-removing-the-field.rs:20:20
diff --git a/tests/ui/issues/issue-83048.rs b/tests/ui/thir-print/break-outside-loop-error-83048.rs
index 6c941133a15..6dcebd77c27 100644
--- a/tests/ui/issues/issue-83048.rs
+++ b/tests/ui/thir-print/break-outside-loop-error-83048.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/83048
 //@ compile-flags: -Z unpretty=thir-tree
 
 pub fn main() {
diff --git a/tests/ui/issues/issue-83048.stderr b/tests/ui/thir-print/break-outside-loop-error-83048.stderr
index 672bf69a732..65a08e62e3d 100644
--- a/tests/ui/issues/issue-83048.stderr
+++ b/tests/ui/thir-print/break-outside-loop-error-83048.stderr
@@ -1,5 +1,5 @@
 error[E0268]: `break` outside of a loop or labeled block
-  --> $DIR/issue-83048.rs:4:5
+  --> $DIR/break-outside-loop-error-83048.rs:5:5
    |
 LL |     break;
    |     ^^^^^ cannot `break` outside of a loop or labeled block
diff --git a/tests/ui/issues/issue-87707.rs b/tests/ui/track-diagnostics/track-caller-for-once-87707.rs
index a0da8a740ac..9b450943f5d 100644
--- a/tests/ui/issues/issue-87707.rs
+++ b/tests/ui/track-diagnostics/track-caller-for-once-87707.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/87707
 // test for #87707
 //@ edition:2018
 //@ run-fail
diff --git a/tests/ui/issues/issue-87707.run.stderr b/tests/ui/track-diagnostics/track-caller-for-once-87707.run.stderr
index 8485c0578b8..093df62836b 100644
--- a/tests/ui/issues/issue-87707.run.stderr
+++ b/tests/ui/track-diagnostics/track-caller-for-once-87707.run.stderr
@@ -1,7 +1,7 @@
 
-thread 'main' ($TID) panicked at $DIR/issue-87707.rs:14:24:
+thread 'main' ($TID) panicked at $DIR/track-caller-for-once-87707.rs:15:24:
 Here Once instance is poisoned.
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
-thread 'main' ($TID) panicked at $DIR/issue-87707.rs:16:7:
+thread 'main' ($TID) panicked at $DIR/track-caller-for-once-87707.rs:17:7:
 Once instance has previously been poisoned
diff --git a/tests/ui/issues/issue-87199.rs b/tests/ui/trait-bounds/relaxed-bounds-assumed-unsized-87199.rs
index dd9dfc74ca3..f3baa4b1feb 100644
--- a/tests/ui/issues/issue-87199.rs
+++ b/tests/ui/trait-bounds/relaxed-bounds-assumed-unsized-87199.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/87199
 // Regression test for issue #87199, where attempting to relax a bound
 // other than the only supported `?Sized` would still cause the compiler
 // to assume that the `Sized` bound was relaxed.
diff --git a/tests/ui/issues/issue-87199.stderr b/tests/ui/trait-bounds/relaxed-bounds-assumed-unsized-87199.stderr
index 8a930a3d704..16223676c06 100644
--- a/tests/ui/issues/issue-87199.stderr
+++ b/tests/ui/trait-bounds/relaxed-bounds-assumed-unsized-87199.stderr
@@ -1,23 +1,23 @@
 error: bound modifier `?` can only be applied to `Sized`
-  --> $DIR/issue-87199.rs:8:11
+  --> $DIR/relaxed-bounds-assumed-unsized-87199.rs:9:11
    |
 LL | fn arg<T: ?Send>(_: T) {}
    |           ^^^^^
 
 error: bound modifier `?` can only be applied to `Sized`
-  --> $DIR/issue-87199.rs:10:15
+  --> $DIR/relaxed-bounds-assumed-unsized-87199.rs:11:15
    |
 LL | fn ref_arg<T: ?Send>(_: &T) {}
    |               ^^^^^
 
 error: bound modifier `?` can only be applied to `Sized`
-  --> $DIR/issue-87199.rs:12:40
+  --> $DIR/relaxed-bounds-assumed-unsized-87199.rs:13:40
    |
 LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
    |                                        ^^^^^
 
 error: bound modifier `?` can only be applied to `Sized`
-  --> $DIR/issue-87199.rs:12:40
+  --> $DIR/relaxed-bounds-assumed-unsized-87199.rs:13:40
    |
 LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
    |                                        ^^^^^
@@ -25,14 +25,14 @@ LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
-  --> $DIR/issue-87199.rs:19:15
+  --> $DIR/relaxed-bounds-assumed-unsized-87199.rs:20:15
    |
 LL |     ref_arg::<[i32]>(&[5]);
    |               ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[i32]`
 note: required by an implicit `Sized` bound in `ref_arg`
-  --> $DIR/issue-87199.rs:10:12
+  --> $DIR/relaxed-bounds-assumed-unsized-87199.rs:11:12
    |
 LL | fn ref_arg<T: ?Send>(_: &T) {}
    |            ^ required by the implicit `Sized` requirement on this type parameter in `ref_arg`
diff --git a/tests/ui/traits/alias/bounds.stderr b/tests/ui/traits/alias/bounds.stderr
index 7fb8e918da3..215a9b57fbf 100644
--- a/tests/ui/traits/alias/bounds.stderr
+++ b/tests/ui/traits/alias/bounds.stderr
@@ -4,7 +4,7 @@ warning: trait `Empty` is never used
 LL | trait Empty {}
    |       ^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/traits/alias/style_lint.stderr b/tests/ui/traits/alias/style_lint.stderr
index 91e2ea90eb9..e11e51c018f 100644
--- a/tests/ui/traits/alias/style_lint.stderr
+++ b/tests/ui/traits/alias/style_lint.stderr
@@ -4,7 +4,7 @@ warning: trait alias `bar` should have an upper camel case name
 LL | trait bar = std::fmt::Display + std::fmt::Debug;
    |       ^^^ help: convert the identifier to upper camel case: `Bar`
    |
-   = note: `#[warn(non_camel_case_types)]` on by default
+   = note: `#[warn(non_camel_case_types)]` (part of `#[warn(nonstandard_style)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/auxiliary/issue-9123.rs b/tests/ui/traits/auxiliary/aux-9123.rs
index 60af53359e8..60af53359e8 100644
--- a/tests/ui/issues/auxiliary/issue-9123.rs
+++ b/tests/ui/traits/auxiliary/aux-9123.rs
diff --git a/tests/ui/traits/bound/not-on-bare-trait.stderr b/tests/ui/traits/bound/not-on-bare-trait.stderr
index 69413ca96cd..fa2c531d535 100644
--- a/tests/ui/traits/bound/not-on-bare-trait.stderr
+++ b/tests/ui/traits/bound/not-on-bare-trait.stderr
@@ -6,7 +6,7 @@ LL | fn foo(_x: Foo + Send) {
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL | fn foo(_x: dyn Foo + Send) {
diff --git a/tests/ui/traits/const-traits/const-supertraits-dyn-compat.rs b/tests/ui/traits/const-traits/const-supertraits-dyn-compat.rs
new file mode 100644
index 00000000000..2d12bc81af6
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-supertraits-dyn-compat.rs
@@ -0,0 +1,18 @@
+#![feature(const_trait_impl)]
+
+const trait Super {}
+
+// Not ok
+const trait Unconditionally: const Super {}
+fn test() {
+    let _: &dyn Unconditionally;
+    //~^ ERROR the trait `Unconditionally` is not dyn compatible
+}
+
+// Okay
+const trait Conditionally: [const] Super {}
+fn test2() {
+    let _: &dyn Conditionally;
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/const-supertraits-dyn-compat.stderr b/tests/ui/traits/const-traits/const-supertraits-dyn-compat.stderr
new file mode 100644
index 00000000000..ceb07081c9e
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-supertraits-dyn-compat.stderr
@@ -0,0 +1,18 @@
+error[E0038]: the trait `Unconditionally` is not dyn compatible
+  --> $DIR/const-supertraits-dyn-compat.rs:8:17
+   |
+LL |     let _: &dyn Unconditionally;
+   |                 ^^^^^^^^^^^^^^^ `Unconditionally` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/const-supertraits-dyn-compat.rs:6:30
+   |
+LL | const trait Unconditionally: const Super {}
+   |             ---------------  ^^^^^^^^^^^ ...because it cannot have a `const` supertrait
+   |             |
+   |             this trait is not dyn compatible...
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr
index 9fad260f0be..7a4061d9c18 100644
--- a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr
+++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr
@@ -45,7 +45,7 @@ LL | demo! { impl const Trait }
    |
    = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
    = note: this warning originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: you might have intended to implement this trait for a given type
    |
diff --git a/tests/ui/traits/default-method-fn-call-9123.rs b/tests/ui/traits/default-method-fn-call-9123.rs
new file mode 100644
index 00000000000..266b95ca960
--- /dev/null
+++ b/tests/ui/traits/default-method-fn-call-9123.rs
@@ -0,0 +1,7 @@
+// https://github.com/rust-lang/rust/issues/9123
+//@ run-pass
+//@ aux-build:aux-9123.rs
+
+extern crate aux_9123;
+
+pub fn main() {}
diff --git a/tests/ui/traits/default-method/bound-subst4.stderr b/tests/ui/traits/default-method/bound-subst4.stderr
index 548c46f1233..62be4c3a8fc 100644
--- a/tests/ui/traits/default-method/bound-subst4.stderr
+++ b/tests/ui/traits/default-method/bound-subst4.stderr
@@ -7,7 +7,7 @@ LL |     fn g(&self, x: usize) -> usize { x }
 LL |     fn h(&self, x: T) { }
    |        ^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/traits/impl-inherent-prefer-over-trait.stderr b/tests/ui/traits/impl-inherent-prefer-over-trait.stderr
index f0bb21402d8..14b3e4d903f 100644
--- a/tests/ui/traits/impl-inherent-prefer-over-trait.stderr
+++ b/tests/ui/traits/impl-inherent-prefer-over-trait.stderr
@@ -6,7 +6,7 @@ LL | trait Trait {
 LL |     fn bar(&self);
    |        ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/traits/impl-object-overlap-issue-23853.stderr b/tests/ui/traits/impl-object-overlap-issue-23853.stderr
index 9fa7a36816e..bdab0ae3532 100644
--- a/tests/ui/traits/impl-object-overlap-issue-23853.stderr
+++ b/tests/ui/traits/impl-object-overlap-issue-23853.stderr
@@ -6,7 +6,7 @@ LL | trait Foo { fn dummy(&self) { } }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/traits/impl.stderr b/tests/ui/traits/impl.stderr
index 9216a33c1d0..c17957f1e64 100644
--- a/tests/ui/traits/impl.stderr
+++ b/tests/ui/traits/impl.stderr
@@ -6,7 +6,7 @@ LL | trait T {
 LL |     fn t(&self) {}
    |        ^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/traits/issue-38033.stderr b/tests/ui/traits/issue-38033.stderr
index 05385e8cf4d..fb713c564cf 100644
--- a/tests/ui/traits/issue-38033.stderr
+++ b/tests/ui/traits/issue-38033.stderr
@@ -7,7 +7,7 @@ LL | trait IntoFuture {
 LL |     fn into_future(self) -> Self::Future;
    |        ^^^^^^^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/traits/issue-6128.stderr b/tests/ui/traits/issue-6128.stderr
index c9518ea41ea..1c0460df69e 100644
--- a/tests/ui/traits/issue-6128.stderr
+++ b/tests/ui/traits/issue-6128.stderr
@@ -8,7 +8,7 @@ LL |     fn f(&self, _: Edge);
 LL |     fn g(&self, _: Node);
    |        ^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
index a0bfc524252..40ebf8f36af 100644
--- a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
+++ b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
@@ -6,7 +6,7 @@ LL | impl Foo<i64> {
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL | impl dyn Foo<i64> {
diff --git a/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr b/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr
index 25313a477f7..8a9c2206331 100644
--- a/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr
+++ b/tests/ui/traits/multidispatch-conditional-impl-not-considered.stderr
@@ -4,7 +4,7 @@ warning: trait `Foo` is never used
 LL | trait Foo {
    |       ^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/traits/multidispatch-infer-convert-target.stderr b/tests/ui/traits/multidispatch-infer-convert-target.stderr
index c8c1b642719..fbf57e9327f 100644
--- a/tests/ui/traits/multidispatch-infer-convert-target.stderr
+++ b/tests/ui/traits/multidispatch-infer-convert-target.stderr
@@ -6,7 +6,7 @@ LL | trait Convert<Target> {
 LL |     fn convert(&self) -> Target;
    |        ^^^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/issues/issue-8249.rs b/tests/ui/traits/mut-trait-in-struct-8249.rs
index 2364fc14d31..b6dcd848b8b 100644
--- a/tests/ui/issues/issue-8249.rs
+++ b/tests/ui/traits/mut-trait-in-struct-8249.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8249
 //@ run-pass
 #![allow(dead_code)]
 
diff --git a/tests/ui/traits/negative-bounds/negative-metasized.current.stderr b/tests/ui/traits/negative-bounds/negative-metasized.current.stderr
new file mode 100644
index 00000000000..4ff51651336
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/negative-metasized.current.stderr
@@ -0,0 +1,39 @@
+error[E0277]: the trait bound `T: !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:12:11
+   |
+LL |     foo::<T>();
+   |           ^ the trait bound `T: !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error[E0277]: the trait bound `(): !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:17:11
+   |
+LL |     foo::<()>();
+   |           ^^ the trait bound `(): !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error[E0277]: the trait bound `str: !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:19:11
+   |
+LL |     foo::<str>();
+   |           ^^^ the trait bound `str: !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/negative-bounds/negative-metasized.next.stderr b/tests/ui/traits/negative-bounds/negative-metasized.next.stderr
new file mode 100644
index 00000000000..4ff51651336
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/negative-metasized.next.stderr
@@ -0,0 +1,39 @@
+error[E0277]: the trait bound `T: !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:12:11
+   |
+LL |     foo::<T>();
+   |           ^ the trait bound `T: !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error[E0277]: the trait bound `(): !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:17:11
+   |
+LL |     foo::<()>();
+   |           ^^ the trait bound `(): !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error[E0277]: the trait bound `str: !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:19:11
+   |
+LL |     foo::<str>();
+   |           ^^^ the trait bound `str: !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/negative-bounds/negative-metasized.rs b/tests/ui/traits/negative-bounds/negative-metasized.rs
new file mode 100644
index 00000000000..479037be852
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/negative-metasized.rs
@@ -0,0 +1,21 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+#![feature(negative_bounds)]
+#![feature(sized_hierarchy)]
+
+use std::marker::MetaSized;
+
+fn foo<T: !MetaSized>() {}
+
+fn bar<T: !Sized + MetaSized>() {
+    foo::<T>();
+    //~^ ERROR the trait bound `T: !MetaSized` is not satisfied
+}
+
+fn main() {
+    foo::<()>();
+    //~^ ERROR the trait bound `(): !MetaSized` is not satisfied
+    foo::<str>();
+    //~^ ERROR the trait bound `str: !MetaSized` is not satisfied
+}
diff --git a/tests/ui/issues/issue-7673-cast-generically-implemented-trait.rs b/tests/ui/traits/polymorphic-trait-creation-7673.rs
index edba3284e31..643818ffe1e 100644
--- a/tests/ui/issues/issue-7673-cast-generically-implemented-trait.rs
+++ b/tests/ui/traits/polymorphic-trait-creation-7673.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/7673
 //@ check-pass
 #![allow(dead_code)]
 
diff --git a/tests/ui/issues/issue-8171-default-method-self-inherit-builtin-trait.rs b/tests/ui/traits/self-implements-kinds-in-default-methods-8171.rs
index 6a03404cdca..59ea62c7690 100644
--- a/tests/ui/issues/issue-8171-default-method-self-inherit-builtin-trait.rs
+++ b/tests/ui/traits/self-implements-kinds-in-default-methods-8171.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8171
 //@ check-pass
 #![allow(dead_code)]
 
diff --git a/tests/ui/issues/issue-7563.rs b/tests/ui/traits/trait-implementation-and-usage-7563.rs
index 9ee8857b999..8cfc7a14ffe 100644
--- a/tests/ui/issues/issue-7563.rs
+++ b/tests/ui/traits/trait-implementation-and-usage-7563.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/7563
 //@ run-pass
 #![allow(dead_code)]
 trait IDummy {
diff --git a/tests/ui/traits/trait-upcasting/lifetime.stderr b/tests/ui/traits/trait-upcasting/lifetime.stderr
index 589e9816d5a..f41ea68053a 100644
--- a/tests/ui/traits/trait-upcasting/lifetime.stderr
+++ b/tests/ui/traits/trait-upcasting/lifetime.stderr
@@ -10,7 +10,7 @@ LL |     fn z(&self) -> i32 {
 LL |     fn y(&self) -> i32 {
    |        ^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: method `w` is never used
   --> $DIR/lifetime.rs:22:8
diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.stderr b/tests/ui/traits/trait-upcasting/replace-vptr.stderr
index 1a8bfd1bfa6..932112470c0 100644
--- a/tests/ui/traits/trait-upcasting/replace-vptr.stderr
+++ b/tests/ui/traits/trait-upcasting/replace-vptr.stderr
@@ -6,7 +6,7 @@ LL | trait A {
 LL |     fn foo_a(&self);
    |        ^^^^^
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: method `foo_c` is never used
   --> $DIR/replace-vptr.rs:12:8
diff --git a/tests/ui/traits/unspecified-self-in-trait-ref.stderr b/tests/ui/traits/unspecified-self-in-trait-ref.stderr
index 2e872453184..3fa74d79adc 100644
--- a/tests/ui/traits/unspecified-self-in-trait-ref.stderr
+++ b/tests/ui/traits/unspecified-self-in-trait-ref.stderr
@@ -6,7 +6,7 @@ LL |     let a = Foo::lol();
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL |     let a = <dyn Foo>::lol();
diff --git a/tests/ui/transmutability/references/reject_lifetime_extension.stderr b/tests/ui/transmutability/references/reject_lifetime_extension.stderr
index a597041c6ca..b9702984145 100644
--- a/tests/ui/transmutability/references/reject_lifetime_extension.stderr
+++ b/tests/ui/transmutability/references/reject_lifetime_extension.stderr
@@ -67,11 +67,11 @@ LL |         unsafe { extend_hrtb(src) }
    |                  `src` escapes the function body here
    |                  argument requires that `'a` must outlive `'static`
    |
-note: due to current limitations in the borrow checker, this implies a `'static` lifetime
-  --> $DIR/reject_lifetime_extension.rs:85:25
+note: due to a current limitation of the type system, this implies a `'static` lifetime
+  --> $DIR/reject_lifetime_extension.rs:85:9
    |
 LL |         for<'b> &'b u8: TransmuteFrom<&'a u8>,
-   |                         ^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr b/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr
index 0f42fcbe04d..79bd1f2adc1 100644
--- a/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr
+++ b/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr
@@ -16,7 +16,7 @@ note: `V` could also refer to the associated type defined here
    |
 LL |     type V;
    |     ^^^^^^
-   = note: `#[deny(ambiguous_associated_items)]` on by default
+   = note: `#[deny(ambiguous_associated_items)]` (part of `#[deny(future_incompatible)]`) on by default
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs b/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs
index 4fb2e60b5c5..04208faddde 100644
--- a/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs
+++ b/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs
@@ -24,8 +24,7 @@ type Successors<'a> = impl std::fmt::Debug + 'a;
 impl Terminator {
     #[define_opaque(Successors, Tait)]
     fn successors(&self, mut f: for<'x> fn(&'x ()) -> <&'x A as B>::C) -> Successors<'_> {
-        f = g;
-        //~^ ERROR mismatched types
+        f = g; //~ ERROR expected generic lifetime parameter, found `'x`
     }
 }
 
diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr b/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr
index 558792987f3..8e6778bdd0b 100644
--- a/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr
+++ b/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr
@@ -1,15 +1,12 @@
-error[E0308]: mismatched types
+error[E0792]: expected generic lifetime parameter, found `'x`
   --> $DIR/higher_kinded_params3.rs:27:9
    |
 LL | type Tait<'a> = impl std::fmt::Debug + 'a;
-   |                 ------------------------- the expected opaque type
+   |           -- this generic parameter must be used with a generic lifetime parameter
 ...
 LL |         f = g;
-   |         ^^^^^ one type is more general than the other
-   |
-   = note: expected fn pointer `for<'x> fn(&'x ()) -> Tait<'x>`
-              found fn pointer `for<'a> fn(&'a ()) -> &'a ()`
+   |         ^^^^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs
index c7f04dc07bb..ba75b114a11 100644
--- a/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs
@@ -8,7 +8,7 @@ fn foo<'a>(x: &'a ()) -> &'a () {
 
 #[define_opaque(Opaque)]
 fn test() -> for<'a> fn(&'a ()) -> Opaque<'a> {
-    foo //~ ERROR: mismatched types
+    foo //~ ERROR: expected generic lifetime parameter, found `'a`
 }
 
 fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr
index b8c04185a7d..d699059e397 100644
--- a/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr
@@ -1,15 +1,12 @@
-error[E0308]: mismatched types
+error[E0792]: expected generic lifetime parameter, found `'a`
   --> $DIR/hkl_forbidden3.rs:11:5
    |
 LL | type Opaque<'a> = impl Sized + 'a;
-   |                   --------------- the expected opaque type
+   |             -- this generic parameter must be used with a generic lifetime parameter
 ...
 LL |     foo
-   |     ^^^ one type is more general than the other
-   |
-   = note: expected fn pointer `for<'a> fn(&'a ()) -> Opaque<'a>`
-              found fn pointer `for<'a> fn(&'a ()) -> &'a ()`
+   |     ^^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/issues/issue-8767.rs b/tests/ui/typeck/impl-for-nonexistent-type-error-8767.rs
index 972101a0bc3..005c676ed39 100644
--- a/tests/ui/issues/issue-8767.rs
+++ b/tests/ui/typeck/impl-for-nonexistent-type-error-8767.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/8767
 impl B { //~ ERROR cannot find type `B` in this scope
 }
 
diff --git a/tests/ui/issues/issue-8767.stderr b/tests/ui/typeck/impl-for-nonexistent-type-error-8767.stderr
index 66141628e28..0e37391a00f 100644
--- a/tests/ui/issues/issue-8767.stderr
+++ b/tests/ui/typeck/impl-for-nonexistent-type-error-8767.stderr
@@ -1,5 +1,5 @@
 error[E0412]: cannot find type `B` in this scope
-  --> $DIR/issue-8767.rs:1:6
+  --> $DIR/impl-for-nonexistent-type-error-8767.rs:2:6
    |
 LL | impl B {
    |      ^ not found in this scope
diff --git a/tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr b/tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr
index 6450cc30ac0..190ef0f4724 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr
@@ -4,7 +4,7 @@ warning: unused variable: `item`
 LL |         for item in y {
    |             ^^^^ help: if this is intentional, prefix it with an underscore: `_item`
    |
-   = note: `#[warn(unused_variables)]` on by default
+   = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
 
 warning: value assigned to `counter` is never read
   --> $DIR/unboxed-closures-counter-not-moved.rs:24:9
@@ -13,7 +13,7 @@ LL |         counter += 1;
    |         ^^^^^^^
    |
    = help: maybe it is overwritten before being read?
-   = note: `#[warn(unused_assignments)]` on by default
+   = note: `#[warn(unused_assignments)]` (part of `#[warn(unused)]`) on by default
 
 warning: unused variable: `counter`
   --> $DIR/unboxed-closures-counter-not-moved.rs:24:9
diff --git a/tests/ui/unboxed-closures/unboxed-closures-move-mutable.stderr b/tests/ui/unboxed-closures/unboxed-closures-move-mutable.stderr
index 813e2eea568..24590128107 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-move-mutable.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closures-move-mutable.stderr
@@ -5,7 +5,7 @@ LL |         move || x += 1;
    |                 ^
    |
    = help: did you mean to capture by reference instead?
-   = note: `#[warn(unused_variables)]` on by default
+   = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
 
 warning: unused variable: `x`
   --> $DIR/unboxed-closures-move-mutable.rs:20:17
diff --git a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr
index 8a26b45117c..b6804511ac2 100644
--- a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr
+++ b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr
@@ -11,7 +11,7 @@ note: an unsafe function restricts its caller, but its body is safe by default
    |
 LL | unsafe fn foo() {
    | ^^^^^^^^^^^^^^^
-   = note: `#[warn(unsafe_op_in_unsafe_fn)]` on by default
+   = note: `#[warn(unsafe_op_in_unsafe_fn)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr
index 458a2180a82..35f9d3a4ebc 100644
--- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr
+++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr
@@ -11,7 +11,7 @@ note: an unsafe function restricts its caller, but its body is safe by default
    |
 LL | unsafe fn foo() {
    | ^^^^^^^^^^^^^^^
-   = note: `#[warn(unsafe_op_in_unsafe_fn)]` on by default
+   = note: `#[warn(unsafe_op_in_unsafe_fn)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
index 26872f60fd3..a0b443ec850 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr
@@ -6,7 +6,7 @@ LL | trait Foo<const N: Bar<2>> {
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
+   = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
 help: if this is a dyn-compatible trait, use `dyn`
    |
 LL | trait Foo<const N: dyn Bar<2>> {
diff --git a/tests/ui/where-clauses/unsupported_attribute.stderr b/tests/ui/where-clauses/unsupported_attribute.stderr
index 411c895ed87..cdd6e82b98d 100644
--- a/tests/ui/where-clauses/unsupported_attribute.stderr
+++ b/tests/ui/where-clauses/unsupported_attribute.stderr
@@ -64,7 +64,7 @@ error: `#[deprecated]` attribute cannot be used on where predicates
 LL |     #[deprecated] T: Trait,
    |     ^^^^^^^^^^^^^
    |
-   = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates
+   = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates
 
 error: `#[deprecated]` attribute cannot be used on where predicates
   --> $DIR/unsupported_attribute.rs:25:5
@@ -72,7 +72,7 @@ error: `#[deprecated]` attribute cannot be used on where predicates
 LL |     #[deprecated] 'a: 'static,
    |     ^^^^^^^^^^^^^
    |
-   = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates
+   = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates
 
 error: `#[automatically_derived]` attribute cannot be used on where predicates
   --> $DIR/unsupported_attribute.rs:26:5
diff --git a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr
index 34ed8bd2146..ebe609af38a 100644
--- a/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr
+++ b/tests/ui/where-clauses/where-clause-early-bound-lifetimes.stderr
@@ -6,7 +6,7 @@ LL | trait TheTrait { fn dummy(&self) { } }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr b/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr
index 9a8faf7a64e..5161e2aabc1 100644
--- a/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr
+++ b/tests/ui/where-clauses/where-clause-method-substituion-rpass.stderr
@@ -6,7 +6,7 @@ LL | trait Foo<T> { fn dummy(&self, arg: T) { } }
    |       |
    |       method in this trait
    |
-   = note: `#[warn(dead_code)]` on by default
+   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
 
 warning: 1 warning emitted
 
diff --git a/triagebot.toml b/triagebot.toml
index 2f31a30019b..31411747848 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -579,7 +579,7 @@ trigger_files = [
     "src/doc/unstable-book/src/compiler-flags/sanitizer.md",
     "src/doc/unstable-book/src/language-features/cfg-sanitize.md",
     "src/doc/unstable-book/src/language-features/cfi-encoding.md",
-    "src/doc/unstable-book/src/language-features/no-sanitize.md",
+    "src/doc/unstable-book/src/language-features/sanitize.md",
     "tests/codegen-llvm/sanitizer",
     "tests/codegen-llvm/split-lto-unit.rs",
     "tests/codegen-llvm/stack-probes-inline.rs",
@@ -1003,11 +1003,12 @@ cc = ["@calebzulawski", "@programmerjake"]
 
 [mentions."library/core/src/unicode/unicode_data.rs"]
 message = """
-`library/core/src/unicode/unicode_data.rs` is generated by
-`src/tools/unicode-table-generator` via `./x run
-src/tools/unicode-table-generator`. If you want to modify `unicode_data.rs`,
-please modify the tool then regenerate the library source file with the tool
-instead of editing the library source file manually.
+`library/core/src/unicode/unicode_data.rs` is generated by the \
+`src/tools/unicode-table-generator` tool.
+
+If you want to modify `unicode_data.rs`, please modify the tool then regenerate the library \
+source file via `./x run src/tools/unicode-table-generator` instead of editing \
+`unicode_data.rs` manually.
 """
 
 [mentions."src/librustdoc/html/static"]
@@ -1070,7 +1071,7 @@ cc = ["@rust-lang/rustfmt"]
 
 [mentions."compiler/rustc_middle/src/mir/syntax.rs"]
 message = "This PR changes MIR"
-cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@davidtwco", "@vakaras"]
+cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@vakaras"]
 
 [mentions."compiler/rustc_error_messages"]
 message = "`rustc_error_messages` was changed"
@@ -1209,7 +1210,7 @@ cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
 [mentions."src/doc/unstable-book/src/language-features/cfi-encoding.md"]
 cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
 
-[mentions."src/doc/unstable-book/src/language-features/no-sanitize.md"]
+[mentions."src/doc/unstable-book/src/language-features/sanitize.md"]
 cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
 
 [mentions."src/doc/rustc/src/check-cfg.md"]
@@ -1404,7 +1405,6 @@ arena = [
     "@spastorino",
 ]
 mir = [
-    "@davidtwco",
     "@oli-obk",
     "@matthewjasper",
     "@saethlin",
@@ -1591,6 +1591,8 @@ days-threshold = 28
 # Prevents mentions in commits to avoid users being spammed
 # Documentation at: https://forge.rust-lang.org/triagebot/no-mentions.html
 [no-mentions]
+# Subtree update authors can't fix it, no point in warning.
+exclude-titles = ["subtree update"]
 
 # Allow members to formally register concerns (`@rustbot concern my concern`)
 # Documentation at: https://forge.rust-lang.org/triagebot/concern.html
diff --git a/typos.toml b/typos.toml
index 317aafc8615..b0ff48f8fa2 100644
--- a/typos.toml
+++ b/typos.toml
@@ -33,6 +33,7 @@ misformed = "misformed"
 targetting = "targetting"
 publically = "publically"
 clonable = "clonable"
+moreso = "moreso"
 
 # this can be valid word, depends on dictionary edition
 #matcheable = "matcheable"