about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs619
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs34
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs3
-rw-r--r--compiler/rustc_infer/src/traits/util.rs78
-rw-r--r--compiler/rustc_lint/src/unused.rs4
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs2
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs14
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs42
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs6
-rw-r--r--config.example.toml171
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/tests/lib.rs3
-rw-r--r--library/core/src/ptr/non_null.rs13
-rw-r--r--library/panic_abort/src/android.rs4
-rw-r--r--library/panic_abort/src/lib.rs2
-rw-r--r--library/panic_unwind/src/lib.rs4
-rw-r--r--library/std/src/io/cursor.rs2
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/panicking.rs15
-rw-r--r--src/bootstrap/builder.rs14
-rw-r--r--src/bootstrap/compile.rs18
-rw-r--r--src/bootstrap/config.rs6
-rw-r--r--src/bootstrap/config/tests.rs2
-rw-r--r--src/bootstrap/defaults/config.user.toml4
-rw-r--r--src/bootstrap/dist.rs12
-rw-r--r--src/bootstrap/download.rs2
-rw-r--r--src/bootstrap/lib.rs2
-rw-r--r--src/bootstrap/llvm.rs (renamed from src/bootstrap/native.rs)65
-rw-r--r--src/bootstrap/test.rs79
-rw-r--r--src/ci/stage-build.py2
-rw-r--r--src/librustdoc/html/static/js/search.js6
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs1
-rw-r--r--tests/rustdoc-gui/setting-go-to-only-result.goml63
-rw-r--r--tests/ui/inference/char-as-str-single.fixed9
-rw-r--r--tests/ui/inference/char-as-str-single.rs9
-rw-r--r--tests/ui/inference/char-as-str-single.stderr15
59 files changed, 782 insertions, 682 deletions
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index c1b3f34e5a6..e2a592d851a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -176,15 +176,14 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
 
     return_if_di_node_created_in_meantime!(cx, unique_type_id);
 
-    let (thin_pointer_size, thin_pointer_align) =
-        cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.types.unit));
+    let data_layout = &cx.tcx.data_layout;
     let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
 
     match fat_pointer_kind(cx, pointee_type) {
         None => {
             // This is a thin pointer. Create a regular pointer type and give it the correct name.
             debug_assert_eq!(
-                (thin_pointer_size, thin_pointer_align),
+                (data_layout.pointer_size, data_layout.pointer_align.abi),
                 cx.size_and_align_of(ptr_type),
                 "ptr_type={}, pointee_type={}",
                 ptr_type,
@@ -195,8 +194,8 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                 llvm::LLVMRustDIBuilderCreatePointerType(
                     DIB(cx),
                     pointee_type_di_node,
-                    thin_pointer_size.bits(),
-                    thin_pointer_align.bits() as u32,
+                    data_layout.pointer_size.bits(),
+                    data_layout.pointer_align.abi.bits() as u32,
                     0, // Ignore DWARF address space.
                     ptr_type_debuginfo_name.as_ptr().cast(),
                     ptr_type_debuginfo_name.len(),
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 037b07dec62..57856b4ddb1 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -10,6 +10,7 @@ use rustc_middle::mir::mono::Linkage;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self as ty, TyCtxt};
 use rustc_session::{lint, parse::feature_err};
+use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span};
 use rustc_target::spec::{abi, SanitizerSet};
 
@@ -83,336 +84,368 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             }
         };
 
-        if attr.has_name(sym::cold) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
-        } else if attr.has_name(sym::rustc_allocator) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
-        } else if attr.has_name(sym::ffi_returns_twice) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
-        } else if attr.has_name(sym::ffi_pure) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
-        } else if attr.has_name(sym::ffi_const) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
-        } else if attr.has_name(sym::rustc_nounwind) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
-        } else if attr.has_name(sym::rustc_reallocator) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
-        } else if attr.has_name(sym::rustc_deallocator) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
-        } else if attr.has_name(sym::rustc_allocator_zeroed) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
-        } else if attr.has_name(sym::naked) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
-        } else if attr.has_name(sym::no_mangle) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
-        } else if attr.has_name(sym::no_coverage) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
-        } else if attr.has_name(sym::rustc_std_internal_symbol) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
-        } else if attr.has_name(sym::used) {
-            let inner = attr.meta_item_list();
-            match inner.as_deref() {
-                Some([item]) if item.has_name(sym::linker) => {
-                    if !tcx.features().used_with_arg {
-                        feature_err(
-                            &tcx.sess.parse_sess,
-                            sym::used_with_arg,
-                            attr.span,
-                            "`#[used(linker)]` is currently unstable",
-                        )
-                        .emit();
-                    }
-                    codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
-                }
-                Some([item]) if item.has_name(sym::compiler) => {
-                    if !tcx.features().used_with_arg {
-                        feature_err(
-                            &tcx.sess.parse_sess,
-                            sym::used_with_arg,
-                            attr.span,
-                            "`#[used(compiler)]` is currently unstable",
-                        )
-                        .emit();
-                    }
-                    codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
-                }
-                Some(_) => {
-                    tcx.sess.emit_err(ExpectedUsedSymbol { span: attr.span });
-                }
-                None => {
-                    // Unfortunately, unconditionally using `llvm.used` causes
-                    // issues in handling `.init_array` with the gold linker,
-                    // but using `llvm.compiler.used` caused a nontrival amount
-                    // of unintentional ecosystem breakage -- particularly on
-                    // Mach-O targets.
-                    //
-                    // As a result, we emit `llvm.compiler.used` only on ELF
-                    // targets. This is somewhat ad-hoc, but actually follows
-                    // our pre-LLVM 13 behavior (prior to the ecosystem
-                    // breakage), and seems to match `clang`'s behavior as well
-                    // (both before and after LLVM 13), possibly because they
-                    // have similar compatibility concerns to us. See
-                    // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
-                    // and following comments for some discussion of this, as
-                    // well as the comments in `rustc_codegen_llvm` where these
-                    // flags are handled.
-                    //
-                    // Anyway, to be clear: this is still up in the air
-                    // somewhat, and is subject to change in the future (which
-                    // is a good thing, because this would ideally be a bit
-                    // more firmed up).
-                    let is_like_elf = !(tcx.sess.target.is_like_osx
-                        || tcx.sess.target.is_like_windows
-                        || tcx.sess.target.is_like_wasm);
-                    codegen_fn_attrs.flags |= if is_like_elf {
-                        CodegenFnAttrFlags::USED
-                    } else {
-                        CodegenFnAttrFlags::USED_LINKER
-                    };
-                }
+        let Some(Ident { name, .. }) = attr.ident() else {
+            continue;
+        };
+
+        match name {
+            sym::cold => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
             }
-        } else if attr.has_name(sym::cmse_nonsecure_entry) {
-            if let Some(fn_sig) = fn_sig()
-                && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. })
-            {
-                struct_span_err!(
-                    tcx.sess,
-                    attr.span,
-                    E0776,
-                    "`#[cmse_nonsecure_entry]` requires C ABI"
-                )
-                .emit();
+            sym::rustc_allocator => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
             }
-            if !tcx.sess.target.llvm_target.contains("thumbv8m") {
-                struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
-                    .emit();
+            sym::ffi_returns_twice => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
             }
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
-        } else if attr.has_name(sym::thread_local) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
-        } else if attr.has_name(sym::track_caller) {
-            if !tcx.is_closure(did.to_def_id())
-                && let Some(fn_sig) = fn_sig()
-                && fn_sig.skip_binder().abi() != abi::Abi::Rust
-            {
-                struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
-                    .emit();
+            sym::ffi_pure => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
             }
-            if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
-                feature_err(
-                    &tcx.sess.parse_sess,
-                    sym::closure_track_caller,
-                    attr.span,
-                    "`#[track_caller]` on closures is currently unstable",
-                )
-                .emit();
+            sym::ffi_const => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
+            }
+            sym::rustc_nounwind => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+            }
+            sym::rustc_reallocator => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
+            }
+            sym::rustc_deallocator => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
+            }
+            sym::rustc_allocator_zeroed => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
+            }
+            sym::naked => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
+            }
+            sym::no_mangle => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
+            }
+            sym::no_coverage => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
+            }
+            sym::rustc_std_internal_symbol => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
+            }
+            sym::used => {
+                let inner = attr.meta_item_list();
+                match inner.as_deref() {
+                    Some([item]) if item.has_name(sym::linker) => {
+                        if !tcx.features().used_with_arg {
+                            feature_err(
+                                &tcx.sess.parse_sess,
+                                sym::used_with_arg,
+                                attr.span,
+                                "`#[used(linker)]` is currently unstable",
+                            )
+                            .emit();
+                        }
+                        codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
+                    }
+                    Some([item]) if item.has_name(sym::compiler) => {
+                        if !tcx.features().used_with_arg {
+                            feature_err(
+                                &tcx.sess.parse_sess,
+                                sym::used_with_arg,
+                                attr.span,
+                                "`#[used(compiler)]` is currently unstable",
+                            )
+                            .emit();
+                        }
+                        codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
+                    }
+                    Some(_) => {
+                        tcx.sess.emit_err(ExpectedUsedSymbol { span: attr.span });
+                    }
+                    None => {
+                        // Unfortunately, unconditionally using `llvm.used` causes
+                        // issues in handling `.init_array` with the gold linker,
+                        // but using `llvm.compiler.used` caused a nontrival amount
+                        // of unintentional ecosystem breakage -- particularly on
+                        // Mach-O targets.
+                        //
+                        // As a result, we emit `llvm.compiler.used` only on ELF
+                        // targets. This is somewhat ad-hoc, but actually follows
+                        // our pre-LLVM 13 behavior (prior to the ecosystem
+                        // breakage), and seems to match `clang`'s behavior as well
+                        // (both before and after LLVM 13), possibly because they
+                        // have similar compatibility concerns to us. See
+                        // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
+                        // and following comments for some discussion of this, as
+                        // well as the comments in `rustc_codegen_llvm` where these
+                        // flags are handled.
+                        //
+                        // Anyway, to be clear: this is still up in the air
+                        // somewhat, and is subject to change in the future (which
+                        // is a good thing, because this would ideally be a bit
+                        // more firmed up).
+                        let is_like_elf = !(tcx.sess.target.is_like_osx
+                            || tcx.sess.target.is_like_windows
+                            || tcx.sess.target.is_like_wasm);
+                        codegen_fn_attrs.flags |= if is_like_elf {
+                            CodegenFnAttrFlags::USED
+                        } else {
+                            CodegenFnAttrFlags::USED_LINKER
+                        };
+                    }
+                }
             }
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
-        } else if attr.has_name(sym::export_name) {
-            if let Some(s) = attr.value_str() {
-                if s.as_str().contains('\0') {
-                    // `#[export_name = ...]` will be converted to a null-terminated string,
-                    // so it may not contain any null characters.
+            sym::cmse_nonsecure_entry => {
+                if let Some(fn_sig) = fn_sig()
+                    && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. })
+                {
                     struct_span_err!(
                         tcx.sess,
                         attr.span,
-                        E0648,
-                        "`export_name` may not contain null characters"
+                        E0776,
+                        "`#[cmse_nonsecure_entry]` requires C ABI"
                     )
                     .emit();
                 }
-                codegen_fn_attrs.export_name = Some(s);
-            }
-        } else if attr.has_name(sym::target_feature) {
-            if !tcx.is_closure(did.to_def_id())
-                && let Some(fn_sig) = fn_sig()
-                && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal
-            {
-                if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
-                    // The `#[target_feature]` attribute is allowed on
-                    // WebAssembly targets on all functions, including safe
-                    // ones. Other targets require that `#[target_feature]` is
-                    // only applied to unsafe functions (pending the
-                    // `target_feature_11` feature) because on most targets
-                    // execution of instructions that are not supported is
-                    // considered undefined behavior. For WebAssembly which is a
-                    // 100% safe target at execution time it's not possible to
-                    // execute undefined instructions, and even if a future
-                    // feature was added in some form for this it would be a
-                    // deterministic trap. There is no undefined behavior when
-                    // executing WebAssembly so `#[target_feature]` is allowed
-                    // on safe functions (but again, only for WebAssembly)
-                    //
-                    // Note that this is also allowed if `actually_rustdoc` so
-                    // if a target is documenting some wasm-specific code then
-                    // it's not spuriously denied.
-                    //
-                    // This exception needs to be kept in sync with allowing
-                    // `#[target_feature]` on `main` and `start`.
-                } else if !tcx.features().target_feature_11 {
-                    let mut err = feature_err(
+                if !tcx.sess.target.llvm_target.contains("thumbv8m") {
+                    struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
+                    .emit();
+                }
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
+            }
+            sym::thread_local => {
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
+            }
+            sym::track_caller => {
+                if !tcx.is_closure(did.to_def_id())
+                    && let Some(fn_sig) = fn_sig()
+                    && fn_sig.skip_binder().abi() != abi::Abi::Rust
+                {
+                    struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
+                        .emit();
+                }
+                if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
+                    feature_err(
                         &tcx.sess.parse_sess,
-                        sym::target_feature_11,
+                        sym::closure_track_caller,
                         attr.span,
-                        "`#[target_feature(..)]` can only be applied to `unsafe` functions",
-                    );
-                    err.span_label(tcx.def_span(did), "not an `unsafe` function");
-                    err.emit();
-                } else {
-                    check_target_feature_trait_unsafe(tcx, did, attr.span);
+                        "`#[track_caller]` on closures is currently unstable",
+                    )
+                    .emit();
                 }
+                codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
             }
-            from_target_feature(
-                tcx,
-                attr,
-                supported_target_features,
-                &mut codegen_fn_attrs.target_features,
-            );
-        } else if attr.has_name(sym::linkage) {
-            if let Some(val) = attr.value_str() {
-                let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
-                if tcx.is_foreign_item(did) {
-                    codegen_fn_attrs.import_linkage = linkage;
-                } else {
-                    codegen_fn_attrs.linkage = linkage;
+            sym::export_name => {
+                if let Some(s) = attr.value_str() {
+                    if s.as_str().contains('\0') {
+                        // `#[export_name = ...]` will be converted to a null-terminated string,
+                        // so it may not contain any null characters.
+                        struct_span_err!(
+                            tcx.sess,
+                            attr.span,
+                            E0648,
+                            "`export_name` may not contain null characters"
+                        )
+                        .emit();
+                    }
+                    codegen_fn_attrs.export_name = Some(s);
                 }
             }
-        } else if attr.has_name(sym::link_section) {
-            if let Some(val) = attr.value_str() {
-                if val.as_str().bytes().any(|b| b == 0) {
-                    let msg = format!(
-                        "illegal null byte in link_section \
-                         value: `{}`",
-                        &val
-                    );
-                    tcx.sess.span_err(attr.span, &msg);
-                } else {
-                    codegen_fn_attrs.link_section = Some(val);
+            sym::target_feature => {
+                if !tcx.is_closure(did.to_def_id())
+                    && let Some(fn_sig) = fn_sig()
+                    && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal
+                {
+                    if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
+                        // The `#[target_feature]` attribute is allowed on
+                        // WebAssembly targets on all functions, including safe
+                        // ones. Other targets require that `#[target_feature]` is
+                        // only applied to unsafe functions (pending the
+                        // `target_feature_11` feature) because on most targets
+                        // execution of instructions that are not supported is
+                        // considered undefined behavior. For WebAssembly which is a
+                        // 100% safe target at execution time it's not possible to
+                        // execute undefined instructions, and even if a future
+                        // feature was added in some form for this it would be a
+                        // deterministic trap. There is no undefined behavior when
+                        // executing WebAssembly so `#[target_feature]` is allowed
+                        // on safe functions (but again, only for WebAssembly)
+                        //
+                        // Note that this is also allowed if `actually_rustdoc` so
+                        // if a target is documenting some wasm-specific code then
+                        // it's not spuriously denied.
+                        //
+                        // This exception needs to be kept in sync with allowing
+                        // `#[target_feature]` on `main` and `start`.
+                    } else if !tcx.features().target_feature_11 {
+                        let mut err = feature_err(
+                            &tcx.sess.parse_sess,
+                            sym::target_feature_11,
+                            attr.span,
+                            "`#[target_feature(..)]` can only be applied to `unsafe` functions",
+                        );
+                        err.span_label(tcx.def_span(did), "not an `unsafe` function");
+                        err.emit();
+                    } else {
+                        check_target_feature_trait_unsafe(tcx, did, attr.span);
+                    }
+                }
+                from_target_feature(
+                    tcx,
+                    attr,
+                    supported_target_features,
+                    &mut codegen_fn_attrs.target_features,
+                );
+            }
+            sym::linkage => {
+                if let Some(val) = attr.value_str() {
+                    let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
+                    if tcx.is_foreign_item(did) {
+                        codegen_fn_attrs.import_linkage = linkage;
+                    } else {
+                        codegen_fn_attrs.linkage = linkage;
+                    }
                 }
             }
-        } else if attr.has_name(sym::link_name) {
-            codegen_fn_attrs.link_name = attr.value_str();
-        } else if attr.has_name(sym::link_ordinal) {
-            link_ordinal_span = Some(attr.span);
-            if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
-                codegen_fn_attrs.link_ordinal = ordinal;
-            }
-        } else if attr.has_name(sym::no_sanitize) {
-            no_sanitize_span = Some(attr.span);
-            if let Some(list) = attr.meta_item_list() {
-                for item in list.iter() {
-                    if item.has_name(sym::address) {
-                        codegen_fn_attrs.no_sanitize |=
-                            SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS;
-                    } else if item.has_name(sym::cfi) {
-                        codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
-                    } else if item.has_name(sym::kcfi) {
-                        codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
-                    } else if item.has_name(sym::memory) {
-                        codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
-                    } else if item.has_name(sym::memtag) {
-                        codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
-                    } else if item.has_name(sym::shadow_call_stack) {
-                        codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
-                    } else if item.has_name(sym::thread) {
-                        codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
-                    } else if item.has_name(sym::hwaddress) {
-                        codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
+            sym::link_section => {
+                if let Some(val) = attr.value_str() {
+                    if val.as_str().bytes().any(|b| b == 0) {
+                        let msg = format!(
+                            "illegal null byte in link_section \
+                             value: `{}`",
+                            &val
+                        );
+                        tcx.sess.span_err(attr.span, &msg);
                     } else {
-                        tcx.sess
-                            .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
-                            .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
-                            .emit();
+                        codegen_fn_attrs.link_section = Some(val);
                     }
                 }
             }
-        } else if attr.has_name(sym::instruction_set) {
-            codegen_fn_attrs.instruction_set = attr.meta_item_list().and_then(|l| match &l[..] {
-                [NestedMetaItem::MetaItem(set)] => {
-                    let segments =
-                        set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
-                    match segments.as_slice() {
-                        [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
-                            if !tcx.sess.target.has_thumb_interworking {
-                                struct_span_err!(
-                                    tcx.sess.diagnostic(),
-                                    attr.span,
-                                    E0779,
-                                    "target does not support `#[instruction_set]`"
-                                )
+            sym::link_name => {
+                codegen_fn_attrs.link_name = attr.value_str();
+            }
+            sym::link_ordinal => {
+                link_ordinal_span = Some(attr.span);
+                if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
+                    codegen_fn_attrs.link_ordinal = ordinal;
+                }
+            }
+            sym::no_sanitize => {
+                no_sanitize_span = Some(attr.span);
+                if let Some(list) = attr.meta_item_list() {
+                    for item in list.iter() {
+                        match item.ident().map(|ident| ident.name) {
+                            Some(sym::address) => {
+                                codegen_fn_attrs.no_sanitize |=
+                                    SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS;
+                            }
+                            Some(sym::cfi) => {
+                                codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
+                            }
+                            Some(sym::kcfi) => {
+                                codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
+                            }
+                            Some(sym::memory) => {
+                                codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
+                            }
+                            Some(sym::memtag) => {
+                                codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
+                            }
+                            Some(sym::shadow_call_stack) => {
+                                codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
+                            }
+                            Some(sym::thread) => {
+                                codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
+                            }
+                            Some(sym::hwaddress) => {
+                                codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
+                            }
+                            _ => {
+                                tcx.sess
+                                .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
+                                .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
                                 .emit();
-                                None
-                            } else if segments[1] == sym::a32 {
-                                Some(InstructionSetAttr::ArmA32)
-                            } else if segments[1] == sym::t32 {
-                                Some(InstructionSetAttr::ArmT32)
-                            } else {
-                                unreachable!()
                             }
                         }
-                        _ => {
-                            struct_span_err!(
-                                tcx.sess.diagnostic(),
-                                attr.span,
-                                E0779,
-                                "invalid instruction set specified",
-                            )
-                            .emit();
-                            None
-                        }
                     }
                 }
-                [] => {
-                    struct_span_err!(
-                        tcx.sess.diagnostic(),
-                        attr.span,
-                        E0778,
-                        "`#[instruction_set]` requires an argument"
-                    )
-                    .emit();
-                    None
-                }
-                _ => {
-                    struct_span_err!(
-                        tcx.sess.diagnostic(),
-                        attr.span,
-                        E0779,
-                        "cannot specify more than one instruction set"
-                    )
-                    .emit();
-                    None
-                }
-            })
-        } else if attr.has_name(sym::repr) {
-            codegen_fn_attrs.alignment = match attr.meta_item_list() {
-                Some(items) => match items.as_slice() {
-                    [item] => match item.name_value_literal() {
-                        Some((sym::align, literal)) => {
-                            let alignment = rustc_attr::parse_alignment(&literal.kind);
-
-                            match alignment {
-                                Ok(align) => Some(align),
-                                Err(msg) => {
+            }
+            sym::instruction_set => {
+                codegen_fn_attrs.instruction_set =
+                    attr.meta_item_list().and_then(|l| match &l[..] {
+                        [NestedMetaItem::MetaItem(set)] => {
+                            let segments =
+                                set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
+                            match segments.as_slice() {
+                                [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
+                                    if !tcx.sess.target.has_thumb_interworking {
+                                        struct_span_err!(
+                                            tcx.sess.diagnostic(),
+                                            attr.span,
+                                            E0779,
+                                            "target does not support `#[instruction_set]`"
+                                        )
+                                        .emit();
+                                        None
+                                    } else if segments[1] == sym::a32 {
+                                        Some(InstructionSetAttr::ArmA32)
+                                    } else if segments[1] == sym::t32 {
+                                        Some(InstructionSetAttr::ArmT32)
+                                    } else {
+                                        unreachable!()
+                                    }
+                                }
+                                _ => {
                                     struct_span_err!(
                                         tcx.sess.diagnostic(),
                                         attr.span,
-                                        E0589,
-                                        "invalid `repr(align)` attribute: {}",
-                                        msg
+                                        E0779,
+                                        "invalid instruction set specified",
                                     )
                                     .emit();
-
                                     None
                                 }
                             }
                         }
-                        _ => None,
-                    },
-                    [] => None,
-                    _ => None,
-                },
-                None => None,
-            };
+                        [] => {
+                            struct_span_err!(
+                                tcx.sess.diagnostic(),
+                                attr.span,
+                                E0778,
+                                "`#[instruction_set]` requires an argument"
+                            )
+                            .emit();
+                            None
+                        }
+                        _ => {
+                            struct_span_err!(
+                                tcx.sess.diagnostic(),
+                                attr.span,
+                                E0779,
+                                "cannot specify more than one instruction set"
+                            )
+                            .emit();
+                            None
+                        }
+                    })
+            }
+            sym::repr => {
+                codegen_fn_attrs.alignment = if let Some(items) = attr.meta_item_list()
+                    && let [item] = items.as_slice()
+                    && let Some((sym::align, literal)) = item.name_value_literal()
+                {
+                    rustc_attr::parse_alignment(&literal.kind).map_err(|msg| {
+                        struct_span_err!(
+                            tcx.sess.diagnostic(),
+                            attr.span,
+                            E0589,
+                            "invalid `repr(align)` attribute: {}",
+                            msg
+                        )
+                        .emit();
+                    })
+                    .ok()
+                } else {
+                    None
+                };
+            }
+            _ => {}
         }
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 5da0e826c56..2d647f5d7f2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -397,8 +397,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             PassMode::Cast(cast_ty, _) => {
                 let op = match self.locals[mir::RETURN_PLACE] {
-                    LocalRef::Operand(Some(op)) => op,
-                    LocalRef::Operand(None) => bug!("use of return before def"),
+                    LocalRef::Operand(op) => op,
+                    LocalRef::PendingOperand => bug!("use of return before def"),
                     LocalRef::Place(cg_place) => OperandRef {
                         val: Ref(cg_place.llval, None, cg_place.align),
                         layout: cg_place.layout,
@@ -1673,7 +1673,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             match self.locals[index] {
                 LocalRef::Place(dest) => dest,
                 LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
-                LocalRef::Operand(None) => {
+                LocalRef::PendingOperand => {
                     // Handle temporary places, specifically `Operand` ones, as
                     // they don't have `alloca`s.
                     return if fn_ret.is_indirect() {
@@ -1694,7 +1694,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         ReturnDest::DirectOperand(index)
                     };
                 }
-                LocalRef::Operand(Some(_)) => {
+                LocalRef::Operand(_) => {
                     bug!("place local already assigned to");
                 }
             }
@@ -1737,7 +1737,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             IndirectOperand(tmp, index) => {
                 let op = bx.load_operand(tmp);
                 tmp.storage_dead(bx);
-                self.locals[index] = LocalRef::Operand(Some(op));
+                self.locals[index] = LocalRef::Operand(op);
                 self.debug_introduce_local(bx, index);
             }
             DirectOperand(index) => {
@@ -1752,7 +1752,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 } else {
                     OperandRef::from_immediate_or_packed_pair(bx, llval, ret_abi.layout)
                 };
-                self.locals[index] = LocalRef::Operand(Some(op));
+                self.locals[index] = LocalRef::Operand(op);
                 self.debug_introduce_local(bx, index);
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 6e32c28a42c..d15774696a5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -312,7 +312,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => {
                     bx.set_var_name(place.llval, name);
                 }
-                LocalRef::Operand(Some(operand)) => match operand.val {
+                LocalRef::Operand(operand) => match operand.val {
                     OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => {
                         bx.set_var_name(x, name);
                     }
@@ -323,7 +323,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         bx.set_var_name(b, &(name.clone() + ".1"));
                     }
                 },
-                LocalRef::Operand(None) => {}
+                LocalRef::PendingOperand => {}
             }
         }
 
@@ -332,9 +332,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         }
 
         let base = match local_ref {
-            LocalRef::Operand(None) => return,
+            LocalRef::PendingOperand => return,
 
-            LocalRef::Operand(Some(operand)) => {
+            LocalRef::Operand(operand) => {
                 // Don't spill operands onto the stack in naked functions.
                 // See: https://github.com/rust-lang/rust/issues/42779
                 let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id());
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 5cffca5230a..189549953d9 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -123,7 +123,10 @@ enum LocalRef<'tcx, V> {
     /// Every time it is initialized, we have to reallocate the place
     /// and update the fat pointer. That's the reason why it is indirect.
     UnsizedPlace(PlaceRef<'tcx, V>),
-    Operand(Option<OperandRef<'tcx, V>>),
+    /// The backend [`OperandValue`] has already been generated.
+    Operand(OperandRef<'tcx, V>),
+    /// Will be a `Self::Operand` once we get to its definition.
+    PendingOperand,
 }
 
 impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> {
@@ -135,9 +138,9 @@ impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> {
             // Zero-size temporaries aren't always initialized, which
             // doesn't matter because they don't contain data, but
             // we need something in the operand.
-            LocalRef::Operand(Some(OperandRef::new_zst(bx, layout)))
+            LocalRef::Operand(OperandRef::new_zst(bx, layout))
         } else {
-            LocalRef::Operand(None)
+            LocalRef::PendingOperand
         }
     }
 }
@@ -337,7 +340,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 // We don't have to cast or keep the argument in the alloca.
                 // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
                 // of putting everything in allocas just so we can use llvm.dbg.declare.
-                let local = |op| LocalRef::Operand(Some(op));
+                let local = |op| LocalRef::Operand(op);
                 match arg.mode {
                     PassMode::Ignore => {
                         return local(OperandRef::new_zst(bx, arg.layout));
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 25721f75583..b45e7c834e7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -370,7 +370,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
 
         match self.locals[place_ref.local] {
-            LocalRef::Operand(Some(mut o)) => {
+            LocalRef::Operand(mut o) => {
                 // Moves out of scalar and scalar pair fields are trivial.
                 for elem in place_ref.projection.iter() {
                     match elem {
@@ -395,7 +395,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
                 Some(o)
             }
-            LocalRef::Operand(None) => {
+            LocalRef::PendingOperand => {
                 bug!("use of {:?} before def", place_ref);
             }
             LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index f6523a448e3..1633cfef19d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -558,6 +558,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     bug!("using operand local {:?} as place", place_ref);
                 }
             }
+            LocalRef::PendingOperand => {
+                bug!("using still-pending operand local {:?} as place", place_ref);
+            }
         };
         for elem in place_ref.projection[base..].iter() {
             cg_base = match *elem {
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 4bc4fdab59e..d867d6b0cd4 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -545,7 +545,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // ZST are passed as operands and require special handling
         // because codegen_place() panics if Local is operand.
         if let Some(index) = place.as_local() {
-            if let LocalRef::Operand(Some(op)) = self.locals[index] {
+            if let LocalRef::Operand(op) = self.locals[index] {
                 if let ty::Array(_, n) = op.layout.ty.kind() {
                     let n = n.eval_target_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
                     return bx.cx().const_usize(n);
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index 41f585f7fcc..3fd7397ad38 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -18,12 +18,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         LocalRef::UnsizedPlace(cg_indirect_dest) => {
                             self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue)
                         }
-                        LocalRef::Operand(None) => {
+                        LocalRef::PendingOperand => {
                             let operand = self.codegen_rvalue_operand(bx, rvalue);
-                            self.locals[index] = LocalRef::Operand(Some(operand));
+                            self.locals[index] = LocalRef::Operand(operand);
                             self.debug_introduce_local(bx, index);
                         }
-                        LocalRef::Operand(Some(op)) => {
+                        LocalRef::Operand(op) => {
                             if !op.layout.is_zst() {
                                 span_bug!(
                                     statement.source_info.span,
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 6d9dfe9697c..4ab6bb5908b 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1427,13 +1427,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         for (base_trait_ref, span, constness) in regular_traits_refs_spans {
             assert_eq!(constness, ty::BoundConstness::NotConst);
 
-            for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) {
-                debug!(
-                    "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`",
-                    obligation.predicate
-                );
+            for pred in traits::elaborate_trait_ref(tcx, base_trait_ref) {
+                debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred);
 
-                let bound_predicate = obligation.predicate.kind();
+                let bound_predicate = pred.kind();
                 match bound_predicate.skip_binder() {
                     ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
                         let pred = bound_predicate.rebind(pred);
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 491bd04f346..c912a8a640d 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1912,14 +1912,13 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
         // Check elaborated bounds.
         let implied_obligations = traits::elaborate_predicates_with_span(tcx, predicates_with_span);
 
-        for obligation in implied_obligations {
+        for (pred, obligation_span) in implied_obligations {
             // We lower empty bounds like `Vec<dyn Copy>:` as
             // `WellFormed(Vec<dyn Copy>)`, which will later get checked by
             // regular WF checking
-            if let ty::PredicateKind::WellFormed(..) = obligation.predicate.kind().skip_binder() {
+            if let ty::PredicateKind::WellFormed(..) = pred.kind().skip_binder() {
                 continue;
             }
-            let pred = obligation.predicate;
             // Match the existing behavior.
             if pred.is_global() && !pred.has_late_bound_vars() {
                 let pred = self.normalize(span, None, pred);
@@ -1930,8 +1929,6 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
                 if let Some(hir::Generics { predicates, .. }) =
                     hir_node.and_then(|node| node.generics())
                 {
-                    let obligation_span = obligation.cause.span();
-
                     span = predicates
                         .iter()
                         // There seems to be no better way to find out which predicate we are in
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index aa66d7bb5ef..d2e45c28658 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -130,12 +130,9 @@ pub(super) fn item_bounds(
     tcx: TyCtxt<'_>,
     def_id: DefId,
 ) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
-    let bounds = tcx.mk_predicates_from_iter(
-        util::elaborate_predicates(
-            tcx,
-            tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
-        )
-        .map(|obligation| obligation.predicate),
-    );
+    let bounds = tcx.mk_predicates_from_iter(util::elaborate_predicates(
+        tcx,
+        tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
+    ));
     ty::EarlyBinder(bounds)
 }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 7f1e4ccc964..dfa9e6148aa 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -318,16 +318,8 @@ fn check_predicates<'tcx>(
     span: Span,
 ) {
     let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
-    let impl1_predicates: Vec<_> = traits::elaborate_predicates_with_span(
-        tcx,
-        std::iter::zip(
-            instantiated.predicates,
-            // Don't drop predicates (unsound!) because `spans` is too short
-            instantiated.spans.into_iter().chain(std::iter::repeat(span)),
-        ),
-    )
-    .map(|obligation| (obligation.predicate, obligation.cause.span))
-    .collect();
+    let impl1_predicates: Vec<_> =
+        traits::elaborate_predicates_with_span(tcx, instantiated.into_iter()).collect();
 
     let mut impl2_predicates = if impl2_node.is_from_trait() {
         // Always applicable traits have to be always applicable without any
@@ -341,7 +333,6 @@ fn check_predicates<'tcx>(
                 .predicates
                 .into_iter(),
         )
-        .map(|obligation| obligation.predicate)
         .collect()
     };
     debug!(?impl1_predicates, ?impl2_predicates);
@@ -361,12 +352,16 @@ fn check_predicates<'tcx>(
     // which is sound because we forbid impls like the following
     //
     // impl<D: Debug> AlwaysApplicable for D { }
-    let always_applicable_traits = impl1_predicates.iter().copied().filter(|&(predicate, _)| {
-        matches!(
-            trait_predicate_kind(tcx, predicate),
-            Some(TraitSpecializationKind::AlwaysApplicable)
-        )
-    });
+    let always_applicable_traits = impl1_predicates
+        .iter()
+        .copied()
+        .filter(|&(predicate, _)| {
+            matches!(
+                trait_predicate_kind(tcx, predicate),
+                Some(TraitSpecializationKind::AlwaysApplicable)
+            )
+        })
+        .map(|(pred, _span)| pred);
 
     // Include the well-formed predicates of the type parameters of the impl.
     for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs {
@@ -380,10 +375,7 @@ fn check_predicates<'tcx>(
             traits::elaborate_obligations(tcx, obligations).map(|obligation| obligation.predicate),
         )
     }
-    impl2_predicates.extend(
-        traits::elaborate_predicates_with_span(tcx, always_applicable_traits)
-            .map(|obligation| obligation.predicate),
-    );
+    impl2_predicates.extend(traits::elaborate_predicates(tcx, always_applicable_traits));
 
     for (predicate, span) in impl1_predicates {
         if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(tcx, predicate, *pred2, span)) {
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index ec391ea80f4..47a8b080166 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -204,15 +204,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut expected_sig = None;
         let mut expected_kind = None;
 
-        for obligation in traits::elaborate_predicates_with_span(
+        for (pred, span) in traits::elaborate_predicates_with_span(
             self.tcx,
             // Reverse the obligations here, since `elaborate_*` uses a stack,
             // and we want to keep inference generally in the same order of
             // the registered obligations.
             predicates.rev(),
         ) {
-            debug!(?obligation.predicate);
-            let bound_predicate = obligation.predicate.kind();
+            debug!(?pred);
+            let bound_predicate = pred.kind();
 
             // Given a Projection predicate, we can potentially infer
             // the complete signature.
@@ -220,9 +220,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 && let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = bound_predicate.skip_binder()
             {
                 let inferred_sig = self.normalize(
-                    obligation.cause.span,
+                    span,
                     self.deduce_sig_from_projection(
-                    Some(obligation.cause.span),
+                    Some(span),
                         bound_predicate.rebind(proj_predicate),
                     ),
                 );
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index a0aa43deadc..2762e778591 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -576,17 +576,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
 
         traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied())
             // We don't care about regions here.
-            .filter_map(|obligation| match obligation.predicate.kind().skip_binder() {
+            .filter_map(|pred| match pred.kind().skip_binder() {
                 ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
                     if trait_pred.def_id() == sized_def_id =>
                 {
                     let span = predicates
                         .iter()
-                        .find_map(
-                            |(p, span)| {
-                                if p == obligation.predicate { Some(span) } else { None }
-                            },
-                        )
+                        .find_map(|(p, span)| if p == pred { Some(span) } else { None })
                         .unwrap_or(rustc_span::DUMMY_SP);
                     Some((trait_pred, span))
                 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index fd16363a1db..75c3d9f641d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1942,7 +1942,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     escaped
                 }
                 let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
-                if let Some((expected, found)) = trace.values.ty() {
+                let values = self.resolve_vars_if_possible(trace.values);
+                if let Some((expected, found)) = values.ty() {
                     match (expected.kind(), found.kind()) {
                         (ty::Tuple(_), ty::Tuple(_)) => {}
                         // If a tuple of length one was expected and the found expression has
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 0d2faeba5fc..f3797499866 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -74,44 +74,58 @@ pub struct Elaborator<'tcx> {
 pub fn elaborate_trait_ref<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
-) -> Elaborator<'tcx> {
+) -> impl Iterator<Item = ty::Predicate<'tcx>> {
     elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate(tcx)))
 }
 
 pub fn elaborate_trait_refs<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
-) -> Elaborator<'tcx> {
-    let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate(tcx));
+) -> impl Iterator<Item = ty::Predicate<'tcx>> {
+    let predicates = trait_refs.map(move |trait_ref| trait_ref.without_const().to_predicate(tcx));
     elaborate_predicates(tcx, predicates)
 }
 
 pub fn elaborate_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
-) -> Elaborator<'tcx> {
-    let obligations = predicates
-        .map(|predicate| {
-            predicate_obligation(predicate, ty::ParamEnv::empty(), ObligationCause::dummy())
-        })
-        .collect();
-    elaborate_obligations(tcx, obligations)
+) -> impl Iterator<Item = ty::Predicate<'tcx>> {
+    elaborate_obligations(
+        tcx,
+        predicates
+            .map(|predicate| {
+                Obligation::new(
+                    tcx,
+                    // We'll dump the cause/param-env later
+                    ObligationCause::dummy(),
+                    ty::ParamEnv::empty(),
+                    predicate,
+                )
+            })
+            .collect(),
+    )
+    .map(|obl| obl.predicate)
 }
 
 pub fn elaborate_predicates_with_span<'tcx>(
     tcx: TyCtxt<'tcx>,
     predicates: impl Iterator<Item = (ty::Predicate<'tcx>, Span)>,
-) -> Elaborator<'tcx> {
-    let obligations = predicates
-        .map(|(predicate, span)| {
-            predicate_obligation(
-                predicate,
-                ty::ParamEnv::empty(),
-                ObligationCause::dummy_with_span(span),
-            )
-        })
-        .collect();
-    elaborate_obligations(tcx, obligations)
+) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> {
+    elaborate_obligations(
+        tcx,
+        predicates
+            .map(|(predicate, span)| {
+                Obligation::new(
+                    tcx,
+                    // We'll dump the cause/param-env later
+                    ObligationCause::dummy_with_span(span),
+                    ty::ParamEnv::empty(),
+                    predicate,
+                )
+            })
+            .collect(),
+    )
+    .map(|obl| (obl.predicate, obl.cause.span))
 }
 
 pub fn elaborate_obligations<'tcx>(
@@ -141,10 +155,6 @@ impl<'tcx> Elaborator<'tcx> {
         self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate)));
     }
 
-    pub fn filter_to_traits(self) -> FilterToTraits<Self> {
-        FilterToTraits::new(self)
-    }
-
     fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
         let tcx = self.visited.tcx;
 
@@ -325,20 +335,18 @@ impl<'tcx> Iterator for Elaborator<'tcx> {
 // Supertrait iterator
 ///////////////////////////////////////////////////////////////////////////
 
-pub type Supertraits<'tcx> = FilterToTraits<Elaborator<'tcx>>;
-
 pub fn supertraits<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
-) -> Supertraits<'tcx> {
-    elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
+) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
+    FilterToTraits::new(elaborate_trait_ref(tcx, trait_ref))
 }
 
 pub fn transitive_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
-    bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
-) -> Supertraits<'tcx> {
-    elaborate_trait_refs(tcx, bounds).filter_to_traits()
+    trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
+) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
+    FilterToTraits::new(elaborate_trait_refs(tcx, trait_refs))
 }
 
 /// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may
@@ -393,12 +401,12 @@ impl<I> FilterToTraits<I> {
     }
 }
 
-impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToTraits<I> {
+impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
     type Item = ty::PolyTraitRef<'tcx>;
 
     fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
-        while let Some(obligation) = self.base_iterator.next() {
-            if let Some(data) = obligation.predicate.to_opt_poly_trait_pred() {
+        while let Some(pred) = self.base_iterator.next() {
+            if let Some(data) = pred.to_opt_poly_trait_pred() {
                 return Some(data.map_bound(|t| t.trait_ref));
             }
         }
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index faca61fc29b..42e59f92840 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -258,11 +258,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                         cx.tcx,
                         cx.tcx.explicit_item_bounds(def).iter().cloned(),
                     )
-                    .find_map(|obligation| {
+                    .find_map(|(pred, _span)| {
                         // We only look at the `DefId`, so it is safe to skip the binder here.
                         if let ty::PredicateKind::Clause(ty::Clause::Trait(
                             ref poly_trait_predicate,
-                        )) = obligation.predicate.kind().skip_binder()
+                        )) = pred.kind().skip_binder()
                         {
                             let def_id = poly_trait_predicate.trait_ref.def_id;
 
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index c1cf6ee0f9e..e7075d5e791 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -117,7 +117,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
             .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
         if traits::impossible_predicates(
             tcx,
-            traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
+            traits::elaborate_predicates(tcx, predicates).collect(),
         ) {
             trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id);
             return;
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 45bd98f39d2..60401b05492 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -93,7 +93,7 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
             .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
         if traits::impossible_predicates(
             tcx,
-            traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
+            traits::elaborate_predicates(tcx, predicates).collect(),
         ) {
             trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id);
             return;
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 80618fd1abe..2ff7de8cb9e 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -1065,7 +1065,7 @@ pub(super) struct CurrentDepGraph<K: DepKind> {
     /// This is used to verify that fingerprints do not change between the creation of a node
     /// and its recomputation.
     #[cfg(debug_assertions)]
-    fingerprints: Lock<FxHashMap<DepNode<K>, Fingerprint>>,
+    fingerprints: Lock<IndexVec<DepNodeIndex, Option<Fingerprint>>>,
 
     /// Used to trap when a specific edge is added to the graph.
     /// This is used for debug purposes and is only active with `debug_assertions`.
@@ -1151,7 +1151,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
             #[cfg(debug_assertions)]
             forbidden_edge,
             #[cfg(debug_assertions)]
-            fingerprints: Lock::new(Default::default()),
+            fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)),
             total_read_count: AtomicU64::new(0),
             total_duplicate_read_count: AtomicU64::new(0),
             node_intern_event_id,
@@ -1163,14 +1163,8 @@ impl<K: DepKind> CurrentDepGraph<K> {
         if let Some(forbidden_edge) = &self.forbidden_edge {
             forbidden_edge.index_to_node.lock().insert(dep_node_index, key);
         }
-        match self.fingerprints.lock().entry(key) {
-            Entry::Vacant(v) => {
-                v.insert(fingerprint);
-            }
-            Entry::Occupied(o) => {
-                assert_eq!(*o.get(), fingerprint, "Unstable fingerprints for {:?}", key);
-            }
-        }
+        let previous = *self.fingerprints.lock().get_or_insert_with(dep_node_index, || fingerprint);
+        assert_eq!(previous, fingerprint, "Unstable fingerprints for {:?}", key);
     }
 
     /// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it.
diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index 995fec78c40..b2658614fd3 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -470,7 +470,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         for assumption in
             elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)))
         {
-            match G::consider_object_bound_candidate(self, goal, assumption.predicate) {
+            match G::consider_object_bound_candidate(self, goal, assumption) {
                 Ok(result) => {
                     candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
                 }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 6a64dfdedd4..65e7bcb7f01 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -9,8 +9,6 @@
 //! FIXME(@lcnr): Write that section. If you read this before then ask me
 //! about it on zulip.
 
-// FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented.
-
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_infer::traits::query::NoSolution;
@@ -105,8 +103,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         goal: Goal<'tcx, SubtypePredicate<'tcx>>,
     ) -> QueryResult<'tcx> {
         if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
-            // FIXME: Do we want to register a subtype relation between these vars?
-            // That won't actually reflect in the query response, so it seems moot.
             self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
         } else {
             self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?;
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index 219890b9dc4..9773a3eacd6 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -78,8 +78,6 @@ impl<'tcx> SearchGraph<'tcx> {
         tcx: TyCtxt<'tcx>,
         goal: CanonicalGoal<'tcx>,
     ) -> Result<(), QueryResult<'tcx>> {
-        // FIXME: start by checking the global cache
-
         // Look at the provisional cache to check for cycles.
         let cache = &mut self.provisional_cache;
         match cache.lookup_table.entry(goal) {
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 6b3a59b1ed5..878c502655c 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -349,8 +349,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
             let normalized_preds = elaborate_predicates(
                 tcx,
                 computed_preds.clone().chain(user_computed_preds.iter().cloned()),
-            )
-            .map(|o| o.predicate);
+            );
             new_env = ty::ParamEnv::new(
                 tcx.mk_predicates_from_iter(normalized_preds),
                 param_env.reveal(),
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 98e00e8223b..03ba125cf2b 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -367,8 +367,8 @@ fn negative_impl_exists<'tcx>(
     }
 
     // Try to prove a negative obligation exists for super predicates
-    for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) {
-        if resolve_negative_obligation(infcx.fork(), &o, body_def_id) {
+    for pred in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) {
+        if resolve_negative_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) {
             return true;
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
index 84045c4d0ed..672b3365ff4 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
@@ -82,15 +82,15 @@ pub fn recompute_applicable_impls<'tcx>(
 
     let predicates =
         tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
-    for obligation in elaborate_predicates_with_span(tcx, predicates.into_iter()) {
-        let kind = obligation.predicate.kind();
+    for (pred, span) in elaborate_predicates_with_span(tcx, predicates.into_iter()) {
+        let kind = pred.kind();
         if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
             && param_env_candidate_may_apply(kind.rebind(trait_pred))
         {
             if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) {
                 ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id())))
             } else {
-                ambiguities.push(Ambiguity::ParamEnv(obligation.cause.span))
+                ambiguities.push(Ambiguity::ParamEnv(span))
             }
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 296fd1ed524..c19798213b7 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1624,8 +1624,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
         };
 
-        for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) {
-            let bound_predicate = obligation.predicate.kind();
+        for pred in super::elaborate_predicates(self.tcx, std::iter::once(cond)) {
+            let bound_predicate = pred.kind();
             if let ty::PredicateKind::Clause(ty::Clause::Trait(implication)) =
                 bound_predicate.skip_binder()
             {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index e8970606704..8d831dca6e3 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -66,7 +66,7 @@ pub use self::util::{expand_trait_aliases, TraitAliasExpander};
 pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
 pub use self::util::{
     supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
-    SupertraitDefIds, Supertraits,
+    SupertraitDefIds,
 };
 
 pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext;
@@ -267,9 +267,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     // and errors will get reported then; so outside of type inference we
     // can be sure that no errors should occur.
     let mut predicates: Vec<_> =
-        util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter())
-            .map(|obligation| obligation.predicate)
-            .collect();
+        util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter()).collect();
 
     debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
 
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 5d2af5ff33c..dbf6b78572a 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -379,26 +379,24 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     // Search for a predicate like `Self : Sized` amongst the trait bounds.
     let predicates = tcx.predicates_of(def_id);
     let predicates = predicates.instantiate_identity(tcx).predicates;
-    elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| {
-        match obligation.predicate.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::Clause::Trait(ref trait_pred)) => {
-                trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
-            }
-            ty::PredicateKind::Clause(ty::Clause::Projection(..))
-            | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-            | ty::PredicateKind::Subtype(..)
-            | ty::PredicateKind::Coerce(..)
-            | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
-            | ty::PredicateKind::WellFormed(..)
-            | ty::PredicateKind::ObjectSafe(..)
-            | ty::PredicateKind::ClosureKind(..)
-            | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
-            | ty::PredicateKind::ConstEvaluatable(..)
-            | ty::PredicateKind::ConstEquate(..)
-            | ty::PredicateKind::AliasRelate(..)
-            | ty::PredicateKind::Ambiguous
-            | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
+    elaborate_predicates(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() {
+        ty::PredicateKind::Clause(ty::Clause::Trait(ref trait_pred)) => {
+            trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
         }
+        ty::PredicateKind::Clause(ty::Clause::Projection(..))
+        | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
+        | ty::PredicateKind::Subtype(..)
+        | ty::PredicateKind::Coerce(..)
+        | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
+        | ty::PredicateKind::WellFormed(..)
+        | ty::PredicateKind::ObjectSafe(..)
+        | ty::PredicateKind::ClosureKind(..)
+        | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
+        | ty::PredicateKind::ConstEvaluatable(..)
+        | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::AliasRelate(..)
+        | ty::PredicateKind::Ambiguous
+        | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
     })
 }
 
@@ -669,9 +667,9 @@ fn object_ty_for_trait<'tcx>(
     debug!(?trait_predicate);
 
     let mut elaborated_predicates: Vec<_> = elaborate_trait_ref(tcx, trait_ref)
-        .filter_map(|obligation| {
-            debug!(?obligation);
-            let pred = obligation.predicate.to_opt_poly_projection_pred()?;
+        .filter_map(|pred| {
+            debug!(?pred);
+            let pred = pred.to_opt_poly_projection_pred()?;
             Some(pred.map_bound(|p| {
                 ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
                     tcx, p,
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index ec5bd982a3c..156674e33c3 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -921,9 +921,9 @@ pub(crate) fn required_region_bounds<'tcx>(
     assert!(!erased_self_ty.has_escaping_bound_vars());
 
     traits::elaborate_predicates(tcx, predicates)
-        .filter_map(|obligation| {
-            debug!(?obligation);
-            match obligation.predicate.kind().skip_binder() {
+        .filter_map(|pred| {
+            debug!(?pred);
+            match pred.kind().skip_binder() {
                 ty::PredicateKind::Clause(ty::Clause::Projection(..))
                 | ty::PredicateKind::Clause(ty::Clause::Trait(..))
                 | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
diff --git a/config.example.toml b/config.example.toml
index 32eab76b369..5ef83760aed 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -1,7 +1,7 @@
 # Sample TOML configuration file for building Rust.
 #
-# To configure rustbuild, copy this file to the directory from which you will be
-# running the build, and name it config.toml.
+# To configure rustbuild, run `./configure` or `./x.py setup`.
+# See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-configtoml for more information.
 #
 # All options are commented out by default in this file, and they're commented
 # out with their default values. The build system by default looks for
@@ -9,12 +9,6 @@
 # a custom configuration file can also be specified with `--config` to the build
 # system.
 
-# Keeps track of the last version of `x.py` used.
-# If it does not match the version that is currently running,
-# `x.py` will prompt you to update it and read the changelog.
-# See `src/bootstrap/CHANGELOG.md` for more information.
-changelog-seen = 2
-
 # =============================================================================
 # Global Settings
 # =============================================================================
@@ -25,6 +19,12 @@ changelog-seen = 2
 # Note that this has no default value (x.py uses the defaults in `config.toml.example`).
 #profile = <none>
 
+# Keeps track of the last version of `x.py` used.
+# If `changelog-seen` does not match the version that is currently running,
+# `x.py` will prompt you to update it and to read the changelog.
+# See `src/bootstrap/CHANGELOG.md` for more information.
+changelog-seen = 2
+
 # =============================================================================
 # Tweaking how LLVM is compiled
 # =============================================================================
@@ -33,7 +33,7 @@ changelog-seen = 2
 # Whether to use Rust CI built LLVM instead of locally building it.
 #
 # Unless you're developing for a target where Rust CI doesn't build a compiler
-# toolchain or changing LLVM locally, you probably want to set this to true.
+# toolchain or changing LLVM locally, you probably want to leave this enabled.
 #
 # All tier 1 targets are currently supported; set this to `"if-available"` if
 # you are not sure whether you're on a tier 1 target.
@@ -42,9 +42,7 @@ changelog-seen = 2
 #
 # Note that many of the LLVM options are not currently supported for
 # downloading. Currently only the "assertions" option can be toggled.
-#
-# Defaults to "if-available" when `channel = "dev"` and "false" otherwise.
-#download-ci-llvm = "if-available"
+#download-ci-llvm = if rust.channel == "dev" { "if-available" } else { false }
 
 # Indicates whether the LLVM build is a Release or Debug build
 #optimize = true
@@ -59,6 +57,8 @@ changelog-seen = 2
 #release-debuginfo = false
 
 # Indicates whether the LLVM assertions are enabled or not
+# NOTE: When assertions are disabled, bugs in the integration between rustc and LLVM can lead to
+# unsoundness (segfaults, etc.) in the rustc process itself, not just in the generated code.
 #assertions = false
 
 # Indicates whether the LLVM testsuite is enabled in the build or not. Does
@@ -70,10 +70,9 @@ changelog-seen = 2
 # Indicates whether the LLVM plugin is enabled or not
 #plugins = false
 
-# Indicates whether ccache is used when building LLVM
+# Indicates whether ccache is used when building LLVM. Set to `true` to use the first `ccache` in
+# PATH, or set an absolute path to use a specific version.
 #ccache = false
-# or alternatively ...
-#ccache = "/path/to/ccache"
 
 # When true, link libstdc++ statically into the rustc_llvm.
 # This is useful if you don't want to use the dynamic version of that
@@ -87,11 +86,8 @@ changelog-seen = 2
 # Note: this is NOT related to Rust compilation targets. However, as Rust is
 # dependent on LLVM for code generation, turning targets off here WILL lead to
 # the resulting rustc being unable to compile for the disabled architectures.
-# Also worth pointing out is that, in case support for new targets are added to
-# LLVM, enabling them here doesn't mean Rust is automatically gaining said
-# support. You'll need to write a target specification at least, and most
-# likely, teach rustc about the C ABI of the target. Get in touch with the
-# Rust team and file an issue if you need assistance in porting!
+#
+# To add support for new targets, see https://rustc-dev-guide.rust-lang.org/building/new-target.html.
 #targets = "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86"
 
 # LLVM experimental targets to build support for. These targets are specified in
@@ -104,19 +100,18 @@ changelog-seen = 2
 # This can be useful when building LLVM with debug info, which significantly
 # increases the size of binaries and consequently the memory required by
 # each linker process.
-# If absent or 0, linker invocations are treated like any other job and
+# If set to 0, linker invocations are treated like any other job and
 # controlled by rustbuild's -j parameter.
 #link-jobs = 0
 
-# When invoking `llvm-config` this configures whether the `--shared` argument is
-# passed to prefer linking to shared libraries.
-# NOTE: `thin-lto = true` requires this to be `true` and will give an error otherwise.
-#link-shared = false
+# Whether to build LLVM as a dynamically linked library (as opposed to statically linked).
+# Under the hood, this passes `--shared` to llvm-config.
+# NOTE: To avoid performing LTO multiple times, we suggest setting this to `true` when `thin-lto` is enabled.
+#link-shared = llvm.thin-lto
 
 # When building llvm, this configures what is being appended to the version.
-# The default is "-rust-$version-$channel", except for dev channel where rustc
-# version number is omitted. To use LLVM version as is, provide an empty string.
-#version-suffix = "-rust-dev"
+# To use LLVM version as is, provide an empty string.
+#version-suffix = if rust.channel == "dev" { "-rust-dev" } else { "-rust-$version-$channel" }
 
 # On MSVC you can compile LLVM with clang-cl, but the test suite doesn't pass
 # with clang-cl, so this is special in that it only compiles LLVM with clang-cl.
@@ -178,47 +173,58 @@ changelog-seen = 2
 # The default stage to use for the `bench` subcommand
 #bench-stage = 2
 
-# Build triple for the original snapshot compiler. This must be a compiler that
-# nightlies are already produced for. The current platform must be able to run
-# binaries of this build triple and the nightly will be used to bootstrap the
-# first compiler.
+# Build triple for the pre-compiled snapshot compiler. If `rustc` is set, this must match its host
+# triple (see `rustc --version --verbose`; cross-compiling the rust build system itself is NOT
+# supported). If `rustc` is unset, this must be a platform with pre-compiled host tools
+# (https://doc.rust-lang.org/nightly/rustc/platform-support.html). The current platform must be
+# able to run binaries of this build triple.
 #
-# Defaults to platform where `x.py` is run.
+# If `rustc` is present in path, this defaults to the host it was compiled for.
+# Otherwise, `x.py` will try to infer it from the output of `uname`.
+# If `uname` is not found in PATH, we assume this is `x86_64-pc-windows-msvc`.
+# This may be changed in the future.
 #build = "x86_64-unknown-linux-gnu" (as an example)
 
-# Which triples to produce a compiler toolchain for. Each of these triples will
-# be bootstrapped from the build triple themselves.
+# Which triples to produce a compiler toolchain for. Each of these triples will be bootstrapped from
+# the build triple themselves. In other words, this is the list of triples for which to build a
+# compiler that can RUN on that triple.
 #
-# Defaults to just the build triple.
-#host = ["x86_64-unknown-linux-gnu"] (as an example)
+# Defaults to just the `build` triple.
+#host = [build.build] (list of triples)
 
-# Which triples to build libraries (core/alloc/std/test/proc_macro) for. Each of
-# these triples will be bootstrapped from the build triple themselves.
+# Which triples to build libraries (core/alloc/std/test/proc_macro) for. Each of these triples will
+# be bootstrapped from the build triple themselves. In other words, this is the list of triples for
+# which to build a library that can CROSS-COMPILE to that triple.
 #
 # Defaults to `host`. If you set this explicitly, you likely want to add all
 # host triples to this list as well in order for those host toolchains to be
 # able to compile programs for their native target.
-#target = ["x86_64-unknown-linux-gnu"] (as an example)
+#target = build.host (list of triples)
 
-# Use this directory to store build artifacts.
-# You can use "$ROOT" to indicate the root of the git repository.
+# Use this directory to store build artifacts. Paths are relative to the current directory, not to
+# the root of the repository.
 #build-dir = "build"
 
 # Instead of downloading the src/stage0.json version of Cargo specified, use
 # this Cargo binary instead to build all Rust code
+# If you set this, you likely want to set `rustc` as well.
 #cargo = "/path/to/cargo"
 
 # Instead of downloading the src/stage0.json version of the compiler
 # specified, use this rustc binary instead as the stage0 snapshot compiler.
+# If you set this, you likely want to set `cargo` as well.
 #rustc = "/path/to/rustc"
 
-# Instead of download the src/stage0.json version of rustfmt specified,
+# Instead of downloading the src/stage0.json version of rustfmt specified,
 # use this rustfmt binary instead as the stage0 snapshot rustfmt.
 #rustfmt = "/path/to/rustfmt"
 
-# Flag to specify whether any documentation is built. If false, rustdoc and
+# Whether to build documentation by default. If false, rustdoc and
 # friends will still be compiled but they will not be used to generate any
 # documentation.
+#
+# You can still build documentation when this is disabled by explicitly passing paths,
+# e.g. `x doc library`.
 #docs = true
 
 # Flag to specify whether CSS, JavaScript, and HTML are minified when
@@ -229,8 +235,8 @@ changelog-seen = 2
 # Flag to specify whether private items should be included in the library docs.
 #library-docs-private-items = false
 
-# Indicate whether the compiler should be documented in addition to the standard
-# library and facade crates.
+# Indicate whether to build compiler documentation by default.
+# You can still build documentation when this is disabled by explicitly passing a path: `x doc compiler`.
 #compiler-docs = false
 
 # Indicate whether git submodules are managed and updated automatically.
@@ -247,14 +253,14 @@ changelog-seen = 2
 # Python interpreter to use for various tasks throughout the build, notably
 # rustdoc tests, the lldb python interpreter, and some dist bits and pieces.
 #
-# Defaults to the Python interpreter used to execute x.py
+# Defaults to the Python interpreter used to execute x.py.
 #python = "python"
 
 # The path to the REUSE executable to use. Note that REUSE is not required in
 # most cases, as our tooling relies on a cached (and shrinked) copy of the
 # REUSE output present in the git repository and in our source tarballs.
 #
-# REUSE is only needed if your changes caused the overral licensing of the
+# REUSE is only needed if your changes caused the overall licensing of the
 # repository to change, and the cached copy has to be regenerated.
 #
 # Defaults to the "reuse" command in the system path.
@@ -264,14 +270,19 @@ changelog-seen = 2
 # set that all the Cargo.toml files create, instead of updating it.
 #locked-deps = false
 
-# Indicate whether the vendored sources are used for Rust dependencies or not
+# Indicate whether the vendored sources are used for Rust dependencies or not.
+#
+# Vendoring requires additional setup. We recommend using the pre-generated source tarballs if you
+# want to use vendoring. See
+# https://forge.rust-lang.org/infra/other-installation-methods.html#source-code.
 #vendor = false
 
 # Typically the build system will build the Rust compiler twice. The second
 # compiler, however, will simply use its own libraries to link against. If you
 # would rather to perform a full bootstrap, compiling the compiler three times,
-# then you can set this option to true. You shouldn't ever need to set this
-# option to true.
+# then you can set this option to true.
+#
+# This is only useful for verifying that rustc generates reproducible builds.
 #full-bootstrap = false
 
 # Enable a build of the extended Rust tool set which is not only the compiler
@@ -300,7 +311,7 @@ changelog-seen = 2
 #    "rust-demangler",  # if profiler = true
 #]
 
-# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
+# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation
 #verbose = 0
 
 # Build the sanitizer runtimes
@@ -320,11 +331,12 @@ changelog-seen = 2
 
 # Arguments passed to the `./configure` script, used during distcheck. You
 # probably won't fill this in but rather it's filled in by the `./configure`
-# script.
+# script. Useful for debugging.
 #configure-args = []
 
 # Indicates that a local rebuild is occurring instead of a full bootstrap,
 # essentially skipping stage0 as the local compiler is recompiling itself again.
+# Useful for modifying only the stage2 compiler without having to pass `--keep-stage 0` each time.
 #local-rebuild = false
 
 # Print out how long each rustbuild step took (mostly intended for CI and
@@ -354,10 +366,10 @@ changelog-seen = 2
 # =============================================================================
 [install]
 
-# Instead of installing to /usr/local, install to this path instead.
+# Where to install the generated toolchain. Must be an absolute path.
 #prefix = "/usr/local"
 
-# Where to install system configuration files
+# Where to install system configuration files.
 # If this is a relative path, it will get installed in `prefix` above
 #sysconfdir = "/etc"
 
@@ -411,9 +423,10 @@ changelog-seen = 2
 #debug = false
 
 # Whether to download the stage 1 and 2 compilers from CI.
-# This is mostly useful for tools; if you have changes to `compiler/` they will be ignored.
+# This is mostly useful for tools; if you have changes to `compiler/` or `library/` they will be ignored.
 #
-# You can set this to "if-unchanged" to only download if `compiler/` has not been modified.
+# Set this to "if-unchanged" to only download if the compiler and standard library have not been modified.
+# Set this to `true` to download unconditionally (useful if e.g. you are only changing doc-comments).
 #download-rustc = false
 
 # Number of codegen units to use for each compiler invocation. A value of 0
@@ -429,10 +442,8 @@ changelog-seen = 2
 # See https://github.com/rust-lang/rust/issues/83600.
 #codegen-units-std = codegen-units
 
-# Whether or not debug assertions are enabled for the compiler and standard
-# library. Debug assertions control the maximum log level used by rustc. When
-# enabled calls to `trace!` and `debug!` macros are preserved in the compiled
-# binary, otherwise they are omitted.
+# Whether or not debug assertions are enabled for the compiler and standard library.
+# These can help find bugs at the cost of a small runtime slowdown.
 #
 # Defaults to rust.debug value
 #debug-assertions = rust.debug (boolean)
@@ -444,13 +455,11 @@ changelog-seen = 2
 #debug-assertions-std = rust.debug-assertions (boolean)
 
 # Whether or not to leave debug! and trace! calls in the rust binary.
-# Overrides the `debug-assertions` option, if defined.
 #
 # Defaults to rust.debug-assertions value
 #
-# If you see a message from `tracing` saying
-# `max_level_info` is enabled and means logging won't be shown,
-# set this value to `true`.
+# If you see a message from `tracing` saying "some trace filter directives would enable traces that
+# are disabled statically" because `max_level_info` is enabled, set this value to `true`.
 #debug-logging = rust.debug-assertions (boolean)
 
 # Whether or not overflow checks are enabled for the compiler and standard
@@ -477,18 +486,16 @@ changelog-seen = 2
 #
 # Note that debuginfo-level = 2 generates several gigabytes of debuginfo
 # and will slow down the linking process significantly.
-#
-# Defaults to 1 if debug is true
-#debuginfo-level = 0
+#debuginfo-level = if rust.debug { 1 } else { 0 }
 
 # Debuginfo level for the compiler.
-#debuginfo-level-rustc = debuginfo-level
+#debuginfo-level-rustc = rust.debuginfo-level
 
 # Debuginfo level for the standard library.
-#debuginfo-level-std = debuginfo-level
+#debuginfo-level-std = rust.debuginfo-level
 
 # Debuginfo level for the tools.
-#debuginfo-level-tools = debuginfo-level
+#debuginfo-level-tools = rust.debuginfo-level
 
 # Debuginfo level for the test suites run with compiletest.
 # FIXME(#61117): Some tests fail when this option is enabled.
@@ -520,6 +527,7 @@ changelog-seen = 2
 
 # Build a multi-threaded rustc
 # FIXME(#75760): Some UI tests fail when this option is enabled.
+# NOTE: This option is NOT SUPPORTED. See #48685.
 #parallel-compiler = false
 
 # The default linker that will be hard-coded into the generated
@@ -546,7 +554,7 @@ changelog-seen = 2
 # upstream Rust you need to set this to "". However, note that if you are not
 # actually compatible -- for example if you've backported patches that change
 # behavior -- this may lead to miscompilations or other bugs.
-#description = <none> (string)
+#description = ""
 
 # The root location of the musl installation directory. The library directory
 # will also need to contain libunwind.a for an unwinding implementation. Note
@@ -575,14 +583,16 @@ changelog-seen = 2
 
 # Flag indicating whether git info will be retrieved from .git automatically.
 # Having the git information can cause a lot of rebuilds during development.
-# Note: If this attribute is not explicitly set (e.g. if left commented out) it
-# will default to true if channel = "dev", but will default to false otherwise.
-#ignore-git = if channel == "dev" { true } else { false }
+#
+# FIXME(#76720): this can causes bugs if different compilers reuse the same metadata cache.
+#ignore-git = if rust.channel == "dev" { true } else { false }
 
-# When creating source tarballs whether or not to create a source tarball.
+# Whether to create a source tarball by default when running `x dist`.
+#
+# You can still build a source tarball when this is disabled by explicitly passing `x dist rustc-src`.
 #dist-src = true
 
-# After building or testing extended tools (e.g. clippy and rustfmt), append the
+# After building or testing an optional component (e.g. the nomicon or reference), append the
 # result (broken, compiling, testing) into this JSON file.
 #save-toolstates = <none> (path)
 
@@ -624,11 +634,12 @@ changelog-seen = 2
 # will make code compile faster at the expense of lower runtime performance.
 #thin-lto-import-instr-limit = if incremental { 10 } else { LLVM default (currently 100) }
 
-# Map debuginfo paths to `/rust/$sha/...`, generally only set for releases
+# Map debuginfo paths to `/rust/$sha/...`.
+# Useful for reproducible builds. Generally only set for releases
 #remap-debuginfo = false
 
-# Link the compiler against `jemalloc`, where on Linux and OSX it should
-# override the default allocator for rustc and LLVM.
+# Link the compiler and LLVM against `jemalloc` instead of the default libc allocator.
+# This option is only tested on Linux and OSX.
 #jemalloc = false
 
 # Run tests in various test suites with the "nll compare mode" in addition to
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 5469261ef56..55e18b04956 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -135,7 +135,6 @@
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_uninit_array_transpose)]
 #![cfg_attr(test, feature(new_uninit))]
-#![feature(nonnull_slice_from_raw_parts)]
 #![feature(pattern)]
 #![feature(pointer_byte_offsets)]
 #![feature(provide_any)]
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 2a93a242d51..966cf575116 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -8,7 +8,7 @@
 #![feature(const_cow_is_borrowed)]
 #![feature(const_heap)]
 #![feature(const_mut_refs)]
-#![feature(const_nonnull_slice_from_raw_parts)]
+#![feature(const_slice_from_raw_parts_mut)]
 #![feature(const_ptr_write)]
 #![feature(const_try)]
 #![feature(core_intrinsics)]
@@ -38,7 +38,6 @@
 #![feature(const_default_impls)]
 #![feature(const_trait_impl)]
 #![feature(const_str_from_utf8)]
-#![feature(nonnull_slice_from_raw_parts)]
 #![feature(panic_update_hook)]
 #![feature(pointer_is_aligned)]
 #![feature(slice_flatten)]
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 8c1a6488605..a46804c186c 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -462,8 +462,6 @@ impl<T> NonNull<[T]> {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(nonnull_slice_from_raw_parts)]
-    ///
     /// use std::ptr::NonNull;
     ///
     /// // create a slice pointer when starting out with a pointer to the first element
@@ -475,8 +473,8 @@ impl<T> NonNull<[T]> {
     ///
     /// (Note that this example artificially demonstrates a use of this method,
     /// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.)
-    #[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")]
-    #[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")]
+    #[stable(feature = "nonnull_slice_from_raw_parts", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")]
     #[must_use]
     #[inline]
     pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
@@ -494,7 +492,6 @@ impl<T> NonNull<[T]> {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(nonnull_slice_from_raw_parts)]
     /// use std::ptr::NonNull;
     ///
     /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
@@ -514,7 +511,7 @@ impl<T> NonNull<[T]> {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
+    /// #![feature(slice_ptr_get)]
     /// use std::ptr::NonNull;
     ///
     /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
@@ -534,7 +531,7 @@ impl<T> NonNull<[T]> {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
+    /// #![feature(slice_ptr_get)]
     /// use std::ptr::NonNull;
     ///
     /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
@@ -668,7 +665,7 @@ impl<T> NonNull<[T]> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
+    /// #![feature(slice_ptr_get)]
     /// use std::ptr::NonNull;
     ///
     /// let x = &mut [1, 2, 4];
diff --git a/library/panic_abort/src/android.rs b/library/panic_abort/src/android.rs
index 0fd824f8a45..20b5b6b5146 100644
--- a/library/panic_abort/src/android.rs
+++ b/library/panic_abort/src/android.rs
@@ -15,7 +15,7 @@ type SetAbortMessageType = unsafe extern "C" fn(*const libc::c_char) -> ();
 //
 // Weakly resolve the symbol for android_set_abort_message. This function is only available
 // for API >= 21.
-pub(crate) unsafe fn android_set_abort_message(payload: *mut &mut dyn BoxMeUp) {
+pub(crate) unsafe fn android_set_abort_message(payload: &mut dyn BoxMeUp) {
     let func_addr =
         libc::dlsym(libc::RTLD_DEFAULT, ANDROID_SET_ABORT_MESSAGE.as_ptr() as *const libc::c_char)
             as usize;
@@ -23,7 +23,7 @@ pub(crate) unsafe fn android_set_abort_message(payload: *mut &mut dyn BoxMeUp) {
         return;
     }
 
-    let payload = (*payload).get();
+    let payload = payload.get();
     let msg = match payload.downcast_ref::<&'static str>() {
         Some(msg) => msg.as_bytes(),
         None => match payload.downcast_ref::<String>() {
diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs
index a3cebf99c53..b193d79b0e1 100644
--- a/library/panic_abort/src/lib.rs
+++ b/library/panic_abort/src/lib.rs
@@ -29,7 +29,7 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen
 
 // "Leak" the payload and shim to the relevant abort on the platform in question.
 #[rustc_std_internal_symbol]
-pub unsafe fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 {
+pub unsafe fn __rust_start_panic(_payload: &mut dyn BoxMeUp) -> u32 {
     // Android has the ability to attach a message as part of the abort.
     #[cfg(target_os = "android")]
     android::android_set_abort_message(_payload);
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index ea3c9a7a663..ce78ab82ef9 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -99,8 +99,8 @@ pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any
 // Entry point for raising an exception, just delegates to the platform-specific
 // implementation.
 #[rustc_std_internal_symbol]
-pub unsafe fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 {
-    let payload = Box::from_raw((*payload).take_box());
+pub unsafe fn __rust_start_panic(payload: &mut dyn BoxMeUp) -> u32 {
+    let payload = Box::from_raw(payload.take_box());
 
     imp::panic(payload)
 }
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index d98ab021cad..25c64240e74 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -34,7 +34,7 @@ use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
 /// use std::fs::File;
 ///
 /// // a library function we've written
-/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
+/// fn write_ten_bytes_at_end<W: Write + Seek>(mut writer: W) -> io::Result<()> {
 ///     writer.seek(SeekFrom::End(-10))?;
 ///
 ///     for i in 0..10 {
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 4e7b6080835..baad6de707b 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -292,7 +292,6 @@
 #![feature(is_some_and)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_write_slice)]
-#![feature(nonnull_slice_from_raw_parts)]
 #![feature(panic_can_unwind)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index e59f32af77d..e505466e535 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -46,12 +46,10 @@ extern "C" {
     fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static);
 }
 
-#[allow(improper_ctypes)]
 extern "Rust" {
-    /// `payload` is passed through another layer of raw pointers as `&mut dyn Trait` is not
-    /// FFI-safe. `BoxMeUp` lazily performs allocation only when needed (this avoids allocations
-    /// when using the "abort" panic runtime).
-    fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32;
+    /// `BoxMeUp` lazily performs allocation only when needed (this avoids
+    /// allocations when using the "abort" panic runtime).
+    fn __rust_start_panic(payload: &mut dyn BoxMeUp) -> u32;
 }
 
 /// This function is called by the panic runtime if FFI code catches a Rust
@@ -738,10 +736,7 @@ pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
 /// yer breakpoints.
 #[inline(never)]
 #[cfg_attr(not(test), rustc_std_internal_symbol)]
-fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
-    let code = unsafe {
-        let obj = &mut msg as *mut &mut dyn BoxMeUp;
-        __rust_start_panic(obj)
-    };
+fn rust_panic(msg: &mut dyn BoxMeUp) -> ! {
+    let code = unsafe { __rust_start_panic(msg) };
     rtabort!("failed to initiate panic, error {code}")
 }
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 838e33aca04..4d528a767e4 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -16,7 +16,7 @@ use crate::config::{SplitDebuginfo, TargetSelection};
 use crate::doc;
 use crate::flags::{Color, Subcommand};
 use crate::install;
-use crate::native;
+use crate::llvm;
 use crate::run;
 use crate::setup;
 use crate::test;
@@ -636,13 +636,13 @@ impl<'a> Builder<'a> {
                 tool::Rustdoc,
                 tool::Clippy,
                 tool::CargoClippy,
-                native::Llvm,
-                native::Sanitizers,
+                llvm::Llvm,
+                llvm::Sanitizers,
                 tool::Rustfmt,
                 tool::Miri,
                 tool::CargoMiri,
-                native::Lld,
-                native::CrtBeginEnd
+                llvm::Lld,
+                llvm::CrtBeginEnd
             ),
             Kind::Check | Kind::Clippy | Kind::Fix => describe!(
                 check::Std,
@@ -1101,7 +1101,7 @@ impl<'a> Builder<'a> {
     /// check build or dry-run, where there's no need to build all of LLVM.
     fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
         if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run() {
-            let native::LlvmResult { llvm_config, .. } = self.ensure(native::Llvm { target });
+            let llvm::LlvmResult { llvm_config, .. } = self.ensure(llvm::Llvm { target });
             if llvm_config.is_file() {
                 return Some(llvm_config);
             }
@@ -1227,7 +1227,7 @@ impl<'a> Builder<'a> {
             // rustc_llvm. But if LLVM is stale, that'll be a tiny amount
             // of work comparatively, and we'd likely need to rebuild it anyway,
             // so that's okay.
-            if crate::native::prebuilt_llvm_config(self, target).is_err() {
+            if crate::llvm::prebuilt_llvm_config(self, target).is_err() {
                 cargo.env("RUST_CHECK", "1");
             }
         }
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 54971af644c..67bd573a855 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -24,7 +24,7 @@ use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::config::{LlvmLibunwind, RustcLto, TargetSelection};
 use crate::dist;
-use crate::native;
+use crate::llvm;
 use crate::tool::SourceType;
 use crate::util::get_clang_cl_resource_dir;
 use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date};
@@ -191,7 +191,7 @@ fn copy_and_stamp(
 }
 
 fn copy_llvm_libunwind(builder: &Builder<'_>, target: TargetSelection, libdir: &Path) -> PathBuf {
-    let libunwind_path = builder.ensure(native::Libunwind { target });
+    let libunwind_path = builder.ensure(llvm::Libunwind { target });
     let libunwind_source = libunwind_path.join("libunwind.a");
     let libunwind_target = libdir.join("libunwind.a");
     builder.copy(&libunwind_source, &libunwind_target);
@@ -266,7 +266,7 @@ fn copy_self_contained_objects(
                 DependencyType::TargetSelfContained,
             );
         }
-        let crt_path = builder.ensure(native::CrtBeginEnd { target });
+        let crt_path = builder.ensure(llvm::CrtBeginEnd { target });
         for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
             let src = crt_path.join(obj);
             let target = libdir_self_contained.join(obj);
@@ -474,7 +474,7 @@ fn copy_sanitizers(
     compiler: &Compiler,
     target: TargetSelection,
 ) -> Vec<PathBuf> {
-    let runtimes: Vec<native::SanitizerRuntime> = builder.ensure(native::Sanitizers { target });
+    let runtimes: Vec<llvm::SanitizerRuntime> = builder.ensure(llvm::Sanitizers { target });
 
     if builder.config.dry_run() {
         return Vec::new();
@@ -876,12 +876,12 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
     // busting caches (e.g. like #71152).
     if builder.config.llvm_enabled()
         && (builder.kind != Kind::Check
-            || crate::native::prebuilt_llvm_config(builder, target).is_ok())
+            || crate::llvm::prebuilt_llvm_config(builder, target).is_ok())
     {
         if builder.is_rust_llvm(target) {
             cargo.env("LLVM_RUSTLLVM", "1");
         }
-        let native::LlvmResult { llvm_config, .. } = builder.ensure(native::Llvm { target });
+        let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target });
         cargo.env("LLVM_CONFIG", &llvm_config);
         if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
             cargo.env("CFG_LLVM_ROOT", s);
@@ -1359,7 +1359,7 @@ impl Step for Assemble {
         }
 
         let lld_install = if builder.config.lld_enabled {
-            Some(builder.ensure(native::Lld { target: target_compiler.host }))
+            Some(builder.ensure(llvm::Lld { target: target_compiler.host }))
         } else {
             None
         };
@@ -1423,8 +1423,8 @@ impl Step for Assemble {
         }
 
         if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
-            let native::LlvmResult { llvm_config, .. } =
-                builder.ensure(native::Llvm { target: target_compiler.host });
+            let llvm::LlvmResult { llvm_config, .. } =
+                builder.ensure(llvm::Llvm { target: target_compiler.host });
             if !builder.config.dry_run() {
                 let llvm_bin_dir = output(Command::new(llvm_config).arg("--bindir"));
                 let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 95625170478..0eba18c3a63 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -1207,11 +1207,11 @@ impl Config {
             config.llvm_from_ci = match llvm.download_ci_llvm {
                 Some(StringOrBool::String(s)) => {
                     assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
-                    crate::native::is_ci_llvm_available(&config, asserts)
+                    crate::llvm::is_ci_llvm_available(&config, asserts)
                 }
                 Some(StringOrBool::Bool(b)) => b,
                 None => {
-                    config.channel == "dev" && crate::native::is_ci_llvm_available(&config, asserts)
+                    config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, asserts)
                 }
             };
 
@@ -1254,7 +1254,7 @@ impl Config {
             }
         } else {
             config.llvm_from_ci =
-                config.channel == "dev" && crate::native::is_ci_llvm_available(&config, false);
+                config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, false);
         }
 
         if let Some(t) = toml.target {
diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs
index 16dc8c63abc..5cea143e0a7 100644
--- a/src/bootstrap/config/tests.rs
+++ b/src/bootstrap/config/tests.rs
@@ -11,7 +11,7 @@ fn parse(config: &str) -> Config {
 
 #[test]
 fn download_ci_llvm() {
-    if crate::native::is_ci_llvm_modified(&parse("")) {
+    if crate::llvm::is_ci_llvm_modified(&parse("")) {
         eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change");
         return;
     }
diff --git a/src/bootstrap/defaults/config.user.toml b/src/bootstrap/defaults/config.user.toml
index ee271c3fb51..25d9e649f23 100644
--- a/src/bootstrap/defaults/config.user.toml
+++ b/src/bootstrap/defaults/config.user.toml
@@ -8,9 +8,11 @@ doc-stage = 2
 # When compiling from source, you usually want all tools.
 extended = true
 
+# Most users installing from source want to build all parts of the project from source.
 [llvm]
-# Most users installing from source want to build all parts of the project from source, not just rustc itself.
 download-ci-llvm = false
+[rust]
+download-rustc = false
 
 [dist]
 # Use better compression when preparing tarballs.
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index dceb4bd1b89..2ce54d9a3b4 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -27,7 +27,7 @@ use crate::channel;
 use crate::compile;
 use crate::config::TargetSelection;
 use crate::doc::DocumentationFormat;
-use crate::native;
+use crate::llvm;
 use crate::tarball::{GeneratedTarball, OverlayKind, Tarball};
 use crate::tool::{self, Tool};
 use crate::util::{exe, is_dylib, output, t, timeit};
@@ -1965,8 +1965,8 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
             builder.install(&llvm_dylib_path, dst_libdir, 0o644);
         }
         !builder.config.dry_run()
-    } else if let Ok(native::LlvmResult { llvm_config, .. }) =
-        native::prebuilt_llvm_config(builder, target)
+    } else if let Ok(llvm::LlvmResult { llvm_config, .. }) =
+        llvm::prebuilt_llvm_config(builder, target)
     {
         let mut cmd = Command::new(llvm_config);
         cmd.arg("--libfiles");
@@ -2154,7 +2154,7 @@ impl Step for LlvmTools {
             }
         }
 
-        builder.ensure(crate::native::Llvm { target });
+        builder.ensure(crate::llvm::Llvm { target });
 
         let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
         tarball.set_overlay(OverlayKind::LLVM);
@@ -2213,10 +2213,10 @@ impl Step for RustDev {
         let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
         tarball.set_overlay(OverlayKind::LLVM);
 
-        builder.ensure(crate::native::Llvm { target });
+        builder.ensure(crate::llvm::Llvm { target });
 
         // We want to package `lld` to use it with `download-ci-llvm`.
-        builder.ensure(crate::native::Lld { target });
+        builder.ensure(crate::llvm::Lld { target });
 
         let src_bindir = builder.llvm_out(target).join("bin");
         // If updating this list, you likely want to change
diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs
index d1e2149d3f9..8fbc034965a 100644
--- a/src/bootstrap/download.rs
+++ b/src/bootstrap/download.rs
@@ -12,7 +12,7 @@ use xz2::bufread::XzDecoder;
 
 use crate::{
     config::RustfmtMetadata,
-    native::detect_llvm_sha,
+    llvm::detect_llvm_sha,
     t,
     util::{check_run, exe, program_out_of_date, try_run},
     Config,
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 54aa5a585bb..20b92b294fe 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -53,8 +53,8 @@ mod download;
 mod flags;
 mod format;
 mod install;
+mod llvm;
 mod metadata;
-mod native;
 mod render_tests;
 mod run;
 mod sanity;
diff --git a/src/bootstrap/native.rs b/src/bootstrap/llvm.rs
index f27db5c91e2..de06f8ca8c0 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/llvm.rs
@@ -870,71 +870,6 @@ impl Step for Lld {
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct TestHelpers {
-    pub target: TargetSelection,
-}
-
-impl Step for TestHelpers {
-    type Output = ();
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("tests/auxiliary/rust_test_helpers.c")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(TestHelpers { target: run.target })
-    }
-
-    /// Compiles the `rust_test_helpers.c` library which we used in various
-    /// `run-pass` tests for ABI testing.
-    fn run(self, builder: &Builder<'_>) {
-        if builder.config.dry_run() {
-            return;
-        }
-        // The x86_64-fortanix-unknown-sgx target doesn't have a working C
-        // toolchain. However, some x86_64 ELF objects can be linked
-        // without issues. Use this hack to compile the test helpers.
-        let target = if self.target == "x86_64-fortanix-unknown-sgx" {
-            TargetSelection::from_user("x86_64-unknown-linux-gnu")
-        } else {
-            self.target
-        };
-        let dst = builder.test_helpers_out(target);
-        let src = builder.src.join("tests/auxiliary/rust_test_helpers.c");
-        if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
-            return;
-        }
-
-        builder.info("Building test helpers");
-        t!(fs::create_dir_all(&dst));
-        let mut cfg = cc::Build::new();
-        // FIXME: Workaround for https://github.com/emscripten-core/emscripten/issues/9013
-        if target.contains("emscripten") {
-            cfg.pic(false);
-        }
-
-        // We may have found various cross-compilers a little differently due to our
-        // extra configuration, so inform cc of these compilers. Note, though, that
-        // on MSVC we still need cc's detection of env vars (ugh).
-        if !target.contains("msvc") {
-            if let Some(ar) = builder.ar(target) {
-                cfg.archiver(ar);
-            }
-            cfg.compiler(builder.cc(target));
-        }
-        cfg.cargo_metadata(false)
-            .out_dir(&dst)
-            .target(&target.triple)
-            .host(&builder.config.build.triple)
-            .opt_level(0)
-            .warnings(false)
-            .debug(false)
-            .file(builder.src.join("tests/auxiliary/rust_test_helpers.c"))
-            .compile("rust_test_helpers");
-    }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Sanitizers {
     pub target: TargetSelection,
 }
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 29d37c09d88..92a7603a9df 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -19,11 +19,11 @@ use crate::config::TargetSelection;
 use crate::dist;
 use crate::doc::DocumentationFormat;
 use crate::flags::Subcommand;
-use crate::native;
+use crate::llvm;
 use crate::render_tests::add_flags_and_try_run_tests;
 use crate::tool::{self, SourceType, Tool};
 use crate::toolstate::ToolState;
-use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t};
+use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t, up_to_date};
 use crate::{envify, CLang, DocTests, GitRepo, Mode};
 
 const ADB_TEST_DIR: &str = "/data/local/tmp/work";
@@ -1434,11 +1434,11 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         builder.ensure(compile::Std::new(compiler, compiler.host));
 
         // Also provide `rust_test_helpers` for the host.
-        builder.ensure(native::TestHelpers { target: compiler.host });
+        builder.ensure(TestHelpers { target: compiler.host });
 
         // As well as the target, except for plain wasm32, which can't build it
         if !target.contains("wasm") || target.contains("emscripten") {
-            builder.ensure(native::TestHelpers { target });
+            builder.ensure(TestHelpers { target });
         }
 
         builder.ensure(RemoteCopyLibs { compiler, target });
@@ -1625,8 +1625,8 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         let mut llvm_components_passed = false;
         let mut copts_passed = false;
         if builder.config.llvm_enabled() {
-            let native::LlvmResult { llvm_config, .. } =
-                builder.ensure(native::Llvm { target: builder.config.build });
+            let llvm::LlvmResult { llvm_config, .. } =
+                builder.ensure(llvm::Llvm { target: builder.config.build });
             if !builder.config.dry_run() {
                 let llvm_version = output(Command::new(&llvm_config).arg("--version"));
                 let llvm_components = output(Command::new(&llvm_config).arg("--components"));
@@ -1664,7 +1664,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
                 // If LLD is available, add it to the PATH
                 if builder.config.lld_enabled {
                     let lld_install_root =
-                        builder.ensure(native::Lld { target: builder.config.build });
+                        builder.ensure(llvm::Lld { target: builder.config.build });
 
                     let lld_bin_path = lld_install_root.join("bin");
 
@@ -2747,3 +2747,68 @@ impl Step for RustInstaller {
         run.builder.ensure(Self);
     }
 }
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct TestHelpers {
+    pub target: TargetSelection,
+}
+
+impl Step for TestHelpers {
+    type Output = ();
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("tests/auxiliary/rust_test_helpers.c")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(TestHelpers { target: run.target })
+    }
+
+    /// Compiles the `rust_test_helpers.c` library which we used in various
+    /// `run-pass` tests for ABI testing.
+    fn run(self, builder: &Builder<'_>) {
+        if builder.config.dry_run() {
+            return;
+        }
+        // The x86_64-fortanix-unknown-sgx target doesn't have a working C
+        // toolchain. However, some x86_64 ELF objects can be linked
+        // without issues. Use this hack to compile the test helpers.
+        let target = if self.target == "x86_64-fortanix-unknown-sgx" {
+            TargetSelection::from_user("x86_64-unknown-linux-gnu")
+        } else {
+            self.target
+        };
+        let dst = builder.test_helpers_out(target);
+        let src = builder.src.join("tests/auxiliary/rust_test_helpers.c");
+        if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
+            return;
+        }
+
+        builder.info("Building test helpers");
+        t!(fs::create_dir_all(&dst));
+        let mut cfg = cc::Build::new();
+        // FIXME: Workaround for https://github.com/emscripten-core/emscripten/issues/9013
+        if target.contains("emscripten") {
+            cfg.pic(false);
+        }
+
+        // We may have found various cross-compilers a little differently due to our
+        // extra configuration, so inform cc of these compilers. Note, though, that
+        // on MSVC we still need cc's detection of env vars (ugh).
+        if !target.contains("msvc") {
+            if let Some(ar) = builder.ar(target) {
+                cfg.archiver(ar);
+            }
+            cfg.compiler(builder.cc(target));
+        }
+        cfg.cargo_metadata(false)
+            .out_dir(&dst)
+            .target(&target.triple)
+            .host(&builder.config.build.triple)
+            .opt_level(0)
+            .warnings(false)
+            .debug(false)
+            .file(builder.src.join("tests/auxiliary/rust_test_helpers.c"))
+            .compile("rust_test_helpers");
+    }
+}
diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py
index d4d80e8f77c..7cd5e88f6a2 100644
--- a/src/ci/stage-build.py
+++ b/src/ci/stage-build.py
@@ -727,7 +727,7 @@ def record_metrics(pipeline: Pipeline, timer: Timer):
     metrics = load_last_metrics(pipeline.metrics_path())
     if metrics is None:
         return
-    llvm_steps = tuple(metrics.find_all_by_type("bootstrap::native::Llvm"))
+    llvm_steps = tuple(metrics.find_all_by_type("bootstrap::llvm::Llvm"))
     assert len(llvm_steps) > 0
     llvm_duration = sum(step.duration for step in llvm_steps)
 
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 840ed8e1080..c081578b8d4 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1946,11 +1946,7 @@ function initSearch(rawSearchIndex) {
     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"
-            // By default, the search DOM element is "empty" (meaning it has no children not
-            // text content). Once a search has been run, it won't be empty, even if you press
-            // ESC or empty the search input (which also "cancels" the search).
-            && (!search.firstChild || search.firstChild.innerText !== searchState.loadingText))
+            && getSettingValue("go-to-only-result") === "true")
         ) {
             const elem = document.createElement("a");
             elem.href = results.others[0].href;
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 1ab81aee7b8..327e090d38b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -124,9 +124,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
 
         let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter())
             .filter(|p| !p.is_global())
-            .filter_map(|obligation| {
+            .filter_map(|pred| {
                 // Note that we do not want to deal with qualified predicates here.
-                match obligation.predicate.kind().no_bound_vars() {
+                match pred.kind().no_bound_vars() {
                     Some(ty::PredicateKind::Clause(ty::Clause::Trait(pred))) if pred.def_id() != sized_trait => {
                         Some(pred)
                     },
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 29830557a44..fd06c0b8677 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -2106,7 +2106,6 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
     traits::impossible_predicates(
         cx.tcx,
         traits::elaborate_predicates(cx.tcx, predicates)
-            .map(|o| o.predicate)
             .collect::<Vec<_>>(),
     )
 }
diff --git a/tests/rustdoc-gui/setting-go-to-only-result.goml b/tests/rustdoc-gui/setting-go-to-only-result.goml
new file mode 100644
index 00000000000..3811011a64e
--- /dev/null
+++ b/tests/rustdoc-gui/setting-go-to-only-result.goml
@@ -0,0 +1,63 @@
+// Checks that the setting "Directly go to item in search if there is only one result " is working as expected.
+
+define-function: (
+    "check-setting",
+    (storage_value, setting_attribute_value),
+    block {
+        assert-local-storage: {"rustdoc-go-to-only-result": |storage_value|}
+        click: "#settings-menu"
+        wait-for: "#settings"
+        assert-property: ("#go-to-only-result", {"checked": |setting_attribute_value|})
+    }
+)
+
+goto: "file://" + |DOC_PATH| + "/lib2/index.html"
+
+call-function: ("check-setting", {
+    "storage_value": null,
+    "setting_attribute_value": "false",
+})
+
+// By default, the search doesn't automatically go to the page if there is only one result.
+goto: "file://" + |DOC_PATH| + "/lib2/index.html?search=HasALongTraitWithParams"
+// It will timeout if the setting isn't working.
+wait-for: "#search"
+assert-document-property: ({"URL": "/lib2/index.html"}, CONTAINS)
+
+// Now we change its value.
+click: "#settings-menu"
+wait-for: "#settings"
+click: "#go-to-only-result"
+assert-local-storage: {"rustdoc-go-to-only-result": "true"}
+
+goto: "file://" + |DOC_PATH| + "/lib2/index.html"
+// We enter it into the search.
+write: (".search-input", "HasALongTraitWithParams")
+wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"}
+assert-document-property: ({"URL": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH)
+
+// We try again to see if it goes to the only result
+goto: "file://" + |DOC_PATH| + "/lib2/index.html?search=HasALongTraitWithParams"
+wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"}
+assert-document-property: ({"URL": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH)
+
+// We check the settings
+call-function: ("check-setting", {
+    "storage_value": "true",
+    "setting_attribute_value": "true",
+})
+
+// And now we re-disable the setting.
+click: "#go-to-only-result"
+assert-local-storage: {"rustdoc-go-to-only-result": "false"}
+
+goto: "file://" + |DOC_PATH| + "/lib2/index.html?search=HasALongTraitWithParams"
+// It will timeout if the setting isn't working.
+wait-for: "#search"
+assert-document-property: ({"URL": "/lib2/index.html"}, CONTAINS)
+
+// And we check everything is back the way it was before.
+call-function: ("check-setting", {
+    "storage_value": "false",
+    "setting_attribute_value": "false",
+})
diff --git a/tests/ui/inference/char-as-str-single.fixed b/tests/ui/inference/char-as-str-single.fixed
index bab1854dc51..1621a279f03 100644
--- a/tests/ui/inference/char-as-str-single.fixed
+++ b/tests/ui/inference/char-as-str-single.fixed
@@ -10,3 +10,12 @@ fn main() {
     let _: char = '人'; //~ ERROR mismatched types
     let _: char = '\''; //~ ERROR mismatched types
 }
+
+// regression test for https://github.com/rust-lang/rust/issues/109586
+#[allow(dead_code)]
+fn convert_c_to_str(c: char) {
+    match c {
+        'A' => {} //~ ERROR mismatched types
+        _ => {}
+    }
+}
diff --git a/tests/ui/inference/char-as-str-single.rs b/tests/ui/inference/char-as-str-single.rs
index 736920643b2..2903142f159 100644
--- a/tests/ui/inference/char-as-str-single.rs
+++ b/tests/ui/inference/char-as-str-single.rs
@@ -10,3 +10,12 @@ fn main() {
     let _: char = "人"; //~ ERROR mismatched types
     let _: char = "'"; //~ ERROR mismatched types
 }
+
+// regression test for https://github.com/rust-lang/rust/issues/109586
+#[allow(dead_code)]
+fn convert_c_to_str(c: char) {
+    match c {
+        "A" => {} //~ ERROR mismatched types
+        _ => {}
+    }
+}
diff --git a/tests/ui/inference/char-as-str-single.stderr b/tests/ui/inference/char-as-str-single.stderr
index 3375ec6ac32..9149efe3240 100644
--- a/tests/ui/inference/char-as-str-single.stderr
+++ b/tests/ui/inference/char-as-str-single.stderr
@@ -37,6 +37,19 @@ help: if you meant to write a `char` literal, use single quotes
 LL |     let _: char = '\'';
    |                   ~~~~
 
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-single.rs:18:9
+   |
+LL |     match c {
+   |           - this expression has type `char`
+LL |         "A" => {}
+   |         ^^^ expected `char`, found `&str`
+   |
+help: if you meant to write a `char` literal, use single quotes
+   |
+LL |         'A' => {}
+   |         ~~~
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0308`.