about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-11-01 09:01:12 +0000
committerbors <bors@rust-lang.org>2022-11-01 09:01:12 +0000
commitc493bae0d8efd75723460ce5c371f726efa93f15 (patch)
tree2ea0e17fd499adaa1c6d2e150edfeb0bf35baad8 /compiler
parentdc05f60c1ff4e2cb2e6eb80c9b3afa612ce28c7f (diff)
parent5d30bfc43124e9c907851a5f36ab4afd48b3578d (diff)
downloadrust-c493bae0d8efd75723460ce5c371f726efa93f15.tar.gz
rust-c493bae0d8efd75723460ce5c371f726efa93f15.zip
Auto merge of #103832 - Dylan-DPC:rollup-maw3kmx, r=Dylan-DPC
Rollup of 6 pull requests

Successful merges:

 - #103061 (Rewrite implementation of `#[alloc_error_handler]`)
 - #103584 (Remove bounds check when array is indexed by enum)
 - #103706 (Fix E0433 No Typo Suggestions)
 - #103729 (interpret: fix align_of_val on packed types)
 - #103759 (Use `adt_def` during type collection.)
 - #103809 (Fix a typo in std::net mod doc comment)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs104
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/allocator.rs9
-rw-r--r--compiler/rustc_codegen_gcc/src/allocator.rs11
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs9
-rw-r--r--compiler/rustc_error_messages/locales/en-US/metadata.ftl16
-rw-r--r--compiler/rustc_error_messages/locales/en-US/passes.ftl6
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs4
-rw-r--r--compiler/rustc_hir/src/lang_items.rs5
-rw-r--r--compiler/rustc_hir/src/weak_lang_items.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs121
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs107
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs43
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs56
-rw-r--r--compiler/rustc_metadata/src/creader.rs97
-rw-r--r--compiler/rustc_metadata/src/errors.rs25
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs6
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs11
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs51
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs4
-rw-r--r--compiler/rustc_passes/src/dead.rs5
-rw-r--r--compiler/rustc_passes/src/errors.rs8
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs10
-rw-r--r--compiler/rustc_resolve/src/late.rs54
33 files changed, 490 insertions, 312 deletions
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
new file mode 100644
index 00000000000..eaf1b1167cf
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -0,0 +1,104 @@
+use crate::util::check_builtin_macro_attribute;
+
+use rustc_ast::ptr::P;
+use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind};
+use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe};
+use rustc_expand::base::{Annotatable, ExtCtxt};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::Span;
+use thin_vec::thin_vec;
+
+pub fn expand(
+    ecx: &mut ExtCtxt<'_>,
+    _span: Span,
+    meta_item: &ast::MetaItem,
+    item: Annotatable,
+) -> Vec<Annotatable> {
+    check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler);
+
+    let orig_item = item.clone();
+    let not_function = || {
+        ecx.sess
+            .parse_sess
+            .span_diagnostic
+            .span_err(item.span(), "alloc_error_handler must be a function");
+        vec![orig_item.clone()]
+    };
+
+    // Allow using `#[alloc_error_handler]` on an item statement
+    // FIXME - if we get deref patterns, use them to reduce duplication here
+    let (item, is_stmt, sig_span) = match &item {
+        Annotatable::Item(item) => match item.kind {
+            ItemKind::Fn(ref fn_kind) => (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)),
+            _ => return not_function(),
+        },
+        Annotatable::Stmt(stmt) => match &stmt.kind {
+            StmtKind::Item(item_) => match item_.kind {
+                ItemKind::Fn(ref fn_kind) => {
+                    (item_, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
+                }
+                _ => return not_function(),
+            },
+            _ => return not_function(),
+        },
+        _ => return not_function(),
+    };
+
+    // Generate a bunch of new items using the AllocFnFactory
+    let span = ecx.with_def_site_ctxt(item.span);
+
+    // Generate item statements for the allocator methods.
+    let stmts = vec![generate_handler(ecx, item.ident, span, sig_span)];
+
+    // Generate anonymous constant serving as container for the allocator methods.
+    let const_ty = ecx.ty(sig_span, TyKind::Tup(Vec::new()));
+    let const_body = ecx.expr_block(ecx.block(span, stmts));
+    let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
+    let const_item = if is_stmt {
+        Annotatable::Stmt(P(ecx.stmt_item(span, const_item)))
+    } else {
+        Annotatable::Item(const_item)
+    };
+
+    // Return the original item and the new methods.
+    vec![orig_item, const_item]
+}
+
+// #[rustc_std_internal_symbol]
+// unsafe fn __rg_oom(size: usize, align: usize) -> ! {
+//     handler(core::alloc::Layout::from_size_align_unchecked(size, align))
+// }
+fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt {
+    let usize = cx.path_ident(span, Ident::new(sym::usize, span));
+    let ty_usize = cx.ty_path(usize);
+    let size = Ident::from_str_and_span("size", span);
+    let align = Ident::from_str_and_span("align", span);
+
+    let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]);
+    let layout_new = cx.expr_path(cx.path(span, layout_new));
+    let layout =
+        cx.expr_call(span, layout_new, vec![cx.expr_ident(span, size), cx.expr_ident(span, align)]);
+
+    let call = cx.expr_call_ident(sig_span, handler, vec![layout]);
+
+    let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never));
+    let params = vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
+    let decl = cx.fn_decl(params, never);
+    let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() };
+    let sig = FnSig { decl, header, span: span };
+
+    let body = Some(cx.block_expr(call));
+    let kind = ItemKind::Fn(Box::new(Fn {
+        defaultness: ast::Defaultness::Final,
+        sig,
+        generics: Generics::default(),
+        body,
+    }));
+
+    let special = sym::rustc_std_internal_symbol;
+    let special = cx.meta_word(span, special);
+    let attrs = thin_vec![cx.attribute(special)];
+
+    let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind);
+    cx.stmt_item(sig_span, item)
+}
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index c7ea7de8f4e..bde0102186a 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -25,6 +25,7 @@ use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
 use rustc_span::symbol::sym;
 
+mod alloc_error_handler;
 mod assert;
 mod cfg;
 mod cfg_accessible;
@@ -94,6 +95,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
     }
 
     register_attr! {
+        alloc_error_handler: alloc_error_handler::expand,
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
         cfg_eval: cfg_eval::expand,
diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs
index bad8a87b9be..12bb00d346d 100644
--- a/compiler/rustc_codegen_cranelift/src/allocator.rs
+++ b/compiler/rustc_codegen_cranelift/src/allocator.rs
@@ -5,6 +5,7 @@ use crate::prelude::*;
 
 use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
 use rustc_session::config::OomStrategy;
+use rustc_span::symbol::sym;
 
 /// Returns whether an allocator shim was created
 pub(crate) fn codegen(
@@ -23,7 +24,7 @@ pub(crate) fn codegen(
             module,
             unwind_context,
             kind,
-            tcx.lang_items().oom().is_some(),
+            tcx.alloc_error_handler_kind(()).unwrap(),
             tcx.sess.opts.unstable_opts.oom,
         );
         true
@@ -36,7 +37,7 @@ fn codegen_inner(
     module: &mut impl Module,
     unwind_context: &mut UnwindContext,
     kind: AllocatorKind,
-    has_alloc_error_handler: bool,
+    alloc_error_handler_kind: AllocatorKind,
     oom_strategy: OomStrategy,
 ) {
     let usize_ty = module.target_config().pointer_type();
@@ -108,12 +109,12 @@ fn codegen_inner(
         returns: vec![],
     };
 
-    let callee_name = if has_alloc_error_handler { "__rg_oom" } else { "__rdl_oom" };
+    let callee_name = alloc_error_handler_kind.fn_name(sym::oom);
 
     let func_id =
         module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap();
 
-    let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap();
+    let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();
 
     let mut ctx = Context::new();
     ctx.func.signature = sig;
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
index 58efb81e800..e2c9ffe9c1c 100644
--- a/compiler/rustc_codegen_gcc/src/allocator.rs
+++ b/compiler/rustc_codegen_gcc/src/allocator.rs
@@ -7,7 +7,7 @@ use rustc_span::symbol::sym;
 
 use crate::GccContext;
 
-pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
+pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) {
     let context = &mods.context;
     let usize =
         match tcx.sess.target.pointer_width {
@@ -90,14 +90,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
         .collect();
     let func = context.new_function(None, FunctionType::Exported, void, &args, name, false);
 
-    let kind =
-        if has_alloc_error_handler {
-            AllocatorKind::Global
-        }
-        else {
-            AllocatorKind::Default
-        };
-    let callee = kind.fn_name(sym::oom);
+    let callee = alloc_error_handler_kind.fn_name(sym::oom);
     let args: Vec<_> = types.iter().enumerate()
         .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
         .collect();
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index accd02ab002..dd0daf2c38b 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -153,11 +153,11 @@ impl CodegenBackend for GccCodegenBackend {
 }
 
 impl ExtraBackendMethods for GccCodegenBackend {
-    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module {
+    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module {
         let mut mods = GccContext {
             context: Context::default(),
         };
-        unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); }
+        unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
         mods
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 72961ae888e..fed56cdd438 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -15,7 +15,7 @@ pub(crate) unsafe fn codegen(
     module_llvm: &mut ModuleLlvm,
     module_name: &str,
     kind: AllocatorKind,
-    has_alloc_error_handler: bool,
+    alloc_error_handler_kind: AllocatorKind,
 ) {
     let llcx = &*module_llvm.llcx;
     let llmod = module_llvm.llmod();
@@ -117,8 +117,7 @@ pub(crate) unsafe fn codegen(
         attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
     }
 
-    let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
-    let callee = kind.fn_name(sym::oom);
+    let callee = alloc_error_handler_kind.fn_name(sym::oom);
     let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
     // -> ! DIFlagNoReturn
     attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 89c7e51d09e..d51aced85df 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -108,11 +108,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
         tcx: TyCtxt<'tcx>,
         module_name: &str,
         kind: AllocatorKind,
-        has_alloc_error_handler: bool,
+        alloc_error_handler_kind: AllocatorKind,
     ) -> ModuleLlvm {
         let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
         unsafe {
-            allocator::codegen(tcx, &mut module_llvm, module_name, kind, has_alloc_error_handler);
+            allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind);
         }
         module_llvm
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index c2ecc41601c..752f6b1ef40 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -193,8 +193,11 @@ fn exported_symbols_provider_local<'tcx>(
     }
 
     if tcx.allocator_kind(()).is_some() {
-        for method in ALLOCATOR_METHODS {
-            let symbol_name = format!("__rust_{}", method.name);
+        for symbol_name in ALLOCATOR_METHODS
+            .iter()
+            .map(|method| format!("__rust_{}", method.name))
+            .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
+        {
             let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
 
             symbols.push((
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index a92087305b8..c1411690f82 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -638,7 +638,14 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         let llmod_id =
             cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
         let module_llvm = tcx.sess.time("write_allocator_module", || {
-            backend.codegen_allocator(tcx, &llmod_id, kind, tcx.lang_items().oom().is_some())
+            backend.codegen_allocator(
+                tcx,
+                &llmod_id,
+                kind,
+                // If allocator_kind is Some then alloc_error_handler_kind must
+                // also be Some.
+                tcx.alloc_error_handler_kind(()).unwrap(),
+            )
         });
 
         Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator })
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 87e347c61e2..5c35070ea66 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -119,7 +119,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
         tcx: TyCtxt<'tcx>,
         module_name: &str,
         kind: AllocatorKind,
-        has_alloc_error_handler: bool,
+        alloc_error_handler_kind: AllocatorKind,
     ) -> Self::Module;
     /// This generates the codegen unit and returns it along with
     /// a `u64` giving an estimate of the unit's processing cost.
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index a9063ad31cf..f7d64f6d4f4 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -598,7 +598,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // the last field).  Can't have foreign types here, how would we
                 // adjust alignment and size for them?
                 let field = layout.field(self, layout.fields.count() - 1);
-                let Some((unsized_size, unsized_align)) = self.size_and_align_of(metadata, &field)? else {
+                let Some((unsized_size, mut unsized_align)) = self.size_and_align_of(metadata, &field)? else {
                     // A field with an extern type. We don't know the actual dynamic size
                     // or the alignment.
                     return Ok(None);
@@ -614,6 +614,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // Return the sum of sizes and max of aligns.
                 let size = sized_size + unsized_size; // `Size` addition
 
+                // Packed types ignore the alignment of their fields.
+                if let ty::Adt(def, _) = layout.ty.kind() {
+                    if def.repr().packed() {
+                        unsized_align = sized_align;
+                    }
+                }
+
                 // Choose max of two known alignments (combined value must
                 // be aligned according to more restrictive of the two).
                 let align = sized_align.max(unsized_align);
diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl
index 08e553d9f15..c292ae9b32a 100644
--- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl
@@ -150,12 +150,28 @@ metadata_no_multiple_global_alloc =
 metadata_prev_global_alloc =
     previous global allocator defined here
 
+metadata_no_multiple_alloc_error_handler =
+    cannot define multiple allocation error handlers
+    .label = cannot define a new allocation error handler
+
+metadata_prev_alloc_error_handler =
+    previous allocation error handler defined here
+
 metadata_conflicting_global_alloc =
     the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
 
+metadata_conflicting_alloc_error_handler =
+    the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name}
+
 metadata_global_alloc_required =
     no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
 
+metadata_alloc_func_required =
+    `#[alloc_error_handler]` function required, but not found
+
+metadata_missing_alloc_error_handler =
+    use `#![feature(default_alloc_error_handler)]` for a default error handler
+
 metadata_no_transitive_needs_dep =
     the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}`
 
diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 4bc6bd9fb22..bc5bfe2a244 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -367,12 +367,6 @@ passes_unknown_external_lang_item =
 passes_missing_panic_handler =
     `#[panic_handler]` function required, but not found
 
-passes_alloc_func_required =
-    `#[alloc_error_handler]` function required, but not found
-
-passes_missing_alloc_error_handler =
-    use `#![feature(default_alloc_error_handler)]` for a default error handler
-
 passes_missing_lang_item =
     language item required, but not found: `{$name}`
     .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 2ead3c2c8d4..14c8e3c458c 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -555,10 +555,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
     rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
     gated!(
-        alloc_error_handler, Normal, template!(Word), WarnFollowing,
-        experimental!(alloc_error_handler)
-    ),
-    gated!(
         default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals,
         experimental!(default_lib_allocator),
     ),
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 72ed73e81b4..a55224d1097 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -126,14 +126,12 @@ impl<CTX> HashStable<CTX> for LangItem {
 }
 
 /// Extracts the first `lang = "$name"` out of a list of attributes.
-/// The attributes `#[panic_handler]` and `#[alloc_error_handler]`
-/// are also extracted out when found.
+/// The `#[panic_handler]` attribute is also extracted out when found.
 pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     attrs.iter().find_map(|attr| {
         Some(match attr {
             _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span),
             _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span),
-            _ if attr.has_name(sym::alloc_error_handler) => (sym::oom, attr.span),
             _ => return None,
         })
     })
@@ -240,7 +238,6 @@ language_item_table! {
     ExchangeMalloc,          sym::exchange_malloc,     exchange_malloc_fn,         Target::Fn,             GenericRequirement::None;
     BoxFree,                 sym::box_free,            box_free_fn,                Target::Fn,             GenericRequirement::Minimum(1);
     DropInPlace,             sym::drop_in_place,       drop_in_place_fn,           Target::Fn,             GenericRequirement::Minimum(1);
-    Oom,                     sym::oom,                 oom,                        Target::Fn,             GenericRequirement::None;
     AllocLayout,             sym::alloc_layout,        alloc_layout,               Target::Struct,         GenericRequirement::None;
 
     Start,                   sym::start,               start_fn,                   Target::Fn,             GenericRequirement::Exact(1);
diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs
index d8e5dd4ffdc..0cc50c6dd85 100644
--- a/compiler/rustc_hir/src/weak_lang_items.rs
+++ b/compiler/rustc_hir/src/weak_lang_items.rs
@@ -27,5 +27,4 @@ weak_lang_items! {
     PanicImpl,          rust_begin_unwind;
     EhPersonality,      rust_eh_personality;
     EhCatchTypeinfo,    rust_eh_catch_typeinfo;
-    Oom,                rust_oom;
 }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index b70ac02058d..133bbd52b91 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -6,7 +6,7 @@ use super::*;
 use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{ItemKind, Node, PathSegment};
@@ -75,7 +75,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         check_simd(tcx, span, def_id);
     }
 
-    check_transparent(tcx, span, def);
+    check_transparent(tcx, def);
     check_packed(tcx, span, def);
 }
 
@@ -83,7 +83,7 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
-    check_transparent(tcx, span, def);
+    check_transparent(tcx, def);
     check_union_fields(tcx, span, def_id);
     check_packed(tcx, span, def);
 }
@@ -506,11 +506,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
             tcx.ensure().typeck(id.owner_id.def_id);
         }
         DefKind::Enum => {
-            let item = tcx.hir().item(id);
-            let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else {
-                return;
-            };
-            check_enum(tcx, &enum_definition.variants, item.owner_id.def_id);
+            check_enum(tcx, id.owner_id.def_id);
         }
         DefKind::Fn => {} // entirely within check_item_body
         DefKind::Impl => {
@@ -1026,7 +1022,7 @@ pub(super) fn check_packed_inner(
     None
 }
 
-pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtDef<'tcx>) {
+pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
     if !adt.repr().transparent() {
         return;
     }
@@ -1035,14 +1031,14 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
         feature_err(
             &tcx.sess.parse_sess,
             sym::transparent_unions,
-            sp,
+            tcx.def_span(adt.did()),
             "transparent unions are unstable",
         )
         .emit();
     }
 
     if adt.variants().len() != 1 {
-        bad_variant_count(tcx, adt, sp, adt.did());
+        bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
         if adt.variants().is_empty() {
             // Don't bother checking the fields. No variants (and thus no fields) exist.
             return;
@@ -1103,7 +1099,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
         .filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
     let non_zst_count = non_zst_fields.clone().count();
     if non_zst_count >= 2 {
-        bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
+        bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
     }
     let incompatible_zst_fields =
         field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
@@ -1143,12 +1139,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
 }
 
 #[allow(trivial_numeric_casts)]
-fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: LocalDefId) {
+fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
-    let sp = tcx.def_span(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
 
-    if vs.is_empty() {
+    if def.variants().is_empty() {
         if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() {
             struct_span_err!(
                 tcx.sess,
@@ -1156,7 +1151,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
                 E0084,
                 "unsupported representation for zero-variant enum"
             )
-            .span_label(sp, "zero-variant enum")
+            .span_label(tcx.def_span(def_id), "zero-variant enum")
             .emit();
         }
     }
@@ -1167,88 +1162,96 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
             feature_err(
                 &tcx.sess.parse_sess,
                 sym::repr128,
-                sp,
+                tcx.def_span(def_id),
                 "repr with 128-bit type is unstable",
             )
             .emit();
         }
     }
 
-    for v in vs {
-        if let Some(ref e) = v.disr_expr {
-            tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
+    for v in def.variants() {
+        if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
+            tcx.ensure().typeck(discr_def_id.expect_local());
         }
     }
 
-    if tcx.adt_def(def_id).repr().int.is_none() {
-        let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
+    if def.repr().int.is_none() {
+        let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind, CtorKind::Const);
+        let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_));
 
-        let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
-        let has_non_units = vs.iter().any(|var| !is_unit(var));
-        let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
-        let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
+        let has_non_units = def.variants().iter().any(|var| !is_unit(var));
+        let disr_units = def.variants().iter().any(|var| is_unit(&var) && has_disr(&var));
+        let disr_non_unit = def.variants().iter().any(|var| !is_unit(&var) && has_disr(&var));
 
         if disr_non_unit || (disr_units && has_non_units) {
-            let mut err =
-                struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified");
+            let mut err = struct_span_err!(
+                tcx.sess,
+                tcx.def_span(def_id),
+                E0732,
+                "`#[repr(inttype)]` must be specified"
+            );
             err.emit();
         }
     }
 
-    detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
-
-    check_transparent(tcx, sp, def);
+    detect_discriminant_duplicate(tcx, def);
+    check_transparent(tcx, def);
 }
 
 /// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
-fn detect_discriminant_duplicate<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
-    vs: &'tcx [hir::Variant<'tcx>],
-    self_span: Span,
-) {
+fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
     // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
     // Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
-    let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| {
-        let var = &vs[idx]; // HIR for the duplicate discriminant
-        let (span, display_discr) = match var.disr_expr {
-            Some(ref expr) => {
+    let report = |dis: Discr<'tcx>, idx, err: &mut Diagnostic| {
+        let var = adt.variant(idx); // HIR for the duplicate discriminant
+        let (span, display_discr) = match var.discr {
+            ty::VariantDiscr::Explicit(discr_def_id) => {
                 // In the case the discriminant is both a duplicate and overflowed, let the user know
-                if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
+                if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local())
+                    && let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
                     && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
                     && *lit_value != dis.val
                 {
-                    (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
-                // Otherwise, format the value as-is
+                    (tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
                 } else {
-                    (tcx.hir().span(expr.hir_id), format!("`{dis}`"))
+                    // Otherwise, format the value as-is
+                    (tcx.def_span(discr_def_id), format!("`{dis}`"))
                 }
             }
-            None => {
+            // This should not happen.
+            ty::VariantDiscr::Relative(0) => (tcx.def_span(var.def_id), format!("`{dis}`")),
+            ty::VariantDiscr::Relative(distance_to_explicit) => {
                 // At this point we know this discriminant is a duplicate, and was not explicitly
                 // assigned by the user. Here we iterate backwards to fetch the HIR for the last
                 // explicitly assigned discriminant, and letting the user know that this was the
                 // increment startpoint, and how many steps from there leading to the duplicate
-                if let Some((n, hir::Variant { span, ident, .. })) =
-                    vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
+                if let Some(explicit_idx) =
+                    idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32)
                 {
-                    let ve_ident = var.ident;
-                    let n = n + 1;
-                    let sp = if n > 1 { "variants" } else { "variant" };
+                    let explicit_variant = adt.variant(explicit_idx);
+                    let ve_ident = var.name;
+                    let ex_ident = explicit_variant.name;
+                    let sp = if distance_to_explicit > 1 { "variants" } else { "variant" };
 
                     err.span_label(
-                        *span,
-                        format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"),
+                        tcx.def_span(explicit_variant.def_id),
+                        format!(
+                            "discriminant for `{ve_ident}` incremented from this startpoint \
+                            (`{ex_ident}` + {distance_to_explicit} {sp} later \
+                             => `{ve_ident}` = {dis})"
+                        ),
                     );
                 }
 
-                (vs[idx].span, format!("`{dis}`"))
+                (tcx.def_span(var.def_id), format!("`{dis}`"))
             }
         };
 
         err.span_label(span, format!("{display_discr} assigned here"));
     };
 
+    let mut discrs = adt.discriminants(tcx).collect::<Vec<_>>();
+
     // Here we loop through the discriminants, comparing each discriminant to another.
     // When a duplicate is detected, we instantiate an error and point to both
     // initial and duplicate value. The duplicate discriminant is then discarded by swapping
@@ -1257,29 +1260,29 @@ fn detect_discriminant_duplicate<'tcx>(
     // style as we are mutating `discrs` on the fly).
     let mut i = 0;
     while i < discrs.len() {
-        let hir_var_i_idx = discrs[i].0.index();
+        let var_i_idx = discrs[i].0;
         let mut error: Option<DiagnosticBuilder<'_, _>> = None;
 
         let mut o = i + 1;
         while o < discrs.len() {
-            let hir_var_o_idx = discrs[o].0.index();
+            let var_o_idx = discrs[o].0;
 
             if discrs[i].1.val == discrs[o].1.val {
                 let err = error.get_or_insert_with(|| {
                     let mut ret = struct_span_err!(
                         tcx.sess,
-                        self_span,
+                        tcx.def_span(adt.did()),
                         E0081,
                         "discriminant value `{}` assigned more than once",
                         discrs[i].1,
                     );
 
-                    report(discrs[i].1, hir_var_i_idx, &mut ret);
+                    report(discrs[i].1, var_i_idx, &mut ret);
 
                     ret
                 });
 
-                report(discrs[o].1, hir_var_o_idx, err);
+                report(discrs[o].1, var_o_idx, err);
 
                 // Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
                 discrs[o] = *discrs.last().unwrap();
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index a2357500465..99d0beacfa0 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -218,19 +218,16 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
         hir::ItemKind::Const(ty, ..) => {
             check_item_type(tcx, def_id, ty.span, false);
         }
-        hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
-            check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
-
+        hir::ItemKind::Struct(_, ref ast_generics) => {
+            check_type_defn(tcx, item, false);
             check_variances_for_type_defn(tcx, item, ast_generics);
         }
-        hir::ItemKind::Union(ref struct_def, ref ast_generics) => {
-            check_type_defn(tcx, item, true, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
-
+        hir::ItemKind::Union(_, ref ast_generics) => {
+            check_type_defn(tcx, item, true);
             check_variances_for_type_defn(tcx, item, ast_generics);
         }
-        hir::ItemKind::Enum(ref enum_def, ref ast_generics) => {
-            check_type_defn(tcx, item, true, |wfcx| wfcx.enum_variants(enum_def));
-
+        hir::ItemKind::Enum(_, ref ast_generics) => {
+            check_type_defn(tcx, item, true);
             check_variances_for_type_defn(tcx, item, ast_generics);
         }
         hir::ItemKind::Trait(..) => {
@@ -1037,27 +1034,25 @@ fn item_adt_kind(kind: &ItemKind<'_>) -> Option<AdtKind> {
 }
 
 /// In a type definition, we check that to ensure that the types of the fields are well-formed.
-fn check_type_defn<'tcx, F>(
-    tcx: TyCtxt<'tcx>,
-    item: &hir::Item<'tcx>,
-    all_sized: bool,
-    mut lookup_fields: F,
-) where
-    F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
-{
+fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) {
     let _ = tcx.representability(item.owner_id.def_id);
+    let adt_def = tcx.adt_def(item.owner_id);
 
     enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
-        let variants = lookup_fields(wfcx);
-        let packed = tcx.adt_def(item.owner_id).repr().packed();
+        let variants = adt_def.variants();
+        let packed = adt_def.repr().packed();
 
-        for variant in &variants {
+        for variant in variants.iter() {
             // All field types must be well-formed.
             for field in &variant.fields {
+                let field_id = field.did.expect_local();
+                let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
+                else { bug!() };
+                let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
                 wfcx.register_wf_obligation(
-                    field.span,
-                    Some(WellFormedLoc::Ty(field.def_id)),
-                    field.ty.into(),
+                    hir_ty.span,
+                    Some(WellFormedLoc::Ty(field_id)),
+                    ty.into(),
                 )
             }
 
@@ -1065,7 +1060,7 @@ fn check_type_defn<'tcx, F>(
             // intermediate types must be sized.
             let needs_drop_copy = || {
                 packed && {
-                    let ty = variant.fields.last().unwrap().ty;
+                    let ty = tcx.type_of(variant.fields.last().unwrap().did);
                     let ty = tcx.erase_regions(ty);
                     if ty.needs_infer() {
                         tcx.sess
@@ -1084,27 +1079,31 @@ fn check_type_defn<'tcx, F>(
                 variant.fields[..variant.fields.len() - unsized_len].iter().enumerate()
             {
                 let last = idx == variant.fields.len() - 1;
+                let field_id = field.did.expect_local();
+                let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
+                else { bug!() };
+                let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
                 wfcx.register_bound(
                     traits::ObligationCause::new(
-                        field.span,
+                        hir_ty.span,
                         wfcx.body_id,
                         traits::FieldSized {
                             adt_kind: match item_adt_kind(&item.kind) {
                                 Some(i) => i,
                                 None => bug!(),
                             },
-                            span: field.span,
+                            span: hir_ty.span,
                             last,
                         },
                     ),
                     wfcx.param_env,
-                    field.ty,
+                    ty,
                     tcx.require_lang_item(LangItem::Sized, None),
                 );
             }
 
             // Explicit `enum` discriminant values must const-evaluate successfully.
-            if let Some(discr_def_id) = variant.explicit_discr {
+            if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr {
                 let cause = traits::ObligationCause::new(
                     tcx.def_span(discr_def_id),
                     wfcx.body_id,
@@ -1114,7 +1113,7 @@ fn check_type_defn<'tcx, F>(
                     cause,
                     wfcx.param_env,
                     ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
-                        ty::Const::from_anon_const(tcx, discr_def_id),
+                        ty::Const::from_anon_const(tcx, discr_def_id.expect_local()),
                     ))
                     .to_predicate(tcx),
                 ));
@@ -1925,56 +1924,6 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) {
     items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id));
 }
 
-///////////////////////////////////////////////////////////////////////////
-// ADT
-
-// FIXME(eddyb) replace this with getting fields/discriminants through `ty::AdtDef`.
-struct AdtVariant<'tcx> {
-    /// Types of fields in the variant, that must be well-formed.
-    fields: Vec<AdtField<'tcx>>,
-
-    /// Explicit discriminant of this variant (e.g. `A = 123`),
-    /// that must evaluate to a constant value.
-    explicit_discr: Option<LocalDefId>,
-}
-
-struct AdtField<'tcx> {
-    ty: Ty<'tcx>,
-    def_id: LocalDefId,
-    span: Span,
-}
-
-impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> {
-    // FIXME(eddyb) replace this with getting fields through `ty::AdtDef`.
-    fn non_enum_variant(&self, struct_def: &hir::VariantData<'_>) -> AdtVariant<'tcx> {
-        let fields = struct_def
-            .fields()
-            .iter()
-            .map(|field| {
-                let def_id = self.tcx().hir().local_def_id(field.hir_id);
-                let field_ty = self.tcx().type_of(def_id);
-                let field_ty = self.normalize(field.ty.span, None, field_ty);
-                debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
-                AdtField { ty: field_ty, span: field.ty.span, def_id }
-            })
-            .collect();
-        AdtVariant { fields, explicit_discr: None }
-    }
-
-    fn enum_variants(&self, enum_def: &hir::EnumDef<'_>) -> Vec<AdtVariant<'tcx>> {
-        enum_def
-            .variants
-            .iter()
-            .map(|variant| AdtVariant {
-                fields: self.non_enum_variant(&variant.data).fields,
-                explicit_discr: variant
-                    .disr_expr
-                    .map(|explicit_discr| self.tcx().hir().local_def_id(explicit_discr.hir_id)),
-            })
-            .collect()
-    }
-}
-
 fn error_392(
     tcx: TyCtxt<'_>,
     span: Span,
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 65a1d61e87c..46db0f74d4d 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -604,11 +604,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                 }
             }
         }
-        hir::ItemKind::Enum(ref enum_definition, _) => {
+        hir::ItemKind::Enum(..) => {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().type_of(def_id);
             tcx.ensure().predicates_of(def_id);
-            convert_enum_variant_types(tcx, def_id.to_def_id(), enum_definition.variants);
+            convert_enum_variant_types(tcx, def_id.to_def_id());
         }
         hir::ItemKind::Impl { .. } => {
             tcx.ensure().generics_of(def_id);
@@ -640,7 +640,8 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             }
 
             if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
-                convert_variant_ctor(tcx, ctor_hir_id);
+                let ctor_def_id = tcx.hir().local_def_id(ctor_hir_id);
+                convert_variant_ctor(tcx, ctor_def_id);
             }
         }
 
@@ -750,37 +751,34 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
     }
 }
 
-fn convert_variant_ctor(tcx: TyCtxt<'_>, ctor_id: hir::HirId) {
-    let def_id = tcx.hir().local_def_id(ctor_id);
+fn convert_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     tcx.ensure().generics_of(def_id);
     tcx.ensure().type_of(def_id);
     tcx.ensure().predicates_of(def_id);
 }
 
-fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::Variant<'_>]) {
+fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
     let def = tcx.adt_def(def_id);
     let repr_type = def.repr().discr_type();
     let initial = repr_type.initial_discriminant(tcx);
     let mut prev_discr = None::<Discr<'_>>;
 
     // fill the discriminant values and field types
-    for variant in variants {
+    for variant in def.variants() {
         let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
         prev_discr = Some(
-            if let Some(ref e) = variant.disr_expr {
-                let expr_did = tcx.hir().local_def_id(e.hir_id);
-                def.eval_explicit_discr(tcx, expr_did.to_def_id())
+            if let ty::VariantDiscr::Explicit(const_def_id) = variant.discr {
+                def.eval_explicit_discr(tcx, const_def_id)
             } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
                 Some(discr)
             } else {
-                struct_span_err!(tcx.sess, variant.span, E0370, "enum discriminant overflowed")
-                    .span_label(
-                        variant.span,
-                        format!("overflowed on value after {}", prev_discr.unwrap()),
-                    )
+                let span = tcx.def_span(variant.def_id);
+                struct_span_err!(tcx.sess, span, E0370, "enum discriminant overflowed")
+                    .span_label(span, format!("overflowed on value after {}", prev_discr.unwrap()))
                     .note(&format!(
                         "explicitly set `{} = {}` if that is desired outcome",
-                        variant.ident, wrapped_discr
+                        tcx.item_name(variant.def_id),
+                        wrapped_discr
                     ))
                     .emit();
                 None
@@ -788,17 +786,16 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::V
             .unwrap_or(wrapped_discr),
         );
 
-        for f in variant.data.fields() {
-            let def_id = tcx.hir().local_def_id(f.hir_id);
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().type_of(def_id);
-            tcx.ensure().predicates_of(def_id);
+        for f in &variant.fields {
+            tcx.ensure().generics_of(f.did);
+            tcx.ensure().type_of(f.did);
+            tcx.ensure().predicates_of(f.did);
         }
 
         // Convert the ctor, if any. This also registers the variant as
         // an item.
-        if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
-            convert_variant_ctor(tcx, ctor_hir_id);
+        if let Some(ctor_def_id) = variant.ctor_def_id {
+            convert_variant_ctor(tcx, ctor_def_id.expect_local());
         }
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 7f76364e15a..b706d786b52 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -211,13 +211,6 @@ pub(super) fn check_fn<'a, 'tcx>(
         check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
     }
 
-    // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
-    if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
-        && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
-    {
-        check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
-    }
-
     (fcx, gen_ty)
 }
 
@@ -273,52 +266,3 @@ fn check_panic_info_fn(
         tcx.sess.span_err(span, "should have no const parameters");
     }
 }
-
-fn check_alloc_error_fn(
-    tcx: TyCtxt<'_>,
-    fn_id: LocalDefId,
-    fn_sig: ty::FnSig<'_>,
-    decl: &hir::FnDecl<'_>,
-    declared_ret_ty: Ty<'_>,
-) {
-    let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
-        tcx.sess.err("language item required, but not found: `alloc_layout`");
-        return;
-    };
-
-    if *declared_ret_ty.kind() != ty::Never {
-        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
-    }
-
-    let inputs = fn_sig.inputs();
-    if inputs.len() != 1 {
-        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
-        return;
-    }
-
-    let arg_is_alloc_layout = match inputs[0].kind() {
-        ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
-        _ => false,
-    };
-
-    if !arg_is_alloc_layout {
-        tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
-    }
-
-    let DefKind::Fn = tcx.def_kind(fn_id) else {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
-        return;
-    };
-
-    let generic_counts = tcx.generics_of(fn_id).own_counts();
-    if generic_counts.types != 0 {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
-    }
-    if generic_counts.consts != 0 {
-        let span = tcx.def_span(fn_id);
-        tcx.sess
-            .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
-    }
-}
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index cfcceecbef4..d4c457975a8 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -1,8 +1,10 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
 use crate::errors::{
-    ConflictingGlobalAlloc, CrateNotPanicRuntime, GlobalAllocRequired, NoMultipleGlobalAlloc,
-    NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore,
+    AllocFuncRequired, ConflictingAllocErrorHandler, ConflictingGlobalAlloc, CrateNotPanicRuntime,
+    GlobalAllocRequired, MissingAllocErrorHandler, NoMultipleAllocErrorHandler,
+    NoMultipleGlobalAlloc, NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime,
+    ProfilerBuiltinsNeedsCore,
 };
 use crate::locator::{CrateError, CrateLocator, CratePaths};
 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
@@ -41,8 +43,13 @@ pub struct CStore {
     /// This crate needs an allocator and either provides it itself, or finds it in a dependency.
     /// If the above is true, then this field denotes the kind of the found allocator.
     allocator_kind: Option<AllocatorKind>,
+    /// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency.
+    /// If the above is true, then this field denotes the kind of the found allocator.
+    alloc_error_handler_kind: Option<AllocatorKind>,
     /// This crate has a `#[global_allocator]` item.
     has_global_allocator: bool,
+    /// This crate has a `#[alloc_error_handler]` item.
+    has_alloc_error_handler: bool,
 
     /// This map is used to verify we get no hash conflicts between
     /// `StableCrateId` values.
@@ -197,10 +204,18 @@ impl CStore {
         self.allocator_kind
     }
 
+    pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> {
+        self.alloc_error_handler_kind
+    }
+
     pub(crate) fn has_global_allocator(&self) -> bool {
         self.has_global_allocator
     }
 
+    pub(crate) fn has_alloc_error_handler(&self) -> bool {
+        self.has_alloc_error_handler
+    }
+
     pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
         let json_unused_externs = tcx.sess.opts.json_unused_externs;
 
@@ -247,7 +262,9 @@ impl<'a> CrateLoader<'a> {
                 metas: IndexVec::from_elem_n(None, 1),
                 injected_panic_runtime: None,
                 allocator_kind: None,
+                alloc_error_handler_kind: None,
                 has_global_allocator: false,
+                has_alloc_error_handler: false,
                 stable_crate_ids,
                 unused_externs: Vec::new(),
             },
@@ -792,6 +809,13 @@ impl<'a> CrateLoader<'a> {
             }
             spans => !spans.is_empty(),
         };
+        self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) {
+            [span1, span2, ..] => {
+                self.sess.emit_err(NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
+                true
+            }
+            spans => !spans.is_empty(),
+        };
 
         // Check to see if we actually need an allocator. This desire comes
         // about through the `#![needs_allocator]` attribute and is typically
@@ -832,22 +856,48 @@ impl<'a> CrateLoader<'a> {
                 }
             }
         }
+        let mut alloc_error_handler =
+            self.cstore.has_alloc_error_handler.then(|| Symbol::intern("this crate"));
+        for (_, data) in self.cstore.iter_crate_data() {
+            if data.has_alloc_error_handler() {
+                match alloc_error_handler {
+                    Some(other_crate) => {
+                        self.sess.emit_err(ConflictingAllocErrorHandler {
+                            crate_name: data.name(),
+                            other_crate_name: other_crate,
+                        });
+                    }
+                    None => alloc_error_handler = Some(data.name()),
+                }
+            }
+        }
 
         if global_allocator.is_some() {
             self.cstore.allocator_kind = Some(AllocatorKind::Global);
-            return;
+        } else {
+            // Ok we haven't found a global allocator but we still need an
+            // allocator. At this point our allocator request is typically fulfilled
+            // by the standard library, denoted by the `#![default_lib_allocator]`
+            // attribute.
+            if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
+                && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
+            {
+                self.sess.emit_err(GlobalAllocRequired);
+            }
+            self.cstore.allocator_kind = Some(AllocatorKind::Default);
         }
 
-        // Ok we haven't found a global allocator but we still need an
-        // allocator. At this point our allocator request is typically fulfilled
-        // by the standard library, denoted by the `#![default_lib_allocator]`
-        // attribute.
-        if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
-            && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
-        {
-            self.sess.emit_err(GlobalAllocRequired);
+        if alloc_error_handler.is_some() {
+            self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global);
+        } else {
+            // The alloc crate provides a default allocation error handler if
+            // one isn't specified.
+            if !self.sess.features_untracked().default_alloc_error_handler {
+                self.sess.emit_err(AllocFuncRequired);
+                self.sess.emit_note(MissingAllocErrorHandler);
+            }
+            self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
         }
-        self.cstore.allocator_kind = Some(AllocatorKind::Default);
     }
 
     fn inject_dependency_if(
@@ -1023,3 +1073,26 @@ fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
     visit::walk_crate(&mut f, krate);
     f.spans
 }
+
+fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
+    struct Finder<'a> {
+        sess: &'a Session,
+        name: Symbol,
+        spans: Vec<Span>,
+    }
+    impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> {
+        fn visit_item(&mut self, item: &'ast ast::Item) {
+            if item.ident.name == self.name
+                && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol)
+            {
+                self.spans.push(item.span);
+            }
+            visit::walk_item(self, item)
+        }
+    }
+
+    let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom));
+    let mut f = Finder { sess, name, spans: Vec::new() };
+    visit::walk_crate(&mut f, krate);
+    f.spans
+}
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 7c387b9a9ec..289fa53aa5e 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -344,6 +344,16 @@ pub struct NoMultipleGlobalAlloc {
 }
 
 #[derive(Diagnostic)]
+#[diag(metadata_no_multiple_alloc_error_handler)]
+pub struct NoMultipleAllocErrorHandler {
+    #[primary_span]
+    #[label]
+    pub span2: Span,
+    #[label(metadata_prev_alloc_error_handler)]
+    pub span1: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(metadata_conflicting_global_alloc)]
 pub struct ConflictingGlobalAlloc {
     pub crate_name: Symbol,
@@ -351,10 +361,25 @@ pub struct ConflictingGlobalAlloc {
 }
 
 #[derive(Diagnostic)]
+#[diag(metadata_conflicting_alloc_error_handler)]
+pub struct ConflictingAllocErrorHandler {
+    pub crate_name: Symbol,
+    pub other_crate_name: Symbol,
+}
+
+#[derive(Diagnostic)]
 #[diag(metadata_global_alloc_required)]
 pub struct GlobalAllocRequired;
 
 #[derive(Diagnostic)]
+#[diag(metadata_alloc_func_required)]
+pub struct AllocFuncRequired;
+
+#[derive(Diagnostic)]
+#[diag(metadata_missing_alloc_error_handler)]
+pub struct MissingAllocErrorHandler;
+
+#[derive(Diagnostic)]
 #[diag(metadata_no_transitive_needs_dep)]
 pub struct NoTransitiveNeedsDep<'a> {
     pub crate_name: Symbol,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 17a7532044a..8e80d794a13 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1764,6 +1764,10 @@ impl CrateMetadata {
         self.root.has_global_allocator
     }
 
+    pub(crate) fn has_alloc_error_handler(&self) -> bool {
+        self.root.has_alloc_error_handler
+    }
+
     pub(crate) fn has_default_lib_allocator(&self) -> bool {
         self.root.has_default_lib_allocator
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index a0a0855251b..f475b0b3981 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -255,6 +255,7 @@ provide! { tcx, def_id, other, cdata,
     is_panic_runtime => { cdata.root.panic_runtime }
     is_compiler_builtins => { cdata.root.compiler_builtins }
     has_global_allocator => { cdata.root.has_global_allocator }
+    has_alloc_error_handler => { cdata.root.has_alloc_error_handler }
     has_panic_handler => { cdata.root.has_panic_handler }
     is_profiler_runtime => { cdata.root.profiler_runtime }
     required_panic_strategy => { cdata.root.required_panic_strategy }
@@ -339,6 +340,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
     // resolve! Does this work? Unsure! That's what the issue is about
     *providers = Providers {
         allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
+        alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(),
         is_private_dep: |_tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
             false
@@ -464,6 +466,10 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
             assert_eq!(cnum, LOCAL_CRATE);
             CStore::from_tcx(tcx).has_global_allocator()
         },
+        has_alloc_error_handler: |tcx, cnum| {
+            assert_eq!(cnum, LOCAL_CRATE);
+            CStore::from_tcx(tcx).has_alloc_error_handler()
+        },
         postorder_cnums: |tcx, ()| {
             tcx.arena
                 .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 87fa69e1639..c907ee64628 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -670,6 +670,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
                 edition: tcx.sess.edition(),
                 has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
+                has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
                 has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
                 has_default_lib_allocator: tcx
                     .sess
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 774cff2075d..aa6d378a43a 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -223,6 +223,7 @@ pub(crate) struct CrateRoot {
     panic_in_drop_strategy: PanicStrategy,
     edition: Edition,
     has_global_allocator: bool,
+    has_alloc_error_handler: bool,
     has_panic_handler: bool,
     has_default_lib_allocator: bool,
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index a098e570305..33acaed435b 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1391,6 +1391,13 @@ rustc_queries! {
         desc { "checking if the crate has_global_allocator" }
         separate_provide_extern
     }
+    query has_alloc_error_handler(_: CrateNum) -> bool {
+        // This query depends on untracked global state in CStore
+        eval_always
+        fatal_cycle
+        desc { "checking if the crate has_alloc_error_handler" }
+        separate_provide_extern
+    }
     query has_panic_handler(_: CrateNum) -> bool {
         fatal_cycle
         desc { "checking if the crate has_panic_handler" }
@@ -1761,6 +1768,10 @@ rustc_queries! {
         eval_always
         desc { "getting the allocator kind for the current crate" }
     }
+    query alloc_error_handler_kind(_: ()) -> Option<AllocatorKind> {
+        eval_always
+        desc { "alloc error handler kind for the current crate" }
+    }
 
     query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
         desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 3dafdcb7887..5c82fb1ddc0 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -2,6 +2,7 @@
 
 use rustc_index::vec::Idx;
 use rustc_middle::ty::util::IntTypeExt;
+use rustc_target::abi::{Abi, Primitive};
 
 use crate::build::expr::as_place::PlaceBase;
 use crate::build::expr::category::{Category, RvalueFunc};
@@ -198,6 +199,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind() && adt_def.is_enum() {
                     let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx);
                     let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not));
+                    let layout = this.tcx.layout_of(this.param_env.and(source.ty));
                     let discr = this.temp(discr_ty, source.span);
                     this.cfg.push_assign(
                         block,
@@ -205,8 +207,55 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         discr,
                         Rvalue::Discriminant(temp.into()),
                     );
+                    let (op,ty) = (Operand::Move(discr), discr_ty);
+
+                    if let Abi::Scalar(scalar) = layout.unwrap().abi{
+                        if let Primitive::Int(_, signed) = scalar.primitive() {
+                            let range = scalar.valid_range(&this.tcx);
+                            // FIXME: Handle wraparound cases too.
+                            if range.end >= range.start {
+                                let mut assumer = |range: u128, bin_op: BinOp| {
+                                    // We will be overwriting this val if our scalar is signed value
+                                    // because sign extension on unsigned types might cause unintended things
+                                    let mut range_val =
+                                        ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty));
+                                    let bool_ty = this.tcx.types.bool;
+                                    if signed {
+                                        let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range);
+                                        let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty));
+                                        let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend);
+                                        range_val = ConstantKind::from_bits(
+                                            this.tcx,
+                                            truncated_val,
+                                            ty::ParamEnv::empty().and(discr_ty),
+                                        );
+                                    }
+                                    let lit_op = this.literal_operand(expr.span, range_val);
+                                    let is_bin_op = this.temp(bool_ty, expr_span);
+                                    this.cfg.push_assign(
+                                        block,
+                                        source_info,
+                                        is_bin_op,
+                                        Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))),
+                                    );
+                                    this.cfg.push(
+                                        block,
+                                        Statement {
+                                            source_info,
+                                            kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
+                                                Operand::Copy(is_bin_op),
+                                            ))),
+                                        },
+                                    )
+                                };
+                                assumer(range.end, BinOp::Ge);
+                                assumer(range.start, BinOp::Le);
+                            }
+                        }
+                    }
+
+                    (op,ty)
 
-                    (Operand::Move(discr), discr_ty)
                 } else {
                     let ty = source.ty;
                     let source = unpack!(
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index f8f04214a2c..959fcf8d89e 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -101,12 +101,10 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
             | StatementKind::Retag { .. }
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {
                 // safe (at least as emitted during MIR construction)
             }
-
-            // Move to above list once mir construction uses it.
-            StatementKind::Intrinsic(..) => unreachable!(),
         }
         self.super_statement(statement, location);
     }
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 753d01f46ca..b779edbc30f 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -470,11 +470,6 @@ fn has_allow_dead_code_or_lang_attr_helper(
         return true;
     }
 
-    // (To be) stable attribute for #[lang = "oom"]
-    if tcx.sess.contains_name(attrs, sym::alloc_error_handler) {
-        return true;
-    }
-
     let def_id = tcx.hir().local_def_id(id);
     if tcx.def_kind(def_id).has_codegen_attrs() {
         let cg_attrs = tcx.codegen_fn_attrs(def_id);
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index adaaf539242..4a5cfd2d429 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -702,14 +702,6 @@ pub struct UnknownExternLangItem {
 pub struct MissingPanicHandler;
 
 #[derive(Diagnostic)]
-#[diag(passes_alloc_func_required)]
-pub struct AllocFuncRequired;
-
-#[derive(Diagnostic)]
-#[diag(passes_missing_alloc_error_handler)]
-pub struct MissingAllocErrorHandler;
-
-#[derive(Diagnostic)]
 #[diag(passes_missing_lang_item)]
 #[note]
 #[help]
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 94d6a405b53..f0815fcd8db 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -7,10 +7,7 @@ use rustc_middle::middle::lang_items::required;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 
-use crate::errors::{
-    AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler,
-    UnknownExternLangItem,
-};
+use crate::errors::{MissingLangItem, MissingPanicHandler, UnknownExternLangItem};
 
 /// Checks the crate for usage of weak lang items, returning a vector of all the
 /// language items required by this crate, but not defined yet.
@@ -69,11 +66,6 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
         if missing.contains(&item) && required(tcx, item) && items.get(item).is_none() {
             if item == LangItem::PanicImpl {
                 tcx.sess.emit_err(MissingPanicHandler);
-            } else if item == LangItem::Oom {
-                if !tcx.features().default_alloc_error_handler {
-                    tcx.sess.emit_err(AllocFuncRequired);
-                    tcx.sess.emit_note(MissingAllocErrorHandler);
-                }
             } else {
                 tcx.sess.emit_err(MissingLangItem { name: item.name() });
             }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 00eb768ad18..6d2ee25df32 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -32,7 +32,7 @@ use smallvec::{smallvec, SmallVec};
 use rustc_span::source_map::{respan, Spanned};
 use std::assert_matches::debug_assert_matches;
 use std::collections::{hash_map::Entry, BTreeSet};
-use std::mem::{replace, take};
+use std::mem::{replace, swap, take};
 
 mod diagnostics;
 
@@ -3369,11 +3369,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             let (mut err, candidates) =
                 this.smart_resolve_report_errors(path, path_span, PathSource::Type, None);
 
-            if candidates.is_empty() {
-                err.cancel();
-                return Some(parent_err);
-            }
-
             // There are two different error messages user might receive at
             // this point:
             // - E0412 cannot find type `{}` in this scope
@@ -3383,37 +3378,62 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             // latter one - for paths in expression-position.
             //
             // Thus (since we're in expression-position at this point), not to
-            // confuse the user, we want to keep the *message* from E0432 (so
+            // confuse the user, we want to keep the *message* from E0433 (so
             // `parent_err`), but we want *hints* from E0412 (so `err`).
             //
             // And that's what happens below - we're just mixing both messages
             // into a single one.
             let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node);
 
+            // overwrite all properties with the parent's error message
             err.message = take(&mut parent_err.message);
             err.code = take(&mut parent_err.code);
+            swap(&mut err.span, &mut parent_err.span);
             err.children = take(&mut parent_err.children);
+            err.sort_span = parent_err.sort_span;
+            err.is_lint = parent_err.is_lint;
+
+            // merge the parent's suggestions with the typo suggestions
+            fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) {
+                match res1 {
+                    Ok(vec1) => match res2 {
+                        Ok(mut vec2) => vec1.append(&mut vec2),
+                        Err(e) => *res1 = Err(e),
+                    },
+                    Err(_) => (),
+                };
+            }
+            append_result(&mut err.suggestions, parent_err.suggestions.clone());
 
             parent_err.cancel();
 
             let def_id = this.parent_scope.module.nearest_parent_mod();
 
             if this.should_report_errs() {
-                this.r.use_injections.push(UseError {
-                    err,
-                    candidates,
-                    def_id,
-                    instead: false,
-                    suggestion: None,
-                    path: path.into(),
-                    is_call: source.is_call(),
-                });
+                if candidates.is_empty() {
+                    // When there is no suggested imports, we can just emit the error
+                    // and suggestions immediately. Note that we bypass the usually error
+                    // reporting routine (ie via `self.r.report_error`) because we need
+                    // to post-process the `ResolutionError` above.
+                    err.emit();
+                } else {
+                    // If there are suggested imports, the error reporting is delayed
+                    this.r.use_injections.push(UseError {
+                        err,
+                        candidates,
+                        def_id,
+                        instead: false,
+                        suggestion: None,
+                        path: path.into(),
+                        is_call: source.is_call(),
+                    });
+                }
             } else {
                 err.cancel();
             }
 
             // We don't return `Some(parent_err)` here, because the error will
-            // be already printed as part of the `use` injections
+            // be already printed either immediately or as part of the `use` injections
             None
         };