about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-02-23 02:05:13 +0000
committerbors <bors@rust-lang.org>2025-02-23 02:05:13 +0000
commitbca5f37cbded0db8d37414bb08c4b101a5f26d36 (patch)
tree9da15a1319e4c1692afd6b59bed28ee35339be7b /compiler
parent07697360aee0cebcb4e304236ba1884d8dde5469 (diff)
parente780b89959c7bfd7ab5a860f517209535884a39d (diff)
downloadrust-bca5f37cbded0db8d37414bb08c4b101a5f26d36.tar.gz
rust-bca5f37cbded0db8d37414bb08c4b101a5f26d36.zip
Auto merge of #137446 - matthiaskrgr:rollup-16moy6v, r=matthiaskrgr
Rollup of 6 pull requests

Successful merges:

 - #135501 (Inject `compiler_builtins` during postprocessing and ensure it is made private)
 - #137121 (stabilize `(const_)ptr_sub_ptr`)
 - #137180 (Give `global_asm` a fake body to store typeck results, represent `sym fn` as a hir expr to fix `sym fn` operands with lifetimes)
 - #137256 (compiler: untangle SIMD alignment assumptions)
 - #137383 (stabilize `unsigned_is_multiple_of`)
 - #137415 (Remove invalid suggestion of into_iter for extern macro)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_abi/src/callconv/reg.rs2
-rw-r--r--compiler/rustc_abi/src/layout.rs37
-rw-r--r--compiler/rustc_abi/src/lib.rs93
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs18
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs7
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs29
-rw-r--r--compiler/rustc_builtin_macros/src/standard_library_imports.rs49
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch2
-rw-r--r--compiler/rustc_codegen_cranelift/src/global_asm.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mono_item.rs9
-rw-r--r--compiler/rustc_hir/src/hir.rs27
-rw-r--r--compiler/rustc_hir/src/intravisit.rs14
-rw-r--r--compiler/rustc_hir/src/target.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs116
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs35
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs9
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs2
-rw-r--r--compiler/rustc_lint/src/builtin.rs8
-rw-r--r--compiler/rustc_lint/src/types.rs2
-rw-r--r--compiler/rustc_metadata/messages.ftl3
-rw-r--r--compiler/rustc_metadata/src/creader.rs175
-rw-r--r--compiler/rustc_metadata/src/errors.rs6
-rw-r--r--compiler/rustc_metadata/src/locator.rs10
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs8
-rw-r--r--compiler/rustc_middle/src/hir/map.rs5
-rw-r--r--compiler/rustc_middle/src/thir.rs4
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs6
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/into.rs17
-rw-r--r--compiler/rustc_mir_build/src/builder/mod.rs5
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs40
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs6
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs13
-rw-r--r--compiler/rustc_passes/src/reachable.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_serialize/src/lib.rs1
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs9
-rw-r--r--compiler/rustc_ty_utils/src/layout/invariant.rs51
49 files changed, 502 insertions, 408 deletions
diff --git a/compiler/rustc_abi/src/callconv/reg.rs b/compiler/rustc_abi/src/callconv/reg.rs
index 66f47c52c15..8cf140dbaad 100644
--- a/compiler/rustc_abi/src/callconv/reg.rs
+++ b/compiler/rustc_abi/src/callconv/reg.rs
@@ -57,7 +57,7 @@ impl Reg {
                 128 => dl.f128_align.abi,
                 _ => panic!("unsupported float: {self:?}"),
             },
-            RegKind::Vector => dl.vector_align(self.size).abi,
+            RegKind::Vector => dl.llvmlike_vector_align(self.size).abi,
         }
     }
 }
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 53243266f99..3f83787ea37 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -310,10 +310,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
         let mut max_repr_align = repr.align;
 
-        // If all the non-ZST fields have the same ABI and union ABI optimizations aren't
-        // disabled, we can use that common ABI for the union as a whole.
+        // If all the non-ZST fields have the same repr and union repr optimizations aren't
+        // disabled, we can use that common repr for the union as a whole.
         struct AbiMismatch;
-        let mut common_non_zst_abi_and_align = if repr.inhibits_union_abi_opt() {
+        let mut common_non_zst_repr_and_align = if repr.inhibits_union_abi_opt() {
             // Can't optimize
             Err(AbiMismatch)
         } else {
@@ -337,14 +337,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
                 continue;
             }
 
-            if let Ok(common) = common_non_zst_abi_and_align {
+            if let Ok(common) = common_non_zst_repr_and_align {
                 // Discard valid range information and allow undef
                 let field_abi = field.backend_repr.to_union();
 
                 if let Some((common_abi, common_align)) = common {
                     if common_abi != field_abi {
                         // Different fields have different ABI: disable opt
-                        common_non_zst_abi_and_align = Err(AbiMismatch);
+                        common_non_zst_repr_and_align = Err(AbiMismatch);
                     } else {
                         // Fields with the same non-Aggregate ABI should also
                         // have the same alignment
@@ -357,7 +357,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
                     }
                 } else {
                     // First non-ZST field: record its ABI and alignment
-                    common_non_zst_abi_and_align = Ok(Some((field_abi, field.align.abi)));
+                    common_non_zst_repr_and_align = Ok(Some((field_abi, field.align.abi)));
                 }
             }
         }
@@ -376,16 +376,25 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
 
         // If all non-ZST fields have the same ABI, we may forward that ABI
         // for the union as a whole, unless otherwise inhibited.
-        let abi = match common_non_zst_abi_and_align {
+        let backend_repr = match common_non_zst_repr_and_align {
             Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true },
-            Ok(Some((abi, _))) => {
-                if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) {
-                    // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
+            Ok(Some((repr, _))) => match repr {
+                // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
+                BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _)
+                    if repr.scalar_align(dl).unwrap() != align.abi =>
+                {
                     BackendRepr::Memory { sized: true }
-                } else {
-                    abi
                 }
-            }
+                // Vectors require at least element alignment, else disable the opt
+                BackendRepr::Vector { element, count: _ } if element.align(dl).abi > align.abi => {
+                    BackendRepr::Memory { sized: true }
+                }
+                // the alignment tests passed and we can use this
+                BackendRepr::Scalar(..)
+                | BackendRepr::ScalarPair(..)
+                | BackendRepr::Vector { .. }
+                | BackendRepr::Memory { .. } => repr,
+            },
         };
 
         let Some(union_field_count) = NonZeroUsize::new(only_variant.len()) else {
@@ -400,7 +409,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         Ok(LayoutData {
             variants: Variants::Single { index: only_variant_idx },
             fields: FieldsShape::Union(union_field_count),
-            backend_repr: abi,
+            backend_repr,
             largest_niche: None,
             uninhabited: false,
             align,
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 34228912041..eb90bb42b72 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -408,16 +408,21 @@ impl TargetDataLayout {
         }
     }
 
+    /// psABI-mandated alignment for a vector type, if any
     #[inline]
-    pub fn vector_align(&self, vec_size: Size) -> AbiAndPrefAlign {
-        for &(size, align) in &self.vector_align {
-            if size == vec_size {
-                return align;
-            }
-        }
-        // Default to natural alignment, which is what LLVM does.
-        // That is, use the size, rounded up to a power of 2.
-        AbiAndPrefAlign::new(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap())
+    fn cabi_vector_align(&self, vec_size: Size) -> Option<AbiAndPrefAlign> {
+        self.vector_align
+            .iter()
+            .find(|(size, _align)| *size == vec_size)
+            .map(|(_size, align)| *align)
+    }
+
+    /// an alignment resembling the one LLVM would pick for a vector
+    #[inline]
+    pub fn llvmlike_vector_align(&self, vec_size: Size) -> AbiAndPrefAlign {
+        self.cabi_vector_align(vec_size).unwrap_or(AbiAndPrefAlign::new(
+            Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(),
+        ))
     }
 }
 
@@ -810,20 +815,19 @@ impl Align {
         self.bits().try_into().unwrap()
     }
 
-    /// Computes the best alignment possible for the given offset
-    /// (the largest power of two that the offset is a multiple of).
+    /// Obtain the greatest factor of `size` that is an alignment
+    /// (the largest power of two the Size is a multiple of).
     ///
-    /// N.B., for an offset of `0`, this happens to return `2^64`.
+    /// Note that all numbers are factors of 0
     #[inline]
-    pub fn max_for_offset(offset: Size) -> Align {
-        Align { pow2: offset.bytes().trailing_zeros() as u8 }
+    pub fn max_aligned_factor(size: Size) -> Align {
+        Align { pow2: size.bytes().trailing_zeros() as u8 }
     }
 
-    /// Lower the alignment, if necessary, such that the given offset
-    /// is aligned to it (the offset is a multiple of the alignment).
+    /// Reduces Align to an aligned factor of `size`.
     #[inline]
-    pub fn restrict_for_offset(self, offset: Size) -> Align {
-        self.min(Align::max_for_offset(offset))
+    pub fn restrict_for_offset(self, size: Size) -> Align {
+        self.min(Align::max_aligned_factor(size))
     }
 }
 
@@ -1455,37 +1459,38 @@ impl BackendRepr {
         matches!(*self, BackendRepr::Scalar(s) if s.is_bool())
     }
 
-    /// Returns the fixed alignment of this ABI, if any is mandated.
-    pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
-        Some(match *self {
-            BackendRepr::Scalar(s) => s.align(cx),
-            BackendRepr::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)),
-            BackendRepr::Vector { element, count } => {
-                cx.data_layout().vector_align(element.size(cx) * count)
-            }
-            BackendRepr::Memory { .. } => return None,
-        })
+    /// The psABI alignment for a `Scalar` or `ScalarPair`
+    ///
+    /// `None` for other variants.
+    pub fn scalar_align<C: HasDataLayout>(&self, cx: &C) -> Option<Align> {
+        match *self {
+            BackendRepr::Scalar(s) => Some(s.align(cx).abi),
+            BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi),
+            // The align of a Vector can vary in surprising ways
+            BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => None,
+        }
     }
 
-    /// Returns the fixed size of this ABI, if any is mandated.
-    pub fn inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
-        Some(match *self {
-            BackendRepr::Scalar(s) => {
-                // No padding in scalars.
-                s.size(cx)
-            }
+    /// The psABI size for a `Scalar` or `ScalarPair`
+    ///
+    /// `None` for other variants
+    pub fn scalar_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
+        match *self {
+            // No padding in scalars.
+            BackendRepr::Scalar(s) => Some(s.size(cx)),
+            // May have some padding between the pair.
             BackendRepr::ScalarPair(s1, s2) => {
-                // May have some padding between the pair.
                 let field2_offset = s1.size(cx).align_to(s2.align(cx).abi);
-                (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi)
+                let size = (field2_offset + s2.size(cx)).align_to(
+                    self.scalar_align(cx)
+                        // We absolutely must have an answer here or everything is FUBAR.
+                        .unwrap(),
+                );
+                Some(size)
             }
-            BackendRepr::Vector { element, count } => {
-                // No padding in vectors, except possibly for trailing padding
-                // to make the size a multiple of align (e.g. for vectors of size 3).
-                (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi)
-            }
-            BackendRepr::Memory { .. } => return None,
-        })
+            // The size of a Vector can vary in surprising ways
+            BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => None,
+        }
     }
 
     /// Discard validity range information and allow undef.
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 96c230ec243..cfd32fc066f 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -1,13 +1,12 @@
 use std::collections::hash_map::Entry;
 use std::fmt::Write;
 
-use rustc_ast::ptr::P;
 use rustc_ast::*;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_session::parse::feature_err;
-use rustc_span::{Span, kw, sym};
+use rustc_span::{Span, sym};
 use rustc_target::asm;
 
 use super::LoweringContext;
@@ -230,20 +229,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 tokens: None,
                             };
 
-                            // Wrap the expression in an AnonConst.
-                            let parent_def_id = self.current_hir_id_owner.def_id;
-                            let node_id = self.next_node_id();
-                            self.create_def(
-                                parent_def_id,
-                                node_id,
-                                kw::Empty,
-                                DefKind::AnonConst,
-                                *op_sp,
-                            );
-                            let anon_const = AnonConst { id: node_id, value: P(expr) };
-                            hir::InlineAsmOperand::SymFn {
-                                anon_const: self.lower_anon_const_to_anon_const(&anon_const),
-                            }
+                            hir::InlineAsmOperand::SymFn { expr: self.lower_expr(&expr) }
                         }
                     }
                     InlineAsmOperand::Label { block } => {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index bc2db415469..1d3db64b47e 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -251,7 +251,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     .arena
                     .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
             },
-            ItemKind::GlobalAsm(asm) => hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)),
+            ItemKind::GlobalAsm(asm) => {
+                let asm = self.lower_inline_asm(span, asm);
+                let fake_body =
+                    self.lower_body(|this| (&[], this.expr(span, hir::ExprKind::InlineAsm(asm))));
+                hir::ItemKind::GlobalAsm { asm, fake_body }
+            }
             ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
                 // We lower
                 //
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index c578eb4dc45..3aa14b2e9b4 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -126,6 +126,11 @@ pub(crate) enum DefiningTy<'tcx> {
     /// The MIR represents an inline const. The signature has no inputs and a
     /// single return value found via `InlineConstArgs::ty`.
     InlineConst(DefId, GenericArgsRef<'tcx>),
+
+    // Fake body for a global asm. Not particularly useful or interesting,
+    // but we need it so we can properly store the typeck results of the asm
+    // operands, which aren't associated with a body otherwise.
+    GlobalAsm(DefId),
 }
 
 impl<'tcx> DefiningTy<'tcx> {
@@ -138,9 +143,10 @@ impl<'tcx> DefiningTy<'tcx> {
             DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
             DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(),
             DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(),
-            DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
-                ty::List::empty()
-            }
+            DefiningTy::FnDef(..)
+            | DefiningTy::Const(..)
+            | DefiningTy::InlineConst(..)
+            | DefiningTy::GlobalAsm(_) => ty::List::empty(),
         }
     }
 
@@ -152,7 +158,10 @@ impl<'tcx> DefiningTy<'tcx> {
             DefiningTy::Closure(..)
             | DefiningTy::CoroutineClosure(..)
             | DefiningTy::Coroutine(..) => 1,
-            DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
+            DefiningTy::FnDef(..)
+            | DefiningTy::Const(..)
+            | DefiningTy::InlineConst(..)
+            | DefiningTy::GlobalAsm(_) => 0,
         }
     }
 
@@ -171,7 +180,8 @@ impl<'tcx> DefiningTy<'tcx> {
             | DefiningTy::Coroutine(def_id, ..)
             | DefiningTy::FnDef(def_id, ..)
             | DefiningTy::Const(def_id, ..)
-            | DefiningTy::InlineConst(def_id, ..) => def_id,
+            | DefiningTy::InlineConst(def_id, ..)
+            | DefiningTy::GlobalAsm(def_id) => def_id,
         }
     }
 }
@@ -411,6 +421,7 @@ impl<'tcx> UniversalRegions<'tcx> {
                     tcx.def_path_str_with_args(def_id, args),
                 ));
             }
+            DefiningTy::GlobalAsm(_) => unreachable!(),
         }
     }
 
@@ -633,6 +644,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                     DefiningTy::InlineConst(self.mir_def.to_def_id(), args)
                 }
             }
+
+            BodyOwnerKind::GlobalAsm => DefiningTy::GlobalAsm(self.mir_def.to_def_id()),
         }
     }
 
@@ -666,6 +679,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             }
 
             DefiningTy::FnDef(_, args) | DefiningTy::Const(_, args) => args,
+
+            DefiningTy::GlobalAsm(_) => ty::List::empty(),
         };
 
         let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
@@ -802,6 +817,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 let ty = args.as_inline_const().ty();
                 ty::Binder::dummy(tcx.mk_type_list(&[ty]))
             }
+
+            DefiningTy::GlobalAsm(def_id) => {
+                ty::Binder::dummy(tcx.mk_type_list(&[tcx.type_of(def_id).instantiate_identity()]))
+            }
         };
 
         // FIXME(#129952): We probably want a more principled approach here.
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index 1a3f4d2d449..6933ca09349 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -19,16 +19,12 @@ pub fn inject(
     let edition = sess.psess.edition;
 
     // the first name in this list is the crate name of the crate with the prelude
-    let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) {
+    let name: Symbol = if attr::contains_name(pre_configured_attrs, sym::no_core) {
         return 0;
     } else if attr::contains_name(pre_configured_attrs, sym::no_std) {
-        if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) {
-            &[sym::core]
-        } else {
-            &[sym::core, sym::compiler_builtins]
-        }
+        sym::core
     } else {
-        &[sym::std]
+        sym::std
     };
 
     let expn_id = resolver.expansion_for_ast_pass(
@@ -43,36 +39,16 @@ pub fn inject(
     let ecfg = ExpansionConfig::default("std_lib_injection".to_string(), features);
     let cx = ExtCtxt::new(sess, ecfg, resolver, None);
 
-    // .rev() to preserve ordering above in combination with insert(0, ...)
-    for &name in names.iter().rev() {
-        let ident_span = if edition >= Edition2018 { span } else { call_site };
-        let item = if name == sym::compiler_builtins {
-            // compiler_builtins is a private implementation detail. We only
-            // need to insert it into the crate graph for linking and should not
-            // expose any of its public API.
-            //
-            // FIXME(#113634) We should inject this during post-processing like
-            // we do for the panic runtime, profiler runtime, etc.
-            cx.item(
-                span,
-                Ident::new(kw::Underscore, ident_span),
-                thin_vec![],
-                ast::ItemKind::ExternCrate(Some(name)),
-            )
-        } else {
-            cx.item(
-                span,
-                Ident::new(name, ident_span),
-                thin_vec![cx.attr_word(sym::macro_use, span)],
-                ast::ItemKind::ExternCrate(None),
-            )
-        };
-        krate.items.insert(0, item);
-    }
+    let ident_span = if edition >= Edition2018 { span } else { call_site };
 
-    // The crates have been injected, the assumption is that the first one is
-    // the one with the prelude.
-    let name = names[0];
+    let item = cx.item(
+        span,
+        Ident::new(name, ident_span),
+        thin_vec![cx.attr_word(sym::macro_use, span)],
+        ast::ItemKind::ExternCrate(None),
+    );
+
+    krate.items.insert(0, item);
 
     let root = (edition == Edition2015).then_some(kw::PathRoot);
 
@@ -88,6 +64,7 @@ pub fn inject(
         .map(|&symbol| Ident::new(symbol, span))
         .collect();
 
+    // Inject the relevant crate's prelude.
     let use_item = cx.item(
         span,
         Ident::empty(),
diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
index e3a9512dda9..eb1fc4b0ad5 100644
--- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
@@ -15,7 +15,7 @@ index 7165c3e48af..968552ad435 100644
  edition = "2021"
  
  [dependencies]
- core = { path = "../core" }
+ core = { path = "../core", public = true }
 -compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std'] }
 +compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std', 'no-f16-f128'] }
  
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index 54745b0d8c1..9ea92c300f8 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -16,7 +16,7 @@ use crate::prelude::*;
 
 pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
     let item = tcx.hir_item(item_id);
-    if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind {
+    if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
         let is_x86 =
             matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
 
@@ -55,7 +55,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
                                 }
                             }
                         }
-                        InlineAsmOperand::SymFn { anon_const } => {
+                        InlineAsmOperand::SymFn { expr } => {
                             if cfg!(not(feature = "inline_asm_sym")) {
                                 tcx.dcx().span_err(
                                     item.span,
@@ -63,7 +63,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
                                 );
                             }
 
-                            let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
+                            let ty = tcx.typeck(item_id.owner_id).expr_ty(expr);
                             let instance = match ty.kind() {
                                 &ty::FnDef(def_id, args) => Instance::new(def_id, args),
                                 _ => span_bug!(op_sp, "asm sym is not a function"),
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index 5f95b6615bd..f6af889fd6e 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -36,7 +36,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
             }
             MonoItem::GlobalAsm(item_id) => {
                 let item = cx.tcx().hir_item(item_id);
-                if let hir::ItemKind::GlobalAsm(asm) = item.kind {
+                if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
                     let operands: Vec<_> = asm
                         .operands
                         .iter()
@@ -71,11 +71,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
                                     }
                                 }
                             }
-                            hir::InlineAsmOperand::SymFn { ref anon_const } => {
-                                let ty = cx
-                                    .tcx()
-                                    .typeck_body(anon_const.body)
-                                    .node_type(anon_const.hir_id);
+                            hir::InlineAsmOperand::SymFn { expr } => {
+                                let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr);
                                 let instance = match ty.kind() {
                                     &ty::FnDef(def_id, args) => Instance::new(def_id, args),
                                     _ => span_bug!(*op_sp, "asm sym is not a function"),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index eafc60f9d72..61f64e62058 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1913,13 +1913,18 @@ pub enum BodyOwnerKind {
 
     /// Initializer of a `static` item.
     Static(Mutability),
+
+    /// Fake body for a global asm to store its const-like value types.
+    GlobalAsm,
 }
 
 impl BodyOwnerKind {
     pub fn is_fn_or_closure(self) -> bool {
         match self {
             BodyOwnerKind::Fn | BodyOwnerKind::Closure => true,
-            BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false,
+            BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) | BodyOwnerKind::GlobalAsm => {
+                false
+            }
         }
     }
 }
@@ -3420,7 +3425,7 @@ pub enum InlineAsmOperand<'hir> {
         anon_const: &'hir AnonConst,
     },
     SymFn {
-        anon_const: &'hir AnonConst,
+        expr: &'hir Expr<'hir>,
     },
     SymStatic {
         path: QPath<'hir>,
@@ -3848,7 +3853,7 @@ impl<'hir> Item<'hir> {
         expect_foreign_mod, (ExternAbi, &'hir [ForeignItemRef]),
             ItemKind::ForeignMod { abi, items }, (*abi, items);
 
-        expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm(asm), asm;
+        expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm { asm, .. }, asm;
 
         expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>),
             ItemKind::TyAlias(ty, generics), (ty, generics);
@@ -4015,7 +4020,15 @@ pub enum ItemKind<'hir> {
     /// An external module, e.g. `extern { .. }`.
     ForeignMod { abi: ExternAbi, items: &'hir [ForeignItemRef] },
     /// Module-level inline assembly (from `global_asm!`).
-    GlobalAsm(&'hir InlineAsm<'hir>),
+    GlobalAsm {
+        asm: &'hir InlineAsm<'hir>,
+        /// A fake body which stores typeck results for the global asm's sym_fn
+        /// operands, which are represented as path expressions. This body contains
+        /// a single [`ExprKind::InlineAsm`] which points to the asm in the field
+        /// above, and which is typechecked like a inline asm expr just for the
+        /// typeck results.
+        fake_body: BodyId,
+    },
     /// A type alias, e.g., `type Foo = Bar<u8>`.
     TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
     /// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
@@ -4081,7 +4094,7 @@ impl ItemKind<'_> {
             ItemKind::Macro(..) => "macro",
             ItemKind::Mod(..) => "module",
             ItemKind::ForeignMod { .. } => "extern block",
-            ItemKind::GlobalAsm(..) => "global asm item",
+            ItemKind::GlobalAsm { .. } => "global asm item",
             ItemKind::TyAlias(..) => "type alias",
             ItemKind::Enum(..) => "enum",
             ItemKind::Struct(..) => "struct",
@@ -4540,6 +4553,10 @@ impl<'hir> Node<'hir> {
                 ..
             }) => Some((owner_id.def_id, *body)),
 
+            Node::Item(Item {
+                owner_id, kind: ItemKind::GlobalAsm { asm: _, fake_body }, ..
+            }) => Some((owner_id.def_id, *fake_body)),
+
             Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => {
                 Some((*def_id, *body))
             }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index f62ae5ed0d6..d5fa7ec366b 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -573,9 +573,13 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_id(item.hir_id()));
             walk_list!(visitor, visit_foreign_item_ref, items);
         }
-        ItemKind::GlobalAsm(asm) => {
+        ItemKind::GlobalAsm { asm: _, fake_body } => {
             try_visit!(visitor.visit_id(item.hir_id()));
-            try_visit!(visitor.visit_inline_asm(asm, item.hir_id()));
+            // Visit the fake body, which contains the asm statement.
+            // Therefore we should not visit the asm statement again
+            // outside of the body, or some visitors won't have their
+            // typeck results set correctly.
+            try_visit!(visitor.visit_nested_body(fake_body));
         }
         ItemKind::TyAlias(ref ty, ref generics) => {
             try_visit!(visitor.visit_id(item.hir_id()));
@@ -1442,10 +1446,12 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>(
                 try_visit!(visitor.visit_expr(in_expr));
                 visit_opt!(visitor, visit_expr, out_expr);
             }
-            InlineAsmOperand::Const { anon_const, .. }
-            | InlineAsmOperand::SymFn { anon_const, .. } => {
+            InlineAsmOperand::Const { anon_const, .. } => {
                 try_visit!(visitor.visit_anon_const(anon_const));
             }
+            InlineAsmOperand::SymFn { expr, .. } => {
+                try_visit!(visitor.visit_expr(expr));
+            }
             InlineAsmOperand::SymStatic { path, .. } => {
                 try_visit!(visitor.visit_qpath(path, id, *op_sp));
             }
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index f3e8f059c9e..70e95a84e68 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -110,7 +110,7 @@ impl Target {
             ItemKind::Macro(..) => Target::MacroDef,
             ItemKind::Mod(..) => Target::Mod,
             ItemKind::ForeignMod { .. } => Target::ForeignMod,
-            ItemKind::GlobalAsm(..) => Target::GlobalAsm,
+            ItemKind::GlobalAsm { .. } => Target::GlobalAsm,
             ItemKind::TyAlias(..) => Target::TyAlias,
             ItemKind::Enum(..) => Target::Enum,
             ItemKind::Struct(..) => Target::Struct,
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index b1b046d7175..3236e0a3644 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -15,7 +15,6 @@ use rustc_lint_defs::builtin::{
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
 use rustc_middle::middle::stability::EvalResult;
-use rustc_middle::span_bug;
 use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::fold::{BottomUpFolder, fold_regions};
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
@@ -35,7 +34,6 @@ use {rustc_attr_parsing as attr, rustc_hir as hir};
 
 use super::compare_impl_item::check_type_bounds;
 use super::*;
-use crate::check::intrinsicck::InlineAsmCtxt;
 
 pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: ExternAbi) {
     if !tcx.sess.target.is_abi_supported(abi) {
@@ -895,13 +893,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                 }
             }
         }
-        DefKind::GlobalAsm => {
-            let it = tcx.hir().expect_item(def_id);
-            let hir::ItemKind::GlobalAsm(asm) = it.kind else {
-                span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it)
-            };
-            InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, def_id);
-        }
         _ => {}
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 90e93bdbb50..e1727fc48a8 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, LangItem};
 use rustc_middle::bug;
-use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
+use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Symbol, sym};
@@ -16,10 +16,11 @@ use rustc_target::asm::{
 
 use crate::errors::RegisterTypeUnstable;
 
-pub struct InlineAsmCtxt<'a, 'tcx> {
+pub struct InlineAsmCtxt<'a, 'tcx: 'a> {
     tcx: TyCtxt<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
-    get_operand_ty: Box<dyn Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
+    target_features: &'tcx FxIndexSet<Symbol>,
+    expr_ty: Box<dyn Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
 }
 
 enum NonAsmTypeReason<'tcx> {
@@ -29,25 +30,24 @@ enum NonAsmTypeReason<'tcx> {
 }
 
 impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
-    pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self {
+    pub fn new(
+        tcx: TyCtxt<'tcx>,
+        def_id: LocalDefId,
+        get_operand_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
+    ) -> Self {
         InlineAsmCtxt {
             tcx,
             typing_env: ty::TypingEnv {
                 typing_mode: ty::TypingMode::non_body_analysis(),
                 param_env: ty::ParamEnv::empty(),
             },
-            get_operand_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")),
+            target_features: tcx.asm_target_features(def_id),
+            expr_ty: Box::new(get_operand_ty),
         }
     }
 
-    // FIXME(#132279): This likely causes us to incorrectly handle opaque types in their
-    // defining scope.
-    pub fn new_in_fn(
-        tcx: TyCtxt<'tcx>,
-        typing_env: ty::TypingEnv<'tcx>,
-        get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
-    ) -> Self {
-        InlineAsmCtxt { tcx, typing_env, get_operand_ty: Box::new(get_operand_ty) }
+    fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> {
+        (self.expr_ty)(expr)
     }
 
     // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
@@ -139,9 +139,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         template: &[InlineAsmTemplatePiece],
         is_input: bool,
         tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>,
-        target_features: &FxIndexSet<Symbol>,
     ) -> Option<InlineAsmType> {
-        let ty = (self.get_operand_ty)(expr);
+        let ty = self.expr_ty(expr);
         if ty.has_non_region_infer() {
             bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
         }
@@ -229,7 +228,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         if let Some((in_expr, Some(in_asm_ty))) = tied_input {
             if in_asm_ty != asm_ty {
                 let msg = "incompatible types for asm inout argument";
-                let in_expr_ty = (self.get_operand_ty)(in_expr);
+                let in_expr_ty = self.expr_ty(in_expr);
                 self.tcx
                     .dcx()
                     .struct_span_err(vec![in_expr.span, expr.span], msg)
@@ -291,7 +290,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         // (!). In that case we still need the earlier check to verify that the
         // register class is usable at all.
         if let Some(feature) = feature {
-            if !target_features.contains(feature) {
+            if !self.target_features.contains(feature) {
                 let msg = format!("`{feature}` target feature is not enabled");
                 self.tcx
                     .dcx()
@@ -351,14 +350,13 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         Some(asm_ty)
     }
 
-    pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) {
-        let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id());
+    pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
         let Some(asm_arch) = self.tcx.sess.asm_arch else {
             self.tcx.dcx().delayed_bug("target architecture does not support asm");
             return;
         };
         let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
-        for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
+        for (idx, &(op, op_sp)) in asm.operands.iter().enumerate() {
             // Validate register classes against currently enabled target
             // features. We check that at least one type is available for
             // the enabled features.
@@ -381,12 +379,12 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     if let Err(msg) = reg.validate(
                         asm_arch,
                         self.tcx.sess.relocation_model(),
-                        target_features,
+                        self.target_features,
                         &self.tcx.sess.target,
                         op.is_clobber(),
                     ) {
                         let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
-                        self.tcx.dcx().span_err(*op_sp, msg);
+                        self.tcx.dcx().span_err(op_sp, msg);
                         continue;
                     }
                 }
@@ -401,7 +399,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     {
                         match feature {
                             Some(feature) => {
-                                if target_features.contains(&feature) {
+                                if self.target_features.contains(&feature) {
                                     missing_required_features.clear();
                                     break;
                                 } else {
@@ -426,7 +424,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                                 reg_class.name(),
                                 feature
                             );
-                            self.tcx.dcx().span_err(*op_sp, msg);
+                            self.tcx.dcx().span_err(op_sp, msg);
                             // register isn't enabled, don't do more checks
                             continue;
                         }
@@ -440,7 +438,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                                     .intersperse(", ")
                                     .collect::<String>(),
                             );
-                            self.tcx.dcx().span_err(*op_sp, msg);
+                            self.tcx.dcx().span_err(op_sp, msg);
                             // register isn't enabled, don't do more checks
                             continue;
                         }
@@ -448,52 +446,21 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                 }
             }
 
-            match *op {
+            match op {
                 hir::InlineAsmOperand::In { reg, expr } => {
-                    self.check_asm_operand_type(
-                        idx,
-                        reg,
-                        expr,
-                        asm.template,
-                        true,
-                        None,
-                        target_features,
-                    );
+                    self.check_asm_operand_type(idx, reg, expr, asm.template, true, None);
                 }
                 hir::InlineAsmOperand::Out { reg, late: _, expr } => {
                     if let Some(expr) = expr {
-                        self.check_asm_operand_type(
-                            idx,
-                            reg,
-                            expr,
-                            asm.template,
-                            false,
-                            None,
-                            target_features,
-                        );
+                        self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
                     }
                 }
                 hir::InlineAsmOperand::InOut { reg, late: _, expr } => {
-                    self.check_asm_operand_type(
-                        idx,
-                        reg,
-                        expr,
-                        asm.template,
-                        false,
-                        None,
-                        target_features,
-                    );
+                    self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
                 }
                 hir::InlineAsmOperand::SplitInOut { reg, late: _, in_expr, out_expr } => {
-                    let in_ty = self.check_asm_operand_type(
-                        idx,
-                        reg,
-                        in_expr,
-                        asm.template,
-                        true,
-                        None,
-                        target_features,
-                    );
+                    let in_ty =
+                        self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None);
                     if let Some(out_expr) = out_expr {
                         self.check_asm_operand_type(
                             idx,
@@ -502,7 +469,6 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                             asm.template,
                             false,
                             Some((in_expr, in_ty)),
-                            target_features,
                         );
                     }
                 }
@@ -514,11 +480,25 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     );
                 }
                 // Typeck has checked that SymFn refers to a function.
-                hir::InlineAsmOperand::SymFn { anon_const } => {
-                    debug_assert_matches!(
-                        self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
-                        ty::Error(_) | ty::FnDef(..)
-                    );
+                hir::InlineAsmOperand::SymFn { expr } => {
+                    let ty = self.expr_ty(expr);
+                    match ty.kind() {
+                        ty::FnDef(..) => {}
+                        ty::Error(_) => {}
+                        _ => {
+                            self.tcx
+                                .dcx()
+                                .struct_span_err(op_sp, "invalid `sym` operand")
+                                .with_span_label(
+                                    expr.span,
+                                    format!("is {} `{}`", ty.kind().article(), ty),
+                                )
+                                .with_help(
+                                    "`sym` operands must refer to either a function or a static",
+                                )
+                                .emit();
+                        }
+                    }
                 }
                 // AST lowering guarantees that SymStatic points to a static.
                 hir::InlineAsmOperand::SymStatic { .. } => {}
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 5bb77c096dc..d2334c8cec5 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -680,7 +680,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
         | hir::ItemKind::Use(..)
         | hir::ItemKind::Macro(..)
         | hir::ItemKind::Mod(_)
-        | hir::ItemKind::GlobalAsm(_) => {}
+        | hir::ItemKind::GlobalAsm { .. } => {}
         hir::ItemKind::ForeignMod { items, .. } => {
             for item in *items {
                 let item = tcx.hir_foreign_item(item.id);
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index a363076b75a..2cdd9a3a934 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -189,8 +189,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                     // Exclude `GlobalAsm` here which cannot have generics.
                     Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
                         if asm.operands.iter().any(|(op, _op_sp)| match op {
-                            hir::InlineAsmOperand::Const { anon_const }
-                            | hir::InlineAsmOperand::SymFn { anon_const } => {
+                            hir::InlineAsmOperand::Const { anon_const } => {
                                 anon_const.hir_id == hir_id
                             }
                             _ => false,
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index fee3c6088ed..e309654d750 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -623,7 +623,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             | hir::ItemKind::Mod(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::Static(..)
-            | hir::ItemKind::GlobalAsm(..) => {
+            | hir::ItemKind::GlobalAsm { .. } => {
                 // These sorts of items have no lifetime parameters at all.
                 intravisit::walk_item(self, item);
             }
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index cd5cf3bc2df..d564dc9699a 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -35,13 +35,6 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx
     let parent_node_id = tcx.parent_hir_id(hir_id);
     let parent_node = tcx.hir_node(parent_node_id);
 
-    let find_sym_fn = |&(op, op_sp)| match op {
-        hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == hir_id => {
-            Some((anon_const, op_sp))
-        }
-        _ => None,
-    };
-
     let find_const = |&(op, op_sp)| match op {
         hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
             Some((anon_const, op_sp))
@@ -59,31 +52,7 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx
 
         // Anon consts outside the type system.
         Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
-        | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
-            if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_sym_fn) =>
-        {
-            let ty = tcx.typeck(def_id).node_type(hir_id);
-
-            match ty.kind() {
-                ty::Error(_) => ty,
-                ty::FnDef(..) => ty,
-                _ => {
-                    let guar = tcx
-                        .dcx()
-                        .struct_span_err(op_sp, "invalid `sym` operand")
-                        .with_span_label(
-                            tcx.def_span(anon_const.def_id),
-                            format!("is {} `{}`", ty.kind().article(), ty),
-                        )
-                        .with_help("`sym` operands must refer to either a function or a static")
-                        .emit();
-
-                    Ty::new_error(tcx, guar)
-                }
-            }
-        }
-        Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
-        | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
+        | Node::Item(&Item { kind: ItemKind::GlobalAsm { asm, .. }, .. })
             if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) =>
         {
             let ty = tcx.typeck(def_id).node_type(hir_id);
@@ -313,12 +282,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
                 Ty::new_adt(tcx, def, args)
             }
+            ItemKind::GlobalAsm { .. } => tcx.typeck(def_id).node_type(hir_id),
             ItemKind::Trait(..)
             | ItemKind::TraitAlias(..)
             | ItemKind::Macro(..)
             | ItemKind::Mod(..)
             | ItemKind::ForeignMod { .. }
-            | ItemKind::GlobalAsm(..)
             | ItemKind::ExternCrate(..)
             | ItemKind::Use(..) => {
                 span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind);
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 82c4d37405a..fd1c3e50d95 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -692,7 +692,7 @@ impl<'a> State<'a> {
                 }
                 self.bclose(item.span);
             }
-            hir::ItemKind::GlobalAsm(asm) => {
+            hir::ItemKind::GlobalAsm { asm, .. } => {
                 self.head("global_asm!");
                 self.print_inline_asm(asm);
                 self.end()
@@ -1431,10 +1431,10 @@ impl<'a> State<'a> {
                     s.space();
                     s.print_anon_const(anon_const);
                 }
-                hir::InlineAsmOperand::SymFn { ref anon_const } => {
+                hir::InlineAsmOperand::SymFn { ref expr } => {
                     s.word("sym_fn");
                     s.space();
-                    s.print_anon_const(anon_const);
+                    s.print_expr(expr);
                 }
                 hir::InlineAsmOperand::SymStatic { ref path, def_id: _ } => {
                     s.word("sym_static");
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 277396da19c..0c71ef4655c 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -3763,7 +3763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut diverge = asm.asm_macro.diverges(asm.options);
 
         for (op, _op_sp) in asm.operands {
-            match op {
+            match *op {
                 hir::InlineAsmOperand::In { expr, .. } => {
                     self.check_expr_asm_operand(expr, true);
                 }
@@ -3778,10 +3778,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self.check_expr_asm_operand(out_expr, false);
                     }
                 }
+                hir::InlineAsmOperand::SymFn { expr } => {
+                    self.check_expr(expr);
+                }
                 // `AnonConst`s have their own body and is type-checked separately.
                 // As they don't flow into the type system we don't need them to
                 // be well-formed.
-                hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {}
+                hir::InlineAsmOperand::Const { .. } => {}
                 hir::InlineAsmOperand::SymStatic { .. } => {}
                 hir::InlineAsmOperand::Label { block } => {
                     let previous_diverges = self.diverges.get();
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index cf61659479b..120a43576e8 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len());
         for (asm, hir_id) in deferred_asm_checks.drain(..) {
             let enclosing_id = self.tcx.hir_enclosing_body_owner(hir_id);
-            let get_operand_ty = |expr| {
+            let expr_ty = |expr: &hir::Expr<'tcx>| {
                 let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
                 let ty = self.resolve_vars_if_possible(ty);
                 if ty.has_non_region_infer() {
@@ -110,12 +110,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.tcx.erase_regions(ty)
                 }
             };
-            InlineAsmCtxt::new_in_fn(
-                self.tcx,
-                self.infcx.typing_env(self.param_env),
-                get_operand_ty,
-            )
-            .check_asm(asm, enclosing_id);
+            InlineAsmCtxt::new(self.tcx, enclosing_id, expr_ty).check_asm(asm);
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 9d5184acb3c..0130ad775d9 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -133,7 +133,12 @@ fn typeck_with_inspect<'tcx>(
     }
     let mut fcx = FnCtxt::new(&root_ctxt, param_env, def_id);
 
-    if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
+    if let hir::Node::Item(hir::Item { kind: hir::ItemKind::GlobalAsm { .. }, .. }) = node {
+        // Check the fake body of a global ASM. There's not much to do here except
+        // for visit the asm expr of the body.
+        let ty = fcx.check_expr(body.value);
+        fcx.write_ty(id, ty);
+    } else if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
         let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() {
             // In the case that we're recovering `fn() -> W<_>` or some other return
             // type that has an infer in it, lower the type directly so that it'll
@@ -277,12 +282,9 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
                 Some(fcx.next_ty_var(span))
             }
             Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. })
-            | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => {
+            | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm { asm, .. }, span, .. }) => {
                 asm.operands.iter().find_map(|(op, _op_sp)| match op {
-                    hir::InlineAsmOperand::Const { anon_const }
-                    | hir::InlineAsmOperand::SymFn { anon_const }
-                        if anon_const.hir_id == id =>
-                    {
+                    hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => {
                         Some(fcx.next_ty_var(span))
                     }
                     _ => None,
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 8dd8398ba24..8438a92219e 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -905,11 +905,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else if self.impl_into_iterator_should_be_iterator(rcvr_ty, span, unsatisfied_predicates)
         {
             err.span_label(span, format!("`{rcvr_ty}` is not an iterator"));
-            err.multipart_suggestion_verbose(
-                "call `.into_iter()` first",
-                vec![(span.shrink_to_lo(), format!("into_iter()."))],
-                Applicability::MaybeIncorrect,
-            );
+            if !span.in_external_macro(self.tcx.sess.source_map()) {
+                err.multipart_suggestion_verbose(
+                    "call `.into_iter()` first",
+                    vec![(span.shrink_to_lo(), format!("into_iter()."))],
+                    Applicability::MaybeIncorrect,
+                );
+            }
             return err.emit();
         } else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) {
             // We special case the situation where we are looking for `_` in
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 8c50cc59c1d..3e9ce0e11e4 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -48,13 +48,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         for param in body.params {
             wbcx.visit_node_id(param.pat.span, param.hir_id);
         }
-        // Type only exists for constants and statics, not functions.
         match self.tcx.hir_body_owner_kind(item_def_id) {
-            hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => {
+            // Visit the type of a const or static, which is used during THIR building.
+            hir::BodyOwnerKind::Const { .. }
+            | hir::BodyOwnerKind::Static(_)
+            | hir::BodyOwnerKind::GlobalAsm => {
                 let item_hir_id = self.tcx.local_def_id_to_hir_id(item_def_id);
                 wbcx.visit_node_id(body.value.span, item_hir_id);
             }
-            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (),
+            // For closures and consts, we already plan to visit liberated signatures.
+            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {}
         }
         wbcx.visit_body(body);
         wbcx.visit_min_capture_map();
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 118a6fed036..56858679af6 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -261,7 +261,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
                     HirItem::ForeignMod { .. } => ("ItemForeignMod", LABELS_HIR_ONLY),
 
                     // Module-level inline assembly (from global_asm!)
-                    HirItem::GlobalAsm(..) => ("ItemGlobalAsm", LABELS_HIR_ONLY),
+                    HirItem::GlobalAsm { .. } => ("ItemGlobalAsm", LABELS_HIR_ONLY),
 
                     // A type alias, e.g., `type Foo = Bar<u8>`
                     HirItem::TyAlias(..) => ("ItemTy", LABELS_HIR_ONLY),
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 681a76e26f0..5e44583b297 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2907,7 +2907,13 @@ enum AsmLabelKind {
 impl<'tcx> LateLintPass<'tcx> for AsmLabels {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::Expr {
-            kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, options, .. }),
+            kind:
+                hir::ExprKind::InlineAsm(hir::InlineAsm {
+                    asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
+                    template_strs,
+                    options,
+                    ..
+                }),
             ..
         } = expr
         {
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index fa019a12469..31f75d3569c 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1740,7 +1740,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
             hir::ItemKind::Impl(..)
             | hir::ItemKind::TraitAlias(..)
             | hir::ItemKind::Trait(..)
-            | hir::ItemKind::GlobalAsm(..)
+            | hir::ItemKind::GlobalAsm { .. }
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::Mod(..)
             | hir::ItemKind::Macro(..)
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 6fc84b06647..df0a25712cc 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -47,6 +47,9 @@ metadata_crate_dep_rustc_driver =
 metadata_crate_location_unknown_type =
     extern location for {$crate_name} is of an unknown type: {$path}
 
+metadata_crate_not_compiler_builtins =
+    the crate `{$crate_name}` resolved as `compiler_builtins` but is not `#![compiler_builtins]`
+
 metadata_crate_not_panic_runtime =
     the crate `{$crate_name}` is not a panic runtime
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 4351d340013..12503ffd1a6 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -32,7 +32,7 @@ use rustc_session::lint::{self, BuiltinLintDiag};
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
 use rustc_span::edition::Edition;
-use rustc_span::{DUMMY_SP, Ident, STDLIB_STABLE_CRATES, Span, Symbol, sym};
+use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
 use rustc_target::spec::{PanicStrategy, Target, TargetTuple};
 use tracing::{debug, info, trace};
 
@@ -147,6 +147,7 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
             writeln!(fmt, "  cnum: {cnum}")?;
             writeln!(fmt, "  hash: {}", data.hash())?;
             writeln!(fmt, "  reqd: {:?}", data.dep_kind())?;
+            writeln!(fmt, "  priv: {:?}", data.is_private_dep())?;
             let CrateSource { dylib, rlib, rmeta } = data.source();
             if let Some(dylib) = dylib {
                 writeln!(fmt, "  dylib: {}", dylib.0.display())?;
@@ -162,6 +163,53 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
     }
 }
 
+/// Reason that a crate is being sourced as a dependency.
+#[derive(Clone, Copy)]
+enum CrateOrigin<'a> {
+    /// This crate was a dependency of another crate.
+    IndirectDependency {
+        /// Where this dependency was included from.
+        dep_root: &'a CratePaths,
+        /// True if the parent is private, meaning the dependent should also be private.
+        parent_private: bool,
+        /// Dependency info about this crate.
+        dep: &'a CrateDep,
+    },
+    /// Injected by `rustc`.
+    Injected,
+    /// Provided by `extern crate foo` or as part of the extern prelude.
+    Extern,
+}
+
+impl<'a> CrateOrigin<'a> {
+    /// Return the dependency root, if any.
+    fn dep_root(&self) -> Option<&'a CratePaths> {
+        match self {
+            CrateOrigin::IndirectDependency { dep_root, .. } => Some(dep_root),
+            _ => None,
+        }
+    }
+
+    /// Return dependency information, if any.
+    fn dep(&self) -> Option<&'a CrateDep> {
+        match self {
+            CrateOrigin::IndirectDependency { dep, .. } => Some(dep),
+            _ => None,
+        }
+    }
+
+    /// `Some(true)` if the dependency is private or its parent is private, `Some(false)` if the
+    /// dependency is not private, `None` if it could not be determined.
+    fn private_dep(&self) -> Option<bool> {
+        match self {
+            CrateOrigin::IndirectDependency { parent_private, dep, .. } => {
+                Some(dep.is_private || *parent_private)
+            }
+            _ => None,
+        }
+    }
+}
+
 impl CStore {
     pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> {
         FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
@@ -497,25 +545,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         &self,
         name: Symbol,
         private_dep: Option<bool>,
-        dep_root: Option<&CratePaths>,
+        origin: CrateOrigin<'_>,
     ) -> bool {
-        // Standard library crates are never private.
-        if STDLIB_STABLE_CRATES.contains(&name) {
-            tracing::info!("returning false for {name} is private");
-            return false;
-        }
-
-        let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep);
-
-        // Any descendants of `std` should be private. These crates are usually not marked
-        // private in metadata, so we ignore that field.
-        if extern_private.is_none()
-            && let Some(dep) = dep_root
-            && STDLIB_STABLE_CRATES.contains(&dep.name)
-        {
+        if matches!(origin, CrateOrigin::Injected) {
             return true;
         }
 
+        let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep);
         match (extern_private, private_dep) {
             // Explicit non-private via `--extern`, explicit non-private from metadata, or
             // unspecified with default to public.
@@ -528,7 +564,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     fn register_crate(
         &mut self,
         host_lib: Option<Library>,
-        dep_root: Option<&CratePaths>,
+        origin: CrateOrigin<'_>,
         lib: Library,
         dep_kind: CrateDepKind,
         name: Symbol,
@@ -540,7 +576,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         let Library { source, metadata } = lib;
         let crate_root = metadata.get_root();
         let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
-        let private_dep = self.is_private_dep(name, private_dep, dep_root);
+        let private_dep = self.is_private_dep(name, private_dep, origin);
 
         // Claim this crate number and cache it
         let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?;
@@ -556,14 +592,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // Maintain a reference to the top most crate.
         // Stash paths for top-most crate locally if necessary.
         let crate_paths;
-        let dep_root = if let Some(dep_root) = dep_root {
+        let dep_root = if let Some(dep_root) = origin.dep_root() {
             dep_root
         } else {
             crate_paths = CratePaths::new(crate_root.name(), source.clone());
             &crate_paths
         };
 
-        let cnum_map = self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind)?;
+        let cnum_map =
+            self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind, private_dep)?;
 
         let raw_proc_macros = if crate_root.is_proc_macro_crate() {
             let temp_root;
@@ -664,17 +701,19 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         name: Symbol,
         span: Span,
         dep_kind: CrateDepKind,
+        origin: CrateOrigin<'_>,
     ) -> Option<CrateNum> {
         self.used_extern_options.insert(name);
-        match self.maybe_resolve_crate(name, dep_kind, None) {
+        match self.maybe_resolve_crate(name, dep_kind, origin) {
             Ok(cnum) => {
                 self.cstore.set_used_recursively(cnum);
                 Some(cnum)
             }
             Err(err) => {
                 debug!("failed to resolve crate {} {:?}", name, dep_kind);
-                let missing_core =
-                    self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
+                let missing_core = self
+                    .maybe_resolve_crate(sym::core, CrateDepKind::Explicit, CrateOrigin::Extern)
+                    .is_err();
                 err.report(self.sess, span, missing_core);
                 None
             }
@@ -685,20 +724,20 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         &'b mut self,
         name: Symbol,
         mut dep_kind: CrateDepKind,
-        dep_of: Option<(&'b CratePaths, &'b CrateDep)>,
+        origin: CrateOrigin<'b>,
     ) -> Result<CrateNum, CrateError> {
         info!("resolving crate `{}`", name);
         if !name.as_str().is_ascii() {
             return Err(CrateError::NonAsciiName(name));
         }
 
-        let dep_root = dep_of.map(|d| d.0);
-        let dep = dep_of.map(|d| d.1);
+        let dep_root = origin.dep_root();
+        let dep = origin.dep();
         let hash = dep.map(|d| d.hash);
         let host_hash = dep.map(|d| d.host_hash).flatten();
         let extra_filename = dep.map(|d| &d.extra_filename[..]);
         let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };
-        let private_dep = dep.map(|d| d.is_private);
+        let private_dep = origin.private_dep();
 
         let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
             (LoadResult::Previous(cnum), None)
@@ -731,12 +770,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
         match result {
             (LoadResult::Previous(cnum), None) => {
-                info!("library for `{}` was loaded previously", name);
+                info!("library for `{}` was loaded previously, cnum {cnum}", name);
                 // When `private_dep` is none, it indicates the directly dependent crate. If it is
                 // not specified by `--extern` on command line parameters, it may be
                 // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
                 // `public-dependency` here.
-                let private_dep = self.is_private_dep(name, private_dep, dep_root);
+                let private_dep = self.is_private_dep(name, private_dep, origin);
                 let data = self.cstore.get_crate_data_mut(cnum);
                 if data.is_proc_macro_crate() {
                     dep_kind = CrateDepKind::MacrosOnly;
@@ -747,7 +786,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             }
             (LoadResult::Loaded(library), host_library) => {
                 info!("register newly loaded library for `{}`", name);
-                self.register_crate(host_library, dep_root, library, dep_kind, name, private_dep)
+                self.register_crate(host_library, origin, library, dep_kind, name, private_dep)
             }
             _ => panic!(),
         }
@@ -783,6 +822,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         metadata: &MetadataBlob,
         krate: CrateNum,
         dep_kind: CrateDepKind,
+        parent_is_private: bool,
     ) -> Result<CrateNumMap, CrateError> {
         debug!(
             "resolving deps of external crate `{}` with dep root `{}`",
@@ -801,17 +841,26 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         crate_num_map.push(krate);
         for dep in deps {
             info!(
-                "resolving dep `{}`->`{}` hash: `{}` extra filename: `{}`",
+                "resolving dep `{}`->`{}` hash: `{}` extra filename: `{}` private {}",
                 crate_root.name(),
                 dep.name,
                 dep.hash,
-                dep.extra_filename
+                dep.extra_filename,
+                dep.is_private,
             );
             let dep_kind = match dep_kind {
                 CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly,
                 _ => dep.kind,
             };
-            let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((dep_root, &dep)))?;
+            let cnum = self.maybe_resolve_crate(
+                dep.name,
+                dep_kind,
+                CrateOrigin::IndirectDependency {
+                    dep_root,
+                    parent_private: parent_is_private,
+                    dep: &dep,
+                },
+            )?;
             crate_num_map.push(cnum);
         }
 
@@ -905,7 +954,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         };
         info!("panic runtime not found -- loading {}", name);
 
-        let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else {
+        let Some(cnum) =
+            self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
+        else {
             return;
         };
         let data = self.cstore.get_crate_data(cnum);
@@ -934,7 +985,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         info!("loading profiler");
 
         let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
-        let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else {
+        let Some(cnum) =
+            self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
+        else {
             return;
         };
         let data = self.cstore.get_crate_data(cnum);
@@ -1047,12 +1100,54 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             if entry.force {
                 let name_interned = Symbol::intern(name);
                 if !self.used_extern_options.contains(&name_interned) {
-                    self.resolve_crate(name_interned, DUMMY_SP, CrateDepKind::Explicit);
+                    self.resolve_crate(
+                        name_interned,
+                        DUMMY_SP,
+                        CrateDepKind::Explicit,
+                        CrateOrigin::Extern,
+                    );
                 }
             }
         }
     }
 
+    /// Inject the `compiler_builtins` crate if it is not already in the graph.
+    fn inject_compiler_builtins(&mut self, krate: &ast::Crate) {
+        // `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates
+        if attr::contains_name(&krate.attrs, sym::compiler_builtins)
+            || attr::contains_name(&krate.attrs, sym::no_core)
+        {
+            info!("`compiler_builtins` unneeded");
+            return;
+        }
+
+        // If a `#![compiler_builtins]` crate already exists, avoid injecting it twice. This is
+        // the common case since usually it appears as a dependency of `std` or `alloc`.
+        for (cnum, cmeta) in self.cstore.iter_crate_data() {
+            if cmeta.is_compiler_builtins() {
+                info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");
+                return;
+            }
+        }
+
+        // `compiler_builtins` is not yet in the graph; inject it. Error on resolution failure.
+        let Some(cnum) = self.resolve_crate(
+            sym::compiler_builtins,
+            krate.spans.inner_span.shrink_to_lo(),
+            CrateDepKind::Explicit,
+            CrateOrigin::Injected,
+        ) else {
+            info!("`compiler_builtins` not resolved");
+            return;
+        };
+
+        // Sanity check that the loaded crate is `#![compiler_builtins]`
+        let cmeta = self.cstore.get_crate_data(cnum);
+        if !cmeta.is_compiler_builtins() {
+            self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
+        }
+    }
+
     fn inject_dependency_if(
         &mut self,
         krate: CrateNum,
@@ -1162,6 +1257,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     }
 
     pub fn postprocess(&mut self, krate: &ast::Crate) {
+        self.inject_compiler_builtins(krate);
         self.inject_forced_externs();
         self.inject_profiler_runtime();
         self.inject_allocator_crate(krate);
@@ -1173,6 +1269,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         info!("{:?}", CrateDump(self.cstore));
     }
 
+    /// Process an `extern crate foo` AST node.
     pub fn process_extern_crate(
         &mut self,
         item: &ast::Item,
@@ -1198,7 +1295,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                     CrateDepKind::Explicit
                 };
 
-                let cnum = self.resolve_crate(name, item.span, dep_kind)?;
+                let cnum = self.resolve_crate(name, item.span, dep_kind, CrateOrigin::Extern)?;
 
                 let path_len = definitions.def_path(def_id).data.len();
                 self.cstore.update_extern_crate(
@@ -1217,7 +1314,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     }
 
     pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
-        let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?;
+        let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?;
 
         self.cstore.update_extern_crate(
             cnum,
@@ -1234,7 +1331,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     }
 
     pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
-        self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok()
+        self.maybe_resolve_crate(name, CrateDepKind::Explicit, CrateOrigin::Extern).ok()
     }
 }
 
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index a77f9bc623b..2ad6389c0b4 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -333,6 +333,12 @@ pub struct CrateNotPanicRuntime {
 }
 
 #[derive(Diagnostic)]
+#[diag(metadata_crate_not_compiler_builtins)]
+pub struct CrateNotCompilerBuiltins {
+    pub crate_name: Symbol,
+}
+
+#[derive(Diagnostic)]
 #[diag(metadata_no_panic_strategy)]
 pub struct NoPanicStrategy {
     pub crate_name: Symbol,
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 2ddabeb49f7..3f3e58384cb 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -260,7 +260,7 @@ pub(crate) struct CrateLocator<'a> {
     crate_rejections: CrateRejections,
 }
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub(crate) struct CratePaths {
     pub(crate) name: Symbol,
     source: CrateSource,
@@ -272,7 +272,7 @@ impl CratePaths {
     }
 }
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq)]
 pub(crate) enum CrateFlavor {
     Rlib,
     Rmeta,
@@ -893,13 +893,13 @@ fn get_flavor_from_path(path: &Path) -> CrateFlavor {
 
 // ------------------------------------------ Error reporting -------------------------------------
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 struct CrateMismatch {
     path: PathBuf,
     got: String,
 }
 
-#[derive(Clone, Default)]
+#[derive(Clone, Debug, Default)]
 struct CrateRejections {
     via_hash: Vec<CrateMismatch>,
     via_triple: Vec<CrateMismatch>,
@@ -912,6 +912,7 @@ struct CrateRejections {
 /// Candidate rejection reasons collected during crate search.
 /// If no candidate is accepted, then these reasons are presented to the user,
 /// otherwise they are ignored.
+#[derive(Debug)]
 pub(crate) struct CombinedLocatorError {
     crate_name: Symbol,
     dep_root: Option<CratePaths>,
@@ -921,6 +922,7 @@ pub(crate) struct CombinedLocatorError {
     crate_rejections: CrateRejections,
 }
 
+#[derive(Debug)]
 pub(crate) enum CrateError {
     NonAsciiName(Symbol),
     ExternLocationNotExist(Symbol, PathBuf),
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index e8dcda875e6..ef0267eb3d9 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1936,6 +1936,10 @@ impl CrateMetadata {
         self.root.needs_panic_runtime
     }
 
+    pub(crate) fn is_private_dep(&self) -> bool {
+        self.private_dep
+    }
+
     pub(crate) fn is_panic_runtime(&self) -> bool {
         self.root.panic_runtime
     }
@@ -1944,6 +1948,10 @@ impl CrateMetadata {
         self.root.profiler_runtime
     }
 
+    pub(crate) fn is_compiler_builtins(&self) -> bool {
+        self.root.compiler_builtins
+    }
+
     pub(crate) fn needs_allocator(&self) -> bool {
         self.root.needs_allocator
     }
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index 40dd6aa73fd..ec046d82ef6 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -305,6 +305,7 @@ impl<'tcx> TyCtxt<'tcx> {
             DefKind::Static { safety: _, mutability, nested: false } => {
                 BodyOwnerKind::Static(mutability)
             }
+            DefKind::GlobalAsm => BodyOwnerKind::GlobalAsm,
             dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
         }
     }
@@ -327,7 +328,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 ConstContext::ConstFn
             }
             BodyOwnerKind::Fn if self.is_const_default_method(def_id) => ConstContext::ConstFn,
-            BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
+            BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None,
         };
 
         Some(ccx)
@@ -1166,7 +1167,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
                 ItemKind::Macro(..) => "macro",
                 ItemKind::Mod(..) => "mod",
                 ItemKind::ForeignMod { .. } => "foreign mod",
-                ItemKind::GlobalAsm(..) => "global asm",
+                ItemKind::GlobalAsm { .. } => "global asm",
                 ItemKind::TyAlias(..) => "ty",
                 ItemKind::Enum(..) => "enum",
                 ItemKind::Struct(..) => "struct",
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index c67ed356818..e5592de81cd 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -94,6 +94,7 @@ thir_with_elements! {
 pub enum BodyTy<'tcx> {
     Const(Ty<'tcx>),
     Fn(FnSig<'tcx>),
+    GlobalAsm(Ty<'tcx>),
 }
 
 /// Description of a type-checked function parameter.
@@ -605,8 +606,7 @@ pub enum InlineAsmOperand<'tcx> {
         span: Span,
     },
     SymFn {
-        value: mir::Const<'tcx>,
-        span: Span,
+        value: ExprId,
     },
     SymStatic {
         def_id: DefId,
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index afe24b55a83..a9df4d1625b 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -172,7 +172,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
                     }
                     Out { expr: None, reg: _, late: _ }
                     | Const { value: _, span: _ }
-                    | SymFn { value: _, span: _ }
+                    | SymFn { value: _ }
                     | SymStatic { def_id: _ } => {}
                     Label { block } => visitor.visit_block(&visitor.thir()[*block]),
                 }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 32a9e67f9ad..361e204fb0f 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1472,7 +1472,11 @@ impl<'tcx> TyCtxt<'tcx> {
             self.codegen_fn_attrs(def_id)
         } else if matches!(
             def_kind,
-            DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst
+            DefKind::AnonConst
+                | DefKind::AssocConst
+                | DefKind::Const
+                | DefKind::InlineConst
+                | DefKind::GlobalAsm
         ) {
             CodegenFnAttrs::EMPTY
         } else {
diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs
index 65dd061003d..72443e2f60d 100644
--- a/compiler/rustc_mir_build/src/builder/expr/into.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/into.rs
@@ -482,15 +482,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 }),
                             }
                         }
-                        thir::InlineAsmOperand::SymFn { value, span } => {
-                            mir::InlineAsmOperand::SymFn {
-                                value: Box::new(ConstOperand {
-                                    span,
-                                    user_ty: None,
-                                    const_: value,
-                                }),
-                            }
-                        }
+                        thir::InlineAsmOperand::SymFn { value } => mir::InlineAsmOperand::SymFn {
+                            value: Box::new(this.as_constant(&this.thir[value])),
+                        },
                         thir::InlineAsmOperand::SymStatic { def_id } => {
                             mir::InlineAsmOperand::SymStatic { def_id }
                         }
@@ -518,10 +512,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
 
                 let asm_macro = match asm_macro {
-                    AsmMacro::Asm => InlineAsmMacro::Asm,
-                    AsmMacro::GlobalAsm => {
-                        span_bug!(expr_span, "unexpected global_asm! in inline asm")
-                    }
+                    AsmMacro::Asm | AsmMacro::GlobalAsm => InlineAsmMacro::Asm,
                     AsmMacro::NakedAsm => InlineAsmMacro::NakedAsm,
                 };
 
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index 4348b7a4b4c..94955954934 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -61,7 +61,9 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
         Ok((thir, expr)) => {
             let build_mir = |thir: &Thir<'tcx>| match thir.body_type {
                 thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig),
-                thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty),
+                thir::BodyTy::Const(ty) | thir::BodyTy::GlobalAsm(ty) => {
+                    construct_const(tcx, def, thir, expr, ty)
+                }
             };
 
             // this must run before MIR dump, because
@@ -576,6 +578,7 @@ fn construct_const<'a, 'tcx>(
             let span = tcx.def_span(def);
             (span, span)
         }
+        Node::Item(hir::Item { kind: hir::ItemKind::GlobalAsm { .. }, span, .. }) => (*span, *span),
         _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
     };
 
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index d65c2097d22..c2eafd0a74e 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -2,6 +2,7 @@ use std::borrow::Cow;
 use std::mem;
 use std::ops::Bound;
 
+use rustc_ast::AsmMacro;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::DiagArgValue;
 use rustc_hir::def::DefKind;
@@ -559,7 +560,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 }
             }
             ExprKind::InlineAsm(box InlineAsmExpr {
-                asm_macro: _,
+                asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
                 ref operands,
                 template: _,
                 options: _,
@@ -583,7 +584,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                         }
                         Out { expr: None, reg: _, late: _ }
                         | Const { value: _, span: _ }
-                        | SymFn { value: _, span: _ }
+                        | SymFn { value: _ }
                         | SymStatic { def_id: _ } => {}
                         Label { block } => {
                             // Label blocks are safe context.
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index eb00b95f3c8..88877d05ffa 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -737,13 +737,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
 
                             InlineAsmOperand::Const { value, span }
                         }
-                        hir::InlineAsmOperand::SymFn { ref anon_const } => {
-                            let value =
-                                mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id())
-                                    .instantiate_identity();
-                            let span = tcx.def_span(anon_const.def_id);
-
-                            InlineAsmOperand::SymFn { value, span }
+                        hir::InlineAsmOperand::SymFn { expr } => {
+                            InlineAsmOperand::SymFn { value: self.mirror_expr(expr) }
                         }
                         hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
                             InlineAsmOperand::SymStatic { def_id }
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 7a9f6e46304..c32082c609e 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -76,23 +76,29 @@ impl<'tcx> ThirBuildCx<'tcx> {
         let hir = tcx.hir();
         let hir_id = tcx.local_def_id_to_hir_id(def);
 
-        let body_type = if tcx.hir_body_owner_kind(def).is_fn_or_closure() {
-            // fetch the fully liberated fn signature (that is, all bound
-            // types/lifetimes replaced)
-            BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
-        } else {
-            // Get the revealed type of this const. This is *not* the adjusted
-            // type of its body, which may be a subtype of this type. For
-            // example:
-            //
-            // fn foo(_: &()) {}
-            // static X: fn(&'static ()) = foo;
-            //
-            // The adjusted type of the body of X is `for<'a> fn(&'a ())` which
-            // is not the same as the type of X. We need the type of the return
-            // place to be the type of the constant because NLL typeck will
-            // equate them.
-            BodyTy::Const(typeck_results.node_type(hir_id))
+        let body_type = match tcx.hir_body_owner_kind(def) {
+            rustc_hir::BodyOwnerKind::Fn | rustc_hir::BodyOwnerKind::Closure => {
+                // fetch the fully liberated fn signature (that is, all bound
+                // types/lifetimes replaced)
+                BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
+            }
+            rustc_hir::BodyOwnerKind::Const { .. } | rustc_hir::BodyOwnerKind::Static(_) => {
+                // Get the revealed type of this const. This is *not* the adjusted
+                // type of its body, which may be a subtype of this type. For
+                // example:
+                //
+                // fn foo(_: &()) {}
+                // static X: fn(&'static ()) = foo;
+                //
+                // The adjusted type of the body of X is `for<'a> fn(&'a ())` which
+                // is not the same as the type of X. We need the type of the return
+                // place to be the type of the constant because NLL typeck will
+                // equate them.
+                BodyTy::Const(typeck_results.node_type(hir_id))
+            }
+            rustc_hir::BodyOwnerKind::GlobalAsm => {
+                BodyTy::GlobalAsm(typeck_results.node_type(hir_id))
+            }
         };
 
         Self {
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 9ab87dd99ff..cd56d93afcf 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -921,10 +921,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
                 print_indented!(self, "}", depth_lvl + 1);
             }
-            InlineAsmOperand::SymFn { value, span } => {
+            InlineAsmOperand::SymFn { value } => {
                 print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl);
-                print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1);
-                print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
+                print_indented!(self, "value: ", depth_lvl + 1);
+                self.print_expr(*value, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
             InlineAsmOperand::SymStatic { def_id } => {
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 1195c25e130..694a4dd5b4c 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -479,24 +479,23 @@ fn collect_items_rec<'tcx>(
             recursion_depth_reset = None;
 
             let item = tcx.hir_item(item_id);
-            if let hir::ItemKind::GlobalAsm(asm) = item.kind {
+            if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
                 for (op, op_sp) in asm.operands {
-                    match op {
+                    match *op {
                         hir::InlineAsmOperand::Const { .. } => {
                             // Only constants which resolve to a plain integer
                             // are supported. Therefore the value should not
                             // depend on any other items.
                         }
-                        hir::InlineAsmOperand::SymFn { anon_const } => {
-                            let fn_ty =
-                                tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
+                        hir::InlineAsmOperand::SymFn { expr } => {
+                            let fn_ty = tcx.typeck(item_id.owner_id).expr_ty(expr);
                             visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items);
                         }
                         hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
-                            let instance = Instance::mono(tcx, *def_id);
+                            let instance = Instance::mono(tcx, def_id);
                             if tcx.should_codegen_locally(instance) {
                                 trace!("collecting static {:?}", def_id);
-                                used_items.push(dummy_spanned(MonoItem::Static(*def_id)));
+                                used_items.push(dummy_spanned(MonoItem::Static(def_id)));
                             }
                         }
                         hir::InlineAsmOperand::In { .. }
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 1fe44bd3d21..fd465717bf7 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -246,7 +246,7 @@ impl<'tcx> ReachableContext<'tcx> {
                     | hir::ItemKind::Struct(..)
                     | hir::ItemKind::Enum(..)
                     | hir::ItemKind::Union(..)
-                    | hir::ItemKind::GlobalAsm(..) => {}
+                    | hir::ItemKind::GlobalAsm { .. } => {}
                 }
             }
             Node::TraitItem(trait_method) => {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 6faa2c1a00d..41725d0c6a4 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -645,7 +645,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // The interface is empty, and no nested items.
             hir::ItemKind::Use(..)
             | hir::ItemKind::ExternCrate(..)
-            | hir::ItemKind::GlobalAsm(..) => {}
+            | hir::ItemKind::GlobalAsm { .. } => {}
             // The interface is empty, and all nested items are processed by `visit_item`.
             hir::ItemKind::Mod(..) => {}
             hir::ItemKind::Macro(macro_def, _) => {
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index 47f72298e22..9e9b78cfdd5 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -13,7 +13,6 @@
 #![feature(core_intrinsics)]
 #![feature(min_specialization)]
 #![feature(never_type)]
-#![feature(ptr_sub_ptr)]
 #![feature(rustdoc_internals)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index c8b3c8a796f..2ab6b8e17c4 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -547,12 +547,15 @@ fn layout_of_uncached<'tcx>(
                 (
                     BackendRepr::Memory { sized: true },
                     AbiAndPrefAlign {
-                        abi: Align::max_for_offset(size),
-                        pref: dl.vector_align(size).pref,
+                        abi: Align::max_aligned_factor(size),
+                        pref: dl.llvmlike_vector_align(size).pref,
                     },
                 )
             } else {
-                (BackendRepr::Vector { element: e_abi, count: e_len }, dl.vector_align(size))
+                (
+                    BackendRepr::Vector { element: e_abi, count: e_len },
+                    dl.llvmlike_vector_align(size),
+                )
             };
             let size = size.align_to(align.abi);
 
diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs
index 5ea6716c5ca..cbbe993b62f 100644
--- a/compiler/rustc_ty_utils/src/layout/invariant.rs
+++ b/compiler/rustc_ty_utils/src/layout/invariant.rs
@@ -69,31 +69,30 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
     }
 
     fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
-        // Verify the ABI mandated alignment and size.
-        let align = layout.backend_repr.inherent_align(cx).map(|align| align.abi);
-        let size = layout.backend_repr.inherent_size(cx);
-        let Some((align, size)) = align.zip(size) else {
-            assert_matches!(
-                layout.layout.backend_repr(),
-                BackendRepr::Memory { .. },
-                "ABI unexpectedly missing alignment and/or size in {layout:#?}"
+        // Verify the ABI-mandated alignment and size for scalars.
+        let align = layout.backend_repr.scalar_align(cx);
+        let size = layout.backend_repr.scalar_size(cx);
+        if let Some(align) = align {
+            assert_eq!(
+                layout.layout.align().abi,
+                align,
+                "alignment mismatch between ABI and layout in {layout:#?}"
             );
-            return;
-        };
-        assert_eq!(
-            layout.layout.align().abi,
-            align,
-            "alignment mismatch between ABI and layout in {layout:#?}"
-        );
-        assert_eq!(
-            layout.layout.size(),
-            size,
-            "size mismatch between ABI and layout in {layout:#?}"
-        );
+        }
+        if let Some(size) = size {
+            assert_eq!(
+                layout.layout.size(),
+                size,
+                "size mismatch between ABI and layout in {layout:#?}"
+            );
+        }
 
         // Verify per-ABI invariants
         match layout.layout.backend_repr() {
             BackendRepr::Scalar(_) => {
+                // These must always be present for `Scalar` types.
+                let align = align.unwrap();
+                let size = size.unwrap();
                 // Check that this matches the underlying field.
                 let inner = skip_newtypes(cx, layout);
                 assert!(
@@ -235,9 +234,15 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
                     "`ScalarPair` second field with bad ABI in {inner:#?}",
                 );
             }
-            BackendRepr::Vector { element, .. } => {
-                assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`.
-                // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair.
+            BackendRepr::Vector { element, count } => {
+                let align = layout.align.abi;
+                let size = layout.size;
+                let element_align = element.align(cx).abi;
+                let element_size = element.size(cx);
+                // Currently, vectors must always be aligned to at least their elements:
+                assert!(align >= element_align);
+                // And the size has to be element * count plus alignment padding, of course
+                assert!(size == (element_size * count).align_to(align));
             }
             BackendRepr::Memory { .. } => {} // Nothing to check.
         }