about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock16
-rw-r--r--compiler/rustc_abi/src/layout/ty.rs12
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs3
-rw-r--r--compiler/rustc_attr_data_structures/src/encode_cross_crate.rs15
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs7
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/allocator.rs41
-rw-r--r--compiler/rustc_codegen_gcc/src/allocator.rs44
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs45
-rw-r--r--compiler/rustc_errors/Cargo.toml2
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs9
-rw-r--r--compiler/rustc_errors/src/emitter.rs17
-rw-r--r--compiler/rustc_errors/src/json.rs7
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs99
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs14
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs1
-rw-r--r--compiler/rustc_passes/src/check_attr.rs8
-rw-r--r--compiler/rustc_session/Cargo.toml2
-rw-r--r--compiler/rustc_session/src/config.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs224
-rw-r--r--compiler/rustc_smir/src/rustc_smir/alloc.rs169
-rw-r--r--compiler/rustc_smir/src/rustc_smir/bridge.rs59
-rw-r--r--compiler/rustc_smir/src/rustc_smir/builder.rs12
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs1000
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context/impls.rs762
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context/mod.rs79
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context/traits.rs46
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/error.rs25
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs403
-rw-r--r--compiler/rustc_smir/src/stable_mir/abi.rs4
-rw-r--r--compiler/rustc_smir/src/stable_mir/alloc.rs77
-rw-r--r--compiler/rustc_smir/src/stable_mir/compiler_interface.rs987
-rw-r--r--compiler/rustc_smir/src/stable_mir/error.rs12
-rw-r--r--compiler/rustc_smir/src/stable_mir/mir/alloc.rs4
-rw-r--r--compiler/rustc_smir/src/stable_mir/mir/mono.rs7
-rw-r--r--compiler/rustc_smir/src/stable_mir/mir/pretty.rs4
-rw-r--r--compiler/rustc_smir/src/stable_mir/mod.rs69
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs16
-rw-r--r--compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs (renamed from compiler/rustc_smir/src/rustc_internal/internal.rs)308
-rw-r--r--compiler/rustc_smir/src/stable_mir/unstable/convert/mod.rs111
-rw-r--r--compiler/rustc_smir/src/stable_mir/unstable/convert/stable/abi.rs (renamed from compiler/rustc_smir/src/rustc_smir/convert/abi.rs)187
-rw-r--r--compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mir.rs (renamed from compiler/rustc_smir/src/rustc_smir/convert/mir.rs)505
-rw-r--r--compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mod.rs (renamed from compiler/rustc_smir/src/rustc_smir/convert/mod.rs)36
-rw-r--r--compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs (renamed from compiler/rustc_smir/src/rustc_smir/convert/ty.rs)506
-rw-r--r--compiler/rustc_smir/src/stable_mir/unstable/mod.rs210
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs79
-rw-r--r--library/alloc/src/alloc.rs4
-rw-r--r--library/alloc/src/boxed.rs5
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/core/src/cell.rs11
-rw-r--r--library/core/src/marker.rs31
-rw-r--r--library/core/src/pin/unsafe_pinned.rs6
-rw-r--r--library/core/src/ptr/non_null.rs3
-rw-r--r--library/std/src/alloc.rs4
-rw-r--r--src/doc/rustc-dev-guide/josh-sync.toml3
-rw-r--r--src/doc/rustc-dev-guide/rust-version2
-rw-r--r--src/doc/rustc-dev-guide/src/autodiff/internals.md4
-rw-r--r--src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md18
-rw-r--r--src/doc/rustc-dev-guide/src/contributing.md4
-rw-r--r--src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md47
-rw-r--r--src/doc/rustc-dev-guide/src/hir/lowering.md6
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ui.md6
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr4
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics.rs1
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics.stderr3
-rw-r--r--src/tools/miri/src/shims/extern_static.rs11
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs6
-rw-r--r--src/tools/miri/tests/pass/alloc-access-tracking.rs4
-rw-r--r--tests/rustdoc-ui/track-diagnostics.rs6
-rw-r--r--tests/rustdoc-ui/track-diagnostics.stderr3
-rw-r--r--tests/ui/track-diagnostics/track.rs5
-rw-r--r--tests/ui/track-diagnostics/track.stderr8
-rw-r--r--tests/ui/track-diagnostics/track2.rs6
-rw-r--r--tests/ui/track-diagnostics/track2.stderr2
-rw-r--r--tests/ui/track-diagnostics/track3.rs4
-rw-r--r--tests/ui/track-diagnostics/track3.stderr6
-rw-r--r--tests/ui/track-diagnostics/track4.rs6
-rw-r--r--tests/ui/track-diagnostics/track4.stderr2
-rw-r--r--tests/ui/track-diagnostics/track5.rs6
-rw-r--r--tests/ui/track-diagnostics/track5.stderr3
-rw-r--r--tests/ui/track-diagnostics/track6.rs6
-rw-r--r--tests/ui/track-diagnostics/track6.stderr2
-rw-r--r--tests/ui/traits/next-solver/pointer-like.rs14
-rw-r--r--tests/ui/traits/next-solver/pointer-like.stderr24
87 files changed, 3908 insertions, 2638 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7cf10628b00..3901e07c5fc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -581,7 +581,7 @@ dependencies = [
  "serde_json",
  "syn 2.0.104",
  "tempfile",
- "termize",
+ "termize 0.1.1",
  "tokio",
  "toml 0.7.8",
  "ui_test",
@@ -3761,7 +3761,7 @@ dependencies = [
  "serde",
  "serde_json",
  "termcolor",
- "termize",
+ "termize 0.2.0",
  "tracing",
  "windows 0.61.3",
 ]
@@ -4522,7 +4522,7 @@ dependencies = [
  "rustc_serialize",
  "rustc_span",
  "rustc_target",
- "termize",
+ "termize 0.2.0",
  "tracing",
  "windows 0.61.3",
 ]
@@ -5295,6 +5295,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "termize"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8da106d1a19c5b9c53c03311936568a0439926a7607815bd3461139cbab1cc"
+dependencies = [
+ "libc",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
 name = "test-float-parse"
 version = "0.1.0"
 dependencies = [
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index 18f0750aaa1..8d3c10fd770 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -6,7 +6,7 @@ use rustc_macros::HashStable_Generic;
 
 use crate::{
     AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
-    PointeeInfo, Primitive, Scalar, Size, TargetDataLayout, Variants,
+    PointeeInfo, Primitive, Size, Variants,
 };
 
 // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
@@ -115,16 +115,6 @@ impl<'a> Layout<'a> {
     pub fn unadjusted_abi_align(self) -> Align {
         self.0.0.unadjusted_abi_align
     }
-
-    /// Whether the layout is from a type that implements [`std::marker::PointerLike`].
-    ///
-    /// Currently, that means that the type is pointer-sized, pointer-aligned,
-    /// and has a initialized (non-union), scalar ABI.
-    pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool {
-        self.size() == data_layout.pointer_size
-            && self.align().abi == data_layout.pointer_align.abi
-            && matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. }))
-    }
 }
 
 /// The layout of a type, alongside the type itself.
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 1fafc97008e..3b5e06c2a88 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -287,6 +287,9 @@ pub enum AttributeKind {
     /// Represents `#[optimize(size|speed)]`
     Optimize(OptimizeAttr, Span),
 
+    /// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint).
+    PassByValue(Span),
+
     /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
     PubTransparent(Span),
 
diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
index a93ebbe97ee..145cfba8e42 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -12,40 +12,43 @@ impl AttributeKind {
         use EncodeCrossCrate::*;
 
         match self {
+            // tidy-alphabetical-start
             Align { .. } => No,
             AllowConstFnUnstable(..) => No,
             AllowInternalUnstable(..) => Yes,
             AsPtr(..) => Yes,
             BodyStability { .. } => No,
+            Cold(..) => No,
             Confusables { .. } => Yes,
+            ConstContinue(..) => No,
             ConstStability { .. } => Yes,
             ConstStabilityIndirect => No,
             Deprecation { .. } => Yes,
             DocComment { .. } => Yes,
             ExportName { .. } => Yes,
             Inline(..) => No,
-            LinkSection { .. } => No,
-            MacroTransparency(..) => Yes,
-            Repr(..) => No,
-            Stability { .. } => Yes,
-            Cold(..) => No,
-            ConstContinue(..) => No,
             LinkName { .. } => Yes,
+            LinkSection { .. } => No,
             LoopMatch(..) => No,
+            MacroTransparency(..) => Yes,
             MayDangle(..) => No,
             MustUse { .. } => Yes,
             Naked(..) => No,
             NoImplicitPrelude(..) => No,
             NoMangle(..) => No,
             Optimize(..) => No,
+            PassByValue(..) => Yes,
             PubTransparent(..) => Yes,
+            Repr(..) => No,
             RustcLayoutScalarValidRangeEnd(..) => Yes,
             RustcLayoutScalarValidRangeStart(..) => Yes,
             RustcObjectLifetimeDefault => No,
             SkipDuringMethodDispatch { .. } => No,
+            Stability { .. } => Yes,
             TargetFeature(..) => No,
             TrackCaller(..) => Yes,
             Used { .. } => No,
+            // tidy-alphabetical-end
         }
     }
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
index 5437803d781..8ad98c8d1d4 100644
--- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
@@ -17,3 +17,10 @@ impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent;
 }
+
+pub(crate) struct PassByValueParser;
+impl<S: Stage> NoArgsAttributeParser<S> for PassByValueParser {
+    const PATH: &[Symbol] = &[sym::rustc_pass_by_value];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue;
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 43b36b4c554..5ddb686a8c0 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -23,7 +23,7 @@ use crate::attributes::confusables::ConfusablesParser;
 use crate::attributes::deprecation::DeprecationParser;
 use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
 use crate::attributes::link_attrs::{LinkNameParser, LinkSectionParser};
-use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
+use crate::attributes::lint_helpers::{AsPtrParser, PassByValueParser, PubTransparentParser};
 use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
 use crate::attributes::must_use::MustUseParser;
 use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
@@ -144,6 +144,7 @@ attribute_parsers!(
         Single<WithoutArgs<MayDangleParser>>,
         Single<WithoutArgs<NoImplicitPreludeParser>>,
         Single<WithoutArgs<NoMangleParser>>,
+        Single<WithoutArgs<PassByValueParser>>,
         Single<WithoutArgs<PubTransparentParser>>,
         Single<WithoutArgs<TrackCallerParser>>,
         // tidy-alphabetical-end
diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs
index ffb932a3c38..04f1129d87c 100644
--- a/compiler/rustc_codegen_cranelift/src/allocator.rs
+++ b/compiler/rustc_codegen_cranelift/src/allocator.rs
@@ -84,19 +84,34 @@ fn codegen_inner(
         &mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)),
     );
 
-    let data_id = module
-        .declare_data(
-            &mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
-            Linkage::Export,
-            false,
-            false,
-        )
-        .unwrap();
-    let mut data = DataDescription::new();
-    data.set_align(1);
-    let val = oom_strategy.should_panic();
-    data.define(Box::new([val]));
-    module.define_data(data_id, &data).unwrap();
+    {
+        let sig = Signature {
+            call_conv: module.target_config().default_call_conv,
+            params: vec![],
+            returns: vec![AbiParam::new(types::I8)],
+        };
+        let func_id = module
+            .declare_function(
+                &mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
+                Linkage::Export,
+                &sig,
+            )
+            .unwrap();
+        let mut ctx = Context::new();
+        ctx.func.signature = sig;
+        {
+            let mut func_ctx = FunctionBuilderContext::new();
+            let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
+
+            let block = bcx.create_block();
+            bcx.switch_to_block(block);
+            let value = bcx.ins().iconst(types::I8, oom_strategy.should_panic() as i64);
+            bcx.ins().return_(&[value]);
+            bcx.seal_all_blocks();
+            bcx.finalize();
+        }
+        module.define_function(func_id, &mut ctx).unwrap();
+    }
 
     {
         let sig = Signature {
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
index cf8aa500c77..0d8dc93274f 100644
--- a/compiler/rustc_codegen_gcc/src/allocator.rs
+++ b/compiler/rustc_codegen_gcc/src/allocator.rs
@@ -1,6 +1,6 @@
-use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type};
 #[cfg(feature = "master")]
-use gccjit::{FnAttribute, VarAttribute};
+use gccjit::FnAttribute;
+use gccjit::{Context, FunctionType, RValue, ToRValue, Type};
 use rustc_ast::expand::allocator::{
     ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
     alloc_error_handler_name, default_fn_name, global_fn_name,
@@ -71,15 +71,13 @@ pub(crate) unsafe fn codegen(
         None,
     );
 
-    let name = mangle_internal_symbol(tcx, OomStrategy::SYMBOL);
-    let global = context.new_global(None, GlobalKind::Exported, i8, name);
-    #[cfg(feature = "master")]
-    global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc(
-        tcx.sess.default_visibility(),
-    )));
-    let value = tcx.sess.opts.unstable_opts.oom.should_panic();
-    let value = context.new_rvalue_from_int(i8, value as i32);
-    global.global_set_initializer_rvalue(value);
+    create_const_value_function(
+        tcx,
+        context,
+        &mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
+        i8,
+        context.new_rvalue_from_int(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as i32),
+    );
 
     create_wrapper_function(
         tcx,
@@ -91,6 +89,30 @@ pub(crate) unsafe fn codegen(
     );
 }
 
+fn create_const_value_function(
+    tcx: TyCtxt<'_>,
+    context: &Context<'_>,
+    name: &str,
+    output: Type<'_>,
+    value: RValue<'_>,
+) {
+    let func = context.new_function(None, FunctionType::Exported, output, &[], name, false);
+
+    #[cfg(feature = "master")]
+    func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc(
+        tcx.sess.default_visibility(),
+    )));
+
+    func.add_attribute(FnAttribute::AlwaysInline);
+
+    if tcx.sess.must_emit_unwind_tables() {
+        // TODO(antoyo): emit unwind tables.
+    }
+
+    let block = func.new_block("entry");
+    block.end_with_return(None, value);
+}
+
 fn create_wrapper_function(
     tcx: TyCtxt<'_>,
     context: &Context<'_>,
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 9dca63cfc8d..2b5090ed6db 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -11,7 +11,7 @@ use rustc_symbol_mangling::mangle_internal_symbol;
 
 use crate::builder::SBuilder;
 use crate::declare::declare_simple_fn;
-use crate::llvm::{self, False, True, Type};
+use crate::llvm::{self, False, True, Type, Value};
 use crate::{SimpleCx, attributes, debuginfo};
 
 pub(crate) unsafe fn codegen(
@@ -73,13 +73,14 @@ pub(crate) unsafe fn codegen(
     );
 
     unsafe {
-        // __rust_alloc_error_handler_should_panic
-        let name = mangle_internal_symbol(tcx, OomStrategy::SYMBOL);
-        let ll_g = cx.declare_global(&name, i8);
-        llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
-        let val = tcx.sess.opts.unstable_opts.oom.should_panic();
-        let llval = llvm::LLVMConstInt(i8, val as u64, False);
-        llvm::set_initializer(ll_g, llval);
+        // __rust_alloc_error_handler_should_panic_v2
+        create_const_value_function(
+            tcx,
+            &cx,
+            &mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
+            &i8,
+            &llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, False),
+        );
 
         // __rust_no_alloc_shim_is_unstable_v2
         create_wrapper_function(
@@ -100,6 +101,34 @@ pub(crate) unsafe fn codegen(
     }
 }
 
+fn create_const_value_function(
+    tcx: TyCtxt<'_>,
+    cx: &SimpleCx<'_>,
+    name: &str,
+    output: &Type,
+    value: &Value,
+) {
+    let ty = cx.type_func(&[], output);
+    let llfn = declare_simple_fn(
+        &cx,
+        name,
+        llvm::CallConv::CCallConv,
+        llvm::UnnamedAddr::Global,
+        llvm::Visibility::from_generic(tcx.sess.default_visibility()),
+        ty,
+    );
+
+    attributes::apply_to_llfn(
+        llfn,
+        llvm::AttributePlace::Function,
+        &[llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx)],
+    );
+
+    let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
+    let mut bx = SBuilder::build(&cx, llbb);
+    bx.ret(value);
+}
+
 fn create_wrapper_function(
     tcx: TyCtxt<'_>,
     cx: &SimpleCx<'_>,
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 82e7468211d..c4181a62a35 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -28,7 +28,7 @@ rustc_type_ir = { path = "../rustc_type_ir" }
 serde = { version = "1.0.125", features = [ "derive" ] }
 serde_json = "1.0.59"
 termcolor = "1.2.0"
-termize = "0.1.1"
+termize = "0.2"
 tracing = "0.1"
 # tidy-alphabetical-end
 
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index fe9797026de..5746c28a2ab 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -417,6 +417,15 @@ impl DiagInner {
         self.args = std::mem::take(&mut self.reserved_args);
     }
 
+    pub fn emitted_at_sub_diag(&self) -> Subdiag {
+        let track = format!("-Ztrack-diagnostics: created at {}", self.emitted_at);
+        Subdiag {
+            level: crate::Level::Note,
+            messages: vec![(DiagMessage::Str(Cow::Owned(track)), Style::NoStyle)],
+            span: MultiSpan::new(),
+        }
+    }
+
     /// Fields used for Hash, and PartialEq trait.
     fn keys(
         &self,
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 3f5872f34a6..2f398cea926 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -28,7 +28,6 @@ use rustc_span::{FileLines, FileName, SourceFile, Span, char_width, str_width};
 use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
 use tracing::{debug, instrument, trace, warn};
 
-use crate::diagnostic::DiagLocation;
 use crate::registry::Registry;
 use crate::snippet::{
     Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
@@ -505,6 +504,10 @@ impl Emitter for HumanEmitter {
     fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) {
         let fluent_args = to_fluent_args(diag.args.iter());
 
+        if self.track_diagnostics && diag.span.has_primary_spans() && !diag.span.is_dummy() {
+            diag.children.insert(0, diag.emitted_at_sub_diag());
+        }
+
         let mut suggestions = diag.suggestions.unwrap_tag();
         self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args);
 
@@ -523,7 +526,6 @@ impl Emitter for HumanEmitter {
             &diag.span,
             &diag.children,
             &suggestions,
-            self.track_diagnostics.then_some(&diag.emitted_at),
         );
     }
 
@@ -1468,7 +1470,6 @@ impl HumanEmitter {
         level: &Level,
         max_line_num_len: usize,
         is_secondary: bool,
-        emitted_at: Option<&DiagLocation>,
         is_cont: bool,
     ) -> io::Result<()> {
         let mut buffer = StyledBuffer::new();
@@ -1978,12 +1979,6 @@ impl HumanEmitter {
             trace!("buffer: {:#?}", buffer.render());
         }
 
-        if let Some(tracked) = emitted_at {
-            let track = format!("-Ztrack-diagnostics: created at {tracked}");
-            let len = buffer.num_lines();
-            buffer.append(len, &track, Style::NoStyle);
-        }
-
         // final step: take our styled buffer, render it, then output it
         emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
 
@@ -2478,7 +2473,6 @@ impl HumanEmitter {
         span: &MultiSpan,
         children: &[Subdiag],
         suggestions: &[CodeSuggestion],
-        emitted_at: Option<&DiagLocation>,
     ) {
         let max_line_num_len = if self.ui_testing {
             ANONYMIZED_LINE_NUM.len()
@@ -2495,7 +2489,6 @@ impl HumanEmitter {
             level,
             max_line_num_len,
             false,
-            emitted_at,
             !children.is_empty()
                 || suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden),
         ) {
@@ -2541,7 +2534,6 @@ impl HumanEmitter {
                             &child.level,
                             max_line_num_len,
                             true,
-                            None,
                             !should_close,
                         ) {
                             panic!("failed to emit error: {err}");
@@ -2561,7 +2553,6 @@ impl HumanEmitter {
                                     &Level::Help,
                                     max_line_num_len,
                                     true,
-                                    None,
                                     // FIXME: this needs to account for the suggestion type,
                                     //        some don't take any space.
                                     i + 1 != suggestions.len(),
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 4348610be0a..719d4ca625a 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -372,13 +372,16 @@ impl Diagnostic {
         };
         let level = diag.level.to_str();
         let spans = DiagnosticSpan::from_multispan(&diag.span, &args, je);
-        let children = diag
+        let mut children: Vec<Diagnostic> = diag
             .children
             .iter()
             .map(|c| Diagnostic::from_sub_diagnostic(c, &args, je))
             .chain(sugg)
             .collect();
-
+        if je.track_diagnostics && diag.span.has_primary_spans() && !diag.span.is_dummy() {
+            children
+                .insert(0, Diagnostic::from_sub_diagnostic(&diag.emitted_at_sub_diag(), &args, je));
+        }
         let buf = BufWriter::default();
         let mut dst: Destination = Box::new(buf.clone());
         let short = je.json_rendered.short();
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 10dd5ff9aa7..c11db63ba11 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -367,8 +367,6 @@ language_item_table! {
     TryTraitBranch,          sym::branch,              branch_fn,                  Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     TryTraitFromYeet,        sym::from_yeet,           from_yeet_fn,               Target::Fn,             GenericRequirement::None;
 
-    PointerLike,             sym::pointer_like,        pointer_like,               Target::Trait,          GenericRequirement::Exact(0);
-
     CoercePointeeValidated, sym::coerce_pointee_validated, coerce_pointee_validated_trait, Target::Trait,     GenericRequirement::Exact(0);
 
     ConstParamTy,            sym::const_param_ty,      const_param_ty_trait,       Target::Trait,          GenericRequirement::Exact(0);
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 734c9c58c08..65bc441a473 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -47,7 +47,6 @@ pub(super) fn check_trait<'tcx>(
     checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
     checker
         .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
-    checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
     checker.check(
         lang_items.coerce_pointee_validated_trait(),
         visit_implementation_of_coerce_pointee_validity,
@@ -707,104 +706,6 @@ fn infringing_fields_error<'tcx>(
     err.emit()
 }
 
-fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
-    let tcx = checker.tcx;
-    let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id);
-    let impl_span = tcx.def_span(checker.impl_def_id);
-    let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
-
-    let is_permitted_primitive = match *self_ty.kind() {
-        ty::Adt(def, _) => def.is_box(),
-        ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
-        _ => false,
-    };
-
-    if is_permitted_primitive
-        && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
-        && layout.layout.is_pointer_like(&tcx.data_layout)
-    {
-        return Ok(());
-    }
-
-    let why_disqualified = match *self_ty.kind() {
-        // If an ADT is repr(transparent)
-        ty::Adt(self_ty_def, args) => {
-            if self_ty_def.repr().transparent() {
-                // FIXME(compiler-errors): This should and could be deduplicated into a query.
-                // Find the nontrivial field.
-                let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, self_ty_def.did());
-                let nontrivial_field = self_ty_def.all_fields().find(|field_def| {
-                    let field_ty = tcx.type_of(field_def.did).instantiate_identity();
-                    !tcx.layout_of(adt_typing_env.as_query_input(field_ty))
-                        .is_ok_and(|layout| layout.layout.is_1zst())
-                });
-
-                if let Some(nontrivial_field) = nontrivial_field {
-                    // Check that the nontrivial field implements `PointerLike`.
-                    let nontrivial_field_ty = nontrivial_field.ty(tcx, args);
-                    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
-                    let ocx = ObligationCtxt::new(&infcx);
-                    ocx.register_bound(
-                        ObligationCause::misc(impl_span, checker.impl_def_id),
-                        param_env,
-                        nontrivial_field_ty,
-                        tcx.require_lang_item(LangItem::PointerLike, impl_span),
-                    );
-                    // FIXME(dyn-star): We should regionck this implementation.
-                    if ocx.select_all_or_error().is_empty() {
-                        return Ok(());
-                    } else {
-                        format!(
-                            "the field `{field_name}` of {descr} `{self_ty}` \
-                    does not implement `PointerLike`",
-                            field_name = nontrivial_field.name,
-                            descr = self_ty_def.descr()
-                        )
-                    }
-                } else {
-                    format!(
-                        "the {descr} `{self_ty}` is `repr(transparent)`, \
-                but does not have a non-trivial field (it is zero-sized)",
-                        descr = self_ty_def.descr()
-                    )
-                }
-            } else if self_ty_def.is_box() {
-                // If we got here, then the `layout.is_pointer_like()` check failed
-                // and this box is not a thin pointer.
-
-                String::from("boxes of dynamically-sized types are too large to be `PointerLike`")
-            } else {
-                format!(
-                    "the {descr} `{self_ty}` is not `repr(transparent)`",
-                    descr = self_ty_def.descr()
-                )
-            }
-        }
-        ty::Ref(..) => {
-            // If we got here, then the `layout.is_pointer_like()` check failed
-            // and this reference is not a thin pointer.
-            String::from("references to dynamically-sized types are too large to be `PointerLike`")
-        }
-        ty::Dynamic(..) | ty::Foreign(..) => {
-            String::from("types of dynamic or unknown size may not implement `PointerLike`")
-        }
-        _ => {
-            // This is a white lie; it is true everywhere outside the standard library.
-            format!("only user-defined sized types are eligible for `impl PointerLike`")
-        }
-    };
-
-    Err(tcx
-        .dcx()
-        .struct_span_err(
-            impl_span,
-            "implementation must be applied to type that has the same ABI as a pointer, \
-            or is `repr(transparent)` and whose field is `PointerLike`",
-        )
-        .with_note(why_disqualified)
-        .emit())
-}
-
 fn visit_implementation_of_coerce_pointee_validity(
     checker: &Checker<'_>,
 ) -> Result<(), ErrorGuaranteed> {
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index d85618f664d..d3b3b55dd4c 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -1,8 +1,8 @@
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_hir::def::Res;
 use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
 
 use crate::lints::PassByValueDiag;
 use crate::{LateContext, LateLintPass, LintContext};
@@ -45,14 +45,16 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
 fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<String> {
     if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
         match path.res {
-            Res::Def(_, def_id) if cx.tcx.has_attr(def_id, sym::rustc_pass_by_value) => {
+            Res::Def(_, def_id)
+                if find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::PassByValue(_)) =>
+            {
                 let name = cx.tcx.item_ident(def_id);
                 let path_segment = path.segments.last().unwrap();
                 return Some(format!("{}{}", name, gen_args(cx, path_segment)));
             }
             Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
                 if let ty::Adt(adt, args) = cx.tcx.type_of(did).instantiate_identity().kind() {
-                    if cx.tcx.has_attr(adt.did(), sym::rustc_pass_by_value) {
+                    if find_attr!(cx.tcx.get_all_attrs(adt.did()), AttributeKind::PassByValue(_)) {
                         return Some(cx.tcx.def_path_str_with_args(adt.did(), args));
                     }
                 }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 7f79cd5d468..a92d6fe3916 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1149,12 +1149,16 @@ impl<'tcx> TypingEnv<'tcx> {
     {
         // FIXME(#132279): We should assert that the value does not contain any placeholders
         // as these placeholders are also local to the current inference context. However, we
-        // currently use pseudo-canonical queries in the trait solver which replaces params with
-        // placeholders. We should also simply not use pseudo-canonical queries in the trait
-        // solver, at which point we can readd this assert. As of writing this comment, this is
-        // only used by `fn layout_is_pointer_like` when calling `layout_of`.
+        // currently use pseudo-canonical queries in the trait solver, which replaces params
+        // with placeholders during canonicalization. We should also simply not use pseudo-
+        // canonical queries in the trait solver, at which point we can readd this assert.
         //
-        // debug_assert!(!value.has_placeholders());
+        // As of writing this comment, this is only used when normalizing consts that mention
+        // params.
+        /* debug_assert!(
+            !value.has_placeholders(),
+            "{value:?} which has placeholder shouldn't be pseudo-canonicalized"
+        ); */
         PseudoCanonicalInput { typing_env: self, value }
     }
 }
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 627e9aabd12..47249b38df5 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -293,6 +293,7 @@ fn emit_malformed_attribute(
             | sym::rustc_force_inline
             | sym::rustc_confusables
             | sym::rustc_skip_during_method_dispatch
+            | sym::rustc_pass_by_value
             | sym::repr
             | sym::align
             | sym::deprecated
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 7880e629e91..c0ef81166ea 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -221,6 +221,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => {
                     self.check_used(*attr_span, target, span);
                 }
+                &Attribute::Parsed(AttributeKind::PassByValue(attr_span)) => {
+                    self.check_pass_by_value(attr_span, span, target)
+                }
                 Attribute::Unparsed(attr_item) => {
                     style = Some(attr_item.style);
                     match attr.path().as_slice() {
@@ -283,7 +286,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target),
                         [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
                         [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
-                        [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
                         [sym::rustc_allow_incoherent_impl, ..] => {
                             self.check_allow_incoherent_impl(attr, span, target)
                         }
@@ -1465,11 +1467,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     }
 
     /// Warns against some misuses of `#[pass_by_value]`
-    fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) {
+    fn check_pass_by_value(&self, attr_span: Span, span: Span, target: Target) {
         match target {
             Target::Struct | Target::Enum | Target::TyAlias => {}
             _ => {
-                self.dcx().emit_err(errors::PassByValue { attr_span: attr.span(), span });
+                self.dcx().emit_err(errors::PassByValue { attr_span, span });
             }
         }
     }
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index 5b88a7017c5..0516982aeab 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -22,7 +22,7 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
-termize = "0.1.1"
+termize = "0.2"
 tracing = "0.1"
 # tidy-alphabetical-end
 
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 74e766a1e95..4627c2978fc 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3340,7 +3340,7 @@ pub enum OomStrategy {
 }
 
 impl OomStrategy {
-    pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
+    pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic_v2";
 
     pub fn should_panic(self) -> u8 {
         match self {
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 2982a920b03..dcdc77b76c2 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -4,28 +4,17 @@
 //! until stable MIR is complete.
 
 use std::cell::{Cell, RefCell};
-use std::fmt::Debug;
-use std::hash::Hash;
-use std::ops::Index;
 
-use rustc_data_structures::fx;
-use rustc_data_structures::fx::FxIndexMap;
-use rustc_middle::mir::interpret::AllocId;
-use rustc_middle::ty;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::Span;
-use rustc_span::def_id::{CrateNum, DefId};
+use rustc_span::def_id::CrateNum;
 use scoped_tls::scoped_thread_local;
 use stable_mir::Error;
-use stable_mir::abi::Layout;
-use stable_mir::compiler_interface::SmirInterface;
-use stable_mir::ty::IndexedVal;
+use stable_mir::unstable::{RustcInternal, Stable};
 
 use crate::rustc_smir::context::SmirCtxt;
-use crate::rustc_smir::{Stable, Tables};
+use crate::rustc_smir::{Bridge, SmirContainer, Tables};
 use crate::stable_mir;
 
-mod internal;
 pub mod pretty;
 
 /// Convert an internal Rust compiler item into its stable counterpart, if one exists.
@@ -40,7 +29,7 @@ pub mod pretty;
 ///
 /// This function will panic if StableMIR has not been properly initialized.
 pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T {
-    with_tables(|tables| item.stable(tables))
+    with_container(|tables, cx| item.stable(tables, cx))
 }
 
 /// Convert a stable item into its internal Rust compiler counterpart, if one exists.
@@ -59,134 +48,9 @@ where
     S: RustcInternal,
 {
     // The tcx argument ensures that the item won't outlive the type context.
-    with_tables(|tables| item.internal(tables, tcx))
-}
-
-impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> {
-    type Output = DefId;
-
-    #[inline(always)]
-    fn index(&self, index: stable_mir::DefId) -> &Self::Output {
-        &self.def_ids[index]
-    }
-}
-
-impl<'tcx> Index<stable_mir::ty::Span> for Tables<'tcx> {
-    type Output = Span;
-
-    #[inline(always)]
-    fn index(&self, index: stable_mir::ty::Span) -> &Self::Output {
-        &self.spans[index]
-    }
-}
-
-impl<'tcx> Tables<'tcx> {
-    pub fn crate_item(&mut self, did: DefId) -> stable_mir::CrateItem {
-        stable_mir::CrateItem(self.create_def_id(did))
-    }
-
-    pub fn adt_def(&mut self, did: DefId) -> stable_mir::ty::AdtDef {
-        stable_mir::ty::AdtDef(self.create_def_id(did))
-    }
-
-    pub fn foreign_module_def(&mut self, did: DefId) -> stable_mir::ty::ForeignModuleDef {
-        stable_mir::ty::ForeignModuleDef(self.create_def_id(did))
-    }
-
-    pub fn foreign_def(&mut self, did: DefId) -> stable_mir::ty::ForeignDef {
-        stable_mir::ty::ForeignDef(self.create_def_id(did))
-    }
-
-    pub fn fn_def(&mut self, did: DefId) -> stable_mir::ty::FnDef {
-        stable_mir::ty::FnDef(self.create_def_id(did))
-    }
-
-    pub fn closure_def(&mut self, did: DefId) -> stable_mir::ty::ClosureDef {
-        stable_mir::ty::ClosureDef(self.create_def_id(did))
-    }
-
-    pub fn coroutine_def(&mut self, did: DefId) -> stable_mir::ty::CoroutineDef {
-        stable_mir::ty::CoroutineDef(self.create_def_id(did))
-    }
-
-    pub fn coroutine_closure_def(&mut self, did: DefId) -> stable_mir::ty::CoroutineClosureDef {
-        stable_mir::ty::CoroutineClosureDef(self.create_def_id(did))
-    }
-
-    pub fn alias_def(&mut self, did: DefId) -> stable_mir::ty::AliasDef {
-        stable_mir::ty::AliasDef(self.create_def_id(did))
-    }
-
-    pub fn param_def(&mut self, did: DefId) -> stable_mir::ty::ParamDef {
-        stable_mir::ty::ParamDef(self.create_def_id(did))
-    }
-
-    pub fn br_named_def(&mut self, did: DefId) -> stable_mir::ty::BrNamedDef {
-        stable_mir::ty::BrNamedDef(self.create_def_id(did))
-    }
-
-    pub fn trait_def(&mut self, did: DefId) -> stable_mir::ty::TraitDef {
-        stable_mir::ty::TraitDef(self.create_def_id(did))
-    }
-
-    pub fn generic_def(&mut self, did: DefId) -> stable_mir::ty::GenericDef {
-        stable_mir::ty::GenericDef(self.create_def_id(did))
-    }
-
-    pub fn const_def(&mut self, did: DefId) -> stable_mir::ty::ConstDef {
-        stable_mir::ty::ConstDef(self.create_def_id(did))
-    }
-
-    pub fn impl_def(&mut self, did: DefId) -> stable_mir::ty::ImplDef {
-        stable_mir::ty::ImplDef(self.create_def_id(did))
-    }
-
-    pub fn region_def(&mut self, did: DefId) -> stable_mir::ty::RegionDef {
-        stable_mir::ty::RegionDef(self.create_def_id(did))
-    }
-
-    pub fn coroutine_witness_def(&mut self, did: DefId) -> stable_mir::ty::CoroutineWitnessDef {
-        stable_mir::ty::CoroutineWitnessDef(self.create_def_id(did))
-    }
-
-    pub fn assoc_def(&mut self, did: DefId) -> stable_mir::ty::AssocDef {
-        stable_mir::ty::AssocDef(self.create_def_id(did))
-    }
-
-    pub fn opaque_def(&mut self, did: DefId) -> stable_mir::ty::OpaqueDef {
-        stable_mir::ty::OpaqueDef(self.create_def_id(did))
-    }
-
-    pub fn prov(&mut self, aid: AllocId) -> stable_mir::ty::Prov {
-        stable_mir::ty::Prov(self.create_alloc_id(aid))
-    }
-
-    pub(crate) fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId {
-        self.def_ids.create_or_fetch(did)
-    }
-
-    pub(crate) fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::mir::alloc::AllocId {
-        self.alloc_ids.create_or_fetch(aid)
-    }
-
-    pub(crate) fn create_span(&mut self, span: Span) -> stable_mir::ty::Span {
-        self.spans.create_or_fetch(span)
-    }
-
-    pub(crate) fn instance_def(
-        &mut self,
-        instance: ty::Instance<'tcx>,
-    ) -> stable_mir::mir::mono::InstanceDef {
-        self.instances.create_or_fetch(instance)
-    }
-
-    pub(crate) fn static_def(&mut self, did: DefId) -> stable_mir::mir::mono::StaticDef {
-        stable_mir::mir::mono::StaticDef(self.create_def_id(did))
-    }
-
-    pub(crate) fn layout_id(&mut self, layout: rustc_abi::Layout<'tcx>) -> Layout {
-        self.layouts.create_or_fetch(layout)
-    }
+    // See https://github.com/rust-lang/rust/pull/120128/commits/9aace6723572438a94378451793ca37deb768e72
+    // for more details.
+    with_container(|tables, _| item.internal(tables, tcx))
 }
 
 pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
@@ -197,25 +61,28 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
 // datastructures and stable MIR datastructures
 scoped_thread_local! (static TLV: Cell<*const ()>);
 
-pub(crate) fn init<'tcx, F, T>(cx: &SmirCtxt<'tcx>, f: F) -> T
+pub(crate) fn init<'tcx, F, T, B: Bridge>(container: &SmirContainer<'tcx, B>, f: F) -> T
 where
     F: FnOnce() -> T,
 {
     assert!(!TLV.is_set());
-    let ptr = cx as *const _ as *const ();
+    let ptr = container as *const _ as *const ();
     TLV.set(&Cell::new(ptr), || f())
 }
 
 /// Loads the current context and calls a function with it.
 /// Do not nest these, as that will ICE.
-pub(crate) fn with_tables<R>(f: impl for<'tcx> FnOnce(&mut Tables<'tcx>) -> R) -> R {
+pub(crate) fn with_container<R, B: Bridge>(
+    f: impl for<'tcx> FnOnce(&mut Tables<'tcx, B>, &SmirCtxt<'tcx, B>) -> R,
+) -> R {
     assert!(TLV.is_set());
     TLV.with(|tlv| {
         let ptr = tlv.get();
         assert!(!ptr.is_null());
-        let context = ptr as *const SmirCtxt<'_>;
-        let mut tables = unsafe { (*context).0.borrow_mut() };
-        f(&mut *tables)
+        let container = ptr as *const SmirContainer<'_, B>;
+        let mut tables = unsafe { (*container).tables.borrow_mut() };
+        let cx = unsafe { (*container).cx.borrow() };
+        f(&mut *tables, &*cx)
     })
 }
 
@@ -223,23 +90,10 @@ pub fn run<F, T>(tcx: TyCtxt<'_>, f: F) -> Result<T, Error>
 where
     F: FnOnce() -> T,
 {
-    let tables = SmirCtxt(RefCell::new(Tables {
-        tcx,
-        def_ids: IndexMap::default(),
-        alloc_ids: IndexMap::default(),
-        spans: IndexMap::default(),
-        types: IndexMap::default(),
-        instances: IndexMap::default(),
-        ty_consts: IndexMap::default(),
-        mir_consts: IndexMap::default(),
-        layouts: IndexMap::default(),
-    }));
+    let smir_cx = RefCell::new(SmirCtxt::new(tcx));
+    let container = SmirContainer { tables: RefCell::new(Tables::default()), cx: smir_cx };
 
-    let interface = SmirInterface { cx: tables };
-
-    // Pass the `SmirInterface` to compiler_interface::run
-    // and initialize the rustc-specific TLS with tables.
-    stable_mir::compiler_interface::run(&interface, || init(&interface.cx, f))
+    stable_mir::compiler_interface::run(&container, || init(&container, f))
 }
 
 /// Instantiate and run the compiler with the provided arguments and callback.
@@ -417,43 +271,3 @@ macro_rules! run_driver {
         StableMir::new($callback).run($args)
     }};
 }
-
-/// Similar to rustc's `FxIndexMap`, `IndexMap` with extra
-/// safety features added.
-pub struct IndexMap<K, V> {
-    index_map: fx::FxIndexMap<K, V>,
-}
-
-impl<K, V> Default for IndexMap<K, V> {
-    fn default() -> Self {
-        Self { index_map: FxIndexMap::default() }
-    }
-}
-
-impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> IndexMap<K, V> {
-    pub fn create_or_fetch(&mut self, key: K) -> V {
-        let len = self.index_map.len();
-        let v = self.index_map.entry(key).or_insert(V::to_val(len));
-        *v
-    }
-}
-
-impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V>
-    for IndexMap<K, V>
-{
-    type Output = K;
-
-    fn index(&self, index: V) -> &Self::Output {
-        let (k, v) = self.index_map.get_index(index.to_index()).unwrap();
-        assert_eq!(*v, index, "Provided value doesn't match with indexed value");
-        k
-    }
-}
-
-/// Trait used to translate a stable construct to its rustc counterpart.
-///
-/// This is basically a mirror of [crate::rustc_smir::Stable].
-pub trait RustcInternal {
-    type T<'tcx>;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx>;
-}
diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs
index a6d31ac4e13..ecaf3571896 100644
--- a/compiler/rustc_smir/src/rustc_smir/alloc.rs
+++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs
@@ -1,102 +1,82 @@
-use rustc_abi::{Align, Size};
-use rustc_middle::mir::ConstValue;
-use rustc_middle::mir::interpret::{AllocInit, AllocRange, Pointer, alloc_range};
-use stable_mir::Error;
-use stable_mir::mir::Mutability;
-use stable_mir::ty::{Allocation, ProvenanceMap};
+//! Internal memory allocator implementation for StableMIR.
+//!
+//! This module handles all direct interactions with rustc queries and performs
+//! the actual memory allocations. The stable interface in `stable_mir::alloc`
+//! delegates all query-related operations to this implementation.
 
-use crate::rustc_smir::{Stable, Tables};
-use crate::stable_mir;
+use rustc_abi::{Size, TyAndLayout};
+use rustc_middle::mir::interpret::{
+    AllocId, AllocInit, AllocRange, Allocation, ConstAllocation, Pointer, Scalar, alloc_range,
+};
+use rustc_middle::ty::{Ty, layout};
 
-/// Creates new empty `Allocation` from given `Align`.
-fn new_empty_allocation(align: Align) -> Allocation {
-    Allocation {
-        bytes: Vec::new(),
-        provenance: ProvenanceMap { ptrs: Vec::new() },
-        align: align.bytes(),
-        mutability: Mutability::Not,
-    }
+use super::{SmirCtxt, Tables};
+use crate::rustc_smir::bridge::Allocation as _;
+use crate::rustc_smir::{Bridge, SmirError};
+
+pub fn create_ty_and_layout<'tcx, B: Bridge>(
+    cx: &SmirCtxt<'tcx, B>,
+    ty: Ty<'tcx>,
+) -> Result<TyAndLayout<'tcx, Ty<'tcx>>, &'tcx layout::LayoutError<'tcx>> {
+    use crate::rustc_smir::context::SmirTypingEnv;
+    cx.tcx.layout_of(cx.fully_monomorphized().as_query_input(ty))
 }
 
-// We need this method instead of a Stable implementation
-// because we need to get `Ty` of the const we are trying to create, to do that
-// we need to have access to `ConstantKind` but we can't access that inside Stable impl.
-#[allow(rustc::usage_of_qualified_ty)]
-pub(crate) fn new_allocation<'tcx>(
-    ty: rustc_middle::ty::Ty<'tcx>,
-    const_value: ConstValue<'tcx>,
-    tables: &mut Tables<'tcx>,
-) -> Allocation {
-    try_new_allocation(ty, const_value, tables)
-        .unwrap_or_else(|_| panic!("Failed to convert: {const_value:?} to {ty:?}"))
+pub fn try_new_scalar<'tcx, B: Bridge>(
+    layout: TyAndLayout<'tcx, Ty<'tcx>>,
+    scalar: Scalar,
+    cx: &SmirCtxt<'tcx, B>,
+) -> Result<Allocation, B::Error> {
+    let size = scalar.size();
+    let mut allocation = Allocation::new(size, layout.align.abi, AllocInit::Uninit, ());
+    allocation
+        .write_scalar(&cx.tcx, alloc_range(Size::ZERO, size), scalar)
+        .map_err(|e| B::Error::from_internal(e))?;
+
+    Ok(allocation)
 }
 
-#[allow(rustc::usage_of_qualified_ty)]
-pub(crate) fn try_new_allocation<'tcx>(
-    ty: rustc_middle::ty::Ty<'tcx>,
-    const_value: ConstValue<'tcx>,
-    tables: &mut Tables<'tcx>,
-) -> Result<Allocation, Error> {
-    let layout = tables
-        .tcx
-        .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
-        .map_err(|e| e.stable(tables))?;
-    Ok(match const_value {
-        ConstValue::Scalar(scalar) => {
-            let size = scalar.size();
-            let mut allocation = rustc_middle::mir::interpret::Allocation::new(
-                size,
-                layout.align.abi,
-                AllocInit::Uninit,
-                (),
-            );
-            allocation
-                .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar)
-                .map_err(|e| e.stable(tables))?;
-            allocation.stable(tables)
-        }
-        ConstValue::ZeroSized => new_empty_allocation(layout.align.abi),
-        ConstValue::Slice { data, meta } => {
-            let alloc_id = tables.tcx.reserve_and_set_memory_alloc(data);
-            let ptr = Pointer::new(alloc_id.into(), Size::ZERO);
-            let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
-            let scalar_meta =
-                rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
-            let mut allocation = rustc_middle::mir::interpret::Allocation::new(
-                layout.size,
-                layout.align.abi,
-                AllocInit::Uninit,
-                (),
-            );
-            allocation
-                .write_scalar(
-                    &tables.tcx,
-                    alloc_range(Size::ZERO, tables.tcx.data_layout.pointer_size),
-                    scalar_ptr,
-                )
-                .map_err(|e| e.stable(tables))?;
-            allocation
-                .write_scalar(
-                    &tables.tcx,
-                    alloc_range(tables.tcx.data_layout.pointer_size, scalar_meta.size()),
-                    scalar_meta,
-                )
-                .map_err(|e| e.stable(tables))?;
-            allocation.stable(tables)
-        }
-        ConstValue::Indirect { alloc_id, offset } => {
-            let alloc = tables.tcx.global_alloc(alloc_id).unwrap_memory();
-            allocation_filter(&alloc.0, alloc_range(offset, layout.size), tables)
-        }
-    })
+pub fn try_new_slice<'tcx, B: Bridge>(
+    layout: TyAndLayout<'tcx, Ty<'tcx>>,
+    data: ConstAllocation<'tcx>,
+    meta: u64,
+    cx: &SmirCtxt<'tcx, B>,
+) -> Result<Allocation, B::Error> {
+    let alloc_id = cx.tcx.reserve_and_set_memory_alloc(data);
+    let ptr = Pointer::new(alloc_id.into(), Size::ZERO);
+    let scalar_ptr = Scalar::from_pointer(ptr, &cx.tcx);
+    let scalar_meta: Scalar = Scalar::from_target_usize(meta, &cx.tcx);
+    let mut allocation = Allocation::new(layout.size, layout.align.abi, AllocInit::Uninit, ());
+    allocation
+        .write_scalar(&cx.tcx, alloc_range(Size::ZERO, cx.tcx.data_layout.pointer_size), scalar_ptr)
+        .map_err(|e| B::Error::from_internal(e))?;
+    allocation
+        .write_scalar(
+            &cx.tcx,
+            alloc_range(cx.tcx.data_layout.pointer_size, scalar_meta.size()),
+            scalar_meta,
+        )
+        .map_err(|e| B::Error::from_internal(e))?;
+
+    Ok(allocation)
+}
+
+pub fn try_new_indirect<'tcx, B: Bridge>(
+    alloc_id: AllocId,
+    cx: &SmirCtxt<'tcx, B>,
+) -> ConstAllocation<'tcx> {
+    let alloc = cx.tcx.global_alloc(alloc_id).unwrap_memory();
+
+    alloc
 }
 
 /// Creates an `Allocation` only from information within the `AllocRange`.
-pub(super) fn allocation_filter<'tcx>(
+pub fn allocation_filter<'tcx, B: Bridge>(
     alloc: &rustc_middle::mir::interpret::Allocation,
     alloc_range: AllocRange,
-    tables: &mut Tables<'tcx>,
-) -> Allocation {
+    tables: &mut Tables<'tcx, B>,
+    cx: &SmirCtxt<'tcx, B>,
+) -> B::Allocation {
     let mut bytes: Vec<Option<u8>> = alloc
         .inspect_with_uninit_and_ptr_outside_interpreter(
             alloc_range.start.bytes_usize()..alloc_range.end().bytes_usize(),
@@ -117,15 +97,8 @@ pub(super) fn allocation_filter<'tcx>(
         .iter()
         .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end())
     {
-        ptrs.push((
-            offset.bytes_usize() - alloc_range.start.bytes_usize(),
-            tables.prov(prov.alloc_id()),
-        ));
-    }
-    Allocation {
-        bytes,
-        provenance: ProvenanceMap { ptrs },
-        align: alloc.align.bytes(),
-        mutability: alloc.mutability.stable(tables),
+        ptrs.push((offset.bytes_usize() - alloc_range.start.bytes_usize(), prov.alloc_id()));
     }
+
+    B::Allocation::new(bytes, ptrs, alloc.align.bytes(), alloc.mutability, tables, cx)
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/bridge.rs b/compiler/rustc_smir/src/rustc_smir/bridge.rs
new file mode 100644
index 00000000000..a31eb93d0e8
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/bridge.rs
@@ -0,0 +1,59 @@
+//! Defines a set of traits that is used for abstracting
+//! stable_mir's components that are needed in rustc_smir.
+//!
+//! These traits are really useful when programming
+//! in stable_mir-agnostic settings.
+
+use std::fmt::Debug;
+
+use super::context::SmirCtxt;
+use super::{Bridge, Tables};
+
+pub trait SmirError {
+    fn new(msg: String) -> Self;
+    fn from_internal<T: Debug>(err: T) -> Self;
+}
+
+pub trait Prov<B: Bridge> {
+    fn new(aid: B::AllocId) -> Self;
+}
+
+pub trait Allocation<B: Bridge> {
+    fn new<'tcx>(
+        bytes: Vec<Option<u8>>,
+        ptrs: Vec<(usize, rustc_middle::mir::interpret::AllocId)>,
+        align: u64,
+        mutability: rustc_middle::mir::Mutability,
+        tables: &mut Tables<'tcx, B>,
+        cx: &SmirCtxt<'tcx, B>,
+    ) -> Self;
+}
+
+macro_rules! make_bridge_trait {
+    ($name:ident) => {
+        pub trait $name<B: Bridge> {
+            fn new(did: B::DefId) -> Self;
+        }
+    };
+}
+
+make_bridge_trait!(CrateItem);
+make_bridge_trait!(AdtDef);
+make_bridge_trait!(ForeignModuleDef);
+make_bridge_trait!(ForeignDef);
+make_bridge_trait!(FnDef);
+make_bridge_trait!(ClosureDef);
+make_bridge_trait!(CoroutineDef);
+make_bridge_trait!(CoroutineClosureDef);
+make_bridge_trait!(AliasDef);
+make_bridge_trait!(ParamDef);
+make_bridge_trait!(BrNamedDef);
+make_bridge_trait!(TraitDef);
+make_bridge_trait!(GenericDef);
+make_bridge_trait!(ConstDef);
+make_bridge_trait!(ImplDef);
+make_bridge_trait!(RegionDef);
+make_bridge_trait!(CoroutineWitnessDef);
+make_bridge_trait!(AssocDef);
+make_bridge_trait!(OpaqueDef);
+make_bridge_trait!(StaticDef);
diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs
index 40e6d21c063..2141053d09a 100644
--- a/compiler/rustc_smir/src/rustc_smir/builder.rs
+++ b/compiler/rustc_smir/src/rustc_smir/builder.rs
@@ -9,9 +9,6 @@ use rustc_middle::mir;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::ty::{self, TyCtxt};
 
-use crate::rustc_smir::{Stable, Tables};
-use crate::stable_mir;
-
 /// Builds a monomorphic body for a given instance.
 pub(crate) struct BodyBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -31,8 +28,8 @@ impl<'tcx> BodyBuilder<'tcx> {
     /// Build a stable monomorphic body for a given instance based on the MIR body.
     ///
     /// All constants are also evaluated.
-    pub(crate) fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body {
-        let body = tables.tcx.instance_mir(self.instance.def).clone();
+    pub(crate) fn build(mut self) -> mir::Body<'tcx> {
+        let body = self.tcx.instance_mir(self.instance.def).clone();
         let mono_body = if !self.instance.args.is_empty()
             // Without the `generic_const_exprs` feature gate, anon consts in signatures do not
             // get generic parameters. Which is wrong, but also not a problem without
@@ -40,7 +37,7 @@ impl<'tcx> BodyBuilder<'tcx> {
             || self.tcx.def_kind(self.instance.def_id()) != DefKind::AnonConst
         {
             let mut mono_body = self.instance.instantiate_mir_and_normalize_erasing_regions(
-                tables.tcx,
+                self.tcx,
                 ty::TypingEnv::fully_monomorphized(),
                 ty::EarlyBinder::bind(body),
             );
@@ -50,7 +47,8 @@ impl<'tcx> BodyBuilder<'tcx> {
             // Already monomorphic.
             body
         };
-        mono_body.stable(tables)
+
+        mono_body
     }
 }
 
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
deleted file mode 100644
index 3fa83cfc6a0..00000000000
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ /dev/null
@@ -1,1000 +0,0 @@
-//! Implementation of StableMIR Context.
-
-#![allow(rustc::usage_of_qualified_ty)]
-
-use std::cell::RefCell;
-use std::iter;
-
-use rustc_abi::HasDataLayout;
-use rustc_hir::{Attribute, LangItem};
-use rustc_middle::ty::layout::{
-    FnAbiOf, FnAbiOfHelpers, HasTyCtxt, HasTypingEnv, LayoutOf, LayoutOfHelpers,
-};
-use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
-use rustc_middle::ty::{
-    CoroutineArgsExt, GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt,
-    ValTree,
-};
-use rustc_middle::{mir, ty};
-use rustc_span::def_id::LOCAL_CRATE;
-use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions};
-use stable_mir::mir::alloc::GlobalAlloc;
-use stable_mir::mir::mono::{InstanceDef, StaticDef};
-use stable_mir::mir::{BinOp, Body, Place, UnOp};
-use stable_mir::target::{MachineInfo, MachineSize};
-use stable_mir::ty::{
-    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
-    ForeignDef, ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy,
-    Span, Ty, TyConst, TyKind, UintTy, VariantDef, VariantIdx,
-};
-use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
-
-use crate::rustc_internal::RustcInternal;
-use crate::rustc_smir::builder::BodyBuilder;
-use crate::rustc_smir::{Stable, Tables, alloc, filter_def_ids, new_item_kind, smir_crate};
-use crate::stable_mir;
-
-/// Provides direct access to rustc's internal queries.
-///
-/// The [`crate::stable_mir::compiler_interface::SmirInterface`] must go through
-/// this context to obtain rustc-level information.
-pub struct SmirCtxt<'tcx>(pub RefCell<Tables<'tcx>>);
-
-impl<'tcx> SmirCtxt<'tcx> {
-    pub fn target_info(&self) -> MachineInfo {
-        let mut tables = self.0.borrow_mut();
-        MachineInfo {
-            endian: tables.tcx.data_layout.endian.stable(&mut *tables),
-            pointer_width: MachineSize::from_bits(
-                tables.tcx.data_layout.pointer_size.bits().try_into().unwrap(),
-            ),
-        }
-    }
-
-    pub fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        Some(tables.crate_item(tcx.entry_fn(())?.0))
-    }
-
-    /// Retrieve all items of the local crate that have a MIR associated with them.
-    pub fn all_local_items(&self) -> stable_mir::CrateItems {
-        let mut tables = self.0.borrow_mut();
-        tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect()
-    }
-
-    /// Retrieve the body of a function.
-    /// This function will panic if the body is not available.
-    pub fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[item];
-        tables.tcx.instance_mir(rustc_middle::ty::InstanceKind::Item(def_id)).stable(&mut tables)
-    }
-
-    /// Check whether the body of a function is available.
-    pub fn has_body(&self, def: DefId) -> bool {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.internal(&mut *tables, tcx);
-        tables.item_has_body(def_id)
-    }
-
-    pub fn foreign_modules(&self, crate_num: CrateNum) -> Vec<stable_mir::ty::ForeignModuleDef> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        tcx.foreign_modules(crate_num.internal(&mut *tables, tcx))
-            .keys()
-            .map(|mod_def_id| tables.foreign_module_def(*mod_def_id))
-            .collect()
-    }
-
-    /// Retrieve all functions defined in this crate.
-    pub fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let krate = crate_num.internal(&mut *tables, tcx);
-        filter_def_ids(tcx, krate, |def_id| tables.to_fn_def(def_id))
-    }
-
-    /// Retrieve all static items defined in this crate.
-    pub fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let krate = crate_num.internal(&mut *tables, tcx);
-        filter_def_ids(tcx, krate, |def_id| tables.to_static(def_id))
-    }
-
-    pub fn foreign_module(
-        &self,
-        mod_def: stable_mir::ty::ForeignModuleDef,
-    ) -> stable_mir::ty::ForeignModule {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[mod_def.def_id()];
-        let mod_def = tables.tcx.foreign_modules(def_id.krate).get(&def_id).unwrap();
-        mod_def.stable(&mut *tables)
-    }
-
-    pub fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec<ForeignDef> {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[mod_def.def_id()];
-        tables
-            .tcx
-            .foreign_modules(def_id.krate)
-            .get(&def_id)
-            .unwrap()
-            .foreign_items
-            .iter()
-            .map(|item_def| tables.foreign_def(*item_def))
-            .collect()
-    }
-
-    pub fn all_trait_decls(&self) -> stable_mir::TraitDecls {
-        let mut tables = self.0.borrow_mut();
-        tables
-            .tcx
-            .all_traits_including_private()
-            .map(|trait_def_id| tables.trait_def(trait_def_id))
-            .collect()
-    }
-
-    pub fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        tcx.traits(crate_num.internal(&mut *tables, tcx))
-            .iter()
-            .map(|trait_def_id| tables.trait_def(*trait_def_id))
-            .collect()
-    }
-
-    pub fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[trait_def.0];
-        let trait_def = tables.tcx.trait_def(def_id);
-        trait_def.stable(&mut *tables)
-    }
-
-    pub fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        iter::once(LOCAL_CRATE)
-            .chain(tables.tcx.crates(()).iter().copied())
-            .flat_map(|cnum| tcx.trait_impls_in_crate(cnum).iter())
-            .map(|impl_def_id| tables.impl_def(*impl_def_id))
-            .collect()
-    }
-
-    pub fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        tcx.trait_impls_in_crate(crate_num.internal(&mut *tables, tcx))
-            .iter()
-            .map(|impl_def_id| tables.impl_def(*impl_def_id))
-            .collect()
-    }
-
-    pub fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[impl_def.0];
-        let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap();
-        impl_trait.stable(&mut *tables)
-    }
-
-    pub fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[def_id];
-        let generics = tables.tcx.generics_of(def_id);
-        generics.stable(&mut *tables)
-    }
-
-    pub fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[def_id];
-        let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
-        stable_mir::ty::GenericPredicates {
-            parent: parent.map(|did| tables.trait_def(did)),
-            predicates: predicates
-                .iter()
-                .map(|(clause, span)| {
-                    (
-                        clause.as_predicate().kind().skip_binder().stable(&mut *tables),
-                        span.stable(&mut *tables),
-                    )
-                })
-                .collect(),
-        }
-    }
-
-    pub fn explicit_predicates_of(
-        &self,
-        def_id: stable_mir::DefId,
-    ) -> stable_mir::ty::GenericPredicates {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[def_id];
-        let GenericPredicates { parent, predicates } = tables.tcx.explicit_predicates_of(def_id);
-        stable_mir::ty::GenericPredicates {
-            parent: parent.map(|did| tables.trait_def(did)),
-            predicates: predicates
-                .iter()
-                .map(|(clause, span)| {
-                    (
-                        clause.as_predicate().kind().skip_binder().stable(&mut *tables),
-                        span.stable(&mut *tables),
-                    )
-                })
-                .collect(),
-        }
-    }
-
-    /// Get information about the local crate.
-    pub fn local_crate(&self) -> stable_mir::Crate {
-        let tables = self.0.borrow();
-        smir_crate(tables.tcx, LOCAL_CRATE)
-    }
-
-    /// Retrieve a list of all external crates.
-    pub fn external_crates(&self) -> Vec<stable_mir::Crate> {
-        let tables = self.0.borrow();
-        tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect()
-    }
-
-    /// Find a crate with the given name.
-    pub fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
-        let tables = self.0.borrow();
-        let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE]
-            .iter()
-            .chain(tables.tcx.crates(()).iter())
-            .filter_map(|crate_num| {
-                let crate_name = tables.tcx.crate_name(*crate_num).to_string();
-                (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num))
-            })
-            .collect();
-        crates
-    }
-
-    /// Returns the name of given `DefId`.
-    pub fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol {
-        let tables = self.0.borrow();
-        if trimmed {
-            with_forced_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
-        } else {
-            with_no_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
-        }
-    }
-
-    /// Return registered tool attributes with the given attribute name.
-    ///
-    /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool
-    /// attributes will simply return an empty list.
-    ///
-    /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
-    /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
-    pub fn tool_attrs(
-        &self,
-        def_id: stable_mir::DefId,
-        attr: &[stable_mir::Symbol],
-    ) -> Vec<stable_mir::crate_def::Attribute> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let did = tables[def_id];
-        let attr_name: Vec<_> = attr.iter().map(|seg| rustc_span::Symbol::intern(&seg)).collect();
-        tcx.get_attrs_by_path(did, &attr_name)
-            .filter_map(|attribute| {
-                if let Attribute::Unparsed(u) = attribute {
-                    let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute);
-                    Some(stable_mir::crate_def::Attribute::new(
-                        attr_str,
-                        u.span.stable(&mut *tables),
-                    ))
-                } else {
-                    None
-                }
-            })
-            .collect()
-    }
-
-    /// Get all tool attributes of a definition.
-    pub fn all_tool_attrs(
-        &self,
-        def_id: stable_mir::DefId,
-    ) -> Vec<stable_mir::crate_def::Attribute> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let did = tables[def_id];
-        let attrs_iter = if let Some(did) = did.as_local() {
-            tcx.hir_attrs(tcx.local_def_id_to_hir_id(did)).iter()
-        } else {
-            tcx.attrs_for_def(did).iter()
-        };
-        attrs_iter
-            .filter_map(|attribute| {
-                if let Attribute::Unparsed(u) = attribute {
-                    let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute);
-                    Some(stable_mir::crate_def::Attribute::new(
-                        attr_str,
-                        u.span.stable(&mut *tables),
-                    ))
-                } else {
-                    None
-                }
-            })
-            .collect()
-    }
-
-    /// Returns printable, human readable form of `Span`.
-    pub fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
-        let tables = self.0.borrow();
-        tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span])
-    }
-
-    /// Return filename from given `Span`, for diagnostic purposes.
-    pub fn get_filename(&self, span: &Span) -> Filename {
-        let tables = self.0.borrow();
-        tables
-            .tcx
-            .sess
-            .source_map()
-            .span_to_filename(tables[*span])
-            .display(rustc_span::FileNameDisplayPreference::Local)
-            .to_string()
-    }
-
-    /// Return lines corresponding to this `Span`.
-    pub fn get_lines(&self, span: &Span) -> LineInfo {
-        let tables = self.0.borrow();
-        let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]);
-        LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
-    }
-
-    /// Returns the `kind` of given `DefId`.
-    pub fn item_kind(&self, item: CrateItem) -> ItemKind {
-        let tables = self.0.borrow();
-        new_item_kind(tables.tcx.def_kind(tables[item.0]))
-    }
-
-    /// Returns whether this is a foreign item.
-    pub fn is_foreign_item(&self, item: DefId) -> bool {
-        let tables = self.0.borrow();
-        tables.tcx.is_foreign_item(tables[item])
-    }
-
-    /// Returns the kind of a given foreign item.
-    pub fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[def.def_id()];
-        let tcx = tables.tcx;
-        use rustc_hir::def::DefKind;
-        match tcx.def_kind(def_id) {
-            DefKind::Fn => ForeignItemKind::Fn(tables.fn_def(def_id)),
-            DefKind::Static { .. } => ForeignItemKind::Static(tables.static_def(def_id)),
-            DefKind::ForeignTy => ForeignItemKind::Type(
-                tables.intern_ty(rustc_middle::ty::Ty::new_foreign(tcx, def_id)),
-            ),
-            def_kind => unreachable!("Unexpected kind for a foreign item: {:?}", def_kind),
-        }
-    }
-
-    /// Returns the kind of a given algebraic data type.
-    pub fn adt_kind(&self, def: AdtDef) -> AdtKind {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).adt_kind().stable(&mut *tables)
-    }
-
-    /// Returns if the ADT is a box.
-    pub fn adt_is_box(&self, def: AdtDef) -> bool {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).is_box()
-    }
-
-    /// Returns whether this ADT is simd.
-    pub fn adt_is_simd(&self, def: AdtDef) -> bool {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).repr().simd()
-    }
-
-    /// Returns whether this definition is a C string.
-    pub fn adt_is_cstr(&self, def: AdtDef) -> bool {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        tables.tcx.is_lang_item(def_id, LangItem::CStr)
-    }
-
-    /// Returns the representation options for this ADT
-    pub fn adt_repr(&self, def: AdtDef) -> ReprOptions {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).repr().stable(&mut *tables)
-    }
-
-    /// Retrieve the function signature for the given generic arguments.
-    pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        let sig =
-            tables.tcx.fn_sig(def_id).instantiate(tables.tcx, args.internal(&mut *tables, tcx));
-        sig.stable(&mut *tables)
-    }
-
-    /// Retrieve the intrinsic definition if the item corresponds one.
-    pub fn intrinsic(&self, def: DefId) -> Option<IntrinsicDef> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.internal(&mut *tables, tcx);
-        let intrinsic = tcx.intrinsic_raw(def_id);
-        intrinsic.map(|_| IntrinsicDef(def))
-    }
-
-    /// Retrieve the plain function name of an intrinsic.
-    pub fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        tcx.intrinsic(def_id).unwrap().name.to_string()
-    }
-
-    /// Retrieve the closure signature for the given generic arguments.
-    pub fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let args_ref = args.internal(&mut *tables, tcx);
-        let sig = args_ref.as_closure().sig();
-        sig.stable(&mut *tables)
-    }
-
-    /// The number of variants in this ADT.
-    pub fn adt_variants_len(&self, def: AdtDef) -> usize {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).variants().len()
-    }
-
-    /// Discriminant for a given variant index of AdtDef
-    pub fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let adt = adt.internal(&mut *tables, tcx);
-        let variant = variant.internal(&mut *tables, tcx);
-        adt.discriminant_for_variant(tcx, variant).stable(&mut *tables)
-    }
-
-    /// Discriminant for a given variand index and args of a coroutine
-    pub fn coroutine_discr_for_variant(
-        &self,
-        coroutine: CoroutineDef,
-        args: &GenericArgs,
-        variant: VariantIdx,
-    ) -> Discr {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let coroutine = coroutine.def_id().internal(&mut *tables, tcx);
-        let args = args.internal(&mut *tables, tcx);
-        let variant = variant.internal(&mut *tables, tcx);
-        args.as_coroutine().discriminant_for_variant(coroutine, tcx, variant).stable(&mut *tables)
-    }
-
-    /// The name of a variant.
-    pub fn variant_name(&self, def: VariantDef) -> Symbol {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).name.to_string()
-    }
-
-    pub fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).fields.iter().map(|f| f.stable(&mut *tables)).collect()
-    }
-
-    /// Evaluate constant as a target usize.
-    pub fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let mir_const = cnst.internal(&mut *tables, tcx);
-        mir_const
-            .try_eval_target_usize(tables.tcx, ty::TypingEnv::fully_monomorphized())
-            .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
-    }
-    pub fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let mir_const = cnst.internal(&mut *tables, tcx);
-        mir_const
-            .try_to_target_usize(tables.tcx)
-            .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
-    }
-
-    /// Create a new zero-sized constant.
-    pub fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let ty_internal = ty.internal(&mut *tables, tcx);
-        let size = tables
-            .tcx
-            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty_internal))
-            .map_err(|err| {
-                Error::new(format!(
-                    "Cannot create a zero-sized constant for type `{ty_internal}`: {err}"
-                ))
-            })?
-            .size;
-        if size.bytes() != 0 {
-            return Err(Error::new(format!(
-                "Cannot create a zero-sized constant for type `{ty_internal}`: \
-                 Type `{ty_internal}` has {} bytes",
-                size.bytes()
-            )));
-        }
-
-        Ok(mir::Const::Ty(ty_internal, ty::Const::zero_sized(tables.tcx, ty_internal))
-            .stable(&mut *tables))
-    }
-
-    /// Create a new constant that represents the given string value.
-    pub fn new_const_str(&self, value: &str) -> MirConst {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let ty = ty::Ty::new_static_str(tcx);
-        let bytes = value.as_bytes();
-        let valtree = ty::ValTree::from_raw_bytes(tcx, bytes);
-        let cv = ty::Value { ty, valtree };
-        let val = tcx.valtree_to_const_val(cv);
-        mir::Const::from_value(val, ty).stable(&mut tables)
-    }
-
-    /// Create a new constant that represents the given boolean value.
-    pub fn new_const_bool(&self, value: bool) -> MirConst {
-        let mut tables = self.0.borrow_mut();
-        mir::Const::from_bool(tables.tcx, value).stable(&mut tables)
-    }
-
-    /// Create a new constant that represents the given value.
-    pub fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx));
-        let size = tables
-            .tcx
-            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
-            .unwrap()
-            .size;
-        let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
-            Error::new(format!("Value overflow: cannot convert `{value}` to `{ty}`."))
-        })?;
-        Ok(mir::Const::from_scalar(tcx, mir::interpret::Scalar::Int(scalar), ty)
-            .stable(&mut tables))
-    }
-    pub fn try_new_ty_const_uint(
-        &self,
-        value: u128,
-        uint_ty: UintTy,
-    ) -> Result<stable_mir::ty::TyConst, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx));
-        let size = tables
-            .tcx
-            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
-            .unwrap()
-            .size;
-
-        // We don't use Const::from_bits since it doesn't have any error checking.
-        let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
-            Error::new(format!("Value overflow: cannot convert `{value}` to `{ty}`."))
-        })?;
-        Ok(ty::Const::new_value(tcx, ValTree::from_scalar_int(tcx, scalar), ty)
-            .stable(&mut *tables))
-    }
-
-    /// Create a new type from the given kind.
-    pub fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let internal_kind = kind.internal(&mut *tables, tcx);
-        tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
-    }
-
-    /// Create a new box type, `Box<T>`, for the given inner type `T`.
-    pub fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let inner = ty.internal(&mut *tables, tcx);
-        ty::Ty::new_box(tables.tcx, inner).stable(&mut *tables)
-    }
-
-    /// Returns the type of given crate item.
-    pub fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        tcx.type_of(item.internal(&mut *tables, tcx)).instantiate_identity().stable(&mut *tables)
-    }
-
-    /// Returns the type of given definition instantiated with the given arguments.
-    pub fn def_ty_with_args(
-        &self,
-        item: stable_mir::DefId,
-        args: &GenericArgs,
-    ) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let args = args.internal(&mut *tables, tcx);
-        let def_ty = tables.tcx.type_of(item.internal(&mut *tables, tcx));
-        tables
-            .tcx
-            .instantiate_and_normalize_erasing_regions(
-                args,
-                ty::TypingEnv::fully_monomorphized(),
-                def_ty,
-            )
-            .stable(&mut *tables)
-    }
-
-    /// Returns literal value of a const as a string.
-    pub fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        cnst.internal(&mut *tables, tcx).to_string()
-    }
-
-    /// `Span` of an item.
-    pub fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
-        let mut tables = self.0.borrow_mut();
-        tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
-    }
-
-    /// Obtain the representation of a type.
-    pub fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String {
-        let tables = self.0.borrow_mut();
-        tables.types[ty].to_string()
-    }
-
-    /// Obtain the representation of a type.
-    pub fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
-        let mut tables = self.0.borrow_mut();
-        tables.types[ty].kind().stable(&mut *tables)
-    }
-
-    pub fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String {
-        let tables = self.0.borrow_mut();
-        tables.ty_consts[ct].to_string()
-    }
-
-    /// Get the discriminant Ty for this Ty if there's one.
-    pub fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let internal_kind = ty.internal(&mut *tables, tcx);
-        let internal_ty = tables.tcx.mk_ty_from_kind(internal_kind);
-        internal_ty.discriminant_ty(tables.tcx).stable(&mut *tables)
-    }
-
-    /// Get the body of an Instance which is already monomorphized.
-    pub fn instance_body(&self, def: InstanceDef) -> Option<Body> {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        tables
-            .instance_has_body(instance)
-            .then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables))
-    }
-
-    /// Get the instance type with generic instantiations applied and lifetimes erased.
-    pub fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation");
-        instance.ty(tables.tcx, ty::TypingEnv::fully_monomorphized()).stable(&mut *tables)
-    }
-
-    /// Get the instantiation types.
-    pub fn instance_args(&self, def: InstanceDef) -> GenericArgs {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        instance.args.stable(&mut *tables)
-    }
-
-    /// Get an instance ABI.
-    pub fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables))
-    }
-
-    /// Get the ABI of a function pointer.
-    pub fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let sig = fn_ptr.internal(&mut *tables, tcx);
-        Ok(tables.fn_abi_of_fn_ptr(sig, List::empty())?.stable(&mut *tables))
-    }
-
-    /// Get the instance.
-    pub fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables.instances[def].def_id();
-        tables.create_def_id(def_id)
-    }
-
-    /// Get the instance mangled name.
-    pub fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
-        let tables = self.0.borrow_mut();
-        let instance = tables.instances[instance];
-        tables.tcx.symbol_name(instance).name.to_string()
-    }
-
-    /// Check if this is an empty DropGlue shim.
-    pub fn is_empty_drop_shim(&self, def: InstanceDef) -> bool {
-        let tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        matches!(instance.def, ty::InstanceKind::DropGlue(_, None))
-    }
-
-    /// Convert a non-generic crate item into an instance.
-    /// This function will panic if the item is generic.
-    pub fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[def_id];
-        Instance::mono(tables.tcx, def_id).stable(&mut *tables)
-    }
-
-    /// Item requires monomorphization.
-    pub fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
-        let tables = self.0.borrow();
-        let def_id = tables[def_id];
-        let generics = tables.tcx.generics_of(def_id);
-        let result = generics.requires_monomorphization(tables.tcx);
-        result
-    }
-
-    /// Resolve an instance from the given function definition and generic arguments.
-    pub fn resolve_instance(
-        &self,
-        def: stable_mir::ty::FnDef,
-        args: &stable_mir::ty::GenericArgs,
-    ) -> Option<stable_mir::mir::mono::Instance> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        let args_ref = args.internal(&mut *tables, tcx);
-        match Instance::try_resolve(
-            tables.tcx,
-            ty::TypingEnv::fully_monomorphized(),
-            def_id,
-            args_ref,
-        ) {
-            Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
-            Ok(None) | Err(_) => None,
-        }
-    }
-
-    /// Resolve an instance for drop_in_place for the given type.
-    pub fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let internal_ty = ty.internal(&mut *tables, tcx);
-        let instance = Instance::resolve_drop_in_place(tables.tcx, internal_ty);
-        instance.stable(&mut *tables)
-    }
-
-    /// Resolve instance for a function pointer.
-    pub fn resolve_for_fn_ptr(
-        &self,
-        def: FnDef,
-        args: &GenericArgs,
-    ) -> Option<stable_mir::mir::mono::Instance> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        let args_ref = args.internal(&mut *tables, tcx);
-        Instance::resolve_for_fn_ptr(
-            tables.tcx,
-            ty::TypingEnv::fully_monomorphized(),
-            def_id,
-            args_ref,
-        )
-        .stable(&mut *tables)
-    }
-
-    /// Resolve instance for a closure with the requested type.
-    pub fn resolve_closure(
-        &self,
-        def: ClosureDef,
-        args: &GenericArgs,
-        kind: ClosureKind,
-    ) -> Option<stable_mir::mir::mono::Instance> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        let args_ref = args.internal(&mut *tables, tcx);
-        let closure_kind = kind.internal(&mut *tables, tcx);
-        Some(
-            Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind)
-                .stable(&mut *tables),
-        )
-    }
-
-    /// Try to evaluate an instance into a constant.
-    pub fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        let tcx = tables.tcx;
-        let result = tcx.const_eval_instance(
-            ty::TypingEnv::fully_monomorphized(),
-            instance,
-            tcx.def_span(instance.def_id()),
-        );
-        result
-            .map(|const_val| {
-                alloc::try_new_allocation(
-                    const_ty.internal(&mut *tables, tcx),
-                    const_val,
-                    &mut *tables,
-                )
-            })
-            .map_err(|e| e.stable(&mut *tables))?
-    }
-
-    /// Evaluate a static's initializer.
-    pub fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        tables.tcx.eval_static_initializer(def_id).stable(&mut *tables)
-    }
-
-    /// Retrieve global allocation for the given allocation ID.
-    pub fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let alloc_id = alloc.internal(&mut *tables, tcx);
-        tables.tcx.global_alloc(alloc_id).stable(&mut *tables)
-    }
-
-    /// Retrieve the id for the virtual table.
-    pub fn vtable_allocation(
-        &self,
-        global_alloc: &GlobalAlloc,
-    ) -> Option<stable_mir::mir::alloc::AllocId> {
-        let mut tables = self.0.borrow_mut();
-        let GlobalAlloc::VTable(ty, trait_ref) = global_alloc else {
-            return None;
-        };
-        let tcx = tables.tcx;
-        let alloc_id = tables.tcx.vtable_allocation((
-            ty.internal(&mut *tables, tcx),
-            trait_ref
-                .internal(&mut *tables, tcx)
-                .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
-        ));
-        Some(alloc_id.stable(&mut *tables))
-    }
-
-    pub fn krate(&self, def_id: stable_mir::DefId) -> Crate {
-        let tables = self.0.borrow();
-        smir_crate(tables.tcx, tables[def_id].krate)
-    }
-
-    /// Retrieve the instance name for diagnostic messages.
-    ///
-    /// This will return the specialized name, e.g., `Vec<char>::new`.
-    pub fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
-        let tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        if trimmed {
-            with_forced_trimmed_paths!(
-                tables.tcx.def_path_str_with_args(instance.def_id(), instance.args)
-            )
-        } else {
-            with_no_trimmed_paths!(
-                tables.tcx.def_path_str_with_args(instance.def_id(), instance.args)
-            )
-        }
-    }
-
-    /// Get the layout of a type.
-    pub fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let ty = ty.internal(&mut *tables, tcx);
-        let layout = tables.layout_of(ty)?.layout;
-        Ok(layout.stable(&mut *tables))
-    }
-
-    /// Get the layout shape.
-    pub fn layout_shape(&self, id: Layout) -> LayoutShape {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        id.internal(&mut *tables, tcx).0.stable(&mut *tables)
-    }
-
-    /// Get a debug string representation of a place.
-    pub fn place_pretty(&self, place: &Place) -> String {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        format!("{:?}", place.internal(&mut *tables, tcx))
-    }
-
-    /// Get the resulting type of binary operation.
-    pub fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let rhs_internal = rhs.internal(&mut *tables, tcx);
-        let lhs_internal = lhs.internal(&mut *tables, tcx);
-        let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal);
-        ty.stable(&mut *tables)
-    }
-
-    /// Get the resulting type of unary operation.
-    pub fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let arg_internal = arg.internal(&mut *tables, tcx);
-        let ty = un_op.internal(&mut *tables, tcx).ty(tcx, arg_internal);
-        ty.stable(&mut *tables)
-    }
-
-    /// Get all associated items of a definition.
-    pub fn associated_items(&self, def_id: stable_mir::DefId) -> stable_mir::AssocItems {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = tables[def_id];
-        let assoc_items = if tcx.is_trait_alias(def_id) {
-            Vec::new()
-        } else {
-            tcx.associated_item_def_ids(def_id)
-                .iter()
-                .map(|did| tcx.associated_item(*did).stable(&mut *tables))
-                .collect()
-        };
-        assoc_items
-    }
-}
-
-/// Implement error handling for extracting function ABI information.
-impl<'tcx> FnAbiOfHelpers<'tcx> for Tables<'tcx> {
-    type FnAbiOfResult = Result<&'tcx rustc_target::callconv::FnAbi<'tcx, ty::Ty<'tcx>>, Error>;
-
-    #[inline]
-    fn handle_fn_abi_err(
-        &self,
-        err: ty::layout::FnAbiError<'tcx>,
-        _span: rustc_span::Span,
-        fn_abi_request: ty::layout::FnAbiRequest<'tcx>,
-    ) -> Error {
-        Error::new(format!("Failed to get ABI for `{fn_abi_request:?}`: {err:?}"))
-    }
-}
-
-impl<'tcx> LayoutOfHelpers<'tcx> for Tables<'tcx> {
-    type LayoutOfResult = Result<ty::layout::TyAndLayout<'tcx>, Error>;
-
-    #[inline]
-    fn handle_layout_err(
-        &self,
-        err: ty::layout::LayoutError<'tcx>,
-        _span: rustc_span::Span,
-        ty: ty::Ty<'tcx>,
-    ) -> Error {
-        Error::new(format!("Failed to get layout for `{ty}`: {err}"))
-    }
-}
-
-impl<'tcx> HasTypingEnv<'tcx> for Tables<'tcx> {
-    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
-        ty::TypingEnv::fully_monomorphized()
-    }
-}
-
-impl<'tcx> HasTyCtxt<'tcx> for Tables<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-}
-
-impl<'tcx> HasDataLayout for Tables<'tcx> {
-    fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
-        self.tcx.data_layout()
-    }
-}
diff --git a/compiler/rustc_smir/src/rustc_smir/context/impls.rs b/compiler/rustc_smir/src/rustc_smir/context/impls.rs
new file mode 100644
index 00000000000..89ae47143ef
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/context/impls.rs
@@ -0,0 +1,762 @@
+//! Implementation of StableMIR Context.
+
+#![allow(rustc::usage_of_qualified_ty)]
+
+use std::iter;
+
+use rustc_abi::{Endian, Layout, ReprOptions};
+use rustc_hir::def::DefKind;
+use rustc_hir::{Attribute, LangItem};
+use rustc_middle::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar};
+use rustc_middle::mir::{BinOp, Body, Const as MirConst, ConstValue, UnOp};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
+use rustc_middle::ty::util::Discr;
+use rustc_middle::ty::{
+    AdtDef, AdtKind, AssocItem, Binder, ClosureKind, CoroutineArgsExt, EarlyBinder,
+    ExistentialTraitRef, FnSig, GenericArgsRef, Instance, InstanceKind, IntrinsicDef, List,
+    PolyFnSig, ScalarInt, TraitDef, TraitRef, Ty, TyCtxt, TyKind, TypeVisitableExt, UintTy,
+    ValTree, VariantDef,
+};
+use rustc_middle::{mir, ty};
+use rustc_session::cstore::ForeignModule;
+use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc_span::{FileNameDisplayPreference, Span, Symbol};
+use rustc_target::callconv::FnAbi;
+
+use super::{SmirAllocRange, SmirCtxt, SmirTy, SmirTypingEnv};
+use crate::rustc_smir::builder::BodyBuilder;
+use crate::rustc_smir::{Bridge, SmirError, Tables, filter_def_ids};
+
+impl<'tcx, B: Bridge> SmirTy<'tcx> for SmirCtxt<'tcx, B> {
+    fn new_foreign(&self, def_id: DefId) -> ty::Ty<'tcx> {
+        ty::Ty::new_foreign(self.tcx, def_id)
+    }
+}
+
+impl<'tcx, B: Bridge> SmirTypingEnv<'tcx> for SmirCtxt<'tcx, B> {
+    fn fully_monomorphized(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv::fully_monomorphized()
+    }
+}
+
+impl<'tcx, B: Bridge> SmirAllocRange<'tcx> for SmirCtxt<'tcx, B> {
+    fn alloc_range(
+        &self,
+        offset: rustc_abi::Size,
+        size: rustc_abi::Size,
+    ) -> mir::interpret::AllocRange {
+        rustc_middle::mir::interpret::alloc_range(offset, size)
+    }
+}
+
+impl<'tcx, B: Bridge> SmirCtxt<'tcx, B> {
+    pub fn lift<T: ty::Lift<TyCtxt<'tcx>>>(&self, value: T) -> Option<T::Lifted> {
+        self.tcx.lift(value)
+    }
+
+    pub fn adt_def(&self, def_id: DefId) -> AdtDef<'tcx> {
+        self.tcx.adt_def(def_id)
+    }
+
+    pub fn coroutine_movability(&self, def_id: DefId) -> ty::Movability {
+        self.tcx.coroutine_movability(def_id)
+    }
+
+    pub fn valtree_to_const_val(&self, key: ty::Value<'tcx>) -> ConstValue<'tcx> {
+        self.tcx.valtree_to_const_val(key)
+    }
+
+    /// Return whether the instance as a body available.
+    ///
+    /// Items and intrinsics may have a body available from its definition.
+    /// Shims body may be generated depending on their type.
+    pub(crate) fn instance_has_body(&self, instance: Instance<'tcx>) -> bool {
+        let def_id = instance.def_id();
+        self.item_has_body(def_id)
+            || !matches!(
+                instance.def,
+                ty::InstanceKind::Virtual(..)
+                    | ty::InstanceKind::Intrinsic(..)
+                    | ty::InstanceKind::Item(..)
+            )
+    }
+
+    /// Return whether the item has a body defined by the user.
+    ///
+    /// Note that intrinsics may have a placeholder body that shouldn't be used in practice.
+    /// In StableMIR, we handle this case as if the body is not available.
+    pub(crate) fn item_has_body(&self, def_id: DefId) -> bool {
+        let must_override = if let Some(intrinsic) = self.tcx.intrinsic(def_id) {
+            intrinsic.must_be_overridden
+        } else {
+            false
+        };
+        !must_override && self.tcx.is_mir_available(def_id)
+    }
+
+    fn filter_fn_def(&self, def_id: DefId) -> Option<DefId> {
+        if matches!(self.tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
+            Some(def_id)
+        } else {
+            None
+        }
+    }
+
+    fn filter_static_def(&self, def_id: DefId) -> Option<DefId> {
+        matches!(self.tcx.def_kind(def_id), DefKind::Static { .. }).then(|| def_id)
+    }
+
+    pub fn target_endian(&self) -> Endian {
+        self.tcx.data_layout.endian
+    }
+
+    pub fn target_pointer_size(&self) -> usize {
+        self.tcx.data_layout.pointer_size.bits().try_into().unwrap()
+    }
+
+    pub fn entry_fn(&self) -> Option<DefId> {
+        Some(self.tcx.entry_fn(())?.0)
+    }
+
+    /// Retrieve all items of the local crate that have a MIR associated with them.
+    pub fn all_local_items(&self) -> Vec<DefId> {
+        self.tcx.mir_keys(()).iter().map(|item| item.to_def_id()).collect()
+    }
+
+    /// Retrieve the body of a function.
+    /// This function will panic if the body is not available.
+    pub fn mir_body(&self, item: DefId) -> &'tcx Body<'tcx> {
+        self.tcx.instance_mir(InstanceKind::Item(item))
+    }
+
+    /// Check whether the body of a function is available.
+    pub fn has_body(&self, def: DefId) -> bool {
+        self.item_has_body(def)
+    }
+
+    pub fn foreign_modules(&self, crate_num: CrateNum) -> Vec<DefId> {
+        self.tcx.foreign_modules(crate_num).keys().map(|mod_def_id| *mod_def_id).collect()
+    }
+
+    /// Retrieve all functions defined in this crate.
+    pub fn crate_functions(&self, crate_num: CrateNum) -> Vec<DefId> {
+        filter_def_ids(self.tcx, crate_num, |def_id| self.filter_fn_def(def_id))
+    }
+
+    /// Retrieve all static items defined in this crate.
+    pub fn crate_statics(&self, crate_num: CrateNum) -> Vec<DefId> {
+        filter_def_ids(self.tcx, crate_num, |def_id| self.filter_static_def(def_id))
+    }
+
+    pub fn foreign_module(&self, mod_def: DefId) -> &ForeignModule {
+        self.tcx.foreign_modules(mod_def.krate).get(&mod_def).unwrap()
+    }
+
+    pub fn foreign_items(&self, mod_def: DefId) -> Vec<DefId> {
+        self.tcx
+            .foreign_modules(mod_def.krate)
+            .get(&mod_def)
+            .unwrap()
+            .foreign_items
+            .iter()
+            .map(|item_def| *item_def)
+            .collect()
+    }
+
+    pub fn all_trait_decls(&self) -> impl Iterator<Item = DefId> {
+        self.tcx.all_traits_including_private()
+    }
+
+    pub fn trait_decls(&self, crate_num: CrateNum) -> Vec<DefId> {
+        self.tcx.traits(crate_num).iter().map(|trait_def_id| *trait_def_id).collect()
+    }
+
+    pub fn trait_decl(&self, trait_def: DefId) -> &'tcx TraitDef {
+        self.tcx.trait_def(trait_def)
+    }
+
+    pub fn all_trait_impls(&self) -> Vec<DefId> {
+        iter::once(LOCAL_CRATE)
+            .chain(self.tcx.crates(()).iter().copied())
+            .flat_map(|cnum| self.tcx.trait_impls_in_crate(cnum).iter())
+            .map(|impl_def_id| *impl_def_id)
+            .collect()
+    }
+
+    pub fn trait_impls(&self, crate_num: CrateNum) -> Vec<DefId> {
+        self.tcx.trait_impls_in_crate(crate_num).iter().map(|impl_def_id| *impl_def_id).collect()
+    }
+
+    pub fn trait_impl(&self, impl_def: DefId) -> EarlyBinder<'tcx, TraitRef<'tcx>> {
+        self.tcx.impl_trait_ref(impl_def).unwrap()
+    }
+
+    pub fn generics_of(&self, def_id: DefId) -> &'tcx ty::Generics {
+        self.tcx.generics_of(def_id)
+    }
+
+    pub fn predicates_of(
+        &self,
+        def_id: DefId,
+    ) -> (Option<DefId>, Vec<(ty::PredicateKind<'tcx>, Span)>) {
+        let ty::GenericPredicates { parent, predicates } = self.tcx.predicates_of(def_id);
+        (
+            parent,
+            predicates
+                .iter()
+                .map(|(clause, span)| (clause.as_predicate().kind().skip_binder(), *span))
+                .collect(),
+        )
+    }
+
+    pub fn explicit_predicates_of(
+        &self,
+        def_id: DefId,
+    ) -> (Option<DefId>, Vec<(ty::PredicateKind<'tcx>, Span)>) {
+        let ty::GenericPredicates { parent, predicates } = self.tcx.explicit_predicates_of(def_id);
+        (
+            parent,
+            predicates
+                .iter()
+                .map(|(clause, span)| (clause.as_predicate().kind().skip_binder(), *span))
+                .collect(),
+        )
+    }
+
+    pub fn crate_name(&self, crate_num: CrateNum) -> String {
+        self.tcx.crate_name(crate_num).to_string()
+    }
+
+    pub fn crate_is_local(&self, crate_num: CrateNum) -> bool {
+        crate_num == LOCAL_CRATE
+    }
+
+    pub fn crate_num_id(&self, crate_num: CrateNum) -> usize {
+        crate_num.into()
+    }
+
+    pub fn local_crate_num(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+
+    /// Retrieve a list of all external crates.
+    pub fn external_crates(&self) -> Vec<CrateNum> {
+        self.tcx.crates(()).iter().map(|crate_num| *crate_num).collect()
+    }
+
+    /// Find a crate with the given name.
+    pub fn find_crates(&self, name: &str) -> Vec<CrateNum> {
+        let crates: Vec<CrateNum> = [LOCAL_CRATE]
+            .iter()
+            .chain(self.tcx.crates(()).iter())
+            .filter_map(|crate_num| {
+                let crate_name = self.tcx.crate_name(*crate_num).to_string();
+                (name == crate_name).then(|| *crate_num)
+            })
+            .collect();
+        crates
+    }
+
+    /// Returns the name of given `DefId`.
+    pub fn def_name(&self, def_id: DefId, trimmed: bool) -> String {
+        if trimmed {
+            with_forced_trimmed_paths!(self.tcx.def_path_str(def_id))
+        } else {
+            with_no_trimmed_paths!(self.tcx.def_path_str(def_id))
+        }
+    }
+
+    /// Return registered tool attributes with the given attribute name.
+    ///
+    /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool
+    /// attributes will simply return an empty list.
+    ///
+    /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
+    /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
+    pub fn tool_attrs(&self, def_id: DefId, attr: &[String]) -> Vec<(String, Span)> {
+        let attr_name: Vec<_> = attr.iter().map(|seg| Symbol::intern(&seg)).collect();
+        self.tcx
+            .get_attrs_by_path(def_id, &attr_name)
+            .filter_map(|attribute| {
+                if let Attribute::Unparsed(u) = attribute {
+                    let attr_str = rustc_hir_pretty::attribute_to_string(&self.tcx, attribute);
+                    Some((attr_str, u.span))
+                } else {
+                    None
+                }
+            })
+            .collect()
+    }
+
+    /// Get all tool attributes of a definition.
+    pub fn all_tool_attrs(&self, did: DefId) -> Vec<(String, Span)> {
+        let attrs_iter = if let Some(did) = did.as_local() {
+            self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(did)).iter()
+        } else {
+            self.tcx.attrs_for_def(did).iter()
+        };
+        attrs_iter
+            .filter_map(|attribute| {
+                if let Attribute::Unparsed(u) = attribute {
+                    let attr_str = rustc_hir_pretty::attribute_to_string(&self.tcx, attribute);
+                    Some((attr_str, u.span))
+                } else {
+                    None
+                }
+            })
+            .collect()
+    }
+
+    /// Returns printable, human readable form of `Span`.
+    pub fn span_to_string(&self, span: Span) -> String {
+        self.tcx.sess.source_map().span_to_diagnostic_string(span)
+    }
+
+    /// Return filename from given `Span`, for diagnostic purposes.
+    pub fn get_filename(&self, span: Span) -> String {
+        self.tcx
+            .sess
+            .source_map()
+            .span_to_filename(span)
+            .display(FileNameDisplayPreference::Local)
+            .to_string()
+    }
+
+    /// Return lines corresponding to this `Span`.
+    pub fn get_lines(&self, span: Span) -> (usize, usize, usize, usize) {
+        let lines = &self.tcx.sess.source_map().span_to_location_info(span);
+        (lines.1, lines.2, lines.3, lines.4)
+    }
+
+    /// Returns the `kind` of given `DefId`.
+    pub fn def_kind(&self, item: DefId) -> DefKind {
+        self.tcx.def_kind(item)
+    }
+
+    /// Returns whether this is a foreign item.
+    pub fn is_foreign_item(&self, item: DefId) -> bool {
+        self.tcx.is_foreign_item(item)
+    }
+
+    /// Returns the kind of a given foreign item.
+    pub fn foreign_item_kind(&self, def_id: DefId) -> DefKind {
+        self.tcx.def_kind(def_id)
+    }
+
+    /// Returns the kind of a given algebraic data type.
+    pub fn adt_kind(&self, def: AdtDef<'tcx>) -> AdtKind {
+        def.adt_kind()
+    }
+
+    /// Returns if the ADT is a box.
+    pub fn adt_is_box(&self, def: AdtDef<'tcx>) -> bool {
+        def.is_box()
+    }
+
+    /// Returns whether this ADT is simd.
+    pub fn adt_is_simd(&self, def: AdtDef<'tcx>) -> bool {
+        def.repr().simd()
+    }
+
+    /// Returns whether this definition is a C string.
+    pub fn adt_is_cstr(&self, def_id: DefId) -> bool {
+        self.tcx.is_lang_item(def_id, LangItem::CStr)
+    }
+
+    /// Returns the representation options for this ADT.
+    pub fn adt_repr(&self, def: AdtDef<'tcx>) -> ReprOptions {
+        def.repr()
+    }
+
+    /// Retrieve the function signature for the given generic arguments.
+    pub fn fn_sig(
+        &self,
+        def_id: DefId,
+        args_ref: GenericArgsRef<'tcx>,
+    ) -> Binder<'tcx, FnSig<'tcx>> {
+        let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args_ref);
+        sig
+    }
+
+    /// Retrieve the intrinsic definition if the item corresponds one.
+    pub fn intrinsic(&self, def_id: DefId) -> Option<IntrinsicDef> {
+        let intrinsic = self.tcx.intrinsic_raw(def_id);
+        intrinsic
+    }
+
+    /// Retrieve the plain function name of an intrinsic.
+    pub fn intrinsic_name(&self, def_id: DefId) -> String {
+        self.tcx.intrinsic(def_id).unwrap().name.to_string()
+    }
+
+    /// Retrieve the closure signature for the given generic arguments.
+    pub fn closure_sig(&self, args_ref: GenericArgsRef<'tcx>) -> Binder<'tcx, FnSig<'tcx>> {
+        args_ref.as_closure().sig()
+    }
+
+    /// The number of variants in this ADT.
+    pub fn adt_variants_len(&self, def: AdtDef<'tcx>) -> usize {
+        def.variants().len()
+    }
+
+    /// Discriminant for a given variant index of AdtDef.
+    pub fn adt_discr_for_variant(
+        &self,
+        adt: AdtDef<'tcx>,
+        variant: rustc_abi::VariantIdx,
+    ) -> Discr<'tcx> {
+        adt.discriminant_for_variant(self.tcx, variant)
+    }
+
+    /// Discriminant for a given variand index and args of a coroutine.
+    pub fn coroutine_discr_for_variant(
+        &self,
+        coroutine: DefId,
+        args: GenericArgsRef<'tcx>,
+        variant: rustc_abi::VariantIdx,
+    ) -> Discr<'tcx> {
+        args.as_coroutine().discriminant_for_variant(coroutine, self.tcx, variant)
+    }
+
+    /// The name of a variant.
+    pub fn variant_name(&self, def: &'tcx VariantDef) -> String {
+        def.name.to_string()
+    }
+
+    /// Evaluate constant as a target usize.
+    pub fn eval_target_usize(&self, cnst: MirConst<'tcx>) -> Result<u64, B::Error> {
+        use crate::rustc_smir::context::SmirTypingEnv;
+        cnst.try_eval_target_usize(self.tcx, self.fully_monomorphized())
+            .ok_or_else(|| B::Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
+    }
+
+    pub fn eval_target_usize_ty(&self, cnst: ty::Const<'tcx>) -> Result<u64, B::Error> {
+        cnst.try_to_target_usize(self.tcx)
+            .ok_or_else(|| B::Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
+    }
+
+    pub(crate) fn try_new_const_zst(
+        &self,
+        ty_internal: Ty<'tcx>,
+    ) -> Result<MirConst<'tcx>, B::Error> {
+        let size = self
+            .tcx
+            .layout_of(self.fully_monomorphized().as_query_input(ty_internal))
+            .map_err(|err| {
+                B::Error::new(format!(
+                    "Cannot create a zero-sized constant for type `{ty_internal}`: {err}"
+                ))
+            })?
+            .size;
+        if size.bytes() != 0 {
+            return Err(B::Error::new(format!(
+                "Cannot create a zero-sized constant for type `{ty_internal}`: \
+                Type `{ty_internal}` has {} bytes",
+                size.bytes()
+            )));
+        }
+
+        Ok(MirConst::Ty(ty_internal, self.const_zero_sized(ty_internal)))
+    }
+
+    pub fn const_zero_sized(&self, ty_internal: Ty<'tcx>) -> ty::Const<'tcx> {
+        ty::Const::zero_sized(self.tcx, ty_internal)
+    }
+
+    /// Create a new constant that represents the given string value.
+    pub fn new_const_str(&self, value: &str) -> MirConst<'tcx> {
+        let ty = Ty::new_static_str(self.tcx);
+        let bytes = value.as_bytes();
+        let valtree = ValTree::from_raw_bytes(self.tcx, bytes);
+        let cv = ty::Value { ty, valtree };
+        let val = self.tcx.valtree_to_const_val(cv);
+        MirConst::from_value(val, ty)
+    }
+
+    /// Create a new constant that represents the given boolean value.
+    pub fn new_const_bool(&self, value: bool) -> MirConst<'tcx> {
+        MirConst::from_bool(self.tcx, value)
+    }
+
+    pub fn try_new_const_uint(
+        &self,
+        value: u128,
+        ty_internal: Ty<'tcx>,
+    ) -> Result<MirConst<'tcx>, B::Error> {
+        let size = self
+            .tcx
+            .layout_of(self.fully_monomorphized().as_query_input(ty_internal))
+            .unwrap()
+            .size;
+        let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
+            B::Error::new(format!("Value overflow: cannot convert `{value}` to `{ty_internal}`."))
+        })?;
+        Ok(self.mir_const_from_scalar(Scalar::Int(scalar), ty_internal))
+    }
+
+    pub fn try_new_ty_const_uint(
+        &self,
+        value: u128,
+        ty_internal: Ty<'tcx>,
+    ) -> Result<ty::Const<'tcx>, B::Error> {
+        let size = self
+            .tcx
+            .layout_of(self.fully_monomorphized().as_query_input(ty_internal))
+            .unwrap()
+            .size;
+        let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
+            B::Error::new(format!("Value overflow: cannot convert `{value}` to `{ty_internal}`."))
+        })?;
+
+        Ok(self.ty_const_new_value(ValTree::from_scalar_int(self.tcx, scalar), ty_internal))
+    }
+
+    pub fn ty_new_uint(&self, ty: UintTy) -> Ty<'tcx> {
+        Ty::new_uint(self.tcx, ty)
+    }
+
+    pub fn mir_const_from_scalar(&self, s: Scalar, ty: Ty<'tcx>) -> MirConst<'tcx> {
+        MirConst::from_scalar(self.tcx, s, ty)
+    }
+
+    pub fn ty_const_new_value(&self, valtree: ValTree<'tcx>, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+        ty::Const::new_value(self.tcx, valtree, ty)
+    }
+
+    pub fn ty_valtree_from_scalar_int(&self, i: ScalarInt) -> ValTree<'tcx> {
+        ValTree::from_scalar_int(self.tcx, i)
+    }
+
+    /// Create a new type from the given kind.
+    pub fn new_rigid_ty(&self, internal_kind: TyKind<'tcx>) -> Ty<'tcx> {
+        self.tcx.mk_ty_from_kind(internal_kind)
+    }
+
+    /// Create a new box type, `Box<T>`, for the given inner type `T`.
+    pub fn new_box_ty(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        ty::Ty::new_box(self.tcx, ty)
+    }
+
+    /// Returns the type of given crate item.
+    pub fn def_ty(&self, item: DefId) -> Ty<'tcx> {
+        self.tcx.type_of(item).instantiate_identity()
+    }
+
+    /// Returns the type of given definition instantiated with the given arguments.
+    pub fn def_ty_with_args(&self, item: DefId, args_ref: GenericArgsRef<'tcx>) -> Ty<'tcx> {
+        let def_ty = self.tcx.type_of(item);
+        self.tcx.instantiate_and_normalize_erasing_regions(
+            args_ref,
+            self.fully_monomorphized(),
+            def_ty,
+        )
+    }
+
+    /// `Span` of an item.
+    pub fn span_of_an_item(&self, def_id: DefId) -> Span {
+        self.tcx.def_span(def_id)
+    }
+
+    pub fn ty_const_pretty(&self, ct: ty::Const<'tcx>) -> String {
+        ct.to_string()
+    }
+
+    /// Obtain the representation of a type.
+    pub fn ty_pretty(&self, ty: Ty<'tcx>) -> String {
+        ty.to_string()
+    }
+
+    /// Obtain the kind of a type.
+    pub fn ty_kind(&self, ty: Ty<'tcx>) -> &'tcx TyKind<'tcx> {
+        ty.kind()
+    }
+
+    /// Get the discriminant Ty for this Ty if there's one.
+    pub fn rigid_ty_discriminant_ty(&self, internal_kind: TyKind<'tcx>) -> Ty<'tcx> {
+        let internal_ty = self.tcx.mk_ty_from_kind(internal_kind);
+        internal_ty.discriminant_ty(self.tcx)
+    }
+
+    /// Get the body of an Instance which is already monomorphized.
+    pub fn instance_body(&self, instance: ty::Instance<'tcx>) -> Option<Body<'tcx>> {
+        self.instance_has_body(instance).then(|| BodyBuilder::new(self.tcx, instance).build())
+    }
+
+    /// Get the instance type with generic instantiations applied and lifetimes erased.
+    pub fn instance_ty(&self, instance: ty::Instance<'tcx>) -> Ty<'tcx> {
+        assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation");
+        instance.ty(self.tcx, self.fully_monomorphized())
+    }
+
+    /// Get the instantiation types.
+    pub fn instance_args(&self, instance: ty::Instance<'tcx>) -> GenericArgsRef<'tcx> {
+        instance.args
+    }
+
+    /// Get an instance ABI.
+    pub fn instance_abi(
+        &self,
+        instance: ty::Instance<'tcx>,
+    ) -> Result<&FnAbi<'tcx, Ty<'tcx>>, B::Error> {
+        Ok(self.fn_abi_of_instance(instance, List::empty())?)
+    }
+
+    /// Get the ABI of a function pointer.
+    pub fn fn_ptr_abi(&self, sig: PolyFnSig<'tcx>) -> Result<&FnAbi<'tcx, Ty<'tcx>>, B::Error> {
+        Ok(self.fn_abi_of_fn_ptr(sig, List::empty())?)
+    }
+
+    /// Get the instance.
+    pub fn instance_def_id(
+        &self,
+        instances: ty::Instance<'tcx>,
+        tables: &mut Tables<'_, B>,
+    ) -> B::DefId {
+        let def_id = instances.def_id();
+        tables.create_def_id(def_id)
+    }
+
+    /// Get the instance mangled name.
+    pub fn instance_mangled_name(&self, instance: ty::Instance<'tcx>) -> String {
+        self.tcx.symbol_name(instance).name.to_string()
+    }
+
+    /// Check if this is an empty DropGlue shim.
+    pub fn is_empty_drop_shim(&self, instance: ty::Instance<'tcx>) -> bool {
+        matches!(instance.def, ty::InstanceKind::DropGlue(_, None))
+    }
+
+    /// Convert a non-generic crate item into an instance.
+    /// This function will panic if the item is generic.
+    pub fn mono_instance(&self, def_id: DefId) -> Instance<'tcx> {
+        Instance::mono(self.tcx, def_id)
+    }
+
+    /// Item requires monomorphization.
+    pub fn requires_monomorphization(&self, def_id: DefId) -> bool {
+        let generics = self.tcx.generics_of(def_id);
+        let result = generics.requires_monomorphization(self.tcx);
+        result
+    }
+
+    /// Resolve an instance from the given function definition and generic arguments.
+    pub fn resolve_instance(
+        &self,
+        def_id: DefId,
+        args_ref: GenericArgsRef<'tcx>,
+    ) -> Option<Instance<'tcx>> {
+        match Instance::try_resolve(self.tcx, self.fully_monomorphized(), def_id, args_ref) {
+            Ok(Some(instance)) => Some(instance),
+            Ok(None) | Err(_) => None,
+        }
+    }
+
+    /// Resolve an instance for drop_in_place for the given type.
+    pub fn resolve_drop_in_place(&self, internal_ty: Ty<'tcx>) -> Instance<'tcx> {
+        let instance = Instance::resolve_drop_in_place(self.tcx, internal_ty);
+        instance
+    }
+
+    /// Resolve instance for a function pointer.
+    pub fn resolve_for_fn_ptr(
+        &self,
+        def_id: DefId,
+        args_ref: GenericArgsRef<'tcx>,
+    ) -> Option<Instance<'tcx>> {
+        Instance::resolve_for_fn_ptr(self.tcx, self.fully_monomorphized(), def_id, args_ref)
+    }
+
+    /// Resolve instance for a closure with the requested type.
+    pub fn resolve_closure(
+        &self,
+        def_id: DefId,
+        args_ref: GenericArgsRef<'tcx>,
+        closure_kind: ClosureKind,
+    ) -> Option<Instance<'tcx>> {
+        Some(Instance::resolve_closure(self.tcx, def_id, args_ref, closure_kind))
+    }
+
+    /// Try to evaluate an instance into a constant.
+    pub fn eval_instance(
+        &self,
+        instance: ty::Instance<'tcx>,
+    ) -> Result<ConstValue<'tcx>, ErrorHandled> {
+        self.tcx.const_eval_instance(
+            self.fully_monomorphized(),
+            instance,
+            self.tcx.def_span(instance.def_id()),
+        )
+    }
+
+    /// Evaluate a static's initializer.
+    pub fn eval_static_initializer(
+        &self,
+        def_id: DefId,
+    ) -> Result<ConstAllocation<'tcx>, ErrorHandled> {
+        self.tcx.eval_static_initializer(def_id)
+    }
+
+    /// Retrieve global allocation for the given allocation ID.
+    pub fn global_alloc(&self, alloc_id: AllocId) -> GlobalAlloc<'tcx> {
+        self.tcx.global_alloc(alloc_id)
+    }
+
+    /// Retrieve the id for the virtual table.
+    pub fn vtable_allocation(
+        &self,
+        ty: Ty<'tcx>,
+        trait_ref: Option<Binder<'tcx, ExistentialTraitRef<'tcx>>>,
+    ) -> AllocId {
+        let alloc_id = self.tcx.vtable_allocation((
+            ty,
+            trait_ref.map(|principal| self.tcx.instantiate_bound_regions_with_erased(principal)),
+        ));
+        alloc_id
+    }
+
+    /// Retrieve the instance name for diagnostic messages.
+    ///
+    /// This will return the specialized name, e.g., `Vec<char>::new`.
+    pub fn instance_name(&self, instance: ty::Instance<'tcx>, trimmed: bool) -> String {
+        if trimmed {
+            with_forced_trimmed_paths!(
+                self.tcx.def_path_str_with_args(instance.def_id(), instance.args)
+            )
+        } else {
+            with_no_trimmed_paths!(
+                self.tcx.def_path_str_with_args(instance.def_id(), instance.args)
+            )
+        }
+    }
+
+    /// Get the layout of a type.
+    pub fn ty_layout(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, B::Error> {
+        let layout = self.layout_of(ty)?.layout;
+        Ok(layout)
+    }
+
+    /// Get the resulting type of binary operation.
+    pub fn binop_ty(&self, bin_op: BinOp, rhs: Ty<'tcx>, lhs: Ty<'tcx>) -> Ty<'tcx> {
+        bin_op.ty(self.tcx, rhs, lhs)
+    }
+
+    /// Get the resulting type of unary operation.
+    pub fn unop_ty(&self, un_op: UnOp, arg: Ty<'tcx>) -> Ty<'tcx> {
+        un_op.ty(self.tcx, arg)
+    }
+
+    /// Get all associated items of a definition.
+    pub fn associated_items(&self, def_id: DefId) -> Vec<AssocItem> {
+        let assoc_items = if self.tcx.is_trait_alias(def_id) {
+            Vec::new()
+        } else {
+            self.tcx
+                .associated_item_def_ids(def_id)
+                .iter()
+                .map(|did| self.tcx.associated_item(*did))
+                .collect()
+        };
+        assoc_items
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/context/mod.rs b/compiler/rustc_smir/src/rustc_smir/context/mod.rs
new file mode 100644
index 00000000000..38743e5f7d3
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/context/mod.rs
@@ -0,0 +1,79 @@
+//! Implementation of StableMIR Context.
+
+#![allow(rustc::usage_of_qualified_ty)]
+
+use std::marker::PhantomData;
+
+use rustc_abi::HasDataLayout;
+use rustc_middle::ty;
+use rustc_middle::ty::layout::{FnAbiOfHelpers, HasTyCtxt, HasTypingEnv, LayoutOfHelpers};
+use rustc_middle::ty::{Ty, TyCtxt};
+
+use crate::rustc_smir::{Bridge, SmirError};
+
+mod impls;
+mod traits;
+
+pub use traits::*;
+
+/// Provides direct access to rustc's internal queries.
+///
+/// The [`crate::stable_mir::compiler_interface::SmirInterface`] must go through
+/// this context to obtain rustc-level information.
+pub struct SmirCtxt<'tcx, B: Bridge> {
+    pub tcx: TyCtxt<'tcx>,
+    _marker: PhantomData<B>,
+}
+
+impl<'tcx, B: Bridge> SmirCtxt<'tcx, B> {
+    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self { tcx, _marker: Default::default() }
+    }
+}
+
+/// Implement error handling for extracting function ABI information.
+impl<'tcx, B: Bridge> FnAbiOfHelpers<'tcx> for SmirCtxt<'tcx, B> {
+    type FnAbiOfResult = Result<&'tcx rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>, B::Error>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: ty::layout::FnAbiError<'tcx>,
+        _span: rustc_span::Span,
+        fn_abi_request: ty::layout::FnAbiRequest<'tcx>,
+    ) -> B::Error {
+        B::Error::new(format!("Failed to get ABI for `{fn_abi_request:?}`: {err:?}"))
+    }
+}
+
+impl<'tcx, B: Bridge> LayoutOfHelpers<'tcx> for SmirCtxt<'tcx, B> {
+    type LayoutOfResult = Result<ty::layout::TyAndLayout<'tcx>, B::Error>;
+
+    #[inline]
+    fn handle_layout_err(
+        &self,
+        err: ty::layout::LayoutError<'tcx>,
+        _span: rustc_span::Span,
+        ty: Ty<'tcx>,
+    ) -> B::Error {
+        B::Error::new(format!("Failed to get layout for `{ty}`: {err}"))
+    }
+}
+
+impl<'tcx, B: Bridge> HasTypingEnv<'tcx> for SmirCtxt<'tcx, B> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv::fully_monomorphized()
+    }
+}
+
+impl<'tcx, B: Bridge> HasTyCtxt<'tcx> for SmirCtxt<'tcx, B> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
+
+impl<'tcx, B: Bridge> HasDataLayout for SmirCtxt<'tcx, B> {
+    fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
+        self.tcx.data_layout()
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/context/traits.rs b/compiler/rustc_smir/src/rustc_smir/context/traits.rs
new file mode 100644
index 00000000000..19e09016cdd
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/context/traits.rs
@@ -0,0 +1,46 @@
+//! A set of traits that define a stable interface to rustc's internals.
+//!
+//! These traits abstract rustc's internal APIs, allowing StableMIR to maintain a stable
+//! interface regardless of internal compiler changes.
+
+use rustc_middle::mir::interpret::AllocRange;
+use rustc_middle::ty;
+use rustc_middle::ty::Ty;
+use rustc_span::def_id::DefId;
+
+pub trait SmirExistentialProjection<'tcx> {
+    fn new_from_args(
+        &self,
+        def_id: DefId,
+        args: ty::GenericArgsRef<'tcx>,
+        term: ty::Term<'tcx>,
+    ) -> ty::ExistentialProjection<'tcx>;
+}
+
+pub trait SmirExistentialTraitRef<'tcx> {
+    fn new_from_args(
+        &self,
+        trait_def_id: DefId,
+        args: ty::GenericArgsRef<'tcx>,
+    ) -> ty::ExistentialTraitRef<'tcx>;
+}
+
+pub trait SmirTraitRef<'tcx> {
+    fn new_from_args(
+        &self,
+        trait_def_id: DefId,
+        args: ty::GenericArgsRef<'tcx>,
+    ) -> ty::TraitRef<'tcx>;
+}
+
+pub trait SmirTy<'tcx> {
+    fn new_foreign(&self, def_id: DefId) -> Ty<'tcx>;
+}
+
+pub trait SmirTypingEnv<'tcx> {
+    fn fully_monomorphized(&self) -> ty::TypingEnv<'tcx>;
+}
+
+pub trait SmirAllocRange<'tcx> {
+    fn alloc_range(&self, offset: rustc_abi::Size, size: rustc_abi::Size) -> AllocRange;
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/error.rs b/compiler/rustc_smir/src/rustc_smir/convert/error.rs
deleted file mode 100644
index 2cde5542483..00000000000
--- a/compiler/rustc_smir/src/rustc_smir/convert/error.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-//! Handle the conversion of different internal errors into a stable version.
-//!
-//! Currently we encode everything as [stable_mir::Error], which is represented as a string.
-
-use rustc_middle::mir::interpret::AllocError;
-use rustc_middle::ty::layout::LayoutError;
-
-use crate::rustc_smir::{Stable, Tables};
-use crate::stable_mir;
-
-impl<'tcx> Stable<'tcx> for LayoutError<'tcx> {
-    type T = stable_mir::Error;
-
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
-        stable_mir::Error::new(format!("{self:?}"))
-    }
-}
-
-impl<'tcx> Stable<'tcx> for AllocError {
-    type T = stable_mir::Error;
-
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
-        stable_mir::Error::new(format!("{self:?}"))
-    }
-}
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 26de9b0a496..e8b7a3fec09 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -7,229 +7,280 @@
 //!
 //! For now, we are developing everything inside `rustc`, thus, we keep this module private.
 
-use std::marker::PointeeSized;
-use std::ops::RangeInclusive;
+use std::cell::RefCell;
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::ops::Index;
 
-use rustc_hir::def::DefKind;
+use bridge::*;
+use context::SmirCtxt;
+use rustc_data_structures::fx::{self, FxIndexMap};
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::AllocId;
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::Span;
 use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
-use stable_mir::abi::Layout;
-use stable_mir::mir::mono::{InstanceDef, StaticDef};
-use stable_mir::ty::{FnDef, MirConstId, Span, TyConstId};
-use stable_mir::{CtorKind, ItemKind};
-use tracing::debug;
 
-use crate::rustc_internal::IndexMap;
-use crate::stable_mir;
-
-mod alloc;
+pub mod alloc;
+pub mod bridge;
 mod builder;
 pub mod context;
-mod convert;
-
-pub struct Tables<'tcx> {
-    pub(crate) tcx: TyCtxt<'tcx>,
-    pub(crate) def_ids: IndexMap<DefId, stable_mir::DefId>,
-    pub(crate) alloc_ids: IndexMap<AllocId, stable_mir::mir::alloc::AllocId>,
-    pub(crate) spans: IndexMap<rustc_span::Span, Span>,
-    pub(crate) types: IndexMap<Ty<'tcx>, stable_mir::ty::Ty>,
-    pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
-    pub(crate) ty_consts: IndexMap<ty::Const<'tcx>, TyConstId>,
-    pub(crate) mir_consts: IndexMap<mir::Const<'tcx>, MirConstId>,
-    pub(crate) layouts: IndexMap<rustc_abi::Layout<'tcx>, Layout>,
+
+/// A container which is used for TLS.
+pub struct SmirContainer<'tcx, B: Bridge> {
+    pub tables: RefCell<Tables<'tcx, B>>,
+    pub cx: RefCell<SmirCtxt<'tcx, B>>,
+}
+
+pub struct Tables<'tcx, B: Bridge> {
+    pub def_ids: IndexMap<DefId, B::DefId>,
+    pub alloc_ids: IndexMap<AllocId, B::AllocId>,
+    pub spans: IndexMap<rustc_span::Span, B::Span>,
+    pub types: IndexMap<Ty<'tcx>, B::Ty>,
+    pub instances: IndexMap<ty::Instance<'tcx>, B::InstanceDef>,
+    pub ty_consts: IndexMap<ty::Const<'tcx>, B::TyConstId>,
+    pub mir_consts: IndexMap<mir::Const<'tcx>, B::MirConstId>,
+    pub layouts: IndexMap<rustc_abi::Layout<'tcx>, B::Layout>,
+}
+
+impl<'tcx, B: Bridge> Default for Tables<'tcx, B> {
+    fn default() -> Self {
+        Self {
+            def_ids: IndexMap::default(),
+            alloc_ids: IndexMap::default(),
+            spans: IndexMap::default(),
+            types: IndexMap::default(),
+            instances: IndexMap::default(),
+            ty_consts: IndexMap::default(),
+            mir_consts: IndexMap::default(),
+            layouts: IndexMap::default(),
+        }
+    }
 }
 
-impl<'tcx> Tables<'tcx> {
-    pub(crate) fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty {
+impl<'tcx, B: Bridge> Index<B::DefId> for Tables<'tcx, B> {
+    type Output = DefId;
+
+    #[inline(always)]
+    fn index(&self, index: B::DefId) -> &Self::Output {
+        &self.def_ids[index]
+    }
+}
+
+impl<'tcx, B: Bridge> Tables<'tcx, B> {
+    pub fn intern_ty(&mut self, ty: Ty<'tcx>) -> B::Ty {
         self.types.create_or_fetch(ty)
     }
 
-    pub(crate) fn intern_ty_const(&mut self, ct: ty::Const<'tcx>) -> TyConstId {
+    pub fn intern_ty_const(&mut self, ct: ty::Const<'tcx>) -> B::TyConstId {
         self.ty_consts.create_or_fetch(ct)
     }
 
-    pub(crate) fn intern_mir_const(&mut self, constant: mir::Const<'tcx>) -> MirConstId {
+    pub fn intern_mir_const(&mut self, constant: mir::Const<'tcx>) -> B::MirConstId {
         self.mir_consts.create_or_fetch(constant)
     }
 
-    /// Return whether the instance as a body available.
-    ///
-    /// Items and intrinsics may have a body available from its definition.
-    /// Shims body may be generated depending on their type.
-    pub(crate) fn instance_has_body(&self, instance: Instance<'tcx>) -> bool {
-        let def_id = instance.def_id();
-        self.item_has_body(def_id)
-            || !matches!(
-                instance.def,
-                ty::InstanceKind::Virtual(..)
-                    | ty::InstanceKind::Intrinsic(..)
-                    | ty::InstanceKind::Item(..)
-            )
-    }
-
-    /// Return whether the item has a body defined by the user.
-    ///
-    /// Note that intrinsics may have a placeholder body that shouldn't be used in practice.
-    /// In StableMIR, we handle this case as if the body is not available.
-    pub(crate) fn item_has_body(&self, def_id: DefId) -> bool {
-        let must_override = if let Some(intrinsic) = self.tcx.intrinsic(def_id) {
-            intrinsic.must_be_overridden
-        } else {
-            false
-        };
-        !must_override && self.tcx.is_mir_available(def_id)
-    }
-
-    fn to_fn_def(&mut self, def_id: DefId) -> Option<FnDef> {
-        if matches!(self.tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
-            Some(self.fn_def(def_id))
-        } else {
-            None
-        }
+    pub fn create_def_id(&mut self, did: DefId) -> B::DefId {
+        self.def_ids.create_or_fetch(did)
     }
 
-    fn to_static(&mut self, def_id: DefId) -> Option<StaticDef> {
-        matches!(self.tcx.def_kind(def_id), DefKind::Static { .. }).then(|| self.static_def(def_id))
+    pub fn create_alloc_id(&mut self, aid: AllocId) -> B::AllocId {
+        self.alloc_ids.create_or_fetch(aid)
     }
-}
 
-/// Iterate over the definitions of the given crate.
-pub(crate) fn filter_def_ids<F, T>(tcx: TyCtxt<'_>, krate: CrateNum, mut func: F) -> Vec<T>
-where
-    F: FnMut(DefId) -> Option<T>,
-{
-    if krate == LOCAL_CRATE {
-        tcx.iter_local_def_id().filter_map(|did| func(did.to_def_id())).collect()
-    } else {
-        let num_definitions = tcx.num_extern_def_ids(krate);
-        (0..num_definitions)
-            .filter_map(move |i| {
-                let def_id = DefId { krate, index: rustc_span::def_id::DefIndex::from_usize(i) };
-                func(def_id)
-            })
-            .collect()
+    pub fn create_span(&mut self, span: Span) -> B::Span {
+        self.spans.create_or_fetch(span)
     }
-}
 
-/// Build a stable mir crate from a given crate number.
-pub(crate) fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
-    let crate_name = tcx.crate_name(crate_num).to_string();
-    let is_local = crate_num == LOCAL_CRATE;
-    debug!(?crate_name, ?crate_num, "smir_crate");
-    stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
-}
+    pub fn instance_def(&mut self, instance: ty::Instance<'tcx>) -> B::InstanceDef {
+        self.instances.create_or_fetch(instance)
+    }
 
-pub(crate) fn new_item_kind(kind: DefKind) -> ItemKind {
-    match kind {
-        DefKind::Mod
-        | DefKind::Struct
-        | DefKind::Union
-        | DefKind::Enum
-        | DefKind::Variant
-        | DefKind::Trait
-        | DefKind::TyAlias
-        | DefKind::ForeignTy
-        | DefKind::TraitAlias
-        | DefKind::AssocTy
-        | DefKind::TyParam
-        | DefKind::ConstParam
-        | DefKind::Macro(_)
-        | DefKind::ExternCrate
-        | DefKind::Use
-        | DefKind::ForeignMod
-        | DefKind::OpaqueTy
-        | DefKind::Field
-        | DefKind::LifetimeParam
-        | DefKind::Impl { .. }
-        | DefKind::GlobalAsm => {
-            unreachable!("Not a valid item kind: {kind:?}");
-        }
-        DefKind::Closure | DefKind::AssocFn | DefKind::Fn | DefKind::SyntheticCoroutineBody => {
-            ItemKind::Fn
-        }
-        DefKind::Const | DefKind::InlineConst | DefKind::AssocConst | DefKind::AnonConst => {
-            ItemKind::Const
-        }
-        DefKind::Static { .. } => ItemKind::Static,
-        DefKind::Ctor(_, rustc_hir::def::CtorKind::Const) => ItemKind::Ctor(CtorKind::Const),
-        DefKind::Ctor(_, rustc_hir::def::CtorKind::Fn) => ItemKind::Ctor(CtorKind::Fn),
+    pub fn layout_id(&mut self, layout: rustc_abi::Layout<'tcx>) -> B::Layout {
+        self.layouts.create_or_fetch(layout)
     }
-}
 
-/// Trait used to convert between an internal MIR type to a Stable MIR type.
-pub trait Stable<'cx>: PointeeSized {
-    /// The stable representation of the type implementing Stable.
-    type T;
-    /// Converts an object to the equivalent Stable MIR representation.
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T;
-}
+    pub fn crate_item(&mut self, did: rustc_span::def_id::DefId) -> B::CrateItem {
+        B::CrateItem::new(self.create_def_id(did))
+    }
 
-impl<'tcx, T> Stable<'tcx> for &T
-where
-    T: Stable<'tcx>,
-{
-    type T = T::T;
+    pub fn adt_def(&mut self, did: rustc_span::def_id::DefId) -> B::AdtDef {
+        B::AdtDef::new(self.create_def_id(did))
+    }
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        (*self).stable(tables)
+    pub fn foreign_module_def(&mut self, did: rustc_span::def_id::DefId) -> B::ForeignModuleDef {
+        B::ForeignModuleDef::new(self.create_def_id(did))
     }
-}
 
-impl<'tcx, T> Stable<'tcx> for Option<T>
-where
-    T: Stable<'tcx>,
-{
-    type T = Option<T::T>;
+    pub fn foreign_def(&mut self, did: rustc_span::def_id::DefId) -> B::ForeignDef {
+        B::ForeignDef::new(self.create_def_id(did))
+    }
+
+    pub fn fn_def(&mut self, did: rustc_span::def_id::DefId) -> B::FnDef {
+        B::FnDef::new(self.create_def_id(did))
+    }
+
+    pub fn closure_def(&mut self, did: rustc_span::def_id::DefId) -> B::ClosureDef {
+        B::ClosureDef::new(self.create_def_id(did))
+    }
+
+    pub fn coroutine_def(&mut self, did: rustc_span::def_id::DefId) -> B::CoroutineDef {
+        B::CoroutineDef::new(self.create_def_id(did))
+    }
+
+    pub fn coroutine_closure_def(
+        &mut self,
+        did: rustc_span::def_id::DefId,
+    ) -> B::CoroutineClosureDef {
+        B::CoroutineClosureDef::new(self.create_def_id(did))
+    }
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        self.as_ref().map(|value| value.stable(tables))
+    pub fn alias_def(&mut self, did: rustc_span::def_id::DefId) -> B::AliasDef {
+        B::AliasDef::new(self.create_def_id(did))
+    }
+
+    pub fn param_def(&mut self, did: rustc_span::def_id::DefId) -> B::ParamDef {
+        B::ParamDef::new(self.create_def_id(did))
+    }
+
+    pub fn br_named_def(&mut self, did: rustc_span::def_id::DefId) -> B::BrNamedDef {
+        B::BrNamedDef::new(self.create_def_id(did))
+    }
+
+    pub fn trait_def(&mut self, did: rustc_span::def_id::DefId) -> B::TraitDef {
+        B::TraitDef::new(self.create_def_id(did))
+    }
+
+    pub fn generic_def(&mut self, did: rustc_span::def_id::DefId) -> B::GenericDef {
+        B::GenericDef::new(self.create_def_id(did))
+    }
+
+    pub fn const_def(&mut self, did: rustc_span::def_id::DefId) -> B::ConstDef {
+        B::ConstDef::new(self.create_def_id(did))
+    }
+
+    pub fn impl_def(&mut self, did: rustc_span::def_id::DefId) -> B::ImplDef {
+        B::ImplDef::new(self.create_def_id(did))
+    }
+
+    pub fn region_def(&mut self, did: rustc_span::def_id::DefId) -> B::RegionDef {
+        B::RegionDef::new(self.create_def_id(did))
+    }
+
+    pub fn coroutine_witness_def(
+        &mut self,
+        did: rustc_span::def_id::DefId,
+    ) -> B::CoroutineWitnessDef {
+        B::CoroutineWitnessDef::new(self.create_def_id(did))
+    }
+
+    pub fn assoc_def(&mut self, did: rustc_span::def_id::DefId) -> B::AssocDef {
+        B::AssocDef::new(self.create_def_id(did))
+    }
+
+    pub fn opaque_def(&mut self, did: rustc_span::def_id::DefId) -> B::OpaqueDef {
+        B::OpaqueDef::new(self.create_def_id(did))
+    }
+
+    pub fn prov(&mut self, aid: rustc_middle::mir::interpret::AllocId) -> B::Prov {
+        B::Prov::new(self.create_alloc_id(aid))
+    }
+
+    pub fn static_def(&mut self, did: rustc_span::def_id::DefId) -> B::StaticDef {
+        B::StaticDef::new(self.create_def_id(did))
     }
 }
 
-impl<'tcx, T, E> Stable<'tcx> for Result<T, E>
-where
-    T: Stable<'tcx>,
-    E: Stable<'tcx>,
-{
-    type T = Result<T::T, E::T>;
+/// A trait defining types that are used to emulate StableMIR components, which is really
+/// useful when programming in stable_mir-agnostic settings.
+pub trait Bridge: Sized {
+    type DefId: Copy + Debug + PartialEq + IndexedVal;
+    type AllocId: Copy + Debug + PartialEq + IndexedVal;
+    type Span: Copy + Debug + PartialEq + IndexedVal;
+    type Ty: Copy + Debug + PartialEq + IndexedVal;
+    type InstanceDef: Copy + Debug + PartialEq + IndexedVal;
+    type TyConstId: Copy + Debug + PartialEq + IndexedVal;
+    type MirConstId: Copy + Debug + PartialEq + IndexedVal;
+    type Layout: Copy + Debug + PartialEq + IndexedVal;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        match self {
-            Ok(val) => Ok(val.stable(tables)),
-            Err(error) => Err(error.stable(tables)),
-        }
+    type Error: SmirError;
+    type CrateItem: CrateItem<Self>;
+    type AdtDef: AdtDef<Self>;
+    type ForeignModuleDef: ForeignModuleDef<Self>;
+    type ForeignDef: ForeignDef<Self>;
+    type FnDef: FnDef<Self>;
+    type ClosureDef: ClosureDef<Self>;
+    type CoroutineDef: CoroutineDef<Self>;
+    type CoroutineClosureDef: CoroutineClosureDef<Self>;
+    type AliasDef: AliasDef<Self>;
+    type ParamDef: ParamDef<Self>;
+    type BrNamedDef: BrNamedDef<Self>;
+    type TraitDef: TraitDef<Self>;
+    type GenericDef: GenericDef<Self>;
+    type ConstDef: ConstDef<Self>;
+    type ImplDef: ImplDef<Self>;
+    type RegionDef: RegionDef<Self>;
+    type CoroutineWitnessDef: CoroutineWitnessDef<Self>;
+    type AssocDef: AssocDef<Self>;
+    type OpaqueDef: OpaqueDef<Self>;
+    type Prov: Prov<Self>;
+    type StaticDef: StaticDef<Self>;
+
+    type Allocation: Allocation<Self>;
+}
+
+pub trait IndexedVal {
+    fn to_val(index: usize) -> Self;
+
+    fn to_index(&self) -> usize;
+}
+
+/// Similar to rustc's `FxIndexMap`, `IndexMap` with extra
+/// safety features added.
+pub struct IndexMap<K, V> {
+    index_map: fx::FxIndexMap<K, V>,
+}
+
+impl<K, V> Default for IndexMap<K, V> {
+    fn default() -> Self {
+        Self { index_map: FxIndexMap::default() }
     }
 }
 
-impl<'tcx, T> Stable<'tcx> for &[T]
-where
-    T: Stable<'tcx>,
-{
-    type T = Vec<T::T>;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        self.iter().map(|e| e.stable(tables)).collect()
+impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> IndexMap<K, V> {
+    pub fn create_or_fetch(&mut self, key: K) -> V {
+        let len = self.index_map.len();
+        let v = self.index_map.entry(key).or_insert(V::to_val(len));
+        *v
     }
 }
 
-impl<'tcx, T, U> Stable<'tcx> for (T, U)
-where
-    T: Stable<'tcx>,
-    U: Stable<'tcx>,
+impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V>
+    for IndexMap<K, V>
 {
-    type T = (T::T, U::T);
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        (self.0.stable(tables), self.1.stable(tables))
+    type Output = K;
+
+    fn index(&self, index: V) -> &Self::Output {
+        let (k, v) = self.index_map.get_index(index.to_index()).unwrap();
+        assert_eq!(*v, index, "Provided value doesn't match with indexed value");
+        k
     }
 }
 
-impl<'tcx, T> Stable<'tcx> for RangeInclusive<T>
+/// Iterate over the definitions of the given crate.
+pub(crate) fn filter_def_ids<F, T>(tcx: TyCtxt<'_>, krate: CrateNum, mut func: F) -> Vec<T>
 where
-    T: Stable<'tcx>,
+    F: FnMut(DefId) -> Option<T>,
 {
-    type T = RangeInclusive<T::T>;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        RangeInclusive::new(self.start().stable(tables), self.end().stable(tables))
+    if krate == LOCAL_CRATE {
+        tcx.iter_local_def_id().filter_map(|did| func(did.to_def_id())).collect()
+    } else {
+        let num_definitions = tcx.num_extern_def_ids(krate);
+        (0..num_definitions)
+            .filter_map(move |i| {
+                let def_id = DefId { krate, index: rustc_span::def_id::DefIndex::from_usize(i) };
+                func(def_id)
+            })
+            .collect()
     }
 }
diff --git a/compiler/rustc_smir/src/stable_mir/abi.rs b/compiler/rustc_smir/src/stable_mir/abi.rs
index d8a2b97662c..369d08e444e 100644
--- a/compiler/rustc_smir/src/stable_mir/abi.rs
+++ b/compiler/rustc_smir/src/stable_mir/abi.rs
@@ -6,7 +6,7 @@ use serde::Serialize;
 use stable_mir::compiler_interface::with;
 use stable_mir::mir::FieldIdx;
 use stable_mir::target::{MachineInfo, MachineSize as Size};
-use stable_mir::ty::{Align, IndexedVal, Ty, VariantIdx};
+use stable_mir::ty::{Align, Ty, VariantIdx};
 use stable_mir::{Error, Opaque, error};
 
 use crate::stable_mir;
@@ -119,7 +119,7 @@ impl Layout {
     }
 }
 
-impl IndexedVal for Layout {
+impl stable_mir::IndexedVal for Layout {
     fn to_val(index: usize) -> Self {
         Layout(index)
     }
diff --git a/compiler/rustc_smir/src/stable_mir/alloc.rs b/compiler/rustc_smir/src/stable_mir/alloc.rs
new file mode 100644
index 00000000000..120cb4404b9
--- /dev/null
+++ b/compiler/rustc_smir/src/stable_mir/alloc.rs
@@ -0,0 +1,77 @@
+//! Memory allocation implementation for StableMIR.
+//!
+//! This module is responsible for constructing stable components.
+//! All operations requiring rustc queries must be delegated
+//! to `rustc_smir::alloc` to maintain stability guarantees.
+
+use rustc_abi::Align;
+use rustc_middle::mir::ConstValue;
+use rustc_middle::mir::interpret::AllocRange;
+use rustc_smir::bridge::SmirError;
+use rustc_smir::context::SmirCtxt;
+use rustc_smir::{Tables, alloc};
+
+use super::Error;
+use super::compiler_interface::BridgeTys;
+use super::mir::Mutability;
+use super::ty::{Allocation, ProvenanceMap};
+use super::unstable::Stable;
+use crate::rustc_smir;
+
+/// Creates new empty `Allocation` from given `Align`.
+fn new_empty_allocation(align: Align) -> Allocation {
+    Allocation {
+        bytes: Vec::new(),
+        provenance: ProvenanceMap { ptrs: Vec::new() },
+        align: align.bytes(),
+        mutability: Mutability::Not,
+    }
+}
+
+// We need this method instead of a Stable implementation
+// because we need to get `Ty` of the const we are trying to create, to do that
+// we need to have access to `ConstantKind` but we can't access that inside Stable impl.
+#[allow(rustc::usage_of_qualified_ty)]
+pub(crate) fn new_allocation<'tcx>(
+    ty: rustc_middle::ty::Ty<'tcx>,
+    const_value: ConstValue<'tcx>,
+    tables: &mut Tables<'tcx, BridgeTys>,
+    cx: &SmirCtxt<'tcx, BridgeTys>,
+) -> Allocation {
+    try_new_allocation(ty, const_value, tables, cx)
+        .unwrap_or_else(|_| panic!("Failed to convert: {const_value:?} to {ty:?}"))
+}
+
+#[allow(rustc::usage_of_qualified_ty)]
+pub(crate) fn try_new_allocation<'tcx>(
+    ty: rustc_middle::ty::Ty<'tcx>,
+    const_value: ConstValue<'tcx>,
+    tables: &mut Tables<'tcx, BridgeTys>,
+    cx: &SmirCtxt<'tcx, BridgeTys>,
+) -> Result<Allocation, Error> {
+    let layout = alloc::create_ty_and_layout(cx, ty).map_err(|e| Error::from_internal(e))?;
+    match const_value {
+        ConstValue::Scalar(scalar) => {
+            alloc::try_new_scalar(layout, scalar, cx).map(|alloc| alloc.stable(tables, cx))
+        }
+        ConstValue::ZeroSized => Ok(new_empty_allocation(layout.align.abi)),
+        ConstValue::Slice { data, meta } => {
+            alloc::try_new_slice(layout, data, meta, cx).map(|alloc| alloc.stable(tables, cx))
+        }
+        ConstValue::Indirect { alloc_id, offset } => {
+            let alloc = alloc::try_new_indirect(alloc_id, cx);
+            use rustc_smir::context::SmirAllocRange;
+            Ok(allocation_filter(&alloc.0, cx.alloc_range(offset, layout.size), tables, cx))
+        }
+    }
+}
+
+/// Creates an `Allocation` only from information within the `AllocRange`.
+pub(super) fn allocation_filter<'tcx>(
+    alloc: &rustc_middle::mir::interpret::Allocation,
+    alloc_range: AllocRange,
+    tables: &mut Tables<'tcx, BridgeTys>,
+    cx: &SmirCtxt<'tcx, BridgeTys>,
+) -> Allocation {
+    alloc::allocation_filter(alloc, alloc_range, tables, cx)
+}
diff --git a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs
index 2668fba9f4f..a19968d2ab7 100644
--- a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs
+++ b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs
@@ -5,133 +5,488 @@
 
 use std::cell::Cell;
 
+use rustc_hir::def::DefKind;
 use rustc_smir::context::SmirCtxt;
+use rustc_smir::{Bridge, SmirContainer};
 use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions};
 use stable_mir::crate_def::Attribute;
 use stable_mir::mir::alloc::{AllocId, GlobalAlloc};
 use stable_mir::mir::mono::{Instance, InstanceDef, StaticDef};
 use stable_mir::mir::{BinOp, Body, Place, UnOp};
-use stable_mir::target::MachineInfo;
+use stable_mir::target::{MachineInfo, MachineSize};
 use stable_mir::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
     ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates,
     Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span,
     TraitDecl, TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx,
 };
+use stable_mir::unstable::{RustcInternal, Stable, new_item_kind};
 use stable_mir::{
-    AssocItems, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls,
-    ItemKind, Symbol, TraitDecls, mir,
+    AssocItems, Crate, CrateDef, CrateItem, CrateItems, CrateNum, DefId, Error, Filename,
+    ImplTraitDecls, ItemKind, Symbol, TraitDecls, alloc, mir,
 };
+use tracing::debug;
 
 use crate::{rustc_smir, stable_mir};
 
+pub struct BridgeTys;
+
+impl Bridge for BridgeTys {
+    type DefId = stable_mir::DefId;
+    type AllocId = stable_mir::mir::alloc::AllocId;
+    type Span = stable_mir::ty::Span;
+    type Ty = stable_mir::ty::Ty;
+    type InstanceDef = stable_mir::mir::mono::InstanceDef;
+    type TyConstId = stable_mir::ty::TyConstId;
+    type MirConstId = stable_mir::ty::MirConstId;
+    type Layout = stable_mir::abi::Layout;
+
+    type Error = stable_mir::Error;
+    type CrateItem = stable_mir::CrateItem;
+    type AdtDef = stable_mir::ty::AdtDef;
+    type ForeignModuleDef = stable_mir::ty::ForeignModuleDef;
+    type ForeignDef = stable_mir::ty::ForeignDef;
+    type FnDef = stable_mir::ty::FnDef;
+    type ClosureDef = stable_mir::ty::ClosureDef;
+    type CoroutineDef = stable_mir::ty::CoroutineDef;
+    type CoroutineClosureDef = stable_mir::ty::CoroutineClosureDef;
+    type AliasDef = stable_mir::ty::AliasDef;
+    type ParamDef = stable_mir::ty::ParamDef;
+    type BrNamedDef = stable_mir::ty::BrNamedDef;
+    type TraitDef = stable_mir::ty::TraitDef;
+    type GenericDef = stable_mir::ty::GenericDef;
+    type ConstDef = stable_mir::ty::ConstDef;
+    type ImplDef = stable_mir::ty::ImplDef;
+    type RegionDef = stable_mir::ty::RegionDef;
+    type CoroutineWitnessDef = stable_mir::ty::CoroutineWitnessDef;
+    type AssocDef = stable_mir::ty::AssocDef;
+    type OpaqueDef = stable_mir::ty::OpaqueDef;
+    type Prov = stable_mir::ty::Prov;
+    type StaticDef = stable_mir::mir::mono::StaticDef;
+
+    type Allocation = stable_mir::ty::Allocation;
+}
+
 /// Stable public API for querying compiler information.
 ///
-/// All queries are delegated to an internal [`SmirCtxt`] that provides
+/// All queries are delegated to [`crate::rustc_smir::context::SmirCtxt`] that provides
 /// similar APIs but based on internal rustc constructs.
 ///
 /// Do not use this directly. This is currently used in the macro expansion.
-pub(crate) struct SmirInterface<'tcx> {
-    pub(crate) cx: SmirCtxt<'tcx>,
+pub(crate) trait SmirInterface {
+    fn entry_fn(&self) -> Option<CrateItem>;
+    /// Retrieve all items of the local crate that have a MIR associated with them.
+    fn all_local_items(&self) -> CrateItems;
+    /// Retrieve the body of a function.
+    /// This function will panic if the body is not available.
+    fn mir_body(&self, item: DefId) -> mir::Body;
+    /// Check whether the body of a function is available.
+    fn has_body(&self, item: DefId) -> bool;
+    fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef>;
+
+    /// Retrieve all functions defined in this crate.
+    fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef>;
+
+    /// Retrieve all static items defined in this crate.
+    fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef>;
+    fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule;
+    fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef>;
+    fn all_trait_decls(&self) -> TraitDecls;
+    fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls;
+    fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
+    fn all_trait_impls(&self) -> ImplTraitDecls;
+    fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls;
+    fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
+    fn generics_of(&self, def_id: DefId) -> Generics;
+    fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
+    fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates;
+
+    /// Get information about the local crate.
+    fn local_crate(&self) -> Crate;
+    /// Retrieve a list of all external crates.
+    fn external_crates(&self) -> Vec<Crate>;
+
+    /// Find a crate with the given name.
+    fn find_crates(&self, name: &str) -> Vec<Crate>;
+
+    /// Returns the name of given `DefId`
+    fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol;
+
+    /// Return registered tool attributes with the given attribute name.
+    ///
+    /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool
+    /// attributes will simply return an empty list.
+    ///
+    /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
+    /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
+    fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute>;
+
+    /// Get all tool attributes of a definition.
+    fn all_tool_attrs(&self, def_id: DefId) -> Vec<Attribute>;
+
+    /// Returns printable, human readable form of `Span`
+    fn span_to_string(&self, span: Span) -> String;
+
+    /// Return filename from given `Span`, for diagnostic purposes
+    fn get_filename(&self, span: &Span) -> Filename;
+
+    /// Return lines corresponding to this `Span`
+    fn get_lines(&self, span: &Span) -> LineInfo;
+
+    /// Returns the `kind` of given `DefId`
+    fn item_kind(&self, item: CrateItem) -> ItemKind;
+
+    /// Returns whether this is a foreign item.
+    fn is_foreign_item(&self, item: DefId) -> bool;
+
+    /// Returns the kind of a given foreign item.
+    fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind;
+
+    /// Returns the kind of a given algebraic data type
+    fn adt_kind(&self, def: AdtDef) -> AdtKind;
+
+    /// Returns if the ADT is a box.
+    fn adt_is_box(&self, def: AdtDef) -> bool;
+
+    /// Returns whether this ADT is simd.
+    fn adt_is_simd(&self, def: AdtDef) -> bool;
+
+    /// Returns whether this definition is a C string.
+    fn adt_is_cstr(&self, def: AdtDef) -> bool;
+
+    /// Returns the representation options for this ADT.
+    fn adt_repr(&self, def: AdtDef) -> ReprOptions;
+
+    /// Retrieve the function signature for the given generic arguments.
+    fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig;
+
+    /// Retrieve the intrinsic definition if the item corresponds one.
+    fn intrinsic(&self, item: DefId) -> Option<IntrinsicDef>;
+
+    /// Retrieve the plain function name of an intrinsic.
+    fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol;
+
+    /// Retrieve the closure signature for the given generic arguments.
+    fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig;
+
+    /// The number of variants in this ADT.
+    fn adt_variants_len(&self, def: AdtDef) -> usize;
+
+    /// Discriminant for a given variant index of AdtDef.
+    fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr;
+
+    /// Discriminant for a given variand index and args of a coroutine.
+    fn coroutine_discr_for_variant(
+        &self,
+        coroutine: CoroutineDef,
+        args: &GenericArgs,
+        variant: VariantIdx,
+    ) -> Discr;
+
+    /// The name of a variant.
+    fn variant_name(&self, def: VariantDef) -> Symbol;
+    fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef>;
+
+    /// Evaluate constant as a target usize.
+    fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error>;
+    fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error>;
+
+    /// Create a new zero-sized constant.
+    fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error>;
+
+    /// Create a new constant that represents the given string value.
+    fn new_const_str(&self, value: &str) -> MirConst;
+
+    /// Create a new constant that represents the given boolean value.
+    fn new_const_bool(&self, value: bool) -> MirConst;
+
+    /// Create a new constant that represents the given value.
+    fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error>;
+    fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<TyConst, Error>;
+
+    /// Create a new type from the given kind.
+    fn new_rigid_ty(&self, kind: RigidTy) -> Ty;
+
+    /// Create a new box type, `Box<T>`, for the given inner type `T`.
+    fn new_box_ty(&self, ty: Ty) -> Ty;
+
+    /// Returns the type of given crate item.
+    fn def_ty(&self, item: DefId) -> Ty;
+
+    /// Returns the type of given definition instantiated with the given arguments.
+    fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty;
+
+    /// Returns literal value of a const as a string.
+    fn mir_const_pretty(&self, cnst: &MirConst) -> String;
+
+    /// `Span` of an item
+    fn span_of_an_item(&self, def_id: DefId) -> Span;
+
+    fn ty_const_pretty(&self, ct: TyConstId) -> String;
+
+    /// Obtain the representation of a type.
+    fn ty_pretty(&self, ty: Ty) -> String;
+
+    /// Obtain the kind of a type.
+    fn ty_kind(&self, ty: Ty) -> TyKind;
+
+    // Get the discriminant Ty for this Ty if there's one.
+    fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty;
+
+    /// Get the body of an Instance which is already monomorphized.
+    fn instance_body(&self, instance: InstanceDef) -> Option<Body>;
+
+    /// Get the instance type with generic instantiations applied and lifetimes erased.
+    fn instance_ty(&self, instance: InstanceDef) -> Ty;
+
+    /// Get the instantiation types.
+    fn instance_args(&self, def: InstanceDef) -> GenericArgs;
+
+    /// Get the instance.
+    fn instance_def_id(&self, instance: InstanceDef) -> DefId;
+
+    /// Get the instance mangled name.
+    fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol;
+
+    /// Check if this is an empty DropGlue shim.
+    fn is_empty_drop_shim(&self, def: InstanceDef) -> bool;
+
+    /// Convert a non-generic crate item into an instance.
+    /// This function will panic if the item is generic.
+    fn mono_instance(&self, def_id: DefId) -> Instance;
+
+    /// Item requires monomorphization.
+    fn requires_monomorphization(&self, def_id: DefId) -> bool;
+
+    /// Resolve an instance from the given function definition and generic arguments.
+    fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
+
+    /// Resolve an instance for drop_in_place for the given type.
+    fn resolve_drop_in_place(&self, ty: Ty) -> Instance;
+
+    /// Resolve instance for a function pointer.
+    fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
+
+    /// Resolve instance for a closure with the requested type.
+    fn resolve_closure(
+        &self,
+        def: ClosureDef,
+        args: &GenericArgs,
+        kind: ClosureKind,
+    ) -> Option<Instance>;
+
+    /// Evaluate a static's initializer.
+    fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error>;
+
+    /// Try to evaluate an instance into a constant.
+    fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error>;
+
+    /// Retrieve global allocation for the given allocation ID.
+    fn global_alloc(&self, id: AllocId) -> GlobalAlloc;
+
+    /// Retrieve the id for the virtual table.
+    fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
+    fn krate(&self, def_id: DefId) -> Crate;
+    fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
+
+    /// Return information about the target machine.
+    fn target_info(&self) -> MachineInfo;
+
+    /// Get an instance ABI.
+    fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error>;
+
+    /// Get the ABI of a function pointer.
+    fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error>;
+
+    /// Get the layout of a type.
+    fn ty_layout(&self, ty: Ty) -> Result<Layout, Error>;
+
+    /// Get the layout shape.
+    fn layout_shape(&self, id: Layout) -> LayoutShape;
+
+    /// Get a debug string representation of a place.
+    fn place_pretty(&self, place: &Place) -> String;
+
+    /// Get the resulting type of binary operation.
+    fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty;
+
+    /// Get the resulting type of unary operation.
+    fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty;
+
+    /// Get all associated items of a definition.
+    fn associated_items(&self, def_id: DefId) -> AssocItems;
 }
 
-impl<'tcx> SmirInterface<'tcx> {
-    pub(crate) fn entry_fn(&self) -> Option<CrateItem> {
-        self.cx.entry_fn()
+impl<'tcx> SmirInterface for SmirContainer<'tcx, BridgeTys> {
+    fn entry_fn(&self) -> Option<CrateItem> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = cx.entry_fn();
+        Some(tables.crate_item(did?))
     }
 
     /// Retrieve all items of the local crate that have a MIR associated with them.
-    pub(crate) fn all_local_items(&self) -> CrateItems {
-        self.cx.all_local_items()
+    fn all_local_items(&self) -> CrateItems {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.all_local_items().iter().map(|did| tables.crate_item(*did)).collect()
     }
 
     /// Retrieve the body of a function.
     /// This function will panic if the body is not available.
-    pub(crate) fn mir_body(&self, item: DefId) -> mir::Body {
-        self.cx.mir_body(item)
+    fn mir_body(&self, item: DefId) -> mir::Body {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[item];
+        cx.mir_body(did).stable(&mut *tables, cx)
     }
 
     /// Check whether the body of a function is available.
-    pub(crate) fn has_body(&self, item: DefId) -> bool {
-        self.cx.has_body(item)
+    fn has_body(&self, item: DefId) -> bool {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let def = item.internal(&mut *tables, cx.tcx);
+        cx.has_body(def)
     }
 
-    pub(crate) fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef> {
-        self.cx.foreign_modules(crate_num)
+    fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.foreign_modules(crate_num.internal(&mut *tables, cx.tcx))
+            .iter()
+            .map(|did| tables.foreign_module_def(*did))
+            .collect()
     }
 
     /// Retrieve all functions defined in this crate.
-    pub(crate) fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
-        self.cx.crate_functions(crate_num)
+    fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let krate = crate_num.internal(&mut *tables, cx.tcx);
+        cx.crate_functions(krate).iter().map(|did| tables.fn_def(*did)).collect()
     }
 
     /// Retrieve all static items defined in this crate.
-    pub(crate) fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
-        self.cx.crate_statics(crate_num)
+    fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let krate = crate_num.internal(&mut *tables, cx.tcx);
+        cx.crate_statics(krate).iter().map(|did| tables.static_def(*did)).collect()
     }
 
-    pub(crate) fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule {
-        self.cx.foreign_module(mod_def)
+    fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[mod_def.def_id()];
+        cx.foreign_module(did).stable(&mut *tables, cx)
     }
 
-    pub(crate) fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef> {
-        self.cx.foreign_items(mod_def)
+    fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[mod_def.def_id()];
+        cx.foreign_items(did).iter().map(|did| tables.foreign_def(*did)).collect()
     }
 
-    pub(crate) fn all_trait_decls(&self) -> TraitDecls {
-        self.cx.all_trait_decls()
+    fn all_trait_decls(&self) -> TraitDecls {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.all_trait_decls().map(|did| tables.trait_def(did)).collect()
     }
 
-    pub(crate) fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls {
-        self.cx.trait_decls(crate_num)
+    fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let krate = crate_num.internal(&mut *tables, cx.tcx);
+        cx.trait_decls(krate).iter().map(|did| tables.trait_def(*did)).collect()
     }
 
-    pub(crate) fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl {
-        self.cx.trait_decl(trait_def)
+    fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[trait_def.0];
+        cx.trait_decl(did).stable(&mut *tables, cx)
     }
 
-    pub(crate) fn all_trait_impls(&self) -> ImplTraitDecls {
-        self.cx.all_trait_impls()
+    fn all_trait_impls(&self) -> ImplTraitDecls {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.all_trait_impls().iter().map(|did| tables.impl_def(*did)).collect()
     }
 
-    pub(crate) fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls {
-        self.cx.trait_impls(crate_num)
+    fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let krate = crate_num.internal(&mut *tables, cx.tcx);
+        cx.trait_impls(krate).iter().map(|did| tables.impl_def(*did)).collect()
     }
 
-    pub(crate) fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait {
-        self.cx.trait_impl(trait_impl)
+    fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[trait_impl.0];
+        cx.trait_impl(did).stable(&mut *tables, cx)
     }
 
-    pub(crate) fn generics_of(&self, def_id: DefId) -> Generics {
-        self.cx.generics_of(def_id)
+    fn generics_of(&self, def_id: DefId) -> Generics {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[def_id];
+        cx.generics_of(did).stable(&mut *tables, cx)
     }
 
-    pub(crate) fn predicates_of(&self, def_id: DefId) -> GenericPredicates {
-        self.cx.predicates_of(def_id)
+    fn predicates_of(&self, def_id: DefId) -> GenericPredicates {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[def_id];
+        let (parent, kinds) = cx.predicates_of(did);
+        stable_mir::ty::GenericPredicates {
+            parent: parent.map(|did| tables.trait_def(did)),
+            predicates: kinds
+                .iter()
+                .map(|(kind, span)| (kind.stable(&mut *tables, cx), span.stable(&mut *tables, cx)))
+                .collect(),
+        }
     }
 
-    pub(crate) fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates {
-        self.cx.explicit_predicates_of(def_id)
+    fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[def_id];
+        let (parent, kinds) = cx.explicit_predicates_of(did);
+        stable_mir::ty::GenericPredicates {
+            parent: parent.map(|did| tables.trait_def(did)),
+            predicates: kinds
+                .iter()
+                .map(|(kind, span)| (kind.stable(&mut *tables, cx), span.stable(&mut *tables, cx)))
+                .collect(),
+        }
     }
 
     /// Get information about the local crate.
-    pub(crate) fn local_crate(&self) -> Crate {
-        self.cx.local_crate()
+    fn local_crate(&self) -> Crate {
+        let cx = &*self.cx.borrow();
+        smir_crate(cx, cx.local_crate_num())
     }
 
     /// Retrieve a list of all external crates.
-    pub(crate) fn external_crates(&self) -> Vec<Crate> {
-        self.cx.external_crates()
+    fn external_crates(&self) -> Vec<Crate> {
+        let cx = &*self.cx.borrow();
+        cx.external_crates().iter().map(|crate_num| smir_crate(cx, *crate_num)).collect()
     }
 
     /// Find a crate with the given name.
-    pub(crate) fn find_crates(&self, name: &str) -> Vec<Crate> {
-        self.cx.find_crates(name)
+    fn find_crates(&self, name: &str) -> Vec<Crate> {
+        let cx = &*self.cx.borrow();
+        cx.find_crates(name).iter().map(|crate_num| smir_crate(cx, *crate_num)).collect()
     }
 
     /// Returns the name of given `DefId`.
-    pub(crate) fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol {
-        self.cx.def_name(def_id, trimmed)
+    fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol {
+        let tables = self.tables.borrow();
+        let cx = &*self.cx.borrow();
+        let did = tables[def_id];
+        cx.def_name(did, trimmed)
     }
 
     /// Return registered tool attributes with the given attribute name.
@@ -141,364 +496,581 @@ impl<'tcx> SmirInterface<'tcx> {
     ///
     /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
     /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
-    pub(crate) fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute> {
-        self.cx.tool_attrs(def_id, attr)
+    fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[def_id];
+        cx.tool_attrs(did, attr)
+            .into_iter()
+            .map(|(attr_str, span)| Attribute::new(attr_str, span.stable(&mut *tables, cx)))
+            .collect()
     }
 
     /// Get all tool attributes of a definition.
-    pub(crate) fn all_tool_attrs(&self, def_id: DefId) -> Vec<Attribute> {
-        self.cx.all_tool_attrs(def_id)
+    fn all_tool_attrs(&self, def_id: DefId) -> Vec<Attribute> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[def_id];
+        cx.all_tool_attrs(did)
+            .into_iter()
+            .map(|(attr_str, span)| Attribute::new(attr_str, span.stable(&mut *tables, cx)))
+            .collect()
     }
 
     /// Returns printable, human readable form of `Span`.
-    pub(crate) fn span_to_string(&self, span: Span) -> String {
-        self.cx.span_to_string(span)
+    fn span_to_string(&self, span: Span) -> String {
+        let tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let sp = tables.spans[span];
+        cx.span_to_string(sp)
     }
 
     /// Return filename from given `Span`, for diagnostic purposes.
-    pub(crate) fn get_filename(&self, span: &Span) -> Filename {
-        self.cx.get_filename(span)
+    fn get_filename(&self, span: &Span) -> Filename {
+        let tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let sp = tables.spans[*span];
+        cx.get_filename(sp)
     }
 
     /// Return lines corresponding to this `Span`.
-    pub(crate) fn get_lines(&self, span: &Span) -> LineInfo {
-        self.cx.get_lines(span)
+    fn get_lines(&self, span: &Span) -> LineInfo {
+        let tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let sp = tables.spans[*span];
+        let lines = cx.get_lines(sp);
+        LineInfo::from(lines)
     }
 
     /// Returns the `kind` of given `DefId`.
-    pub(crate) fn item_kind(&self, item: CrateItem) -> ItemKind {
-        self.cx.item_kind(item)
+    fn item_kind(&self, item: CrateItem) -> ItemKind {
+        let tables = self.tables.borrow();
+        let cx = &*self.cx.borrow();
+        let did = tables[item.0];
+        new_item_kind(cx.def_kind(did))
     }
 
     /// Returns whether this is a foreign item.
-    pub(crate) fn is_foreign_item(&self, item: DefId) -> bool {
-        self.cx.is_foreign_item(item)
+    fn is_foreign_item(&self, item: DefId) -> bool {
+        let tables = self.tables.borrow();
+        let cx = &*self.cx.borrow();
+        let did = tables[item];
+        cx.is_foreign_item(did)
     }
 
     /// Returns the kind of a given foreign item.
-    pub(crate) fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind {
-        self.cx.foreign_item_kind(def)
+    fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let def_id = tables[def.def_id()];
+        let def_kind = cx.foreign_item_kind(def_id);
+        match def_kind {
+            DefKind::Fn => ForeignItemKind::Fn(tables.fn_def(def_id)),
+            DefKind::Static { .. } => ForeignItemKind::Static(tables.static_def(def_id)),
+            DefKind::ForeignTy => {
+                use rustc_smir::context::SmirTy;
+                ForeignItemKind::Type(tables.intern_ty(cx.new_foreign(def_id)))
+            }
+            def_kind => unreachable!("Unexpected kind for a foreign item: {:?}", def_kind),
+        }
     }
 
     /// Returns the kind of a given algebraic data type.
-    pub(crate) fn adt_kind(&self, def: AdtDef) -> AdtKind {
-        self.cx.adt_kind(def)
+    fn adt_kind(&self, def: AdtDef) -> AdtKind {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.adt_kind(def.internal(&mut *tables, cx.tcx)).stable(&mut *tables, cx)
     }
 
     /// Returns if the ADT is a box.
-    pub(crate) fn adt_is_box(&self, def: AdtDef) -> bool {
-        self.cx.adt_is_box(def)
+    fn adt_is_box(&self, def: AdtDef) -> bool {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.adt_is_box(def.internal(&mut *tables, cx.tcx))
     }
 
     /// Returns whether this ADT is simd.
-    pub(crate) fn adt_is_simd(&self, def: AdtDef) -> bool {
-        self.cx.adt_is_simd(def)
+    fn adt_is_simd(&self, def: AdtDef) -> bool {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.adt_is_simd(def.internal(&mut *tables, cx.tcx))
     }
 
     /// Returns whether this definition is a C string.
-    pub(crate) fn adt_is_cstr(&self, def: AdtDef) -> bool {
-        self.cx.adt_is_cstr(def)
+    fn adt_is_cstr(&self, def: AdtDef) -> bool {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.adt_is_cstr(def.0.internal(&mut *tables, cx.tcx))
     }
 
     /// Returns the representation options for this ADT
-    pub(crate) fn adt_repr(&self, def: AdtDef) -> ReprOptions {
-        self.cx.adt_repr(def)
+    fn adt_repr(&self, def: AdtDef) -> ReprOptions {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.adt_repr(def.internal(&mut *tables, cx.tcx)).stable(&mut *tables, cx)
     }
 
     /// Retrieve the function signature for the given generic arguments.
-    pub(crate) fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
-        self.cx.fn_sig(def, args)
+    fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let def_id = def.0.internal(&mut *tables, cx.tcx);
+        let args_ref = args.internal(&mut *tables, cx.tcx);
+        cx.fn_sig(def_id, args_ref).stable(&mut *tables, cx)
     }
 
     /// Retrieve the intrinsic definition if the item corresponds one.
-    pub(crate) fn intrinsic(&self, item: DefId) -> Option<IntrinsicDef> {
-        self.cx.intrinsic(item)
+    fn intrinsic(&self, item: DefId) -> Option<IntrinsicDef> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let def_id = item.internal(&mut *tables, cx.tcx);
+        cx.intrinsic(def_id).map(|_| IntrinsicDef(item))
     }
 
     /// Retrieve the plain function name of an intrinsic.
-    pub(crate) fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
-        self.cx.intrinsic_name(def)
+    fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let def_id = def.0.internal(&mut *tables, cx.tcx);
+        cx.intrinsic_name(def_id)
     }
 
     /// Retrieve the closure signature for the given generic arguments.
-    pub(crate) fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
-        self.cx.closure_sig(args)
+    fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let args_ref = args.internal(&mut *tables, cx.tcx);
+        cx.closure_sig(args_ref).stable(&mut *tables, cx)
     }
 
     /// The number of variants in this ADT.
-    pub(crate) fn adt_variants_len(&self, def: AdtDef) -> usize {
-        self.cx.adt_variants_len(def)
+    fn adt_variants_len(&self, def: AdtDef) -> usize {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.adt_variants_len(def.internal(&mut *tables, cx.tcx))
     }
 
-    /// Discriminant for a given variant index of AdtDef
-    pub(crate) fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr {
-        self.cx.adt_discr_for_variant(adt, variant)
+    /// Discriminant for a given variant index of AdtDef.
+    fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.adt_discr_for_variant(
+            adt.internal(&mut *tables, cx.tcx),
+            variant.internal(&mut *tables, cx.tcx),
+        )
+        .stable(&mut *tables, cx)
     }
 
-    /// Discriminant for a given variand index and args of a coroutine
-    pub(crate) fn coroutine_discr_for_variant(
+    /// Discriminant for a given variand index and args of a coroutine.
+    fn coroutine_discr_for_variant(
         &self,
         coroutine: CoroutineDef,
         args: &GenericArgs,
         variant: VariantIdx,
     ) -> Discr {
-        self.cx.coroutine_discr_for_variant(coroutine, args, variant)
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let tcx = cx.tcx;
+        let def = coroutine.def_id().internal(&mut *tables, tcx);
+        let args_ref = args.internal(&mut *tables, tcx);
+        cx.coroutine_discr_for_variant(def, args_ref, variant.internal(&mut *tables, tcx))
+            .stable(&mut *tables, cx)
     }
 
     /// The name of a variant.
-    pub(crate) fn variant_name(&self, def: VariantDef) -> Symbol {
-        self.cx.variant_name(def)
+    fn variant_name(&self, def: VariantDef) -> Symbol {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.variant_name(def.internal(&mut *tables, cx.tcx))
     }
 
-    pub(crate) fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
-        self.cx.variant_fields(def)
+    fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        def.internal(&mut *tables, cx.tcx)
+            .fields
+            .iter()
+            .map(|f| f.stable(&mut *tables, cx))
+            .collect()
     }
 
     /// Evaluate constant as a target usize.
-    pub(crate) fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error> {
-        self.cx.eval_target_usize(cnst)
+    fn eval_target_usize(&self, mir_const: &MirConst) -> Result<u64, Error> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let cnst = mir_const.internal(&mut *tables, cx.tcx);
+        cx.eval_target_usize(cnst)
     }
 
-    pub(crate) fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> {
-        self.cx.eval_target_usize_ty(cnst)
+    fn eval_target_usize_ty(&self, ty_const: &TyConst) -> Result<u64, Error> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let cnst = ty_const.internal(&mut *tables, cx.tcx);
+        cx.eval_target_usize_ty(cnst)
     }
 
     /// Create a new zero-sized constant.
-    pub(crate) fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> {
-        self.cx.try_new_const_zst(ty)
+    fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let ty_internal = ty.internal(&mut *tables, cx.tcx);
+        cx.try_new_const_zst(ty_internal).map(|cnst| cnst.stable(&mut *tables, cx))
     }
 
     /// Create a new constant that represents the given string value.
-    pub(crate) fn new_const_str(&self, value: &str) -> MirConst {
-        self.cx.new_const_str(value)
+    fn new_const_str(&self, value: &str) -> MirConst {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.new_const_str(value).stable(&mut *tables, cx)
     }
 
     /// Create a new constant that represents the given boolean value.
-    pub(crate) fn new_const_bool(&self, value: bool) -> MirConst {
-        self.cx.new_const_bool(value)
+    fn new_const_bool(&self, value: bool) -> MirConst {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.new_const_bool(value).stable(&mut *tables, cx)
     }
 
     /// Create a new constant that represents the given value.
-    pub(crate) fn try_new_const_uint(
-        &self,
-        value: u128,
-        uint_ty: UintTy,
-    ) -> Result<MirConst, Error> {
-        self.cx.try_new_const_uint(value, uint_ty)
+    fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let ty = cx.ty_new_uint(uint_ty.internal(&mut *tables, cx.tcx));
+        cx.try_new_const_uint(value, ty).map(|cnst| cnst.stable(&mut *tables, cx))
     }
 
-    pub(crate) fn try_new_ty_const_uint(
-        &self,
-        value: u128,
-        uint_ty: UintTy,
-    ) -> Result<TyConst, Error> {
-        self.cx.try_new_ty_const_uint(value, uint_ty)
+    fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<TyConst, Error> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let ty = cx.ty_new_uint(uint_ty.internal(&mut *tables, cx.tcx));
+        cx.try_new_ty_const_uint(value, ty).map(|cnst| cnst.stable(&mut *tables, cx))
     }
 
     /// Create a new type from the given kind.
-    pub(crate) fn new_rigid_ty(&self, kind: RigidTy) -> Ty {
-        self.cx.new_rigid_ty(kind)
+    fn new_rigid_ty(&self, kind: RigidTy) -> Ty {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let internal_kind = kind.internal(&mut *tables, cx.tcx);
+        cx.new_rigid_ty(internal_kind).stable(&mut *tables, cx)
     }
 
     /// Create a new box type, `Box<T>`, for the given inner type `T`.
-    pub(crate) fn new_box_ty(&self, ty: Ty) -> Ty {
-        self.cx.new_box_ty(ty)
+    fn new_box_ty(&self, ty: Ty) -> Ty {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let inner = ty.internal(&mut *tables, cx.tcx);
+        cx.new_box_ty(inner).stable(&mut *tables, cx)
     }
 
     /// Returns the type of given crate item.
-    pub(crate) fn def_ty(&self, item: DefId) -> Ty {
-        self.cx.def_ty(item)
+    fn def_ty(&self, item: DefId) -> Ty {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let inner = item.internal(&mut *tables, cx.tcx);
+        cx.def_ty(inner).stable(&mut *tables, cx)
     }
 
     /// Returns the type of given definition instantiated with the given arguments.
-    pub(crate) fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty {
-        self.cx.def_ty_with_args(item, args)
+    fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let inner = item.internal(&mut *tables, cx.tcx);
+        let args_ref = args.internal(&mut *tables, cx.tcx);
+        cx.def_ty_with_args(inner, args_ref).stable(&mut *tables, cx)
     }
 
     /// Returns literal value of a const as a string.
-    pub(crate) fn mir_const_pretty(&self, cnst: &MirConst) -> String {
-        self.cx.mir_const_pretty(cnst)
+    fn mir_const_pretty(&self, cnst: &MirConst) -> String {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cnst.internal(&mut *tables, cx.tcx).to_string()
     }
 
     /// `Span` of an item.
-    pub(crate) fn span_of_an_item(&self, def_id: DefId) -> Span {
-        self.cx.span_of_an_item(def_id)
+    fn span_of_an_item(&self, def_id: DefId) -> Span {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[def_id];
+        cx.span_of_an_item(did).stable(&mut *tables, cx)
     }
 
-    pub(crate) fn ty_const_pretty(&self, ct: TyConstId) -> String {
-        self.cx.ty_const_pretty(ct)
+    fn ty_const_pretty(&self, ct: TyConstId) -> String {
+        let tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.ty_const_pretty(tables.ty_consts[ct])
     }
 
     /// Obtain the representation of a type.
-    pub(crate) fn ty_pretty(&self, ty: Ty) -> String {
-        self.cx.ty_pretty(ty)
+    fn ty_pretty(&self, ty: Ty) -> String {
+        let tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.ty_pretty(tables.types[ty])
     }
 
-    /// Obtain the representation of a type.
-    pub(crate) fn ty_kind(&self, ty: Ty) -> TyKind {
-        self.cx.ty_kind(ty)
+    /// Obtain the kind of a type.
+    fn ty_kind(&self, ty: Ty) -> TyKind {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        cx.ty_kind(tables.types[ty]).stable(&mut *tables, cx)
     }
 
     /// Get the discriminant Ty for this Ty if there's one.
-    pub(crate) fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty {
-        self.cx.rigid_ty_discriminant_ty(ty)
+    fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let internal_kind = ty.internal(&mut *tables, cx.tcx);
+        cx.rigid_ty_discriminant_ty(internal_kind).stable(&mut *tables, cx)
     }
 
     /// Get the body of an Instance which is already monomorphized.
-    pub(crate) fn instance_body(&self, instance: InstanceDef) -> Option<Body> {
-        self.cx.instance_body(instance)
+    fn instance_body(&self, instance: InstanceDef) -> Option<Body> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let instance = tables.instances[instance];
+        cx.instance_body(instance).map(|body| body.stable(&mut *tables, cx))
     }
 
     /// Get the instance type with generic instantiations applied and lifetimes erased.
-    pub(crate) fn instance_ty(&self, instance: InstanceDef) -> Ty {
-        self.cx.instance_ty(instance)
+    fn instance_ty(&self, instance: InstanceDef) -> Ty {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let instance = tables.instances[instance];
+        cx.instance_ty(instance).stable(&mut *tables, cx)
     }
 
     /// Get the instantiation types.
-    pub(crate) fn instance_args(&self, def: InstanceDef) -> GenericArgs {
-        self.cx.instance_args(def)
+    fn instance_args(&self, def: InstanceDef) -> GenericArgs {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let instance = tables.instances[def];
+        cx.instance_args(instance).stable(&mut *tables, cx)
     }
 
     /// Get the instance.
-    pub(crate) fn instance_def_id(&self, instance: InstanceDef) -> DefId {
-        self.cx.instance_def_id(instance)
+    fn instance_def_id(&self, instance: InstanceDef) -> DefId {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let instance = tables.instances[instance];
+        cx.instance_def_id(instance, &mut *tables)
     }
 
     /// Get the instance mangled name.
-    pub(crate) fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
-        self.cx.instance_mangled_name(instance)
+    fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
+        let tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let instance = tables.instances[instance];
+        cx.instance_mangled_name(instance)
     }
 
     /// Check if this is an empty DropGlue shim.
-    pub(crate) fn is_empty_drop_shim(&self, def: InstanceDef) -> bool {
-        self.cx.is_empty_drop_shim(def)
+    fn is_empty_drop_shim(&self, def: InstanceDef) -> bool {
+        let tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let instance = tables.instances[def];
+        cx.is_empty_drop_shim(instance)
     }
 
     /// Convert a non-generic crate item into an instance.
     /// This function will panic if the item is generic.
-    pub(crate) fn mono_instance(&self, def_id: DefId) -> Instance {
-        self.cx.mono_instance(def_id)
+    fn mono_instance(&self, def_id: DefId) -> Instance {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[def_id];
+        cx.mono_instance(did).stable(&mut *tables, cx)
     }
 
     /// Item requires monomorphization.
-    pub(crate) fn requires_monomorphization(&self, def_id: DefId) -> bool {
-        self.cx.requires_monomorphization(def_id)
+    fn requires_monomorphization(&self, def_id: DefId) -> bool {
+        let tables = self.tables.borrow();
+        let cx = &*self.cx.borrow();
+        let did = tables[def_id];
+        cx.requires_monomorphization(did)
     }
 
     /// Resolve an instance from the given function definition and generic arguments.
-    pub(crate) fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance> {
-        self.cx.resolve_instance(def, args)
+    fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let def_id = def.0.internal(&mut *tables, cx.tcx);
+        let args_ref = args.internal(&mut *tables, cx.tcx);
+        cx.resolve_instance(def_id, args_ref).map(|inst| inst.stable(&mut *tables, cx))
     }
 
     /// Resolve an instance for drop_in_place for the given type.
-    pub(crate) fn resolve_drop_in_place(&self, ty: Ty) -> Instance {
-        self.cx.resolve_drop_in_place(ty)
+    fn resolve_drop_in_place(&self, ty: Ty) -> Instance {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let internal_ty = ty.internal(&mut *tables, cx.tcx);
+
+        cx.resolve_drop_in_place(internal_ty).stable(&mut *tables, cx)
     }
 
     /// Resolve instance for a function pointer.
-    pub(crate) fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance> {
-        self.cx.resolve_for_fn_ptr(def, args)
+    fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let def_id = def.0.internal(&mut *tables, cx.tcx);
+        let args_ref = args.internal(&mut *tables, cx.tcx);
+        cx.resolve_for_fn_ptr(def_id, args_ref).stable(&mut *tables, cx)
     }
 
     /// Resolve instance for a closure with the requested type.
-    pub(crate) fn resolve_closure(
+    fn resolve_closure(
         &self,
         def: ClosureDef,
         args: &GenericArgs,
         kind: ClosureKind,
     ) -> Option<Instance> {
-        self.cx.resolve_closure(def, args, kind)
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let def_id = def.0.internal(&mut *tables, cx.tcx);
+        let args_ref = args.internal(&mut *tables, cx.tcx);
+        let closure_kind = kind.internal(&mut *tables, cx.tcx);
+        cx.resolve_closure(def_id, args_ref, closure_kind).map(|inst| inst.stable(&mut *tables, cx))
     }
 
     /// Evaluate a static's initializer.
-    pub(crate) fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
-        self.cx.eval_static_initializer(def)
+    fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let def_id = def.0.internal(&mut *tables, cx.tcx);
+
+        cx.eval_static_initializer(def_id).stable(&mut *tables, cx)
     }
 
     /// Try to evaluate an instance into a constant.
-    pub(crate) fn eval_instance(
-        &self,
-        def: InstanceDef,
-        const_ty: Ty,
-    ) -> Result<Allocation, Error> {
-        self.cx.eval_instance(def, const_ty)
+    fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {
+        let mut tables = self.tables.borrow_mut();
+        let instance = tables.instances[def];
+        let cx = &*self.cx.borrow();
+        let const_ty = const_ty.internal(&mut *tables, cx.tcx);
+        cx.eval_instance(instance)
+            .map(|const_val| alloc::try_new_allocation(const_ty, const_val, &mut *tables, cx))
+            .map_err(|e| e.stable(&mut *tables, cx))?
     }
 
     /// Retrieve global allocation for the given allocation ID.
-    pub(crate) fn global_alloc(&self, id: AllocId) -> GlobalAlloc {
-        self.cx.global_alloc(id)
+    fn global_alloc(&self, id: AllocId) -> GlobalAlloc {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let alloc_id = id.internal(&mut *tables, cx.tcx);
+        cx.global_alloc(alloc_id).stable(&mut *tables, cx)
     }
 
     /// Retrieve the id for the virtual table.
-    pub(crate) fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId> {
-        self.cx.vtable_allocation(global_alloc)
+    fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId> {
+        let mut tables = self.tables.borrow_mut();
+        let GlobalAlloc::VTable(ty, trait_ref) = global_alloc else {
+            return None;
+        };
+        let cx = &*self.cx.borrow();
+        let ty = ty.internal(&mut *tables, cx.tcx);
+        let trait_ref = trait_ref.internal(&mut *tables, cx.tcx);
+        let alloc_id = cx.vtable_allocation(ty, trait_ref);
+        Some(alloc_id.stable(&mut *tables, cx))
     }
 
-    pub(crate) fn krate(&self, def_id: DefId) -> Crate {
-        self.cx.krate(def_id)
+    fn krate(&self, def_id: DefId) -> Crate {
+        let tables = self.tables.borrow();
+        let cx = &*self.cx.borrow();
+        smir_crate(cx, tables[def_id].krate)
     }
 
-    pub(crate) fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
-        self.cx.instance_name(def, trimmed)
+    fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
+        let tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let instance = tables.instances[def];
+        cx.instance_name(instance, trimmed)
     }
 
     /// Return information about the target machine.
-    pub(crate) fn target_info(&self) -> MachineInfo {
-        self.cx.target_info()
+    fn target_info(&self) -> MachineInfo {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        MachineInfo {
+            endian: cx.target_endian().stable(&mut *tables, cx),
+            pointer_width: MachineSize::from_bits(cx.target_pointer_size()),
+        }
     }
 
     /// Get an instance ABI.
-    pub(crate) fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
-        self.cx.instance_abi(def)
+    fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let instance = tables.instances[def];
+        cx.instance_abi(instance).map(|fn_abi| fn_abi.stable(&mut *tables, cx))
     }
 
     /// Get the ABI of a function pointer.
-    pub(crate) fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> {
-        self.cx.fn_ptr_abi(fn_ptr)
+    fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let sig = fn_ptr.internal(&mut *tables, cx.tcx);
+        cx.fn_ptr_abi(sig).map(|fn_abi| fn_abi.stable(&mut *tables, cx))
     }
 
     /// Get the layout of a type.
-    pub(crate) fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
-        self.cx.ty_layout(ty)
+    fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let internal_ty = ty.internal(&mut *tables, cx.tcx);
+        cx.ty_layout(internal_ty).map(|layout| layout.stable(&mut *tables, cx))
     }
 
     /// Get the layout shape.
-    pub(crate) fn layout_shape(&self, id: Layout) -> LayoutShape {
-        self.cx.layout_shape(id)
+    fn layout_shape(&self, id: Layout) -> LayoutShape {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        id.internal(&mut *tables, cx.tcx).0.stable(&mut *tables, cx)
     }
 
     /// Get a debug string representation of a place.
-    pub(crate) fn place_pretty(&self, place: &Place) -> String {
-        self.cx.place_pretty(place)
+    fn place_pretty(&self, place: &Place) -> String {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+
+        format!("{:?}", place.internal(&mut *tables, cx.tcx))
     }
 
     /// Get the resulting type of binary operation.
-    pub(crate) fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
-        self.cx.binop_ty(bin_op, rhs, lhs)
+    fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let rhs_internal = rhs.internal(&mut *tables, cx.tcx);
+        let lhs_internal = lhs.internal(&mut *tables, cx.tcx);
+        let bin_op_internal = bin_op.internal(&mut *tables, cx.tcx);
+        cx.binop_ty(bin_op_internal, rhs_internal, lhs_internal).stable(&mut *tables, cx)
     }
 
     /// Get the resulting type of unary operation.
-    pub(crate) fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
-        self.cx.unop_ty(un_op, arg)
+    fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let un_op = un_op.internal(&mut *tables, cx.tcx);
+        let arg = arg.internal(&mut *tables, cx.tcx);
+        cx.unop_ty(un_op, arg).stable(&mut *tables, cx)
     }
 
     /// Get all associated items of a definition.
-    pub(crate) fn associated_items(&self, def_id: DefId) -> AssocItems {
-        self.cx.associated_items(def_id)
+    fn associated_items(&self, def_id: DefId) -> AssocItems {
+        let mut tables = self.tables.borrow_mut();
+        let cx = &*self.cx.borrow();
+        let did = tables[def_id];
+        cx.associated_items(did).iter().map(|assoc| assoc.stable(&mut *tables, cx)).collect()
     }
 }
 
 // A thread local variable that stores a pointer to [`SmirInterface`].
 scoped_tls::scoped_thread_local!(static TLV: Cell<*const ()>);
 
-pub(crate) fn run<'tcx, T, F>(interface: &SmirInterface<'tcx>, f: F) -> Result<T, Error>
+pub(crate) fn run<F, T>(interface: &dyn SmirInterface, f: F) -> Result<T, Error>
 where
     F: FnOnce() -> T,
 {
     if TLV.is_set() {
         Err(Error::from("StableMIR already running"))
     } else {
-        let ptr: *const () = (interface as *const SmirInterface<'tcx>) as *const ();
+        let ptr: *const () = (&raw const interface) as _;
         TLV.set(&Cell::new(ptr), || Ok(f()))
     }
 }
@@ -507,11 +1079,22 @@ where
 ///
 /// I.e., This function will load the current interface and calls a function with it.
 /// Do not nest these, as that will ICE.
-pub(crate) fn with<R>(f: impl FnOnce(&SmirInterface<'_>) -> R) -> R {
+pub(crate) fn with<R>(f: impl FnOnce(&dyn SmirInterface) -> R) -> R {
     assert!(TLV.is_set());
     TLV.with(|tlv| {
         let ptr = tlv.get();
         assert!(!ptr.is_null());
-        f(unsafe { &*(ptr as *const SmirInterface<'_>) })
+        f(unsafe { *(ptr as *const &dyn SmirInterface) })
     })
 }
+
+fn smir_crate<'tcx>(
+    cx: &SmirCtxt<'tcx, BridgeTys>,
+    crate_num: rustc_span::def_id::CrateNum,
+) -> Crate {
+    let name = cx.crate_name(crate_num);
+    let is_local = cx.crate_is_local(crate_num);
+    let id = cx.crate_num_id(crate_num);
+    debug!(?name, ?crate_num, "smir_crate");
+    Crate { id, name, is_local }
+}
diff --git a/compiler/rustc_smir/src/stable_mir/error.rs b/compiler/rustc_smir/src/stable_mir/error.rs
index 050752e41eb..3f9d67954b9 100644
--- a/compiler/rustc_smir/src/stable_mir/error.rs
+++ b/compiler/rustc_smir/src/stable_mir/error.rs
@@ -7,6 +7,10 @@
 use std::fmt::{Debug, Display, Formatter};
 use std::{fmt, io};
 
+use rustc_smir::bridge::SmirError;
+
+use crate::rustc_smir;
+
 macro_rules! error {
      ($fmt: literal $(,)?) => { Error(format!($fmt)) };
      ($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg)*)) };
@@ -30,10 +34,14 @@ pub enum CompilerError<T> {
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct Error(pub(crate) String);
 
-impl Error {
-    pub fn new(msg: String) -> Self {
+impl SmirError for Error {
+    fn new(msg: String) -> Self {
         Self(msg)
     }
+
+    fn from_internal<T: Debug>(err: T) -> Self {
+        Self(format!("{err:?}"))
+    }
 }
 
 impl From<&str> for Error {
diff --git a/compiler/rustc_smir/src/stable_mir/mir/alloc.rs b/compiler/rustc_smir/src/stable_mir/mir/alloc.rs
index 782f52888b7..26f30898a9c 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/alloc.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/alloc.rs
@@ -5,8 +5,8 @@ use std::io::Read;
 use serde::Serialize;
 use stable_mir::mir::mono::{Instance, StaticDef};
 use stable_mir::target::{Endian, MachineInfo};
-use stable_mir::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty};
-use stable_mir::{Error, with};
+use stable_mir::ty::{Allocation, Binder, ExistentialTraitRef, Ty};
+use stable_mir::{Error, IndexedVal, with};
 
 use crate::stable_mir;
 
diff --git a/compiler/rustc_smir/src/stable_mir/mir/mono.rs b/compiler/rustc_smir/src/stable_mir/mir/mono.rs
index f5239cccae1..5f177416714 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/mono.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/mono.rs
@@ -1,14 +1,15 @@
 use std::fmt::{Debug, Formatter};
 use std::io;
 
+use rustc_smir::bridge::SmirError;
 use serde::Serialize;
 use stable_mir::abi::FnAbi;
 use stable_mir::crate_def::CrateDef;
 use stable_mir::mir::Body;
-use stable_mir::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
-use stable_mir::{CrateItem, DefId, Error, ItemKind, Opaque, Symbol, with};
+use stable_mir::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, Ty};
+use stable_mir::{CrateItem, DefId, Error, IndexedVal, ItemKind, Opaque, Symbol, with};
 
-use crate::stable_mir;
+use crate::{rustc_smir, stable_mir};
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum MonoItem {
diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs
index b068a9a1081..a7347e9b021 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs
@@ -7,8 +7,8 @@ use fmt::{Display, Formatter};
 use stable_mir::mir::{
     Operand, Place, RawPtrKind, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents,
 };
-use stable_mir::ty::{AdtKind, AssocKind, IndexedVal, MirConst, Ty, TyConst};
-use stable_mir::{Body, CrateDef, Mutability, with};
+use stable_mir::ty::{AdtKind, AssocKind, MirConst, Ty, TyConst};
+use stable_mir::{Body, CrateDef, IndexedVal, Mutability, with};
 
 use super::{AggregateKind, AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind};
 use crate::stable_mir;
diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs
index c59758d4ad3..70c09c12854 100644
--- a/compiler/rustc_smir/src/stable_mir/mod.rs
+++ b/compiler/rustc_smir/src/stable_mir/mod.rs
@@ -27,17 +27,25 @@
 use std::fmt::Debug;
 use std::{fmt, io};
 
+pub(crate) use rustc_smir::IndexedVal;
+use rustc_smir::Tables;
+use rustc_smir::context::SmirCtxt;
 use serde::Serialize;
 use stable_mir::compiler_interface::with;
 pub use stable_mir::crate_def::{CrateDef, CrateDefItems, CrateDefType, DefId};
 pub use stable_mir::error::*;
 use stable_mir::mir::mono::StaticDef;
 use stable_mir::mir::{Body, Mutability};
-use stable_mir::ty::{AssocItem, FnDef, ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
+use stable_mir::ty::{
+    AssocItem, FnDef, ForeignModuleDef, ImplDef, ProvenanceMap, Span, TraitDef, Ty,
+};
+use stable_mir::unstable::Stable;
 
-use crate::stable_mir;
+use crate::{rustc_smir, stable_mir};
 
 pub mod abi;
+mod alloc;
+pub(crate) mod unstable;
 #[macro_use]
 pub mod crate_def;
 pub mod compiler_interface;
@@ -237,3 +245,60 @@ impl std::fmt::Debug for Opaque {
 pub fn opaque<T: Debug>(value: &T) -> Opaque {
     Opaque(format!("{value:?}"))
 }
+
+macro_rules! bridge_impl {
+    ($name: ident, $ty: ty) => {
+        impl rustc_smir::bridge::$name<compiler_interface::BridgeTys> for $ty {
+            fn new(def: stable_mir::DefId) -> Self {
+                Self(def)
+            }
+        }
+    };
+}
+
+bridge_impl!(CrateItem, stable_mir::CrateItem);
+bridge_impl!(AdtDef, stable_mir::ty::AdtDef);
+bridge_impl!(ForeignModuleDef, stable_mir::ty::ForeignModuleDef);
+bridge_impl!(ForeignDef, stable_mir::ty::ForeignDef);
+bridge_impl!(FnDef, stable_mir::ty::FnDef);
+bridge_impl!(ClosureDef, stable_mir::ty::ClosureDef);
+bridge_impl!(CoroutineDef, stable_mir::ty::CoroutineDef);
+bridge_impl!(CoroutineClosureDef, stable_mir::ty::CoroutineClosureDef);
+bridge_impl!(AliasDef, stable_mir::ty::AliasDef);
+bridge_impl!(ParamDef, stable_mir::ty::ParamDef);
+bridge_impl!(BrNamedDef, stable_mir::ty::BrNamedDef);
+bridge_impl!(TraitDef, stable_mir::ty::TraitDef);
+bridge_impl!(GenericDef, stable_mir::ty::GenericDef);
+bridge_impl!(ConstDef, stable_mir::ty::ConstDef);
+bridge_impl!(ImplDef, stable_mir::ty::ImplDef);
+bridge_impl!(RegionDef, stable_mir::ty::RegionDef);
+bridge_impl!(CoroutineWitnessDef, stable_mir::ty::CoroutineWitnessDef);
+bridge_impl!(AssocDef, stable_mir::ty::AssocDef);
+bridge_impl!(OpaqueDef, stable_mir::ty::OpaqueDef);
+bridge_impl!(StaticDef, stable_mir::mir::mono::StaticDef);
+
+impl rustc_smir::bridge::Prov<compiler_interface::BridgeTys> for stable_mir::ty::Prov {
+    fn new(aid: stable_mir::mir::alloc::AllocId) -> Self {
+        Self(aid)
+    }
+}
+
+impl rustc_smir::bridge::Allocation<compiler_interface::BridgeTys> for stable_mir::ty::Allocation {
+    fn new<'tcx>(
+        bytes: Vec<Option<u8>>,
+        ptrs: Vec<(usize, rustc_middle::mir::interpret::AllocId)>,
+        align: u64,
+        mutability: rustc_middle::mir::Mutability,
+        tables: &mut Tables<'tcx, compiler_interface::BridgeTys>,
+        cx: &SmirCtxt<'tcx, compiler_interface::BridgeTys>,
+    ) -> Self {
+        Self {
+            bytes,
+            provenance: ProvenanceMap {
+                ptrs: ptrs.iter().map(|(i, aid)| (*i, tables.prov(*aid))).collect(),
+            },
+            align,
+            mutability: mutability.stable(tables, cx),
+        }
+    }
+}
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 398738d1c38..004a7c02234 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -7,7 +7,7 @@ use stable_mir::crate_def::{CrateDef, CrateDefItems, CrateDefType};
 use stable_mir::mir::alloc::{AllocId, read_target_int, read_target_uint};
 use stable_mir::mir::mono::StaticDef;
 use stable_mir::target::MachineInfo;
-use stable_mir::{Filename, Opaque};
+use stable_mir::{Filename, IndexedVal, Opaque};
 
 use super::abi::ReprOptions;
 use super::mir::{Body, Mutability, Safety};
@@ -298,6 +298,12 @@ pub struct LineInfo {
     pub end_col: usize,
 }
 
+impl LineInfo {
+    pub fn from(lines: (usize, usize, usize, usize)) -> Self {
+        LineInfo { start_line: lines.0, start_col: lines.1, end_line: lines.2, end_col: lines.3 }
+    }
+}
+
 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum TyKind {
     RigidTy(RigidTy),
@@ -1557,15 +1563,9 @@ pub enum PredicatePolarity {
     Negative,
 }
 
-pub trait IndexedVal {
-    fn to_val(index: usize) -> Self;
-
-    fn to_index(&self) -> usize;
-}
-
 macro_rules! index_impl {
     ($name:ident) => {
-        impl IndexedVal for $name {
+        impl stable_mir::IndexedVal for $name {
             fn to_val(index: usize) -> Self {
                 $name(index)
             }
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs
index f878b6e6b71..4cbe02bfa0d 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs
@@ -5,55 +5,76 @@
 
 // Prefer importing stable_mir over internal rustc constructs to make this file more readable.
 
-use rustc_middle::ty::{self as rustc_ty, Const as InternalConst, Ty as InternalTy, TyCtxt};
+use rustc_middle::ty::{self as rustc_ty, Const as InternalConst, Ty as InternalTy};
+use rustc_smir::Tables;
 use rustc_span::Symbol;
 use stable_mir::abi::Layout;
+use stable_mir::compiler_interface::BridgeTys;
 use stable_mir::mir::alloc::AllocId;
 use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
 use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, RawPtrKind, Safety, UnOp};
 use stable_mir::ty::{
     Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, DynKind,
     ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
-    GenericArgKind, GenericArgs, IndexedVal, IntTy, MirConst, Movability, Pattern, Region, RigidTy,
-    Span, TermKind, TraitRef, Ty, TyConst, UintTy, VariantDef, VariantIdx,
+    GenericArgKind, GenericArgs, IntTy, MirConst, Movability, Pattern, Region, RigidTy, Span,
+    TermKind, TraitRef, Ty, TyConst, UintTy, VariantDef, VariantIdx,
 };
-use stable_mir::{CrateItem, CrateNum, DefId};
+use stable_mir::unstable::{InternalCx, RustcInternal};
+use stable_mir::{CrateItem, CrateNum, DefId, IndexedVal};
 
-use super::RustcInternal;
-use crate::rustc_smir::Tables;
-use crate::stable_mir;
+use crate::{rustc_smir, stable_mir};
 
 impl RustcInternal for CrateItem {
     type T<'tcx> = rustc_span::def_id::DefId;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         self.0.internal(tables, tcx)
     }
 }
 
 impl RustcInternal for CrateNum {
     type T<'tcx> = rustc_span::def_id::CrateNum;
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         rustc_span::def_id::CrateNum::from_usize(*self)
     }
 }
 
 impl RustcInternal for DefId {
     type T<'tcx> = rustc_span::def_id::DefId;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         tcx.lift(tables.def_ids[*self]).unwrap()
     }
 }
 
 impl RustcInternal for GenericArgs {
     type T<'tcx> = rustc_ty::GenericArgsRef<'tcx>;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
-        tcx.mk_args_from_iter(self.0.iter().map(|arg| arg.internal(tables, tcx)))
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
+        InternalCx::mk_args_from_iter(tcx, self.0.iter().map(|arg| arg.internal(tables, tcx)))
     }
 }
 
 impl RustcInternal for GenericArgKind {
     type T<'tcx> = rustc_ty::GenericArg<'tcx>;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         let arg: rustc_ty::GenericArg<'tcx> = match self {
             GenericArgKind::Lifetime(reg) => reg.internal(tables, tcx).into(),
             GenericArgKind::Type(ty) => ty.internal(tables, tcx).into(),
@@ -65,29 +86,45 @@ impl RustcInternal for GenericArgKind {
 
 impl RustcInternal for Region {
     type T<'tcx> = rustc_ty::Region<'tcx>;
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         // Cannot recover region. Use erased for now.
-        tcx.lifetimes.re_erased
+        tcx.lifetimes_re_erased()
     }
 }
 
 impl RustcInternal for Ty {
     type T<'tcx> = InternalTy<'tcx>;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         tcx.lift(tables.types[*self]).unwrap()
     }
 }
 
 impl RustcInternal for TyConst {
     type T<'tcx> = InternalConst<'tcx>;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         tcx.lift(tables.ty_consts[self.id]).unwrap()
     }
 }
 
 impl RustcInternal for Pattern {
     type T<'tcx> = rustc_ty::Pattern<'tcx>;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         tcx.mk_pat(match self {
             Pattern::Range { start, end, include_end: _ } => rustc_ty::PatternKind::Range {
                 start: start.as_ref().unwrap().internal(tables, tcx),
@@ -100,7 +137,11 @@ impl RustcInternal for Pattern {
 impl RustcInternal for RigidTy {
     type T<'tcx> = rustc_ty::TyKind<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             RigidTy::Bool => rustc_ty::TyKind::Bool,
             RigidTy::Char => rustc_ty::TyKind::Char,
@@ -164,7 +205,11 @@ impl RustcInternal for RigidTy {
 impl RustcInternal for IntTy {
     type T<'tcx> = rustc_ty::IntTy;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             IntTy::Isize => rustc_ty::IntTy::Isize,
             IntTy::I8 => rustc_ty::IntTy::I8,
@@ -179,7 +224,11 @@ impl RustcInternal for IntTy {
 impl RustcInternal for UintTy {
     type T<'tcx> = rustc_ty::UintTy;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             UintTy::Usize => rustc_ty::UintTy::Usize,
             UintTy::U8 => rustc_ty::UintTy::U8,
@@ -194,7 +243,11 @@ impl RustcInternal for UintTy {
 impl RustcInternal for FloatTy {
     type T<'tcx> = rustc_ty::FloatTy;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             FloatTy::F16 => rustc_ty::FloatTy::F16,
             FloatTy::F32 => rustc_ty::FloatTy::F32,
@@ -207,7 +260,11 @@ impl RustcInternal for FloatTy {
 impl RustcInternal for Mutability {
     type T<'tcx> = rustc_ty::Mutability;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             Mutability::Not => rustc_ty::Mutability::Not,
             Mutability::Mut => rustc_ty::Mutability::Mut,
@@ -218,7 +275,11 @@ impl RustcInternal for Mutability {
 impl RustcInternal for Movability {
     type T<'tcx> = rustc_ty::Movability;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             Movability::Static => rustc_ty::Movability::Static,
             Movability::Movable => rustc_ty::Movability::Movable,
@@ -229,7 +290,11 @@ impl RustcInternal for Movability {
 impl RustcInternal for RawPtrKind {
     type T<'tcx> = rustc_middle::mir::RawPtrKind;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             RawPtrKind::Mut => rustc_middle::mir::RawPtrKind::Mut,
             RawPtrKind::Const => rustc_middle::mir::RawPtrKind::Const,
@@ -241,7 +306,11 @@ impl RustcInternal for RawPtrKind {
 impl RustcInternal for FnSig {
     type T<'tcx> = rustc_ty::FnSig<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         tcx.lift(rustc_ty::FnSig {
             inputs_and_output: tcx.mk_type_list(&self.inputs_and_output.internal(tables, tcx)),
             c_variadic: self.c_variadic,
@@ -255,7 +324,11 @@ impl RustcInternal for FnSig {
 impl RustcInternal for VariantIdx {
     type T<'tcx> = rustc_abi::VariantIdx;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         rustc_abi::VariantIdx::from(self.to_index())
     }
 }
@@ -263,14 +336,22 @@ impl RustcInternal for VariantIdx {
 impl RustcInternal for VariantDef {
     type T<'tcx> = &'tcx rustc_ty::VariantDef;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         self.adt_def.internal(tables, tcx).variant(self.idx.internal(tables, tcx))
     }
 }
 
 impl RustcInternal for MirConst {
     type T<'tcx> = rustc_middle::mir::Const<'tcx>;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         let constant = tables.mir_consts[self.id];
         match constant {
             rustc_middle::mir::Const::Ty(ty, ct) => {
@@ -292,7 +373,11 @@ impl RustcInternal for MirConst {
 impl RustcInternal for MonoItem {
     type T<'tcx> = rustc_middle::mir::mono::MonoItem<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         use rustc_middle::mir::mono as rustc_mono;
         match self {
             MonoItem::Fn(instance) => rustc_mono::MonoItem::Fn(instance.internal(tables, tcx)),
@@ -307,7 +392,11 @@ impl RustcInternal for MonoItem {
 impl RustcInternal for Instance {
     type T<'tcx> = rustc_ty::Instance<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         tcx.lift(tables.instances[self.def]).unwrap()
     }
 }
@@ -315,7 +404,11 @@ impl RustcInternal for Instance {
 impl RustcInternal for StaticDef {
     type T<'tcx> = rustc_span::def_id::DefId;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         self.0.internal(tables, tcx)
     }
 }
@@ -328,7 +421,11 @@ where
 {
     type T<'tcx> = rustc_ty::Binder<'tcx, T::T<'tcx>>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         rustc_ty::Binder::bind_with_vars(
             self.value.internal(tables, tcx),
             tcx.mk_bound_variable_kinds_from_iter(
@@ -341,7 +438,11 @@ where
 impl RustcInternal for BoundVariableKind {
     type T<'tcx> = rustc_ty::BoundVariableKind;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             BoundVariableKind::Ty(kind) => rustc_ty::BoundVariableKind::Ty(match kind {
                 BoundTyKind::Anon => rustc_ty::BoundTyKind::Anon,
@@ -366,7 +467,11 @@ impl RustcInternal for BoundVariableKind {
 impl RustcInternal for DynKind {
     type T<'tcx> = rustc_ty::DynKind;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             DynKind::Dyn => rustc_ty::DynKind::Dyn,
         }
@@ -376,7 +481,11 @@ impl RustcInternal for DynKind {
 impl RustcInternal for ExistentialPredicate {
     type T<'tcx> = rustc_ty::ExistentialPredicate<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             ExistentialPredicate::Trait(trait_ref) => {
                 rustc_ty::ExistentialPredicate::Trait(trait_ref.internal(tables, tcx))
@@ -394,9 +503,13 @@ impl RustcInternal for ExistentialPredicate {
 impl RustcInternal for ExistentialProjection {
     type T<'tcx> = rustc_ty::ExistentialProjection<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
-        rustc_ty::ExistentialProjection::new_from_args(
-            tcx,
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
+        use rustc_smir::context::SmirExistentialProjection;
+        tcx.new_from_args(
             self.def_id.0.internal(tables, tcx),
             self.generic_args.internal(tables, tcx),
             self.term.internal(tables, tcx),
@@ -407,7 +520,11 @@ impl RustcInternal for ExistentialProjection {
 impl RustcInternal for TermKind {
     type T<'tcx> = rustc_ty::Term<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             TermKind::Type(ty) => ty.internal(tables, tcx).into(),
             TermKind::Const(cnst) => cnst.internal(tables, tcx).into(),
@@ -418,9 +535,13 @@ impl RustcInternal for TermKind {
 impl RustcInternal for ExistentialTraitRef {
     type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
-        rustc_ty::ExistentialTraitRef::new_from_args(
-            tcx,
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
+        use rustc_smir::context::SmirExistentialTraitRef;
+        tcx.new_from_args(
             self.def_id.0.internal(tables, tcx),
             self.generic_args.internal(tables, tcx),
         )
@@ -430,18 +551,23 @@ impl RustcInternal for ExistentialTraitRef {
 impl RustcInternal for TraitRef {
     type T<'tcx> = rustc_ty::TraitRef<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
-        rustc_ty::TraitRef::new_from_args(
-            tcx,
-            self.def_id.0.internal(tables, tcx),
-            self.args().internal(tables, tcx),
-        )
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
+        use rustc_smir::context::SmirTraitRef;
+        tcx.new_from_args(self.def_id.0.internal(tables, tcx), self.args().internal(tables, tcx))
     }
 }
 
 impl RustcInternal for AllocId {
     type T<'tcx> = rustc_middle::mir::interpret::AllocId;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         tcx.lift(tables.alloc_ids[*self]).unwrap()
     }
 }
@@ -449,7 +575,11 @@ impl RustcInternal for AllocId {
 impl RustcInternal for ClosureKind {
     type T<'tcx> = rustc_ty::ClosureKind;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             ClosureKind::Fn => rustc_ty::ClosureKind::Fn,
             ClosureKind::FnMut => rustc_ty::ClosureKind::FnMut,
@@ -460,15 +590,23 @@ impl RustcInternal for ClosureKind {
 
 impl RustcInternal for AdtDef {
     type T<'tcx> = rustc_ty::AdtDef<'tcx>;
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
-        tcx.adt_def(self.0.internal(tables, tcx))
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
+        InternalCx::adt_def(tcx, self.0.internal(tables, tcx))
     }
 }
 
 impl RustcInternal for Abi {
     type T<'tcx> = rustc_abi::ExternAbi;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match *self {
             Abi::Rust => rustc_abi::ExternAbi::Rust,
             Abi::C { unwind } => rustc_abi::ExternAbi::C { unwind },
@@ -504,7 +642,11 @@ impl RustcInternal for Abi {
 impl RustcInternal for Safety {
     type T<'tcx> = rustc_hir::Safety;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             Safety::Unsafe => rustc_hir::Safety::Unsafe,
             Safety::Safe => rustc_hir::Safety::Safe,
@@ -514,15 +656,23 @@ impl RustcInternal for Safety {
 impl RustcInternal for Span {
     type T<'tcx> = rustc_span::Span;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
-        tables[*self]
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
+        tables.spans[*self]
     }
 }
 
 impl RustcInternal for Layout {
     type T<'tcx> = rustc_abi::Layout<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         tcx.lift(tables.layouts[*self]).unwrap()
     }
 }
@@ -530,7 +680,11 @@ impl RustcInternal for Layout {
 impl RustcInternal for Place {
     type T<'tcx> = rustc_middle::mir::Place<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         rustc_middle::mir::Place {
             local: rustc_middle::mir::Local::from_usize(self.local),
             projection: tcx.mk_place_elems(&self.projection.internal(tables, tcx)),
@@ -541,7 +695,11 @@ impl RustcInternal for Place {
 impl RustcInternal for ProjectionElem {
     type T<'tcx> = rustc_middle::mir::PlaceElem<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             ProjectionElem::Deref => rustc_middle::mir::PlaceElem::Deref,
             ProjectionElem::Field(idx, ty) => {
@@ -574,7 +732,11 @@ impl RustcInternal for ProjectionElem {
 impl RustcInternal for BinOp {
     type T<'tcx> = rustc_middle::mir::BinOp;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             BinOp::Add => rustc_middle::mir::BinOp::Add,
             BinOp::AddUnchecked => rustc_middle::mir::BinOp::AddUnchecked,
@@ -606,7 +768,11 @@ impl RustcInternal for BinOp {
 impl RustcInternal for UnOp {
     type T<'tcx> = rustc_middle::mir::UnOp;
 
-    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        _tables: &mut Tables<'_, BridgeTys>,
+        _tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         match self {
             UnOp::Not => rustc_middle::mir::UnOp::Not,
             UnOp::Neg => rustc_middle::mir::UnOp::Neg,
@@ -621,7 +787,11 @@ where
 {
     type T<'tcx> = T::T<'tcx>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         (*self).internal(tables, tcx)
     }
 }
@@ -632,7 +802,11 @@ where
 {
     type T<'tcx> = Option<T::T<'tcx>>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         self.as_ref().map(|inner| inner.internal(tables, tcx))
     }
 }
@@ -643,7 +817,11 @@ where
 {
     type T<'tcx> = Vec<T::T<'tcx>>;
 
-    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx> {
         self.iter().map(|e| e.internal(tables, tcx)).collect()
     }
 }
diff --git a/compiler/rustc_smir/src/stable_mir/unstable/convert/mod.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/mod.rs
new file mode 100644
index 00000000000..6e1b85671f8
--- /dev/null
+++ b/compiler/rustc_smir/src/stable_mir/unstable/convert/mod.rs
@@ -0,0 +1,111 @@
+//! This module holds the logic to convert rustc internal ADTs into stable mir ADTs.
+//!
+//! The conversion from stable to internal is not meant to be complete,
+//! and it should be added as when needed to be passed as input to rustc_smir functions.
+//!
+//! For contributors, please make sure to avoid calling rustc's internal functions and queries.
+//! These should be done via `rustc_smir` APIs, but it's possible to access ADT fields directly.
+
+use std::ops::RangeInclusive;
+
+use rustc_smir::Tables;
+use rustc_smir::context::SmirCtxt;
+use stable_mir::compiler_interface::BridgeTys;
+
+use super::Stable;
+use crate::{rustc_smir, stable_mir};
+
+mod internal;
+mod stable;
+
+impl<'tcx, T> Stable<'tcx> for &T
+where
+    T: Stable<'tcx>,
+{
+    type T = T::T;
+
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        (*self).stable(tables, cx)
+    }
+}
+
+impl<'tcx, T> Stable<'tcx> for Option<T>
+where
+    T: Stable<'tcx>,
+{
+    type T = Option<T::T>;
+
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        self.as_ref().map(|value| value.stable(tables, cx))
+    }
+}
+
+impl<'tcx, T, E> Stable<'tcx> for Result<T, E>
+where
+    T: Stable<'tcx>,
+    E: Stable<'tcx>,
+{
+    type T = Result<T::T, E::T>;
+
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        match self {
+            Ok(val) => Ok(val.stable(tables, cx)),
+            Err(error) => Err(error.stable(tables, cx)),
+        }
+    }
+}
+
+impl<'tcx, T> Stable<'tcx> for &[T]
+where
+    T: Stable<'tcx>,
+{
+    type T = Vec<T::T>;
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        self.iter().map(|e| e.stable(tables, cx)).collect()
+    }
+}
+
+impl<'tcx, T, U> Stable<'tcx> for (T, U)
+where
+    T: Stable<'tcx>,
+    U: Stable<'tcx>,
+{
+    type T = (T::T, U::T);
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        (self.0.stable(tables, cx), self.1.stable(tables, cx))
+    }
+}
+
+impl<'tcx, T> Stable<'tcx> for RangeInclusive<T>
+where
+    T: Stable<'tcx>,
+{
+    type T = RangeInclusive<T::T>;
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        RangeInclusive::new(self.start().stable(tables, cx), self.end().stable(tables, cx))
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/abi.rs
index 35d5b7fb89a..d8823a0d10c 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
+++ b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/abi.rs
@@ -4,22 +4,25 @@
 
 use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call};
 use rustc_middle::ty;
+use rustc_smir::Tables;
+use rustc_smir::context::SmirCtxt;
 use rustc_target::callconv;
 use stable_mir::abi::{
     AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength,
     IntegerType, Layout, LayoutShape, PassMode, Primitive, ReprFlags, ReprOptions, Scalar,
     TagEncoding, TyAndLayout, ValueAbi, VariantsShape, WrappingRange,
 };
-use stable_mir::opaque;
+use stable_mir::compiler_interface::BridgeTys;
 use stable_mir::target::MachineSize as Size;
-use stable_mir::ty::{Align, IndexedVal, VariantIdx};
+use stable_mir::ty::{Align, VariantIdx};
+use stable_mir::unstable::Stable;
+use stable_mir::{IndexedVal, opaque};
 
-use crate::rustc_smir::{Stable, Tables};
-use crate::stable_mir;
+use crate::{rustc_smir, stable_mir};
 
 impl<'tcx> Stable<'tcx> for rustc_abi::VariantIdx {
     type T = VariantIdx;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         VariantIdx::to_val(self.as_usize())
     }
 }
@@ -27,7 +30,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::VariantIdx {
 impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
     type T = stable_mir::target::Endian;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
             rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
@@ -38,29 +41,41 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
 impl<'tcx> Stable<'tcx> for rustc_abi::TyAndLayout<'tcx, ty::Ty<'tcx>> {
     type T = TyAndLayout;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        TyAndLayout { ty: self.ty.stable(tables), layout: self.layout.stable(tables) }
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        TyAndLayout { ty: self.ty.stable(tables, cx), layout: self.layout.stable(tables, cx) }
     }
 }
 
 impl<'tcx> Stable<'tcx> for rustc_abi::Layout<'tcx> {
     type T = Layout;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        tables.layout_id(tables.tcx.lift(*self).unwrap())
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        tables.layout_id(cx.lift(*self).unwrap())
     }
 }
 
 impl<'tcx> Stable<'tcx> for rustc_abi::LayoutData<rustc_abi::FieldIdx, rustc_abi::VariantIdx> {
     type T = LayoutShape;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         LayoutShape {
-            fields: self.fields.stable(tables),
-            variants: self.variants.stable(tables),
-            abi: self.backend_repr.stable(tables),
-            abi_align: self.align.abi.stable(tables),
-            size: self.size.stable(tables),
+            fields: self.fields.stable(tables, cx),
+            variants: self.variants.stable(tables, cx),
+            abi: self.backend_repr.stable(tables, cx),
+            abi_align: self.align.abi.stable(tables, cx),
+            size: self.size.stable(tables, cx),
         }
     }
 }
@@ -68,14 +83,18 @@ impl<'tcx> Stable<'tcx> for rustc_abi::LayoutData<rustc_abi::FieldIdx, rustc_abi
 impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> {
     type T = FnAbi;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         assert!(self.args.len() >= self.fixed_count as usize);
         assert!(!self.c_variadic || matches!(self.conv, CanonAbi::C));
         FnAbi {
-            args: self.args.as_ref().stable(tables),
-            ret: self.ret.stable(tables),
+            args: self.args.as_ref().stable(tables, cx),
+            ret: self.ret.stable(tables, cx),
             fixed_count: self.fixed_count,
-            conv: self.conv.stable(tables),
+            conv: self.conv.stable(tables, cx),
             c_variadic: self.c_variadic,
         }
     }
@@ -84,11 +103,15 @@ impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> {
 impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> {
     type T = ArgAbi;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         ArgAbi {
-            ty: self.layout.ty.stable(tables),
-            layout: self.layout.layout.stable(tables),
-            mode: self.mode.stable(tables),
+            ty: self.layout.ty.stable(tables, cx),
+            layout: self.layout.layout.stable(tables, cx),
+            mode: self.mode.stable(tables, cx),
         }
     }
 }
@@ -96,7 +119,7 @@ impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> {
 impl<'tcx> Stable<'tcx> for CanonAbi {
     type T = CallConvention;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             CanonAbi::C => CallConvention::C,
             CanonAbi::Rust => CallConvention::Rust,
@@ -132,7 +155,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi {
 impl<'tcx> Stable<'tcx> for callconv::PassMode {
     type T = PassMode;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             callconv::PassMode::Ignore => PassMode::Ignore,
             callconv::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)),
@@ -154,15 +177,19 @@ impl<'tcx> Stable<'tcx> for callconv::PassMode {
 impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_abi::FieldIdx> {
     type T = FieldsShape;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             rustc_abi::FieldsShape::Primitive => FieldsShape::Primitive,
             rustc_abi::FieldsShape::Union(count) => FieldsShape::Union(*count),
             rustc_abi::FieldsShape::Array { stride, count } => {
-                FieldsShape::Array { stride: stride.stable(tables), count: *count }
+                FieldsShape::Array { stride: stride.stable(tables, cx), count: *count }
             }
             rustc_abi::FieldsShape::Arbitrary { offsets, .. } => {
-                FieldsShape::Arbitrary { offsets: offsets.iter().as_slice().stable(tables) }
+                FieldsShape::Arbitrary { offsets: offsets.iter().as_slice().stable(tables, cx) }
             }
         }
     }
@@ -171,18 +198,22 @@ impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_abi::FieldIdx> {
 impl<'tcx> Stable<'tcx> for rustc_abi::Variants<rustc_abi::FieldIdx, rustc_abi::VariantIdx> {
     type T = VariantsShape;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             rustc_abi::Variants::Single { index } => {
-                VariantsShape::Single { index: index.stable(tables) }
+                VariantsShape::Single { index: index.stable(tables, cx) }
             }
             rustc_abi::Variants::Empty => VariantsShape::Empty,
             rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => {
                 VariantsShape::Multiple {
-                    tag: tag.stable(tables),
-                    tag_encoding: tag_encoding.stable(tables),
-                    tag_field: tag_field.stable(tables),
-                    variants: variants.iter().as_slice().stable(tables),
+                    tag: tag.stable(tables, cx),
+                    tag_encoding: tag_encoding.stable(tables, cx),
+                    tag_field: tag_field.stable(tables, cx),
+                    variants: variants.iter().as_slice().stable(tables, cx),
                 }
             }
         }
@@ -192,13 +223,17 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Variants<rustc_abi::FieldIdx, rustc_abi::
 impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_abi::VariantIdx> {
     type T = TagEncoding;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             rustc_abi::TagEncoding::Direct => TagEncoding::Direct,
             rustc_abi::TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => {
                 TagEncoding::Niche {
-                    untagged_variant: untagged_variant.stable(tables),
-                    niche_variants: niche_variants.stable(tables),
+                    untagged_variant: untagged_variant.stable(tables, cx),
+                    niche_variants: niche_variants.stable(tables, cx),
                     niche_start: *niche_start,
                 }
             }
@@ -209,14 +244,18 @@ impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_abi::VariantIdx> {
 impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr {
     type T = ValueAbi;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match *self {
-            rustc_abi::BackendRepr::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)),
+            rustc_abi::BackendRepr::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables, cx)),
             rustc_abi::BackendRepr::ScalarPair(first, second) => {
-                ValueAbi::ScalarPair(first.stable(tables), second.stable(tables))
+                ValueAbi::ScalarPair(first.stable(tables, cx), second.stable(tables, cx))
             }
             rustc_abi::BackendRepr::SimdVector { element, count } => {
-                ValueAbi::Vector { element: element.stable(tables), count }
+                ValueAbi::Vector { element: element.stable(tables, cx), count }
             }
             rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized },
         }
@@ -226,7 +265,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr {
 impl<'tcx> Stable<'tcx> for rustc_abi::Size {
     type T = Size;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         Size::from_bits(self.bits_usize())
     }
 }
@@ -234,7 +273,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Size {
 impl<'tcx> Stable<'tcx> for rustc_abi::Align {
     type T = Align;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         self.bytes()
     }
 }
@@ -242,13 +281,17 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Align {
 impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
     type T = Scalar;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             rustc_abi::Scalar::Initialized { value, valid_range } => Scalar::Initialized {
-                value: value.stable(tables),
-                valid_range: valid_range.stable(tables),
+                value: value.stable(tables, cx),
+                valid_range: valid_range.stable(tables, cx),
             },
-            rustc_abi::Scalar::Union { value } => Scalar::Union { value: value.stable(tables) },
+            rustc_abi::Scalar::Union { value } => Scalar::Union { value: value.stable(tables, cx) },
         }
     }
 }
@@ -256,15 +299,19 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
 impl<'tcx> Stable<'tcx> for rustc_abi::Primitive {
     type T = Primitive;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             rustc_abi::Primitive::Int(length, signed) => {
-                Primitive::Int { length: length.stable(tables), signed: *signed }
+                Primitive::Int { length: length.stable(tables, cx), signed: *signed }
             }
             rustc_abi::Primitive::Float(length) => {
-                Primitive::Float { length: length.stable(tables) }
+                Primitive::Float { length: length.stable(tables, cx) }
             }
-            rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables)),
+            rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables, cx)),
         }
     }
 }
@@ -272,7 +319,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Primitive {
 impl<'tcx> Stable<'tcx> for rustc_abi::AddressSpace {
     type T = AddressSpace;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         AddressSpace(self.0)
     }
 }
@@ -280,7 +327,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::AddressSpace {
 impl<'tcx> Stable<'tcx> for rustc_abi::Integer {
     type T = IntegerLength;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             rustc_abi::Integer::I8 => IntegerLength::I8,
             rustc_abi::Integer::I16 => IntegerLength::I16,
@@ -294,7 +341,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Integer {
 impl<'tcx> Stable<'tcx> for rustc_abi::Float {
     type T = FloatLength;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             rustc_abi::Float::F16 => FloatLength::F16,
             rustc_abi::Float::F32 => FloatLength::F32,
@@ -307,7 +354,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Float {
 impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange {
     type T = WrappingRange;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         WrappingRange { start: self.start, end: self.end }
     }
 }
@@ -315,7 +362,11 @@ impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange {
 impl<'tcx> Stable<'tcx> for rustc_abi::ReprFlags {
     type T = ReprFlags;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        _tables: &mut Tables<'cx, BridgeTys>,
+        _cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         ReprFlags {
             is_simd: self.intersects(Self::IS_SIMD),
             is_c: self.intersects(Self::IS_C),
@@ -328,11 +379,15 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ReprFlags {
 impl<'tcx> Stable<'tcx> for rustc_abi::IntegerType {
     type T = IntegerType;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             rustc_abi::IntegerType::Pointer(signed) => IntegerType::Pointer { is_signed: *signed },
             rustc_abi::IntegerType::Fixed(integer, signed) => {
-                IntegerType::Fixed { length: integer.stable(tables), is_signed: *signed }
+                IntegerType::Fixed { length: integer.stable(tables, cx), is_signed: *signed }
             }
         }
     }
@@ -341,12 +396,16 @@ impl<'tcx> Stable<'tcx> for rustc_abi::IntegerType {
 impl<'tcx> Stable<'tcx> for rustc_abi::ReprOptions {
     type T = ReprOptions;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         ReprOptions {
-            int: self.int.map(|int| int.stable(tables)),
-            align: self.align.map(|align| align.stable(tables)),
-            pack: self.pack.map(|pack| pack.stable(tables)),
-            flags: self.flags.stable(tables),
+            int: self.int.map(|int| int.stable(tables, cx)),
+            align: self.align.map(|align| align.stable(tables, cx)),
+            pack: self.pack.map(|pack| pack.stable(tables, cx)),
+            flags: self.flags.stable(tables, cx),
         }
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mir.rs
index daea4acc36c..99f9f456567 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mir.rs
@@ -1,56 +1,67 @@
 //! Conversion of internal Rust compiler `mir` items to stable ones.
 
-use rustc_middle::mir::interpret::alloc_range;
 use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::{bug, mir};
+use rustc_smir::Tables;
+use rustc_smir::bridge::SmirError;
+use rustc_smir::context::SmirCtxt;
+use stable_mir::compiler_interface::BridgeTys;
 use stable_mir::mir::alloc::GlobalAlloc;
 use stable_mir::mir::{ConstOperand, Statement, UserTypeProjection, VarDebugInfoFragment};
 use stable_mir::ty::{Allocation, ConstantKind, MirConst};
-use stable_mir::{Error, opaque};
+use stable_mir::unstable::Stable;
+use stable_mir::{Error, alloc, opaque};
 
-use crate::rustc_smir::{Stable, Tables, alloc};
-use crate::stable_mir;
+use crate::{rustc_smir, stable_mir};
 
 impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
     type T = stable_mir::mir::Body;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         stable_mir::mir::Body::new(
             self.basic_blocks
                 .iter()
                 .map(|block| stable_mir::mir::BasicBlock {
-                    terminator: block.terminator().stable(tables),
+                    terminator: block.terminator().stable(tables, cx),
                     statements: block
                         .statements
                         .iter()
-                        .map(|statement| statement.stable(tables))
+                        .map(|statement| statement.stable(tables, cx))
                         .collect(),
                 })
                 .collect(),
             self.local_decls
                 .iter()
                 .map(|decl| stable_mir::mir::LocalDecl {
-                    ty: decl.ty.stable(tables),
-                    span: decl.source_info.span.stable(tables),
-                    mutability: decl.mutability.stable(tables),
+                    ty: decl.ty.stable(tables, cx),
+                    span: decl.source_info.span.stable(tables, cx),
+                    mutability: decl.mutability.stable(tables, cx),
                 })
                 .collect(),
             self.arg_count,
-            self.var_debug_info.iter().map(|info| info.stable(tables)).collect(),
-            self.spread_arg.stable(tables),
-            self.span.stable(tables),
+            self.var_debug_info.iter().map(|info| info.stable(tables, cx)).collect(),
+            self.spread_arg.stable(tables, cx),
+            self.span.stable(tables, cx),
         )
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::VarDebugInfo<'tcx> {
     type T = stable_mir::mir::VarDebugInfo;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         stable_mir::mir::VarDebugInfo {
             name: self.name.to_string(),
-            source_info: self.source_info.stable(tables),
-            composite: self.composite.as_ref().map(|composite| composite.stable(tables)),
-            value: self.value.stable(tables),
+            source_info: self.source_info.stable(tables, cx),
+            composite: self.composite.as_ref().map(|composite| composite.stable(tables, cx)),
+            value: self.value.stable(tables, cx),
             argument_index: self.argument_index,
         }
     }
@@ -58,40 +69,59 @@ impl<'tcx> Stable<'tcx> for mir::VarDebugInfo<'tcx> {
 
 impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> {
     type T = stable_mir::mir::Statement;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        Statement { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) }
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        Statement {
+            kind: self.kind.stable(tables, cx),
+            span: self.source_info.span.stable(tables, cx),
+        }
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::SourceInfo {
     type T = stable_mir::mir::SourceInfo;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        stable_mir::mir::SourceInfo { span: self.span.stable(tables), scope: self.scope.into() }
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        stable_mir::mir::SourceInfo { span: self.span.stable(tables, cx), scope: self.scope.into() }
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::VarDebugInfoFragment<'tcx> {
     type T = stable_mir::mir::VarDebugInfoFragment;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         VarDebugInfoFragment {
-            ty: self.ty.stable(tables),
-            projection: self.projection.iter().map(|e| e.stable(tables)).collect(),
+            ty: self.ty.stable(tables, cx),
+            projection: self.projection.iter().map(|e| e.stable(tables, cx)).collect(),
         }
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::VarDebugInfoContents<'tcx> {
     type T = stable_mir::mir::VarDebugInfoContents;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             mir::VarDebugInfoContents::Place(place) => {
-                stable_mir::mir::VarDebugInfoContents::Place(place.stable(tables))
+                stable_mir::mir::VarDebugInfoContents::Place(place.stable(tables, cx))
             }
             mir::VarDebugInfoContents::Const(const_operand) => {
                 let op = ConstOperand {
-                    span: const_operand.span.stable(tables),
+                    span: const_operand.span.stable(tables, cx),
                     user_ty: const_operand.user_ty.map(|index| index.as_usize()),
-                    const_: const_operand.const_.stable(tables),
+                    const_: const_operand.const_.stable(tables, cx),
                 };
                 stable_mir::mir::VarDebugInfoContents::Const(op)
             }
@@ -101,53 +131,58 @@ impl<'tcx> Stable<'tcx> for mir::VarDebugInfoContents<'tcx> {
 
 impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> {
     type T = stable_mir::mir::StatementKind;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             mir::StatementKind::Assign(assign) => stable_mir::mir::StatementKind::Assign(
-                assign.0.stable(tables),
-                assign.1.stable(tables),
+                assign.0.stable(tables, cx),
+                assign.1.stable(tables, cx),
             ),
             mir::StatementKind::FakeRead(fake_read_place) => {
                 stable_mir::mir::StatementKind::FakeRead(
-                    fake_read_place.0.stable(tables),
-                    fake_read_place.1.stable(tables),
+                    fake_read_place.0.stable(tables, cx),
+                    fake_read_place.1.stable(tables, cx),
                 )
             }
             mir::StatementKind::SetDiscriminant { place, variant_index } => {
                 stable_mir::mir::StatementKind::SetDiscriminant {
-                    place: place.as_ref().stable(tables),
-                    variant_index: variant_index.stable(tables),
+                    place: place.as_ref().stable(tables, cx),
+                    variant_index: variant_index.stable(tables, cx),
                 }
             }
             mir::StatementKind::Deinit(place) => {
-                stable_mir::mir::StatementKind::Deinit(place.stable(tables))
+                stable_mir::mir::StatementKind::Deinit(place.stable(tables, cx))
             }
 
             mir::StatementKind::StorageLive(place) => {
-                stable_mir::mir::StatementKind::StorageLive(place.stable(tables))
+                stable_mir::mir::StatementKind::StorageLive(place.stable(tables, cx))
             }
 
             mir::StatementKind::StorageDead(place) => {
-                stable_mir::mir::StatementKind::StorageDead(place.stable(tables))
-            }
-            mir::StatementKind::Retag(retag, place) => {
-                stable_mir::mir::StatementKind::Retag(retag.stable(tables), place.stable(tables))
+                stable_mir::mir::StatementKind::StorageDead(place.stable(tables, cx))
             }
+            mir::StatementKind::Retag(retag, place) => stable_mir::mir::StatementKind::Retag(
+                retag.stable(tables, cx),
+                place.stable(tables, cx),
+            ),
             mir::StatementKind::PlaceMention(place) => {
-                stable_mir::mir::StatementKind::PlaceMention(place.stable(tables))
+                stable_mir::mir::StatementKind::PlaceMention(place.stable(tables, cx))
             }
             mir::StatementKind::AscribeUserType(place_projection, variance) => {
                 stable_mir::mir::StatementKind::AscribeUserType {
-                    place: place_projection.as_ref().0.stable(tables),
-                    projections: place_projection.as_ref().1.stable(tables),
-                    variance: variance.stable(tables),
+                    place: place_projection.as_ref().0.stable(tables, cx),
+                    projections: place_projection.as_ref().1.stable(tables, cx),
+                    variance: variance.stable(tables, cx),
                 }
             }
             mir::StatementKind::Coverage(coverage) => {
                 stable_mir::mir::StatementKind::Coverage(opaque(coverage))
             }
             mir::StatementKind::Intrinsic(intrinstic) => {
-                stable_mir::mir::StatementKind::Intrinsic(intrinstic.stable(tables))
+                stable_mir::mir::StatementKind::Intrinsic(intrinstic.stable(tables, cx))
             }
             mir::StatementKind::ConstEvalCounter => {
                 stable_mir::mir::StatementKind::ConstEvalCounter
@@ -163,61 +198,68 @@ impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> {
 
 impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
     type T = stable_mir::mir::Rvalue;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::mir::Rvalue::*;
         match self {
-            Use(op) => stable_mir::mir::Rvalue::Use(op.stable(tables)),
+            Use(op) => stable_mir::mir::Rvalue::Use(op.stable(tables, cx)),
             Repeat(op, len) => {
-                let len = len.stable(tables);
-                stable_mir::mir::Rvalue::Repeat(op.stable(tables), len)
+                let len = len.stable(tables, cx);
+                stable_mir::mir::Rvalue::Repeat(op.stable(tables, cx), len)
             }
             Ref(region, kind, place) => stable_mir::mir::Rvalue::Ref(
-                region.stable(tables),
-                kind.stable(tables),
-                place.stable(tables),
+                region.stable(tables, cx),
+                kind.stable(tables, cx),
+                place.stable(tables, cx),
             ),
             ThreadLocalRef(def_id) => {
                 stable_mir::mir::Rvalue::ThreadLocalRef(tables.crate_item(*def_id))
             }
-            RawPtr(mutability, place) => {
-                stable_mir::mir::Rvalue::AddressOf(mutability.stable(tables), place.stable(tables))
-            }
-            Len(place) => stable_mir::mir::Rvalue::Len(place.stable(tables)),
+            RawPtr(mutability, place) => stable_mir::mir::Rvalue::AddressOf(
+                mutability.stable(tables, cx),
+                place.stable(tables, cx),
+            ),
+            Len(place) => stable_mir::mir::Rvalue::Len(place.stable(tables, cx)),
             Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast(
-                cast_kind.stable(tables),
-                op.stable(tables),
-                ty.stable(tables),
+                cast_kind.stable(tables, cx),
+                op.stable(tables, cx),
+                ty.stable(tables, cx),
             ),
             BinaryOp(bin_op, ops) => {
                 if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
                     stable_mir::mir::Rvalue::CheckedBinaryOp(
-                        bin_op.stable(tables),
-                        ops.0.stable(tables),
-                        ops.1.stable(tables),
+                        bin_op.stable(tables, cx),
+                        ops.0.stable(tables, cx),
+                        ops.1.stable(tables, cx),
                     )
                 } else {
                     stable_mir::mir::Rvalue::BinaryOp(
-                        bin_op.stable(tables),
-                        ops.0.stable(tables),
-                        ops.1.stable(tables),
+                        bin_op.stable(tables, cx),
+                        ops.0.stable(tables, cx),
+                        ops.1.stable(tables, cx),
                     )
                 }
             }
-            NullaryOp(null_op, ty) => {
-                stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), ty.stable(tables))
-            }
+            NullaryOp(null_op, ty) => stable_mir::mir::Rvalue::NullaryOp(
+                null_op.stable(tables, cx),
+                ty.stable(tables, cx),
+            ),
             UnaryOp(un_op, op) => {
-                stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables), op.stable(tables))
+                stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables, cx), op.stable(tables, cx))
             }
-            Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable(tables)),
+            Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable(tables, cx)),
             Aggregate(agg_kind, operands) => {
-                let operands = operands.iter().map(|op| op.stable(tables)).collect();
-                stable_mir::mir::Rvalue::Aggregate(agg_kind.stable(tables), operands)
+                let operands = operands.iter().map(|op| op.stable(tables, cx)).collect();
+                stable_mir::mir::Rvalue::Aggregate(agg_kind.stable(tables, cx), operands)
             }
-            ShallowInitBox(op, ty) => {
-                stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables))
-            }
-            CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)),
+            ShallowInitBox(op, ty) => stable_mir::mir::Rvalue::ShallowInitBox(
+                op.stable(tables, cx),
+                ty.stable(tables, cx),
+            ),
+            CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables, cx)),
             WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
         }
     }
@@ -225,7 +267,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
 
 impl<'tcx> Stable<'tcx> for mir::Mutability {
     type T = stable_mir::mir::Mutability;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_hir::Mutability::*;
         match *self {
             Not => stable_mir::mir::Mutability::Not,
@@ -236,7 +278,7 @@ impl<'tcx> Stable<'tcx> for mir::Mutability {
 
 impl<'tcx> Stable<'tcx> for mir::RawPtrKind {
     type T = stable_mir::mir::RawPtrKind;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use mir::RawPtrKind::*;
         match *self {
             Const => stable_mir::mir::RawPtrKind::Const,
@@ -248,19 +290,23 @@ impl<'tcx> Stable<'tcx> for mir::RawPtrKind {
 
 impl<'tcx> Stable<'tcx> for mir::BorrowKind {
     type T = stable_mir::mir::BorrowKind;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::mir::BorrowKind::*;
         match *self {
             Shared => stable_mir::mir::BorrowKind::Shared,
-            Fake(kind) => stable_mir::mir::BorrowKind::Fake(kind.stable(tables)),
-            Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables) },
+            Fake(kind) => stable_mir::mir::BorrowKind::Fake(kind.stable(tables, cx)),
+            Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables, cx) },
         }
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::MutBorrowKind {
     type T = stable_mir::mir::MutBorrowKind;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::mir::MutBorrowKind::*;
         match *self {
             Default => stable_mir::mir::MutBorrowKind::Default,
@@ -272,7 +318,7 @@ impl<'tcx> Stable<'tcx> for mir::MutBorrowKind {
 
 impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind {
     type T = stable_mir::mir::FakeBorrowKind;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::mir::FakeBorrowKind::*;
         match *self {
             Deep => stable_mir::mir::FakeBorrowKind::Deep,
@@ -283,13 +329,17 @@ impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind {
 
 impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
     type T = stable_mir::mir::NullOp;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::mir::NullOp::*;
         match self {
             SizeOf => stable_mir::mir::NullOp::SizeOf,
             AlignOf => stable_mir::mir::NullOp::AlignOf,
             OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf(
-                indices.iter().map(|idx| idx.stable(tables)).collect(),
+                indices.iter().map(|idx| idx.stable(tables, cx)).collect(),
             ),
             UbChecks => stable_mir::mir::NullOp::UbChecks,
             ContractChecks => stable_mir::mir::NullOp::ContractChecks,
@@ -299,12 +349,18 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
 
 impl<'tcx> Stable<'tcx> for mir::CastKind {
     type T = stable_mir::mir::CastKind;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::mir::CastKind::*;
         match self {
             PointerExposeProvenance => stable_mir::mir::CastKind::PointerExposeAddress,
             PointerWithExposedProvenance => stable_mir::mir::CastKind::PointerWithExposedProvenance,
-            PointerCoercion(c, _) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
+            PointerCoercion(c, _) => {
+                stable_mir::mir::CastKind::PointerCoercion(c.stable(tables, cx))
+            }
             IntToInt => stable_mir::mir::CastKind::IntToInt,
             FloatToInt => stable_mir::mir::CastKind::FloatToInt,
             FloatToFloat => stable_mir::mir::CastKind::FloatToFloat,
@@ -318,7 +374,7 @@ impl<'tcx> Stable<'tcx> for mir::CastKind {
 
 impl<'tcx> Stable<'tcx> for mir::FakeReadCause {
     type T = stable_mir::mir::FakeReadCause;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::mir::FakeReadCause::*;
         match self {
             ForMatchGuard => stable_mir::mir::FakeReadCause::ForMatchGuard,
@@ -334,12 +390,16 @@ impl<'tcx> Stable<'tcx> for mir::FakeReadCause {
 
 impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> {
     type T = stable_mir::mir::Operand;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::mir::Operand::*;
         match self {
-            Copy(place) => stable_mir::mir::Operand::Copy(place.stable(tables)),
-            Move(place) => stable_mir::mir::Operand::Move(place.stable(tables)),
-            Constant(c) => stable_mir::mir::Operand::Constant(c.stable(tables)),
+            Copy(place) => stable_mir::mir::Operand::Copy(place.stable(tables, cx)),
+            Move(place) => stable_mir::mir::Operand::Move(place.stable(tables, cx)),
+            Constant(c) => stable_mir::mir::Operand::Constant(c.stable(tables, cx)),
         }
     }
 }
@@ -347,35 +407,48 @@ impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> {
 impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> {
     type T = stable_mir::mir::ConstOperand;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         stable_mir::mir::ConstOperand {
-            span: self.span.stable(tables),
+            span: self.span.stable(tables, cx),
             user_ty: self.user_ty.map(|u| u.as_usize()).or(None),
-            const_: self.const_.stable(tables),
+            const_: self.const_.stable(tables, cx),
         }
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::Place<'tcx> {
     type T = stable_mir::mir::Place;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         stable_mir::mir::Place {
             local: self.local.as_usize(),
-            projection: self.projection.iter().map(|e| e.stable(tables)).collect(),
+            projection: self.projection.iter().map(|e| e.stable(tables, cx)).collect(),
         }
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> {
     type T = stable_mir::mir::ProjectionElem;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::mir::ProjectionElem::*;
         match self {
             Deref => stable_mir::mir::ProjectionElem::Deref,
-            Field(idx, ty) => {
-                stable_mir::mir::ProjectionElem::Field(idx.stable(tables), ty.stable(tables))
-            }
-            Index(local) => stable_mir::mir::ProjectionElem::Index(local.stable(tables)),
+            Field(idx, ty) => stable_mir::mir::ProjectionElem::Field(
+                idx.stable(tables, cx),
+                ty.stable(tables, cx),
+            ),
+            Index(local) => stable_mir::mir::ProjectionElem::Index(local.stable(tables, cx)),
             ConstantIndex { offset, min_length, from_end } => {
                 stable_mir::mir::ProjectionElem::ConstantIndex {
                     offset: *offset,
@@ -393,9 +466,9 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> {
             // via a lookup using the `VariantIdx`. The `Option<Symbol>` argument is therefore
             // dropped when converting to Stable MIR. A brief justification for this decision can be
             // found at https://github.com/rust-lang/rust/pull/117517#issuecomment-1811683486
-            Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)),
-            OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)),
-            Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)),
+            Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables, cx)),
+            OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables, cx)),
+            Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables, cx)),
             UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
         }
     }
@@ -404,21 +477,21 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> {
 impl<'tcx> Stable<'tcx> for mir::UserTypeProjection {
     type T = stable_mir::mir::UserTypeProjection;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         UserTypeProjection { base: self.base.as_usize(), projection: opaque(&self.projs) }
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::Local {
     type T = stable_mir::mir::Local;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         self.as_usize()
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::RetagKind {
     type T = stable_mir::mir::RetagKind;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::mir::RetagKind;
         match self {
             RetagKind::FnEntry => stable_mir::mir::RetagKind::FnEntry,
@@ -431,7 +504,7 @@ impl<'tcx> Stable<'tcx> for mir::RetagKind {
 
 impl<'tcx> Stable<'tcx> for mir::UnwindAction {
     type T = stable_mir::mir::UnwindAction;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::mir::UnwindAction;
         match self {
             UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue,
@@ -445,18 +518,22 @@ impl<'tcx> Stable<'tcx> for mir::UnwindAction {
 impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> {
     type T = stable_mir::mir::NonDivergingIntrinsic;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::mir::NonDivergingIntrinsic;
         use stable_mir::mir::CopyNonOverlapping;
         match self {
             NonDivergingIntrinsic::Assume(op) => {
-                stable_mir::mir::NonDivergingIntrinsic::Assume(op.stable(tables))
+                stable_mir::mir::NonDivergingIntrinsic::Assume(op.stable(tables, cx))
             }
             NonDivergingIntrinsic::CopyNonOverlapping(copy_non_overlapping) => {
                 stable_mir::mir::NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
-                    src: copy_non_overlapping.src.stable(tables),
-                    dst: copy_non_overlapping.dst.stable(tables),
-                    count: copy_non_overlapping.count.stable(tables),
+                    src: copy_non_overlapping.src.stable(tables, cx),
+                    dst: copy_non_overlapping.dst.stable(tables, cx),
+                    count: copy_non_overlapping.count.stable(tables, cx),
                 })
             }
         }
@@ -465,47 +542,51 @@ impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> {
 
 impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> {
     type T = stable_mir::mir::AssertMessage;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::mir::AssertKind;
         match self {
             AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck {
-                len: len.stable(tables),
-                index: index.stable(tables),
+                len: len.stable(tables, cx),
+                index: index.stable(tables, cx),
             },
             AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow(
-                bin_op.stable(tables),
-                op1.stable(tables),
-                op2.stable(tables),
+                bin_op.stable(tables, cx),
+                op1.stable(tables, cx),
+                op2.stable(tables, cx),
             ),
             AssertKind::OverflowNeg(op) => {
-                stable_mir::mir::AssertMessage::OverflowNeg(op.stable(tables))
+                stable_mir::mir::AssertMessage::OverflowNeg(op.stable(tables, cx))
             }
             AssertKind::DivisionByZero(op) => {
-                stable_mir::mir::AssertMessage::DivisionByZero(op.stable(tables))
+                stable_mir::mir::AssertMessage::DivisionByZero(op.stable(tables, cx))
             }
             AssertKind::RemainderByZero(op) => {
-                stable_mir::mir::AssertMessage::RemainderByZero(op.stable(tables))
+                stable_mir::mir::AssertMessage::RemainderByZero(op.stable(tables, cx))
             }
             AssertKind::ResumedAfterReturn(coroutine) => {
-                stable_mir::mir::AssertMessage::ResumedAfterReturn(coroutine.stable(tables))
+                stable_mir::mir::AssertMessage::ResumedAfterReturn(coroutine.stable(tables, cx))
             }
             AssertKind::ResumedAfterPanic(coroutine) => {
-                stable_mir::mir::AssertMessage::ResumedAfterPanic(coroutine.stable(tables))
+                stable_mir::mir::AssertMessage::ResumedAfterPanic(coroutine.stable(tables, cx))
             }
             AssertKind::ResumedAfterDrop(coroutine) => {
-                stable_mir::mir::AssertMessage::ResumedAfterDrop(coroutine.stable(tables))
+                stable_mir::mir::AssertMessage::ResumedAfterDrop(coroutine.stable(tables, cx))
             }
             AssertKind::MisalignedPointerDereference { required, found } => {
                 stable_mir::mir::AssertMessage::MisalignedPointerDereference {
-                    required: required.stable(tables),
-                    found: found.stable(tables),
+                    required: required.stable(tables, cx),
+                    found: found.stable(tables, cx),
                 }
             }
             AssertKind::NullPointerDereference => {
                 stable_mir::mir::AssertMessage::NullPointerDereference
             }
             AssertKind::InvalidEnumConstruction(source) => {
-                stable_mir::mir::AssertMessage::InvalidEnumConstruction(source.stable(tables))
+                stable_mir::mir::AssertMessage::InvalidEnumConstruction(source.stable(tables, cx))
             }
         }
     }
@@ -513,7 +594,7 @@ impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> {
 
 impl<'tcx> Stable<'tcx> for mir::BinOp {
     type T = stable_mir::mir::BinOp;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::mir::BinOp;
         match self {
             BinOp::Add => stable_mir::mir::BinOp::Add,
@@ -548,7 +629,7 @@ impl<'tcx> Stable<'tcx> for mir::BinOp {
 
 impl<'tcx> Stable<'tcx> for mir::UnOp {
     type T = stable_mir::mir::UnOp;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::mir::UnOp;
         match self {
             UnOp::Not => stable_mir::mir::UnOp::Not,
@@ -560,17 +641,21 @@ impl<'tcx> Stable<'tcx> for mir::UnOp {
 
 impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
     type T = stable_mir::mir::AggregateKind;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             mir::AggregateKind::Array(ty) => {
-                stable_mir::mir::AggregateKind::Array(ty.stable(tables))
+                stable_mir::mir::AggregateKind::Array(ty.stable(tables, cx))
             }
             mir::AggregateKind::Tuple => stable_mir::mir::AggregateKind::Tuple,
             mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => {
                 stable_mir::mir::AggregateKind::Adt(
                     tables.adt_def(*def_id),
-                    var_idx.stable(tables),
-                    generic_arg.stable(tables),
+                    var_idx.stable(tables, cx),
+                    generic_arg.stable(tables, cx),
                     user_ty_index.map(|idx| idx.index()),
                     field_idx.map(|idx| idx.index()),
                 )
@@ -578,39 +663,46 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
             mir::AggregateKind::Closure(def_id, generic_arg) => {
                 stable_mir::mir::AggregateKind::Closure(
                     tables.closure_def(*def_id),
-                    generic_arg.stable(tables),
+                    generic_arg.stable(tables, cx),
                 )
             }
             mir::AggregateKind::Coroutine(def_id, generic_arg) => {
                 stable_mir::mir::AggregateKind::Coroutine(
                     tables.coroutine_def(*def_id),
-                    generic_arg.stable(tables),
-                    tables.tcx.coroutine_movability(*def_id).stable(tables),
+                    generic_arg.stable(tables, cx),
+                    cx.coroutine_movability(*def_id).stable(tables, cx),
                 )
             }
             mir::AggregateKind::CoroutineClosure(def_id, generic_args) => {
                 stable_mir::mir::AggregateKind::CoroutineClosure(
                     tables.coroutine_closure_def(*def_id),
-                    generic_args.stable(tables),
+                    generic_args.stable(tables, cx),
                 )
             }
-            mir::AggregateKind::RawPtr(ty, mutability) => {
-                stable_mir::mir::AggregateKind::RawPtr(ty.stable(tables), mutability.stable(tables))
-            }
+            mir::AggregateKind::RawPtr(ty, mutability) => stable_mir::mir::AggregateKind::RawPtr(
+                ty.stable(tables, cx),
+                mutability.stable(tables, cx),
+            ),
         }
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> {
     type T = stable_mir::mir::InlineAsmOperand;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::mir::InlineAsmOperand;
 
         let (in_value, out_place) = match self {
-            InlineAsmOperand::In { value, .. } => (Some(value.stable(tables)), None),
-            InlineAsmOperand::Out { place, .. } => (None, place.map(|place| place.stable(tables))),
+            InlineAsmOperand::In { value, .. } => (Some(value.stable(tables, cx)), None),
+            InlineAsmOperand::Out { place, .. } => {
+                (None, place.map(|place| place.stable(tables, cx)))
+            }
             InlineAsmOperand::InOut { in_value, out_place, .. } => {
-                (Some(in_value.stable(tables)), out_place.map(|place| place.stable(tables)))
+                (Some(in_value.stable(tables, cx)), out_place.map(|place| place.stable(tables, cx)))
             }
             InlineAsmOperand::Const { .. }
             | InlineAsmOperand::SymFn { .. }
@@ -624,22 +716,33 @@ impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> {
 
 impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> {
     type T = stable_mir::mir::Terminator;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::mir::Terminator;
-        Terminator { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) }
+        Terminator {
+            kind: self.kind.stable(tables, cx),
+            span: self.source_info.span.stable(tables, cx),
+        }
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
     type T = stable_mir::mir::TerminatorKind;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::mir::TerminatorKind;
         match self {
             mir::TerminatorKind::Goto { target } => {
                 TerminatorKind::Goto { target: target.as_usize() }
             }
             mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt {
-                discr: discr.stable(tables),
+                discr: discr.stable(tables, cx),
                 targets: {
                     let branches = targets.iter().map(|(val, target)| (val, target.as_usize()));
                     stable_mir::mir::SwitchTargets::new(
@@ -660,9 +763,9 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
                 drop: _,
                 async_fut: _,
             } => TerminatorKind::Drop {
-                place: place.stable(tables),
+                place: place.stable(tables, cx),
                 target: target.as_usize(),
-                unwind: unwind.stable(tables),
+                unwind: unwind.stable(tables, cx),
             },
             mir::TerminatorKind::Call {
                 func,
@@ -673,20 +776,20 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
                 call_source: _,
                 fn_span: _,
             } => TerminatorKind::Call {
-                func: func.stable(tables),
-                args: args.iter().map(|arg| arg.node.stable(tables)).collect(),
-                destination: destination.stable(tables),
+                func: func.stable(tables, cx),
+                args: args.iter().map(|arg| arg.node.stable(tables, cx)).collect(),
+                destination: destination.stable(tables, cx),
                 target: target.map(|t| t.as_usize()),
-                unwind: unwind.stable(tables),
+                unwind: unwind.stable(tables, cx),
             },
             mir::TerminatorKind::TailCall { func: _, args: _, fn_span: _ } => todo!(),
             mir::TerminatorKind::Assert { cond, expected, msg, target, unwind } => {
                 TerminatorKind::Assert {
-                    cond: cond.stable(tables),
+                    cond: cond.stable(tables, cx),
                     expected: *expected,
-                    msg: msg.stable(tables),
+                    msg: msg.stable(tables, cx),
                     target: target.as_usize(),
-                    unwind: unwind.stable(tables),
+                    unwind: unwind.stable(tables, cx),
                 }
             }
             mir::TerminatorKind::InlineAsm {
@@ -699,12 +802,12 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
                 unwind,
             } => TerminatorKind::InlineAsm {
                 template: format!("{template:?}"),
-                operands: operands.iter().map(|operand| operand.stable(tables)).collect(),
+                operands: operands.iter().map(|operand| operand.stable(tables, cx)).collect(),
                 options: format!("{options:?}"),
                 line_spans: format!("{line_spans:?}"),
                 // FIXME: Figure out how to do labels in SMIR
                 destination: targets.first().map(|d| d.as_usize()),
-                unwind: unwind.stable(tables),
+                unwind: unwind.stable(tables, cx),
             },
             mir::TerminatorKind::Yield { .. }
             | mir::TerminatorKind::CoroutineDrop
@@ -717,22 +820,40 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
 impl<'tcx> Stable<'tcx> for mir::interpret::ConstAllocation<'tcx> {
     type T = Allocation;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        self.inner().stable(tables)
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        self.inner().stable(tables, cx)
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::interpret::Allocation {
     type T = stable_mir::ty::Allocation;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        alloc::allocation_filter(self, alloc_range(rustc_abi::Size::ZERO, self.size()), tables)
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        use rustc_smir::context::SmirAllocRange;
+        alloc::allocation_filter(
+            self,
+            cx.alloc_range(rustc_abi::Size::ZERO, self.size()),
+            tables,
+            cx,
+        )
     }
 }
 
 impl<'tcx> Stable<'tcx> for mir::interpret::AllocId {
     type T = stable_mir::mir::alloc::AllocId;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        _: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         tables.create_alloc_id(*self)
     }
 }
@@ -740,19 +861,25 @@ impl<'tcx> Stable<'tcx> for mir::interpret::AllocId {
 impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> {
     type T = GlobalAlloc;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             mir::interpret::GlobalAlloc::Function { instance, .. } => {
-                GlobalAlloc::Function(instance.stable(tables))
+                GlobalAlloc::Function(instance.stable(tables, cx))
             }
             mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => {
                 // FIXME: Should we record the whole vtable?
-                GlobalAlloc::VTable(ty.stable(tables), dyn_ty.principal().stable(tables))
+                GlobalAlloc::VTable(ty.stable(tables, cx), dyn_ty.principal().stable(tables, cx))
             }
             mir::interpret::GlobalAlloc::Static(def) => {
                 GlobalAlloc::Static(tables.static_def(*def))
             }
-            mir::interpret::GlobalAlloc::Memory(alloc) => GlobalAlloc::Memory(alloc.stable(tables)),
+            mir::interpret::GlobalAlloc::Memory(alloc) => {
+                GlobalAlloc::Memory(alloc.stable(tables, cx))
+            }
         }
     }
 }
@@ -760,33 +887,37 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> {
 impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> {
     type T = stable_mir::ty::MirConst;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        let id = tables.intern_mir_const(tables.tcx.lift(*self).unwrap());
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        let id = tables.intern_mir_const(cx.lift(*self).unwrap());
         match *self {
             mir::Const::Ty(ty, c) => MirConst::new(
-                stable_mir::ty::ConstantKind::Ty(c.stable(tables)),
-                ty.stable(tables),
+                stable_mir::ty::ConstantKind::Ty(c.stable(tables, cx)),
+                ty.stable(tables, cx),
                 id,
             ),
             mir::Const::Unevaluated(unev_const, ty) => {
                 let kind =
                     stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
                         def: tables.const_def(unev_const.def),
-                        args: unev_const.args.stable(tables),
+                        args: unev_const.args.stable(tables, cx),
                         promoted: unev_const.promoted.map(|u| u.as_u32()),
                     });
-                let ty = ty.stable(tables);
+                let ty = ty.stable(tables, cx);
                 MirConst::new(kind, ty, id)
             }
             mir::Const::Val(mir::ConstValue::ZeroSized, ty) => {
-                let ty = ty.stable(tables);
+                let ty = ty.stable(tables, cx);
                 MirConst::new(ConstantKind::ZeroSized, ty, id)
             }
             mir::Const::Val(val, ty) => {
-                let ty = tables.tcx.lift(ty).unwrap();
-                let val = tables.tcx.lift(val).unwrap();
-                let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables));
-                let ty = ty.stable(tables);
+                let ty = cx.lift(ty).unwrap();
+                let val = cx.lift(val).unwrap();
+                let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables, cx));
+                let ty = ty.stable(tables, cx);
                 MirConst::new(kind, ty, id)
             }
         }
@@ -796,7 +927,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> {
 impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled {
     type T = Error;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         Error::new(format!("{self:?}"))
     }
 }
@@ -804,10 +935,14 @@ impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled {
 impl<'tcx> Stable<'tcx> for MonoItem<'tcx> {
     type T = stable_mir::mir::mono::MonoItem;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::mir::mono::MonoItem as StableMonoItem;
         match self {
-            MonoItem::Fn(instance) => StableMonoItem::Fn(instance.stable(tables)),
+            MonoItem::Fn(instance) => StableMonoItem::Fn(instance.stable(tables, cx)),
             MonoItem::Static(def_id) => StableMonoItem::Static(tables.static_def(*def_id)),
             MonoItem::GlobalAsm(item_id) => StableMonoItem::GlobalAsm(opaque(item_id)),
         }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mod.rs
index 3494de62d83..799917c6e17 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
+++ b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mod.rs
@@ -1,18 +1,20 @@
 //! Conversion of internal Rust compiler items to stable ones.
 
 use rustc_abi::FieldIdx;
+use rustc_smir::Tables;
+use rustc_smir::context::SmirCtxt;
+use stable_mir::compiler_interface::BridgeTys;
 
-use crate::rustc_smir::{Stable, Tables};
-use crate::stable_mir;
+use super::Stable;
+use crate::{rustc_smir, stable_mir};
 
 mod abi;
-mod error;
 mod mir;
 mod ty;
 
 impl<'tcx> Stable<'tcx> for rustc_hir::Safety {
     type T = stable_mir::mir::Safety;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             rustc_hir::Safety::Unsafe => stable_mir::mir::Safety::Unsafe,
             rustc_hir::Safety::Safe => stable_mir::mir::Safety::Safe,
@@ -22,14 +24,14 @@ impl<'tcx> Stable<'tcx> for rustc_hir::Safety {
 
 impl<'tcx> Stable<'tcx> for FieldIdx {
     type T = usize;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         self.as_usize()
     }
 }
 
 impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource {
     type T = stable_mir::mir::CoroutineSource;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_hir::CoroutineSource;
         match self {
             CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block,
@@ -41,28 +43,32 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource {
 
 impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
     type T = stable_mir::mir::CoroutineKind;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_hir::{CoroutineDesugaring, CoroutineKind};
         match *self {
             CoroutineKind::Desugared(CoroutineDesugaring::Async, source) => {
                 stable_mir::mir::CoroutineKind::Desugared(
                     stable_mir::mir::CoroutineDesugaring::Async,
-                    source.stable(tables),
+                    source.stable(tables, cx),
                 )
             }
             CoroutineKind::Desugared(CoroutineDesugaring::Gen, source) => {
                 stable_mir::mir::CoroutineKind::Desugared(
                     stable_mir::mir::CoroutineDesugaring::Gen,
-                    source.stable(tables),
+                    source.stable(tables, cx),
                 )
             }
             CoroutineKind::Coroutine(movability) => {
-                stable_mir::mir::CoroutineKind::Coroutine(movability.stable(tables))
+                stable_mir::mir::CoroutineKind::Coroutine(movability.stable(tables, cx))
             }
             CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, source) => {
                 stable_mir::mir::CoroutineKind::Desugared(
                     stable_mir::mir::CoroutineDesugaring::AsyncGen,
-                    source.stable(tables),
+                    source.stable(tables, cx),
                 )
             }
         }
@@ -72,7 +78,7 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
 impl<'tcx> Stable<'tcx> for rustc_span::Symbol {
     type T = stable_mir::Symbol;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         self.to_string()
     }
 }
@@ -80,7 +86,11 @@ impl<'tcx> Stable<'tcx> for rustc_span::Symbol {
 impl<'tcx> Stable<'tcx> for rustc_span::Span {
     type T = stable_mir::ty::Span;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        _: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         tables.create_span(*self)
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs
index ff0b8e833dc..c0a430079d8 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs
@@ -2,16 +2,20 @@
 
 use rustc_middle::ty::Ty;
 use rustc_middle::{mir, ty};
+use rustc_smir::Tables;
+use rustc_smir::context::SmirCtxt;
+use stable_mir::alloc;
+use stable_mir::compiler_interface::BridgeTys;
 use stable_mir::ty::{
     AdtKind, FloatTy, GenericArgs, GenericParamDef, IntTy, Region, RigidTy, TyKind, UintTy,
 };
+use stable_mir::unstable::Stable;
 
-use crate::rustc_smir::{Stable, Tables, alloc};
-use crate::stable_mir;
+use crate::{rustc_smir, stable_mir};
 
 impl<'tcx> Stable<'tcx> for ty::AliasTyKind {
     type T = stable_mir::ty::AliasKind;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             ty::Projection => stable_mir::ty::AliasKind::Projection,
             ty::Inherent => stable_mir::ty::AliasKind::Inherent,
@@ -23,24 +27,35 @@ impl<'tcx> Stable<'tcx> for ty::AliasTyKind {
 
 impl<'tcx> Stable<'tcx> for ty::AliasTy<'tcx> {
     type T = stable_mir::ty::AliasTy;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         let ty::AliasTy { args, def_id, .. } = self;
-        stable_mir::ty::AliasTy { def_id: tables.alias_def(*def_id), args: args.stable(tables) }
+        stable_mir::ty::AliasTy { def_id: tables.alias_def(*def_id), args: args.stable(tables, cx) }
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::AliasTerm<'tcx> {
     type T = stable_mir::ty::AliasTerm;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         let ty::AliasTerm { args, def_id, .. } = self;
-        stable_mir::ty::AliasTerm { def_id: tables.alias_def(*def_id), args: args.stable(tables) }
+        stable_mir::ty::AliasTerm {
+            def_id: tables.alias_def(*def_id),
+            args: args.stable(tables, cx),
+        }
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::DynKind {
     type T = stable_mir::ty::DynKind;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             ty::Dyn => stable_mir::ty::DynKind::Dyn,
         }
@@ -50,14 +65,18 @@ impl<'tcx> Stable<'tcx> for ty::DynKind {
 impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> {
     type T = stable_mir::ty::ExistentialPredicate;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::ExistentialPredicate::*;
         match self {
             ty::ExistentialPredicate::Trait(existential_trait_ref) => {
-                Trait(existential_trait_ref.stable(tables))
+                Trait(existential_trait_ref.stable(tables, cx))
             }
             ty::ExistentialPredicate::Projection(existential_projection) => {
-                Projection(existential_projection.stable(tables))
+                Projection(existential_projection.stable(tables, cx))
             }
             ty::ExistentialPredicate::AutoTrait(def_id) => AutoTrait(tables.trait_def(*def_id)),
         }
@@ -67,11 +86,15 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> {
     type T = stable_mir::ty::ExistentialTraitRef;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         let ty::ExistentialTraitRef { def_id, args, .. } = self;
         stable_mir::ty::ExistentialTraitRef {
             def_id: tables.trait_def(*def_id),
-            generic_args: args.stable(tables),
+            generic_args: args.stable(tables, cx),
         }
     }
 }
@@ -79,12 +102,16 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> {
     type T = stable_mir::ty::TermKind;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::TermKind;
         match self {
-            ty::TermKind::Ty(ty) => TermKind::Type(ty.stable(tables)),
+            ty::TermKind::Ty(ty) => TermKind::Type(ty.stable(tables, cx)),
             ty::TermKind::Const(cnst) => {
-                let cnst = cnst.stable(tables);
+                let cnst = cnst.stable(tables, cx);
                 TermKind::Const(cnst)
             }
         }
@@ -94,25 +121,33 @@ impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> {
     type T = stable_mir::ty::ExistentialProjection;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         let ty::ExistentialProjection { def_id, args, term, .. } = self;
         stable_mir::ty::ExistentialProjection {
             def_id: tables.trait_def(*def_id),
-            generic_args: args.stable(tables),
-            term: term.kind().stable(tables),
+            generic_args: args.stable(tables, cx),
+            term: term.kind().stable(tables, cx),
         }
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion {
     type T = stable_mir::mir::PointerCoercion;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::ty::adjustment::PointerCoercion;
         match self {
             PointerCoercion::ReifyFnPointer => stable_mir::mir::PointerCoercion::ReifyFnPointer,
             PointerCoercion::UnsafeFnPointer => stable_mir::mir::PointerCoercion::UnsafeFnPointer,
             PointerCoercion::ClosureFnPointer(safety) => {
-                stable_mir::mir::PointerCoercion::ClosureFnPointer(safety.stable(tables))
+                stable_mir::mir::PointerCoercion::ClosureFnPointer(safety.stable(tables, cx))
             }
             PointerCoercion::MutToConstPointer => {
                 stable_mir::mir::PointerCoercion::MutToConstPointer
@@ -125,7 +160,7 @@ impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion {
 
 impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex {
     type T = usize;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         self.as_usize()
     }
 }
@@ -133,7 +168,7 @@ impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex {
 impl<'tcx> Stable<'tcx> for ty::AdtKind {
     type T = AdtKind;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             ty::AdtKind::Struct => AdtKind::Struct,
             ty::AdtKind::Union => AdtKind::Union,
@@ -145,30 +180,44 @@ impl<'tcx> Stable<'tcx> for ty::AdtKind {
 impl<'tcx> Stable<'tcx> for ty::FieldDef {
     type T = stable_mir::ty::FieldDef;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         stable_mir::ty::FieldDef {
             def: tables.create_def_id(self.did),
-            name: self.name.stable(tables),
+            name: self.name.stable(tables, cx),
         }
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> {
     type T = stable_mir::ty::GenericArgs;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        GenericArgs(self.iter().map(|arg| arg.kind().stable(tables)).collect())
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        GenericArgs(self.iter().map(|arg| arg.kind().stable(tables, cx)).collect())
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::GenericArgKind<'tcx> {
     type T = stable_mir::ty::GenericArgKind;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::GenericArgKind;
         match self {
-            ty::GenericArgKind::Lifetime(region) => GenericArgKind::Lifetime(region.stable(tables)),
-            ty::GenericArgKind::Type(ty) => GenericArgKind::Type(ty.stable(tables)),
-            ty::GenericArgKind::Const(cnst) => GenericArgKind::Const(cnst.stable(tables)),
+            ty::GenericArgKind::Lifetime(region) => {
+                GenericArgKind::Lifetime(region.stable(tables, cx))
+            }
+            ty::GenericArgKind::Type(ty) => GenericArgKind::Type(ty.stable(tables, cx)),
+            ty::GenericArgKind::Const(cnst) => GenericArgKind::Const(cnst.stable(tables, cx)),
         }
     }
 }
@@ -179,15 +228,19 @@ where
 {
     type T = stable_mir::ty::Binder<V>;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::Binder;
 
         Binder {
-            value: self.as_ref().skip_binder().stable(tables),
+            value: self.as_ref().skip_binder().stable(tables, cx),
             bound_vars: self
                 .bound_vars()
                 .iter()
-                .map(|bound_var| bound_var.stable(tables))
+                .map(|bound_var| bound_var.stable(tables, cx))
                 .collect(),
         }
     }
@@ -199,23 +252,35 @@ where
 {
     type T = stable_mir::ty::EarlyBinder<V>;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::EarlyBinder;
 
-        EarlyBinder { value: self.as_ref().skip_binder().stable(tables) }
+        EarlyBinder { value: self.as_ref().skip_binder().stable(tables, cx) }
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
     type T = stable_mir::ty::FnSig;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::FnSig;
 
         FnSig {
-            inputs_and_output: self.inputs_and_output.iter().map(|ty| ty.stable(tables)).collect(),
+            inputs_and_output: self
+                .inputs_and_output
+                .iter()
+                .map(|ty| ty.stable(tables, cx))
+                .collect(),
             c_variadic: self.c_variadic,
-            safety: self.safety.stable(tables),
-            abi: self.abi.stable(tables),
+            safety: self.safety.stable(tables, cx),
+            abi: self.abi.stable(tables, cx),
         }
     }
 }
@@ -223,7 +288,11 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::BoundTyKind {
     type T = stable_mir::ty::BoundTyKind;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        _: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::BoundTyKind;
 
         match self {
@@ -238,7 +307,11 @@ impl<'tcx> Stable<'tcx> for ty::BoundTyKind {
 impl<'tcx> Stable<'tcx> for ty::BoundRegionKind {
     type T = stable_mir::ty::BoundRegionKind;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        _: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::BoundRegionKind;
 
         match self {
@@ -254,15 +327,19 @@ impl<'tcx> Stable<'tcx> for ty::BoundRegionKind {
 impl<'tcx> Stable<'tcx> for ty::BoundVariableKind {
     type T = stable_mir::ty::BoundVariableKind;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::BoundVariableKind;
 
         match self {
             ty::BoundVariableKind::Ty(bound_ty_kind) => {
-                BoundVariableKind::Ty(bound_ty_kind.stable(tables))
+                BoundVariableKind::Ty(bound_ty_kind.stable(tables, cx))
             }
             ty::BoundVariableKind::Region(bound_region_kind) => {
-                BoundVariableKind::Region(bound_region_kind.stable(tables))
+                BoundVariableKind::Region(bound_region_kind.stable(tables, cx))
             }
             ty::BoundVariableKind::Const => BoundVariableKind::Const,
         }
@@ -272,7 +349,7 @@ impl<'tcx> Stable<'tcx> for ty::BoundVariableKind {
 impl<'tcx> Stable<'tcx> for ty::IntTy {
     type T = IntTy;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             ty::IntTy::Isize => IntTy::Isize,
             ty::IntTy::I8 => IntTy::I8,
@@ -287,7 +364,7 @@ impl<'tcx> Stable<'tcx> for ty::IntTy {
 impl<'tcx> Stable<'tcx> for ty::UintTy {
     type T = UintTy;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             ty::UintTy::Usize => UintTy::Usize,
             ty::UintTy::U8 => UintTy::U8,
@@ -302,7 +379,7 @@ impl<'tcx> Stable<'tcx> for ty::UintTy {
 impl<'tcx> Stable<'tcx> for ty::FloatTy {
     type T = FloatTy;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             ty::FloatTy::F16 => FloatTy::F16,
             ty::FloatTy::F32 => FloatTy::F32,
@@ -314,46 +391,55 @@ impl<'tcx> Stable<'tcx> for ty::FloatTy {
 
 impl<'tcx> Stable<'tcx> for Ty<'tcx> {
     type T = stable_mir::ty::Ty;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        tables.intern_ty(tables.tcx.lift(*self).unwrap())
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        tables.intern_ty(cx.lift(*self).unwrap())
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
     type T = stable_mir::ty::TyKind;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match self {
             ty::Bool => TyKind::RigidTy(RigidTy::Bool),
             ty::Char => TyKind::RigidTy(RigidTy::Char),
-            ty::Int(int_ty) => TyKind::RigidTy(RigidTy::Int(int_ty.stable(tables))),
-            ty::Uint(uint_ty) => TyKind::RigidTy(RigidTy::Uint(uint_ty.stable(tables))),
-            ty::Float(float_ty) => TyKind::RigidTy(RigidTy::Float(float_ty.stable(tables))),
+            ty::Int(int_ty) => TyKind::RigidTy(RigidTy::Int(int_ty.stable(tables, cx))),
+            ty::Uint(uint_ty) => TyKind::RigidTy(RigidTy::Uint(uint_ty.stable(tables, cx))),
+            ty::Float(float_ty) => TyKind::RigidTy(RigidTy::Float(float_ty.stable(tables, cx))),
             ty::Adt(adt_def, generic_args) => TyKind::RigidTy(RigidTy::Adt(
                 tables.adt_def(adt_def.did()),
-                generic_args.stable(tables),
+                generic_args.stable(tables, cx),
             )),
             ty::Foreign(def_id) => TyKind::RigidTy(RigidTy::Foreign(tables.foreign_def(*def_id))),
             ty::Str => TyKind::RigidTy(RigidTy::Str),
             ty::Array(ty, constant) => {
-                TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables)))
+                TyKind::RigidTy(RigidTy::Array(ty.stable(tables, cx), constant.stable(tables, cx)))
             }
             ty::Pat(ty, pat) => {
-                TyKind::RigidTy(RigidTy::Pat(ty.stable(tables), pat.stable(tables)))
+                TyKind::RigidTy(RigidTy::Pat(ty.stable(tables, cx), pat.stable(tables, cx)))
             }
-            ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))),
+            ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables, cx))),
             ty::RawPtr(ty, mutbl) => {
-                TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables)))
+                TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables, cx), mutbl.stable(tables, cx)))
             }
             ty::Ref(region, ty, mutbl) => TyKind::RigidTy(RigidTy::Ref(
-                region.stable(tables),
-                ty.stable(tables),
-                mutbl.stable(tables),
+                region.stable(tables, cx),
+                ty.stable(tables, cx),
+                mutbl.stable(tables, cx),
+            )),
+            ty::FnDef(def_id, generic_args) => TyKind::RigidTy(RigidTy::FnDef(
+                tables.fn_def(*def_id),
+                generic_args.stable(tables, cx),
             )),
-            ty::FnDef(def_id, generic_args) => {
-                TyKind::RigidTy(RigidTy::FnDef(tables.fn_def(*def_id), generic_args.stable(tables)))
-            }
             ty::FnPtr(sig_tys, hdr) => {
-                TyKind::RigidTy(RigidTy::FnPtr(sig_tys.with(*hdr).stable(tables)))
+                TyKind::RigidTy(RigidTy::FnPtr(sig_tys.with(*hdr).stable(tables, cx)))
             }
             // FIXME(unsafe_binders):
             ty::UnsafeBinder(_) => todo!(),
@@ -361,36 +447,36 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
                 TyKind::RigidTy(RigidTy::Dynamic(
                     existential_predicates
                         .iter()
-                        .map(|existential_predicate| existential_predicate.stable(tables))
+                        .map(|existential_predicate| existential_predicate.stable(tables, cx))
                         .collect(),
-                    region.stable(tables),
-                    dyn_kind.stable(tables),
+                    region.stable(tables, cx),
+                    dyn_kind.stable(tables, cx),
                 ))
             }
             ty::Closure(def_id, generic_args) => TyKind::RigidTy(RigidTy::Closure(
                 tables.closure_def(*def_id),
-                generic_args.stable(tables),
+                generic_args.stable(tables, cx),
             )),
             ty::CoroutineClosure(..) => todo!("FIXME(async_closures): Lower these to SMIR"),
             ty::Coroutine(def_id, generic_args) => TyKind::RigidTy(RigidTy::Coroutine(
                 tables.coroutine_def(*def_id),
-                generic_args.stable(tables),
-                tables.tcx.coroutine_movability(*def_id).stable(tables),
+                generic_args.stable(tables, cx),
+                cx.coroutine_movability(*def_id).stable(tables, cx),
             )),
             ty::Never => TyKind::RigidTy(RigidTy::Never),
-            ty::Tuple(fields) => {
-                TyKind::RigidTy(RigidTy::Tuple(fields.iter().map(|ty| ty.stable(tables)).collect()))
-            }
+            ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple(
+                fields.iter().map(|ty| ty.stable(tables, cx)).collect(),
+            )),
             ty::Alias(alias_kind, alias_ty) => {
-                TyKind::Alias(alias_kind.stable(tables), alias_ty.stable(tables))
+                TyKind::Alias(alias_kind.stable(tables, cx), alias_ty.stable(tables, cx))
             }
-            ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables)),
+            ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables, cx)),
             ty::Bound(debruijn_idx, bound_ty) => {
-                TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables))
+                TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables, cx))
             }
             ty::CoroutineWitness(def_id, args) => TyKind::RigidTy(RigidTy::CoroutineWitness(
                 tables.coroutine_witness_def(*def_id),
-                args.stable(tables),
+                args.stable(tables, cx),
             )),
             ty::Placeholder(..) | ty::Infer(_) | ty::Error(_) => {
                 unreachable!();
@@ -402,12 +488,16 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
     type T = stable_mir::ty::Pattern;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         match **self {
             ty::PatternKind::Range { start, end } => stable_mir::ty::Pattern::Range {
                 // FIXME(SMIR): update data structures to not have an Option here anymore
-                start: Some(start.stable(tables)),
-                end: Some(end.stable(tables)),
+                start: Some(start.stable(tables, cx)),
+                end: Some(end.stable(tables, cx)),
                 include_end: true,
             },
             ty::PatternKind::Or(_) => todo!(),
@@ -418,24 +508,30 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
     type T = stable_mir::ty::TyConst;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        let ct = tables.tcx.lift(*self).unwrap();
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        let ct = cx.lift(*self).unwrap();
         let kind = match ct.kind() {
             ty::ConstKind::Value(cv) => {
-                let const_val = tables.tcx.valtree_to_const_val(cv);
+                let const_val = cx.valtree_to_const_val(cv);
                 if matches!(const_val, mir::ConstValue::ZeroSized) {
-                    stable_mir::ty::TyConstKind::ZSTValue(cv.ty.stable(tables))
+                    stable_mir::ty::TyConstKind::ZSTValue(cv.ty.stable(tables, cx))
                 } else {
                     stable_mir::ty::TyConstKind::Value(
-                        cv.ty.stable(tables),
-                        alloc::new_allocation(cv.ty, const_val, tables),
+                        cv.ty.stable(tables, cx),
+                        alloc::new_allocation(cv.ty, const_val, tables, cx),
                     )
                 }
             }
-            ty::ConstKind::Param(param) => stable_mir::ty::TyConstKind::Param(param.stable(tables)),
+            ty::ConstKind::Param(param) => {
+                stable_mir::ty::TyConstKind::Param(param.stable(tables, cx))
+            }
             ty::ConstKind::Unevaluated(uv) => stable_mir::ty::TyConstKind::Unevaluated(
                 tables.const_def(uv.def),
-                uv.args.stable(tables),
+                uv.args.stable(tables, cx),
             ),
             ty::ConstKind::Error(_) => unreachable!(),
             ty::ConstKind::Infer(_) => unreachable!(),
@@ -450,7 +546,7 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
 
 impl<'tcx> Stable<'tcx> for ty::ParamConst {
     type T = stable_mir::ty::ParamConst;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use stable_mir::ty::ParamConst;
         ParamConst { index: self.index, name: self.name.to_string() }
     }
@@ -458,7 +554,7 @@ impl<'tcx> Stable<'tcx> for ty::ParamConst {
 
 impl<'tcx> Stable<'tcx> for ty::ParamTy {
     type T = stable_mir::ty::ParamTy;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use stable_mir::ty::ParamTy;
         ParamTy { index: self.index, name: self.name.to_string() }
     }
@@ -466,15 +562,19 @@ impl<'tcx> Stable<'tcx> for ty::ParamTy {
 
 impl<'tcx> Stable<'tcx> for ty::BoundTy {
     type T = stable_mir::ty::BoundTy;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::BoundTy;
-        BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables) }
+        BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables, cx) }
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind {
     type T = stable_mir::ty::TraitSpecializationKind;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use stable_mir::ty::TraitSpecializationKind;
 
         match self {
@@ -489,20 +589,24 @@ impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind {
 
 impl<'tcx> Stable<'tcx> for ty::TraitDef {
     type T = stable_mir::ty::TraitDecl;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::opaque;
         use stable_mir::ty::TraitDecl;
 
         TraitDecl {
             def_id: tables.trait_def(self.def_id),
-            safety: self.safety.stable(tables),
+            safety: self.safety.stable(tables, cx),
             paren_sugar: self.paren_sugar,
             has_auto_impl: self.has_auto_impl,
             is_marker: self.is_marker,
             is_coinductive: self.is_coinductive,
             skip_array_during_method_dispatch: self.skip_array_during_method_dispatch,
             skip_boxed_slice_during_method_dispatch: self.skip_boxed_slice_during_method_dispatch,
-            specialization_kind: self.specialization_kind.stable(tables),
+            specialization_kind: self.specialization_kind.stable(tables, cx),
             must_implement_one_of: self
                 .must_implement_one_of
                 .as_ref()
@@ -515,20 +619,28 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef {
 
 impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> {
     type T = stable_mir::ty::TraitRef;
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::TraitRef;
 
-        TraitRef::try_new(tables.trait_def(self.def_id), self.args.stable(tables)).unwrap()
+        TraitRef::try_new(tables.trait_def(self.def_id), self.args.stable(tables, cx)).unwrap()
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::Generics {
     type T = stable_mir::ty::Generics;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::Generics;
 
-        let params: Vec<_> = self.own_params.iter().map(|param| param.stable(tables)).collect();
+        let params: Vec<_> = self.own_params.iter().map(|param| param.stable(tables, cx)).collect();
         let param_def_id_to_index =
             params.iter().map(|param| (param.def_id, param.index)).collect();
 
@@ -541,7 +653,7 @@ impl<'tcx> Stable<'tcx> for ty::Generics {
             has_late_bound_regions: self
                 .has_late_bound_regions
                 .as_ref()
-                .map(|late_bound_regions| late_bound_regions.stable(tables)),
+                .map(|late_bound_regions| late_bound_regions.stable(tables, cx)),
         }
     }
 }
@@ -549,7 +661,7 @@ impl<'tcx> Stable<'tcx> for ty::Generics {
 impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind {
     type T = stable_mir::ty::GenericParamDefKind;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use stable_mir::ty::GenericParamDefKind;
         match self {
             ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime,
@@ -566,13 +678,17 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind {
 impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDef {
     type T = stable_mir::ty::GenericParamDef;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         GenericParamDef {
             name: self.name.to_string(),
             def_id: tables.generic_def(self.def_id),
             index: self.index,
             pure_wrt_drop: self.pure_wrt_drop,
-            kind: self.kind.stable(tables),
+            kind: self.kind.stable(tables, cx),
         }
     }
 }
@@ -580,31 +696,36 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDef {
 impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> {
     type T = stable_mir::ty::PredicateKind;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::ty::PredicateKind;
         match self {
             PredicateKind::Clause(clause_kind) => {
-                stable_mir::ty::PredicateKind::Clause(clause_kind.stable(tables))
+                stable_mir::ty::PredicateKind::Clause(clause_kind.stable(tables, cx))
             }
             PredicateKind::DynCompatible(did) => {
                 stable_mir::ty::PredicateKind::DynCompatible(tables.trait_def(*did))
             }
             PredicateKind::Subtype(subtype_predicate) => {
-                stable_mir::ty::PredicateKind::SubType(subtype_predicate.stable(tables))
+                stable_mir::ty::PredicateKind::SubType(subtype_predicate.stable(tables, cx))
             }
             PredicateKind::Coerce(coerce_predicate) => {
-                stable_mir::ty::PredicateKind::Coerce(coerce_predicate.stable(tables))
-            }
-            PredicateKind::ConstEquate(a, b) => {
-                stable_mir::ty::PredicateKind::ConstEquate(a.stable(tables), b.stable(tables))
+                stable_mir::ty::PredicateKind::Coerce(coerce_predicate.stable(tables, cx))
             }
+            PredicateKind::ConstEquate(a, b) => stable_mir::ty::PredicateKind::ConstEquate(
+                a.stable(tables, cx),
+                b.stable(tables, cx),
+            ),
             PredicateKind::Ambiguous => stable_mir::ty::PredicateKind::Ambiguous,
             PredicateKind::NormalizesTo(_pred) => unimplemented!(),
             PredicateKind::AliasRelate(a, b, alias_relation_direction) => {
                 stable_mir::ty::PredicateKind::AliasRelate(
-                    a.kind().stable(tables),
-                    b.kind().stable(tables),
-                    alias_relation_direction.stable(tables),
+                    a.kind().stable(tables, cx),
+                    b.kind().stable(tables, cx),
+                    alias_relation_direction.stable(tables, cx),
                 )
             }
         }
@@ -614,34 +735,38 @@ impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
     type T = stable_mir::ty::ClauseKind;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use rustc_middle::ty::ClauseKind;
         match *self {
             ClauseKind::Trait(trait_object) => {
-                stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables))
+                stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables, cx))
             }
             ClauseKind::RegionOutlives(region_outlives) => {
-                stable_mir::ty::ClauseKind::RegionOutlives(region_outlives.stable(tables))
+                stable_mir::ty::ClauseKind::RegionOutlives(region_outlives.stable(tables, cx))
             }
             ClauseKind::TypeOutlives(type_outlives) => {
                 let ty::OutlivesPredicate::<_, _>(a, b) = type_outlives;
                 stable_mir::ty::ClauseKind::TypeOutlives(stable_mir::ty::OutlivesPredicate(
-                    a.stable(tables),
-                    b.stable(tables),
+                    a.stable(tables, cx),
+                    b.stable(tables, cx),
                 ))
             }
             ClauseKind::Projection(projection_predicate) => {
-                stable_mir::ty::ClauseKind::Projection(projection_predicate.stable(tables))
+                stable_mir::ty::ClauseKind::Projection(projection_predicate.stable(tables, cx))
             }
             ClauseKind::ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType(
-                const_.stable(tables),
-                ty.stable(tables),
+                const_.stable(tables, cx),
+                ty.stable(tables, cx),
             ),
             ClauseKind::WellFormed(term) => {
-                stable_mir::ty::ClauseKind::WellFormed(term.kind().stable(tables))
+                stable_mir::ty::ClauseKind::WellFormed(term.kind().stable(tables, cx))
             }
             ClauseKind::ConstEvaluatable(const_) => {
-                stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables))
+                stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables, cx))
             }
             ClauseKind::HostEffect(..) => {
                 todo!()
@@ -653,7 +778,7 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::ClosureKind {
     type T = stable_mir::ty::ClosureKind;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::ty::ClosureKind::*;
         match self {
             Fn => stable_mir::ty::ClosureKind::Fn,
@@ -666,25 +791,33 @@ impl<'tcx> Stable<'tcx> for ty::ClosureKind {
 impl<'tcx> Stable<'tcx> for ty::SubtypePredicate<'tcx> {
     type T = stable_mir::ty::SubtypePredicate;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         let ty::SubtypePredicate { a, b, a_is_expected: _ } = self;
-        stable_mir::ty::SubtypePredicate { a: a.stable(tables), b: b.stable(tables) }
+        stable_mir::ty::SubtypePredicate { a: a.stable(tables, cx), b: b.stable(tables, cx) }
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::CoercePredicate<'tcx> {
     type T = stable_mir::ty::CoercePredicate;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         let ty::CoercePredicate { a, b } = self;
-        stable_mir::ty::CoercePredicate { a: a.stable(tables), b: b.stable(tables) }
+        stable_mir::ty::CoercePredicate { a: a.stable(tables, cx), b: b.stable(tables, cx) }
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::AliasRelationDirection {
     type T = stable_mir::ty::AliasRelationDirection;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::ty::AliasRelationDirection::*;
         match self {
             Equate => stable_mir::ty::AliasRelationDirection::Equate,
@@ -696,11 +829,15 @@ impl<'tcx> Stable<'tcx> for ty::AliasRelationDirection {
 impl<'tcx> Stable<'tcx> for ty::TraitPredicate<'tcx> {
     type T = stable_mir::ty::TraitPredicate;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         let ty::TraitPredicate { trait_ref, polarity } = self;
         stable_mir::ty::TraitPredicate {
-            trait_ref: trait_ref.stable(tables),
-            polarity: polarity.stable(tables),
+            trait_ref: trait_ref.stable(tables, cx),
+            polarity: polarity.stable(tables, cx),
         }
     }
 }
@@ -711,20 +848,28 @@ where
 {
     type T = stable_mir::ty::OutlivesPredicate<T::T, Region>;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         let ty::OutlivesPredicate(a, b) = self;
-        stable_mir::ty::OutlivesPredicate(a.stable(tables), b.stable(tables))
+        stable_mir::ty::OutlivesPredicate(a.stable(tables, cx), b.stable(tables, cx))
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::ProjectionPredicate<'tcx> {
     type T = stable_mir::ty::ProjectionPredicate;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         let ty::ProjectionPredicate { projection_term, term } = self;
         stable_mir::ty::ProjectionPredicate {
-            projection_term: projection_term.stable(tables),
-            term: term.kind().stable(tables),
+            projection_term: projection_term.stable(tables, cx),
+            term: term.kind().stable(tables, cx),
         }
     }
 }
@@ -732,7 +877,7 @@ impl<'tcx> Stable<'tcx> for ty::ProjectionPredicate<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::ImplPolarity {
     type T = stable_mir::ty::ImplPolarity;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::ty::ImplPolarity::*;
         match self {
             Positive => stable_mir::ty::ImplPolarity::Positive,
@@ -745,7 +890,7 @@ impl<'tcx> Stable<'tcx> for ty::ImplPolarity {
 impl<'tcx> Stable<'tcx> for ty::PredicatePolarity {
     type T = stable_mir::ty::PredicatePolarity;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_middle::ty::PredicatePolarity::*;
         match self {
             Positive => stable_mir::ty::PredicatePolarity::Positive,
@@ -757,15 +902,23 @@ impl<'tcx> Stable<'tcx> for ty::PredicatePolarity {
 impl<'tcx> Stable<'tcx> for ty::Region<'tcx> {
     type T = stable_mir::ty::Region;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        Region { kind: self.kind().stable(tables) }
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        Region { kind: self.kind().stable(tables, cx) }
     }
 }
 
 impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> {
     type T = stable_mir::ty::RegionKind;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::{BoundRegion, EarlyParamRegion, RegionKind};
         match self {
             ty::ReEarlyParam(early_reg) => RegionKind::ReEarlyParam(EarlyParamRegion {
@@ -774,7 +927,10 @@ impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> {
             }),
             ty::ReBound(db_index, bound_reg) => RegionKind::ReBound(
                 db_index.as_u32(),
-                BoundRegion { var: bound_reg.var.as_u32(), kind: bound_reg.kind.stable(tables) },
+                BoundRegion {
+                    var: bound_reg.var.as_u32(),
+                    kind: bound_reg.kind.stable(tables, cx),
+                },
             ),
             ty::ReStatic => RegionKind::ReStatic,
             ty::RePlaceholder(place_holder) => {
@@ -782,7 +938,7 @@ impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> {
                     universe: place_holder.universe.as_u32(),
                     bound: BoundRegion {
                         var: place_holder.bound.var.as_u32(),
-                        kind: place_holder.bound.kind.stable(tables),
+                        kind: place_holder.bound.kind.stable(tables, cx),
                     },
                 })
             }
@@ -795,8 +951,12 @@ impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> {
     type T = stable_mir::mir::mono::Instance;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        let def = tables.instance_def(tables.tcx.lift(*self).unwrap());
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        let def = tables.instance_def(cx.lift(*self).unwrap());
         let kind = match self.def {
             ty::InstanceKind::Item(..) => stable_mir::mir::mono::InstanceKind::Item,
             ty::InstanceKind::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic,
@@ -824,7 +984,7 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> {
 
 impl<'tcx> Stable<'tcx> for ty::Variance {
     type T = stable_mir::mir::Variance;
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             ty::Bivariant => stable_mir::mir::Variance::Bivariant,
             ty::Contravariant => stable_mir::mir::Variance::Contravariant,
@@ -837,7 +997,7 @@ impl<'tcx> Stable<'tcx> for ty::Variance {
 impl<'tcx> Stable<'tcx> for ty::Movability {
     type T = stable_mir::ty::Movability;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         match self {
             ty::Movability::Static => stable_mir::ty::Movability::Static,
             ty::Movability::Movable => stable_mir::ty::Movability::Movable,
@@ -848,7 +1008,7 @@ impl<'tcx> Stable<'tcx> for ty::Movability {
 impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
     type T = stable_mir::ty::Abi;
 
-    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use rustc_abi::ExternAbi;
         use stable_mir::ty::Abi;
         match *self {
@@ -886,10 +1046,14 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
 impl<'tcx> Stable<'tcx> for rustc_session::cstore::ForeignModule {
     type T = stable_mir::ty::ForeignModule;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         stable_mir::ty::ForeignModule {
             def_id: tables.foreign_module_def(self.def_id),
-            abi: self.abi.stable(tables),
+            abi: self.abi.stable(tables, cx),
         }
     }
 }
@@ -897,7 +1061,11 @@ impl<'tcx> Stable<'tcx> for rustc_session::cstore::ForeignModule {
 impl<'tcx> Stable<'tcx> for ty::AssocKind {
     type T = stable_mir::ty::AssocKind;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::{AssocKind, AssocTypeData};
         match *self {
             ty::AssocKind::Const { name } => AssocKind::Const { name: name.to_string() },
@@ -908,7 +1076,7 @@ impl<'tcx> Stable<'tcx> for ty::AssocKind {
                 data: match data {
                     ty::AssocTypeData::Normal(name) => AssocTypeData::Normal(name.to_string()),
                     ty::AssocTypeData::Rpitit(rpitit) => {
-                        AssocTypeData::Rpitit(rpitit.stable(tables))
+                        AssocTypeData::Rpitit(rpitit.stable(tables, cx))
                     }
                 },
             },
@@ -919,7 +1087,7 @@ impl<'tcx> Stable<'tcx> for ty::AssocKind {
 impl<'tcx> Stable<'tcx> for ty::AssocItemContainer {
     type T = stable_mir::ty::AssocItemContainer;
 
-    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T {
         use stable_mir::ty::AssocItemContainer;
         match self {
             ty::AssocItemContainer::Trait => AssocItemContainer::Trait,
@@ -931,11 +1099,15 @@ impl<'tcx> Stable<'tcx> for ty::AssocItemContainer {
 impl<'tcx> Stable<'tcx> for ty::AssocItem {
     type T = stable_mir::ty::AssocItem;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         stable_mir::ty::AssocItem {
             def_id: tables.assoc_def(self.def_id),
-            kind: self.kind.stable(tables),
-            container: self.container.stable(tables),
+            kind: self.kind.stable(tables, cx),
+            container: self.container.stable(tables, cx),
             trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)),
         }
     }
@@ -944,7 +1116,11 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem {
 impl<'tcx> Stable<'tcx> for ty::ImplTraitInTraitData {
     type T = stable_mir::ty::ImplTraitInTraitData;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        _: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
         use stable_mir::ty::ImplTraitInTraitData;
         match self {
             ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id } => {
@@ -963,7 +1139,11 @@ impl<'tcx> Stable<'tcx> for ty::ImplTraitInTraitData {
 impl<'tcx> Stable<'tcx> for rustc_middle::ty::util::Discr<'tcx> {
     type T = stable_mir::ty::Discr;
 
-    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        stable_mir::ty::Discr { val: self.val, ty: self.ty.stable(tables) }
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T {
+        stable_mir::ty::Discr { val: self.val, ty: self.ty.stable(tables, cx) }
     }
 }
diff --git a/compiler/rustc_smir/src/stable_mir/unstable/mod.rs b/compiler/rustc_smir/src/stable_mir/unstable/mod.rs
new file mode 100644
index 00000000000..77a772019eb
--- /dev/null
+++ b/compiler/rustc_smir/src/stable_mir/unstable/mod.rs
@@ -0,0 +1,210 @@
+//! Module that collects the things that have no stability guarantees.
+//!
+//! We want to keep StableMIR definitions and logic separate from
+//! any sort of conversion and usage of internal rustc code. So we
+//! restrict the usage of internal items to be inside this module.
+
+use std::marker::PointeeSized;
+
+use rustc_hir::def::DefKind;
+use rustc_middle::ty::{List, Ty, TyCtxt};
+use rustc_middle::{mir, ty};
+use rustc_smir::Tables;
+use rustc_smir::context::{
+    SmirCtxt, SmirExistentialProjection, SmirExistentialTraitRef, SmirTraitRef,
+};
+use stable_mir::{CtorKind, ItemKind};
+
+use super::compiler_interface::BridgeTys;
+use crate::{rustc_smir, stable_mir};
+
+pub(crate) mod convert;
+
+impl<'tcx, T: InternalCx<'tcx>> SmirExistentialProjection<'tcx> for T {
+    fn new_from_args(
+        &self,
+        def_id: rustc_span::def_id::DefId,
+        args: ty::GenericArgsRef<'tcx>,
+        term: ty::Term<'tcx>,
+    ) -> ty::ExistentialProjection<'tcx> {
+        ty::ExistentialProjection::new_from_args(self.tcx(), def_id, args, term)
+    }
+}
+
+impl<'tcx, T: InternalCx<'tcx>> SmirExistentialTraitRef<'tcx> for T {
+    fn new_from_args(
+        &self,
+        trait_def_id: rustc_span::def_id::DefId,
+        args: ty::GenericArgsRef<'tcx>,
+    ) -> ty::ExistentialTraitRef<'tcx> {
+        ty::ExistentialTraitRef::new_from_args(self.tcx(), trait_def_id, args)
+    }
+}
+
+impl<'tcx, T: InternalCx<'tcx>> SmirTraitRef<'tcx> for T {
+    fn new_from_args(
+        &self,
+        trait_def_id: rustc_span::def_id::DefId,
+        args: ty::GenericArgsRef<'tcx>,
+    ) -> ty::TraitRef<'tcx> {
+        ty::TraitRef::new_from_args(self.tcx(), trait_def_id, args)
+    }
+}
+
+impl<'tcx> InternalCx<'tcx> for TyCtxt<'tcx> {
+    fn tcx(self) -> TyCtxt<'tcx> {
+        self
+    }
+
+    fn lift<T: ty::Lift<TyCtxt<'tcx>>>(self, value: T) -> Option<T::Lifted> {
+        TyCtxt::lift(self, value)
+    }
+
+    fn mk_args_from_iter<I, T>(self, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: ty::CollectAndApply<ty::GenericArg<'tcx>, ty::GenericArgsRef<'tcx>>,
+    {
+        TyCtxt::mk_args_from_iter(self, iter)
+    }
+
+    fn mk_pat(self, v: ty::PatternKind<'tcx>) -> ty::Pattern<'tcx> {
+        TyCtxt::mk_pat(self, v)
+    }
+
+    fn mk_poly_existential_predicates(
+        self,
+        eps: &[ty::PolyExistentialPredicate<'tcx>],
+    ) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> {
+        TyCtxt::mk_poly_existential_predicates(self, eps)
+    }
+
+    fn mk_type_list(self, v: &[Ty<'tcx>]) -> &'tcx List<Ty<'tcx>> {
+        TyCtxt::mk_type_list(self, v)
+    }
+
+    fn lifetimes_re_erased(self) -> ty::Region<'tcx> {
+        self.lifetimes.re_erased
+    }
+
+    fn mk_bound_variable_kinds_from_iter<I, T>(self, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: ty::CollectAndApply<ty::BoundVariableKind, &'tcx List<ty::BoundVariableKind>>,
+    {
+        TyCtxt::mk_bound_variable_kinds_from_iter(self, iter)
+    }
+
+    fn mk_place_elems(self, v: &[mir::PlaceElem<'tcx>]) -> &'tcx List<mir::PlaceElem<'tcx>> {
+        TyCtxt::mk_place_elems(self, v)
+    }
+
+    fn adt_def(self, def_id: rustc_hir::def_id::DefId) -> ty::AdtDef<'tcx> {
+        self.adt_def(def_id)
+    }
+}
+
+/// Trait that defines the methods that are fine to call from [`RustcInternal`].
+///
+/// This trait is only for [`RustcInternal`]. Any other other access to rustc's internals
+/// should go through [`crate::rustc_smir::context::SmirCtxt`].
+pub trait InternalCx<'tcx>: Copy + Clone {
+    fn tcx(self) -> TyCtxt<'tcx>;
+
+    fn lift<T: ty::Lift<TyCtxt<'tcx>>>(self, value: T) -> Option<T::Lifted>;
+
+    fn mk_args_from_iter<I, T>(self, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: ty::CollectAndApply<ty::GenericArg<'tcx>, ty::GenericArgsRef<'tcx>>;
+
+    fn mk_pat(self, v: ty::PatternKind<'tcx>) -> ty::Pattern<'tcx>;
+
+    fn mk_poly_existential_predicates(
+        self,
+        eps: &[ty::PolyExistentialPredicate<'tcx>],
+    ) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>>;
+
+    fn mk_type_list(self, v: &[Ty<'tcx>]) -> &'tcx List<Ty<'tcx>>;
+
+    fn lifetimes_re_erased(self) -> ty::Region<'tcx>;
+
+    fn mk_bound_variable_kinds_from_iter<I, T>(self, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: ty::CollectAndApply<ty::BoundVariableKind, &'tcx List<ty::BoundVariableKind>>;
+
+    fn mk_place_elems(self, v: &[mir::PlaceElem<'tcx>]) -> &'tcx List<mir::PlaceElem<'tcx>>;
+
+    fn adt_def(self, def_id: rustc_hir::def_id::DefId) -> ty::AdtDef<'tcx>;
+}
+
+/// Trait used to convert between an internal MIR type to a Stable MIR type.
+///
+/// This trait is currently exposed to users so they can have interoperability between internal MIR
+/// and StableMIR constructs. However, they should be used seldom and they have no influence
+/// in this crate semver.
+#[doc(hidden)]
+pub trait Stable<'tcx>: PointeeSized {
+    /// The stable representation of the type implementing Stable.
+    type T;
+    /// Converts an object to the equivalent Stable MIR representation.
+    fn stable<'cx>(
+        &self,
+        tables: &mut Tables<'cx, BridgeTys>,
+        cx: &SmirCtxt<'cx, BridgeTys>,
+    ) -> Self::T;
+}
+
+/// Trait used to translate a stable construct to its rustc counterpart.
+///
+/// This is basically a mirror of [Stable].
+///
+/// This trait is currently exposed to users so they can have interoperability between internal MIR
+/// and StableMIR constructs. They should be used seldom as they have no stability guarantees.
+#[doc(hidden)]
+pub trait RustcInternal {
+    type T<'tcx>;
+    fn internal<'tcx>(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        tcx: impl InternalCx<'tcx>,
+    ) -> Self::T<'tcx>;
+}
+
+pub(crate) fn new_item_kind(kind: DefKind) -> ItemKind {
+    match kind {
+        DefKind::Mod
+        | DefKind::Struct
+        | DefKind::Union
+        | DefKind::Enum
+        | DefKind::Variant
+        | DefKind::Trait
+        | DefKind::TyAlias
+        | DefKind::ForeignTy
+        | DefKind::TraitAlias
+        | DefKind::AssocTy
+        | DefKind::TyParam
+        | DefKind::ConstParam
+        | DefKind::Macro(_)
+        | DefKind::ExternCrate
+        | DefKind::Use
+        | DefKind::ForeignMod
+        | DefKind::OpaqueTy
+        | DefKind::Field
+        | DefKind::LifetimeParam
+        | DefKind::Impl { .. }
+        | DefKind::GlobalAsm => {
+            unreachable!("Not a valid item kind: {kind:?}");
+        }
+        DefKind::Closure | DefKind::AssocFn | DefKind::Fn | DefKind::SyntheticCoroutineBody => {
+            ItemKind::Fn
+        }
+        DefKind::Const | DefKind::InlineConst | DefKind::AssocConst | DefKind::AnonConst => {
+            ItemKind::Const
+        }
+        DefKind::Static { .. } => ItemKind::Static,
+        DefKind::Ctor(_, rustc_hir::def::CtorKind::Const) => ItemKind::Ctor(CtorKind::Const),
+        DefKind::Ctor(_, rustc_hir::def::CtorKind::Fn) => ItemKind::Ctor(CtorKind::Fn),
+    }
+}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d6537d49be7..09f01d8704e 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1623,7 +1623,6 @@ symbols! {
         pointee_sized,
         pointee_trait,
         pointer,
-        pointer_like,
         poll,
         poll_next,
         position,
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 3a369f13e79..a6b77583fdc 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -14,9 +14,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
-use rustc_middle::ty::{
-    self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast, elaborate,
-};
+use rustc_middle::ty::{self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use thin_vec::thin_vec;
@@ -1147,38 +1145,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     ty::ClauseKind::TypeOutlives(outlives).upcast(tcx),
                 ));
 
-                // Require that all AFIT will return something that can be coerced into `dyn*`
-                // -- a shim will be responsible for doing the actual coercion to `dyn*`.
-                if let Some(principal) = data.principal() {
-                    for supertrait in
-                        elaborate::supertraits(tcx, principal.with_self_ty(tcx, source))
-                    {
-                        if tcx.is_trait_alias(supertrait.def_id()) {
-                            continue;
-                        }
-
-                        for &assoc_item in tcx.associated_item_def_ids(supertrait.def_id()) {
-                            if !tcx.is_impl_trait_in_trait(assoc_item) {
-                                continue;
-                            }
-
-                            // RPITITs with `Self: Sized` don't need to be checked.
-                            if tcx.generics_require_sized_self(assoc_item) {
-                                continue;
-                            }
-
-                            let pointer_like_goal = pointer_like_goal_for_rpitit(
-                                tcx,
-                                supertrait,
-                                assoc_item,
-                                &obligation.cause,
-                            );
-
-                            nested.push(predicate_to_obligation(pointer_like_goal.upcast(tcx)));
-                        }
-                    }
-                }
-
                 ImplSource::Builtin(BuiltinImplSource::Misc, nested)
             }
 
@@ -1344,46 +1310,3 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
     }
 }
-
-/// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures)
-/// implements the `PointerLike` trait, which is a requirement for the RPITIT to be
-/// coercible to `dyn* Future`, which is itself a requirement for the RPITIT's parent
-/// trait to be coercible to `dyn Trait`.
-///
-/// We do this given a supertrait's substitutions, and then augment the substitutions
-/// with bound variables to compute the goal universally. Given that `PointerLike` has
-/// no region requirements (at least for the built-in pointer types), this shouldn't
-/// *really* matter, but it is the best choice for soundness.
-fn pointer_like_goal_for_rpitit<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    supertrait: ty::PolyTraitRef<'tcx>,
-    rpitit_item: DefId,
-    cause: &ObligationCause<'tcx>,
-) -> ty::PolyTraitRef<'tcx> {
-    let mut bound_vars = supertrait.bound_vars().to_vec();
-
-    let args = supertrait.skip_binder().args.extend_to(tcx, rpitit_item, |arg, _| match arg.kind {
-        ty::GenericParamDefKind::Lifetime => {
-            let kind = ty::BoundRegionKind::Named(arg.def_id, tcx.item_name(arg.def_id));
-            bound_vars.push(ty::BoundVariableKind::Region(kind));
-            ty::Region::new_bound(
-                tcx,
-                ty::INNERMOST,
-                ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
-            )
-            .into()
-        }
-        ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
-            unreachable!()
-        }
-    });
-
-    ty::Binder::bind_with_vars(
-        ty::TraitRef::new(
-            tcx,
-            tcx.require_lang_item(LangItem::PointerLike, cause.span),
-            [Ty::new_projection_from_args(tcx, rpitit_item, args)],
-        ),
-        tcx.mk_bound_variable_kinds(&bound_vars),
-    )
-}
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index b4176e9c1f4..c9b98fa4e5a 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -429,10 +429,10 @@ pub mod __alloc_error_handler {
             // This symbol is emitted by rustc next to __rust_alloc_error_handler.
             // Its value depends on the -Zoom={panic,abort} compiler option.
             #[rustc_std_internal_symbol]
-            static __rust_alloc_error_handler_should_panic: u8;
+            fn __rust_alloc_error_handler_should_panic_v2() -> u8;
         }
 
-        if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
+        if unsafe { __rust_alloc_error_handler_should_panic_v2() != 0 } {
             panic!("memory allocation of {size} bytes failed")
         } else {
             core::panicking::panic_nounwind_fmt(
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 4e3f76de49e..3db37f1d16f 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -191,7 +191,7 @@ use core::error::{self, Error};
 use core::fmt;
 use core::future::Future;
 use core::hash::{Hash, Hasher};
-use core::marker::{PointerLike, Tuple, Unsize};
+use core::marker::{Tuple, Unsize};
 use core::mem::{self, SizedTypeProperties};
 use core::ops::{
     AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut,
@@ -2132,6 +2132,3 @@ impl<E: Error> Error for Box<E> {
         Error::provide(&**self, request);
     }
 }
-
-#[unstable(feature = "pointer_like_trait", issue = "none")]
-impl<T> PointerLike for Box<T> {}
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index f416732a8d6..4290bb7a8a9 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -134,7 +134,6 @@
 #![feature(panic_internals)]
 #![feature(pattern)]
 #![feature(pin_coerce_unsized_trait)]
-#![feature(pointer_like_trait)]
 #![feature(ptr_alignment_type)]
 #![feature(ptr_internals)]
 #![feature(ptr_metadata)]
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 7ce03e3d831..dfed8a00b7d 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -252,7 +252,7 @@
 
 use crate::cmp::Ordering;
 use crate::fmt::{self, Debug, Display};
-use crate::marker::{PhantomData, PointerLike, Unsize};
+use crate::marker::{PhantomData, Unsize};
 use crate::mem;
 use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
 use crate::panic::const_panic;
@@ -669,9 +669,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
 impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Cell<U>> for Cell<T> {}
 
-#[unstable(feature = "pointer_like_trait", issue = "none")]
-impl<T: PointerLike> PointerLike for Cell<T> {}
-
 impl<T> Cell<[T]> {
     /// Returns a `&[Cell<T>]` from a `&Cell<[T]>`
     ///
@@ -2361,9 +2358,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
 impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {}
 
-#[unstable(feature = "pointer_like_trait", issue = "none")]
-impl<T: PointerLike> PointerLike for UnsafeCell<T> {}
-
 /// [`UnsafeCell`], but [`Sync`].
 ///
 /// This is just an `UnsafeCell`, except it implements `Sync`
@@ -2470,9 +2464,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell
 //#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
 impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
 
-#[unstable(feature = "pointer_like_trait", issue = "none")]
-impl<T: PointerLike> PointerLike for SyncUnsafeCell<T> {}
-
 #[allow(unused)]
 fn assert_coerce_unsized(
     a: UnsafeCell<&i32>,
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 67f95a02af3..ccbd2b00cfd 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -1066,37 +1066,6 @@ pub trait Destruct {}
 #[rustc_do_not_implement_via_object]
 pub trait Tuple {}
 
-/// A marker for pointer-like types.
-///
-/// This trait can only be implemented for types that are certain to have
-/// the same size and alignment as a [`usize`] or [`*const ()`](pointer).
-/// To ensure this, there are special requirements on implementations
-/// of `PointerLike` (other than the already-provided implementations
-/// for built-in types):
-///
-/// * The type must have `#[repr(transparent)]`.
-/// * The type’s sole non-zero-sized field must itself implement `PointerLike`.
-#[unstable(feature = "pointer_like_trait", issue = "none")]
-#[lang = "pointer_like"]
-#[diagnostic::on_unimplemented(
-    message = "`{Self}` needs to have the same ABI as a pointer",
-    label = "`{Self}` needs to be a pointer-like type"
-)]
-#[rustc_do_not_implement_via_object]
-pub trait PointerLike {}
-
-marker_impls! {
-    #[unstable(feature = "pointer_like_trait", issue = "none")]
-    PointerLike for
-        isize,
-        usize,
-        {T} &T,
-        {T} &mut T,
-        {T} *const T,
-        {T} *mut T,
-        {T: PointerLike} crate::pin::Pin<T>,
-}
-
 /// A marker for types which can be used as types of `const` generic parameters.
 ///
 /// These types must have a proper equivalence relation (`Eq`) and it must be automatically
diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs
index 17f7bcd306b..b18b5d7c9ec 100644
--- a/library/core/src/pin/unsafe_pinned.rs
+++ b/library/core/src/pin/unsafe_pinned.rs
@@ -1,5 +1,5 @@
 use crate::cell::UnsafeCell;
-use crate::marker::{PointerLike, Unpin};
+use crate::marker::Unpin;
 use crate::ops::{CoerceUnsized, DispatchFromDyn};
 use crate::pin::Pin;
 use crate::{fmt, ptr};
@@ -178,8 +178,4 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafePinned<U>> for UnsafePinned<T>
 // #[unstable(feature = "unsafe_pinned", issue = "125735")]
 impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafePinned<U>> for UnsafePinned<T> {}
 
-#[unstable(feature = "pointer_like_trait", issue = "none")]
-// #[unstable(feature = "unsafe_pinned", issue = "125735")]
-impl<T: PointerLike> PointerLike for UnsafePinned<T> {}
-
 // FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned<T>?
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index c26c3a32ef3..c4ca29a3679 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -1628,9 +1628,6 @@ impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<NonNull<U>> for NonNull<T
 #[stable(feature = "pin", since = "1.33.0")]
 unsafe impl<T: PointeeSized> PinCoerceUnsized for NonNull<T> {}
 
-#[unstable(feature = "pointer_like_trait", issue = "none")]
-impl<T> core::marker::PointerLike for NonNull<T> {}
-
 #[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: PointeeSized> fmt::Debug for NonNull<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index b574e9f3a25..1d61630269a 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -349,10 +349,10 @@ fn default_alloc_error_hook(layout: Layout) {
         // This symbol is emitted by rustc next to __rust_alloc_error_handler.
         // Its value depends on the -Zoom={panic,abort} compiler option.
         #[rustc_std_internal_symbol]
-        static __rust_alloc_error_handler_should_panic: u8;
+        fn __rust_alloc_error_handler_should_panic_v2() -> u8;
     }
 
-    if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
+    if unsafe { __rust_alloc_error_handler_should_panic_v2() != 0 } {
         panic!("memory allocation of {} bytes failed", layout.size());
     } else {
         // This is the default path taken on OOM, and the only path taken on stable with std.
diff --git a/src/doc/rustc-dev-guide/josh-sync.toml b/src/doc/rustc-dev-guide/josh-sync.toml
new file mode 100644
index 00000000000..7882051e233
--- /dev/null
+++ b/src/doc/rustc-dev-guide/josh-sync.toml
@@ -0,0 +1,3 @@
+org = "rust-lang"
+repo = "rustc-dev-guide"
+path = "src/doc/rustc-dev-guide"
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 30ba3070e1f..e444613e631 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-d1d8e386c5e84c4ba857f56c3291f73c27e2d62a
+c96a69059ecc618b519da385a6ccd03155aa0237
diff --git a/src/doc/rustc-dev-guide/src/autodiff/internals.md b/src/doc/rustc-dev-guide/src/autodiff/internals.md
index 0093ef044c8..c1b31a0e4bd 100644
--- a/src/doc/rustc-dev-guide/src/autodiff/internals.md
+++ b/src/doc/rustc-dev-guide/src/autodiff/internals.md
@@ -2,11 +2,11 @@ The `std::autodiff` module in Rust allows differentiable programming:
 
 ```rust
 #![feature(autodiff)]
-use std::autodiff::autodiff;
+use std::autodiff::*;
 
 // f(x) = x * x, f'(x) = 2.0 * x
 // bar therefore returns (x * x, 2.0 * x)
-#[autodiff(bar, Reverse, Active, Active)]
+#[autodiff_reverse(bar, Active, Active)]
 fn foo(x: f32) -> f32 { x * x }
 
 fn main() {
diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md
index c4783002b85..d29cd144810 100644
--- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md
+++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md
@@ -2,6 +2,24 @@
 
 <!-- toc -->
 
+<div class="warning">
+
+For `profile = "library"` users, or users who use `download-rustc = true | "if-unchanged"`, please be advised that
+the `./x test library/std` flow where `download-rustc` is active (i.e. no compiler changes) is currently broken.
+This is tracked in <https://github.com/rust-lang/rust/issues/142505>. Only the `./x test` flow is affected in this
+case, `./x {check,build} library/std` should still work.
+
+In the short-term, you may need to disable `download-rustc` for `./x test library/std`. This can be done either by:
+
+1. `./x test library/std --set rust.download-rustc=false`
+2. Or set `rust.download-rustc=false` in `bootstrap.toml`.
+
+Unfortunately that will require building the stage 1 compiler. The bootstrap team is working on this, but
+implementing a maintainable fix is taking some time.
+
+</div>
+
+
 The compiler is built using a tool called `x.py`. You will need to
 have Python installed to run it.
 
diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md
index 46d74b96734..b3fcd79ec81 100644
--- a/src/doc/rustc-dev-guide/src/contributing.md
+++ b/src/doc/rustc-dev-guide/src/contributing.md
@@ -434,6 +434,10 @@ Just a few things to keep in mind:
   it might benefit from having a Table of Contents at the beginning,
   which you can auto-generate by including the `<!-- toc -->` marker at the top.
 
+#### ⚠️ Note: Where to contribute `rustc-dev-guide` changes
+
+For detailed information about where to contribute rustc-dev-guide changes and the benefits of doing so, see [the rustc-dev-guide working group documentation](https://forge.rust-lang.org/wg-rustc-dev-guide/index.html#where-to-contribute-rustc-dev-guide-changes).
+
 ## Issue triage
 
 Please see <https://forge.rust-lang.org/release/issue-triaging.html>.
diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md
index e01b8f2f135..4e5c3413cb8 100644
--- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md
+++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md
@@ -1,14 +1,18 @@
 # Diagnostic and subdiagnostic structs
 rustc has three diagnostic traits that can be used to create diagnostics:
-`Diagnostic`, `LintDiagnostic`, and `Subdiagnostic`. For simple diagnostics,
-instead of using the `Diag` API to create and emit diagnostics,
-derived impls can be used. They are only suitable for simple diagnostics that
+`Diagnostic`, `LintDiagnostic`, and `Subdiagnostic`.
+
+For simple diagnostics,
+derived impls can be used, e.g. `#[derive(Diagnostic)]`. They are only suitable for simple diagnostics that
 don't require much logic in deciding whether or not to add additional
 subdiagnostics.
 
-Such diagnostic can be translated into
-different languages and each has a slug that uniquely identifies the
-diagnostic.
+In cases where diagnostics require more complex or dynamic behavior, such as conditionally adding subdiagnostics,
+customizing the rendering logic, or selecting messages at runtime, you will need to manually implement
+the corresponding trait (`Diagnostic`, `LintDiagnostic`, or `Subdiagnostic`).
+This approach provides greater flexibility and is recommended for diagnostics that go beyond simple, static structures.
+
+Diagnostic can be translated into different languages and each has a slug that uniquely identifies the diagnostic.
 
 ## `#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]`
 
@@ -142,7 +146,7 @@ tcx.dcx().emit_err(FieldAlreadyDeclared {
 });
 ```
 
-### Reference
+### Reference for `#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]`
 `#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]` support the
 following attributes:
 
@@ -330,7 +334,34 @@ function ([example][subdiag_use_1] and [example][subdiag_use_2]) on a
 diagnostic or by assigning it to a `#[subdiagnostic]`-annotated field of a
 diagnostic struct.
 
-### Reference
+### Argument sharing and isolation
+
+Subdiagnostics add their own arguments (i.e., certain fields in their structure) to the `Diag` structure before rendering the information.
+`Diag` structure also stores the arguments from the main diagnostic, so the subdiagnostic can also use the arguments from the main diagnostic.
+
+However, when a subdiagnostic is added to a main diagnostic by implementing `#[derive(Subdiagnostic)]`,
+the following rules, introduced in [rust-lang/rust#142724](https://github.com/rust-lang/rust/pull/142724)
+apply to the handling of arguments (i.e., variables used in Fluent messages):
+
+**Argument isolation between sub diagnostics**:
+Arguments set by a subdiagnostic are only available during the rendering of that subdiagnostic.
+After the subdiagnostic is rendered, all arguments it introduced are restored from the main diagnostic.
+This ensures that multiple subdiagnostics do not pollute each other's argument scope.
+For example, when using a `Vec<Subdiag>`, it iteratively adds the same argument over and over again.
+
+**Same argument override between sub and main diagnostics**:
+If a subdiagnostic sets a argument with the same name as a arguments already in the main diagnostic,
+it will report an error at runtime unless both have exactly the same value.
+It has two benefits:
+- preserves the flexibility that arguments in the main diagnostic are allowed to appear in the attributes of the subdiagnostic.
+For example, There is an attribute `#[suggestion(code = "{new_vis}")]` in the subdiagnostic, but `new_vis` is the field in the main diagnostic struct.
+- prevents accidental overwriting or deletion of arguments required by the main diagnostic or other subdiagnostics.
+
+These rules guarantee that arguments injected by subdiagnostics are strictly scoped to their own rendering.
+The main diagnostic's arguments remain unaffected by subdiagnostic logic, even in the presence of name collisions.
+Additionally, subdiagnostics can access arguments from the main diagnostic with the same name when needed.
+
+### Reference for `#[derive(Subdiagnostic)]`
 `#[derive(Subdiagnostic)]` supports the following attributes:
 
 - `#[label(slug)]`, `#[help(slug)]`, `#[warning(slug)]` or `#[note(slug)]`
diff --git a/src/doc/rustc-dev-guide/src/hir/lowering.md b/src/doc/rustc-dev-guide/src/hir/lowering.md
index 02c69b8609f..c0057a69c10 100644
--- a/src/doc/rustc-dev-guide/src/hir/lowering.md
+++ b/src/doc/rustc-dev-guide/src/hir/lowering.md
@@ -7,10 +7,8 @@ of such structures include but are not limited to
 
 * Parenthesis
     * Removed without replacement, the tree structure makes order explicit
-* `for` loops and `while (let)` loops
-    * Converted to `loop` + `match` and some `let` bindings
-* `if let`
-    * Converted to `match`
+* `for` loops
+    * Converted to `match` + `loop` + `match`
 * Universal `impl Trait`
     * Converted to generic arguments
       (but with some flags, to know that the user didn't write them)
diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md
index f7e62e1eccf..4fce5838b6e 100644
--- a/src/doc/rustc-dev-guide/src/tests/ui.md
+++ b/src/doc/rustc-dev-guide/src/tests/ui.md
@@ -453,9 +453,9 @@ even run the resulting program. Just add one of the following
   - `//@ check-fail` — compilation should fail (the codegen phase is skipped).
     This is the default for UI tests.
   - `//@ build-fail` — compilation should fail during the codegen phase.
-    This will run `rustc` twice, once to verify that it compiles successfully
-    without the codegen phase, then a second time the full compile should
-    fail.
+    This will run `rustc` twice:
+    - First time is to ensure that the compile succeeds without the codegen phase
+    - Second time is to ensure that the full compile fails
   - `//@ run-fail` — compilation should succeed, but running the resulting
     binary should fail.
 
diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
index f3aca685417..9d6538112bf 100644
--- a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
+++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
@@ -3,8 +3,8 @@ error: casting to the same type is unnecessary (`u32` -> `u32`)
    |
 LL |     let b = a as u32;
    |             ^^^^^^^^ help: try: `a`
--Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs:LL:CC
    |
+   = note: -Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs:LL:CC
    = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]`
 
@@ -15,8 +15,8 @@ LL |         let d = 42;
    |         ----------- unnecessary `let` binding
 LL |         d
    |         ^
--Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/returns.rs:LL:CC
    |
+   = note: -Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/returns.rs:LL:CC
    = note: `-D clippy::let-and-return` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]`
 help: return the expression directly
diff --git a/src/tools/clippy/tests/ui/track-diagnostics.rs b/src/tools/clippy/tests/ui/track-diagnostics.rs
index 723ea23e9a6..0fbde867390 100644
--- a/src/tools/clippy/tests/ui/track-diagnostics.rs
+++ b/src/tools/clippy/tests/ui/track-diagnostics.rs
@@ -8,5 +8,6 @@ struct A;
 struct B;
 const S: A = B;
 //~^ ERROR: mismatched types
+//~| NOTE: created at
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/track-diagnostics.stderr b/src/tools/clippy/tests/ui/track-diagnostics.stderr
index 83451fb658d..45262ba618f 100644
--- a/src/tools/clippy/tests/ui/track-diagnostics.stderr
+++ b/src/tools/clippy/tests/ui/track-diagnostics.stderr
@@ -3,7 +3,8 @@ error[E0308]: mismatched types
    |
 LL | const S: A = B;
    |              ^ expected `A`, found `B`
--Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC
+   |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs
index a2ea3dbd88b..f02a3f425d1 100644
--- a/src/tools/miri/src/shims/extern_static.rs
+++ b/src/tools/miri/src/shims/extern_static.rs
@@ -1,7 +1,5 @@
 //! Provides the `extern static` that this platform expects.
 
-use rustc_symbol_mangling::mangle_internal_symbol;
-
 use crate::*;
 
 impl<'tcx> MiriMachine<'tcx> {
@@ -45,15 +43,6 @@ impl<'tcx> MiriMachine<'tcx> {
 
     /// Sets up the "extern statics" for this machine.
     pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> {
-        // "__rust_alloc_error_handler_should_panic"
-        let val = ecx.tcx.sess.opts.unstable_opts.oom.should_panic();
-        let val = ImmTy::from_int(val, ecx.machine.layouts.u8);
-        Self::alloc_extern_static(
-            ecx,
-            &mangle_internal_symbol(*ecx.tcx, "__rust_alloc_error_handler_should_panic"),
-            val,
-        )?;
-
         if ecx.target_os_is_unix() {
             // "environ" is mandated by POSIX.
             let environ = ecx.machine.env_vars.unix().environ();
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 97070eb742f..1b66735ddb1 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -615,6 +615,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // This is a no-op shim that only exists to prevent making the allocator shims instantly stable.
                 let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
             }
+            name if name == this.mangle_internal_symbol("__rust_alloc_error_handler_should_panic_v2") => {
+                // Gets the value of the `oom` option.
+                let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
+                let val = this.tcx.sess.opts.unstable_opts.oom.should_panic();
+                this.write_int(val, dest)?;
+            }
 
             // C memory handling functions
             "memcmp" => {
diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs
index 9eba0ca171b..b285250c8ab 100644
--- a/src/tools/miri/tests/pass/alloc-access-tracking.rs
+++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs
@@ -1,7 +1,7 @@
 #![no_std]
 #![no_main]
-//@compile-flags: -Zmiri-track-alloc-id=19 -Zmiri-track-alloc-accesses -Cpanic=abort
-//@normalize-stderr-test: "id 19" -> "id $$ALLOC"
+//@compile-flags: -Zmiri-track-alloc-id=18 -Zmiri-track-alloc-accesses -Cpanic=abort
+//@normalize-stderr-test: "id 18" -> "id $$ALLOC"
 //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations)
 
 extern "Rust" {
diff --git a/tests/rustdoc-ui/track-diagnostics.rs b/tests/rustdoc-ui/track-diagnostics.rs
index d18d26bf794..f8e710659a5 100644
--- a/tests/rustdoc-ui/track-diagnostics.rs
+++ b/tests/rustdoc-ui/track-diagnostics.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -Z track-diagnostics
-//@ error-pattern: created at
 
 // Normalize the emitted location so this doesn't need
 // updating everytime someone adds or removes a line.
@@ -8,4 +7,7 @@
 struct A;
 struct B;
 
-pub const S: A = B; //~ ERROR mismatched types
+pub const S: A = B;
+//~^ ERROR mismatched types
+//~| NOTE created at
+//~| NOTE expected `A`, found `B`
diff --git a/tests/rustdoc-ui/track-diagnostics.stderr b/tests/rustdoc-ui/track-diagnostics.stderr
index fb0d7b86644..a25fd2862aa 100644
--- a/tests/rustdoc-ui/track-diagnostics.stderr
+++ b/tests/rustdoc-ui/track-diagnostics.stderr
@@ -3,7 +3,8 @@ error[E0308]: mismatched types
    |
 LL | pub const S: A = B;
    |                  ^ expected `A`, found `B`
--Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC
+   |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/track-diagnostics/track.rs b/tests/ui/track-diagnostics/track.rs
index 78ff85489be..1b2558c724b 100644
--- a/tests/ui/track-diagnostics/track.rs
+++ b/tests/ui/track-diagnostics/track.rs
@@ -1,5 +1,5 @@
 //@ compile-flags: -Z track-diagnostics
-//@ error-pattern: created at
+//@ dont-require-annotations: NOTE
 //@ rustc-env:RUST_BACKTRACE=0
 //@ failure-status: 101
 
@@ -16,6 +16,9 @@
 fn main() {
     break rust
     //~^ ERROR cannot find value `rust` in this scope
+    //~| NOTE created at
     //~| ERROR `break` outside of a loop or labeled block
+    //~| NOTE created at
     //~| ERROR It looks like you're trying to break rust; would you like some ICE?
+    //~| NOTE created at
 }
diff --git a/tests/ui/track-diagnostics/track.stderr b/tests/ui/track-diagnostics/track.stderr
index 527c0d1b898..f82764958d4 100644
--- a/tests/ui/track-diagnostics/track.stderr
+++ b/tests/ui/track-diagnostics/track.stderr
@@ -3,22 +3,24 @@ error[E0425]: cannot find value `rust` in this scope
    |
 LL |     break rust
    |           ^^^^ not found in this scope
--Ztrack-diagnostics: created at compiler/rustc_resolve/src/late/diagnostics.rs:LL:CC
+   |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_resolve/src/late/diagnostics.rs:LL:CC
 
 error[E0268]: `break` outside of a loop or labeled block
   --> $DIR/track.rs:LL:CC
    |
 LL |     break rust
    |     ^^^^^^^^^^ cannot `break` outside of a loop or labeled block
--Ztrack-diagnostics: created at compiler/rustc_hir_typeck/src/loops.rs:LL:CC
+   |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_hir_typeck/src/loops.rs:LL:CC
 
 error: internal compiler error: It looks like you're trying to break rust; would you like some ICE?
   --> $DIR/track.rs:LL:CC
    |
 LL |     break rust
    |     ^^^^^^^^^^
--Ztrack-diagnostics: created at compiler/rustc_hir_typeck/src/lib.rs:LL:CC
    |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_hir_typeck/src/lib.rs:LL:CC
    = note: the compiler expectedly panicked. this is a feature.
    = note: we would appreciate a joke overview: https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675
    = note: rustc $VERSION running on $TARGET
diff --git a/tests/ui/track-diagnostics/track2.rs b/tests/ui/track-diagnostics/track2.rs
index f51a42cf86f..591b84f330b 100644
--- a/tests/ui/track-diagnostics/track2.rs
+++ b/tests/ui/track-diagnostics/track2.rs
@@ -1,10 +1,12 @@
 //@ compile-flags: -Z track-diagnostics
-//@ error-pattern: created at
+//@ dont-require-annotations: NOTE
 
 // Normalize the emitted location so this doesn't need
 // updating everytime someone adds or removes a line.
 //@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:CC"
 
 fn main() {
-    let _moved @ _from = String::from("foo"); //~ ERROR use of moved value
+    let _moved @ _from = String::from("foo");
+    //~^ ERROR use of moved value
+    //~| NOTE created at
 }
diff --git a/tests/ui/track-diagnostics/track2.stderr b/tests/ui/track-diagnostics/track2.stderr
index dffa0b0c91c..02010639c02 100644
--- a/tests/ui/track-diagnostics/track2.stderr
+++ b/tests/ui/track-diagnostics/track2.stderr
@@ -6,8 +6,8 @@ LL |     let _moved @ _from = String::from("foo");
    |         |        |
    |         |        value moved here
    |         value used here after move
--Ztrack-diagnostics: created at compiler/rustc_borrowck/src/borrowck_errors.rs:LL:CC
    |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_borrowck/src/borrowck_errors.rs:LL:CC
 help: borrow this binding in the pattern to avoid moving the value
    |
 LL |     let ref _moved @ ref _from = String::from("foo");
diff --git a/tests/ui/track-diagnostics/track3.rs b/tests/ui/track-diagnostics/track3.rs
index 428067572af..a39e71915d9 100644
--- a/tests/ui/track-diagnostics/track3.rs
+++ b/tests/ui/track-diagnostics/track3.rs
@@ -1,5 +1,5 @@
 //@ compile-flags: -Z track-diagnostics
-//@ error-pattern: created at
+//@ dont-require-annotations: NOTE
 
 // Normalize the emitted location so this doesn't need
 // updating everytime someone adds or removes a line.
@@ -8,5 +8,7 @@
 fn main() {
     let _unimported = Blah { field: u8 };
     //~^ ERROR cannot find struct, variant or union type `Blah` in this scope
+    //~| NOTE created at
     //~| ERROR expected value, found builtin type `u8`
+    //~| NOTE created at
 }
diff --git a/tests/ui/track-diagnostics/track3.stderr b/tests/ui/track-diagnostics/track3.stderr
index dc468d7e8ee..3e99c8d5f33 100644
--- a/tests/ui/track-diagnostics/track3.stderr
+++ b/tests/ui/track-diagnostics/track3.stderr
@@ -3,14 +3,16 @@ error[E0422]: cannot find struct, variant or union type `Blah` in this scope
    |
 LL |     let _unimported = Blah { field: u8 };
    |                       ^^^^ not found in this scope
--Ztrack-diagnostics: created at compiler/rustc_resolve/src/late/diagnostics.rs:LL:CC
+   |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_resolve/src/late/diagnostics.rs:LL:CC
 
 error[E0423]: expected value, found builtin type `u8`
   --> $DIR/track3.rs:LL:CC
    |
 LL |     let _unimported = Blah { field: u8 };
    |                                     ^^ not a value
--Ztrack-diagnostics: created at compiler/rustc_resolve/src/late/diagnostics.rs:LL:CC
+   |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_resolve/src/late/diagnostics.rs:LL:CC
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/track-diagnostics/track4.rs b/tests/ui/track-diagnostics/track4.rs
index b6edfdba259..0038c616aa5 100644
--- a/tests/ui/track-diagnostics/track4.rs
+++ b/tests/ui/track-diagnostics/track4.rs
@@ -1,11 +1,13 @@
 //@ compile-flags: -Z track-diagnostics
-//@ error-pattern: created at
+//@ dont-require-annotations: NOTE
 
 // Normalize the emitted location so this doesn't need
 // updating everytime someone adds or removes a line.
 //@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:CC"
 
-pub onion { //~ ERROR missing `enum` for enum definition
+pub onion {
+    //~^ ERROR missing `enum` for enum definition
+    //~| NOTE created at
     Owo(u8),
     Uwu(i8),
 }
diff --git a/tests/ui/track-diagnostics/track4.stderr b/tests/ui/track-diagnostics/track4.stderr
index 19499fa7abc..2b6805849b5 100644
--- a/tests/ui/track-diagnostics/track4.stderr
+++ b/tests/ui/track-diagnostics/track4.stderr
@@ -3,8 +3,8 @@ error: missing `enum` for enum definition
    |
 LL | pub onion {
    | ^^^^^^^^^
--Ztrack-diagnostics: created at compiler/rustc_parse/src/parser/item.rs:LL:CC
    |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_parse/src/parser/item.rs:LL:CC
 help: add `enum` here to parse `onion` as an enum
    |
 LL | pub enum onion {
diff --git a/tests/ui/track-diagnostics/track5.rs b/tests/ui/track-diagnostics/track5.rs
index 800bb21b2b1..09fda4eb527 100644
--- a/tests/ui/track-diagnostics/track5.rs
+++ b/tests/ui/track-diagnostics/track5.rs
@@ -1,8 +1,10 @@
 //@ compile-flags: -Z track-diagnostics
-//@ error-pattern: created at
+//@ dont-require-annotations: NOTE
 
 // Normalize the emitted location so this doesn't need
 // updating everytime someone adds or removes a line.
 //@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:CC"
 
-} //~ ERROR unexpected closing delimiter: `}`
+}
+//~^ ERROR unexpected closing delimiter: `}`
+//~| NOTE created at
diff --git a/tests/ui/track-diagnostics/track5.stderr b/tests/ui/track-diagnostics/track5.stderr
index ecc7d81b3c3..5de0550918e 100644
--- a/tests/ui/track-diagnostics/track5.stderr
+++ b/tests/ui/track-diagnostics/track5.stderr
@@ -3,7 +3,8 @@ error: unexpected closing delimiter: `}`
    |
 LL | }
    | ^ unexpected closing delimiter
--Ztrack-diagnostics: created at compiler/rustc_parse/src/lexer/tokentrees.rs:LL:CC
+   |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_parse/src/lexer/tokentrees.rs:LL:CC
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/track-diagnostics/track6.rs b/tests/ui/track-diagnostics/track6.rs
index 55db2ecf939..11d3b7e9764 100644
--- a/tests/ui/track-diagnostics/track6.rs
+++ b/tests/ui/track-diagnostics/track6.rs
@@ -1,5 +1,5 @@
 //@ compile-flags: -Z track-diagnostics
-//@ error-pattern: created at
+//@ dont-require-annotations: NOTE
 
 // Normalize the emitted location so this doesn't need
 // updating everytime someone adds or removes a line.
@@ -11,7 +11,9 @@ pub trait Foo {
 }
 
 impl <T> Foo for T {
-    default fn bar() {} //~ ERROR specialization is unstable
+    default fn bar() {}
+    //~^ ERROR specialization is unstable
+    //~| NOTE created at
 }
 
 fn main() {}
diff --git a/tests/ui/track-diagnostics/track6.stderr b/tests/ui/track-diagnostics/track6.stderr
index 9ed8a19629d..a61f7855e32 100644
--- a/tests/ui/track-diagnostics/track6.stderr
+++ b/tests/ui/track-diagnostics/track6.stderr
@@ -3,8 +3,8 @@ error[E0658]: specialization is unstable
    |
 LL |     default fn bar() {}
    |     ^^^^^^^^^^^^^^^^^^^
--Ztrack-diagnostics: created at compiler/rustc_ast_passes/src/feature_gate.rs:LL:CC
    |
+   = note: -Ztrack-diagnostics: created at compiler/rustc_ast_passes/src/feature_gate.rs:LL:CC
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
    = help: add `#![feature(specialization)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
diff --git a/tests/ui/traits/next-solver/pointer-like.rs b/tests/ui/traits/next-solver/pointer-like.rs
deleted file mode 100644
index bdcad4d4c5e..00000000000
--- a/tests/ui/traits/next-solver/pointer-like.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ compile-flags: -Znext-solver
-
-#![feature(pointer_like_trait)]
-
-use std::marker::PointerLike;
-
-fn require_(_: impl PointerLike) {}
-
-fn main() {
-    require_(1usize);
-    require_(1u16);
-    //~^ ERROR `u16` needs to have the same ABI as a pointer
-    require_(&1i16);
-}
diff --git a/tests/ui/traits/next-solver/pointer-like.stderr b/tests/ui/traits/next-solver/pointer-like.stderr
deleted file mode 100644
index 4b624fd0d35..00000000000
--- a/tests/ui/traits/next-solver/pointer-like.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0277]: `u16` needs to have the same ABI as a pointer
-  --> $DIR/pointer-like.rs:11:14
-   |
-LL |     require_(1u16);
-   |     -------- ^^^^ the trait `PointerLike` is not implemented for `u16`
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = note: the trait bound `u16: PointerLike` is not satisfied
-note: required by a bound in `require_`
-  --> $DIR/pointer-like.rs:7:21
-   |
-LL | fn require_(_: impl PointerLike) {}
-   |                     ^^^^^^^^^^^ required by this bound in `require_`
-help: consider borrowing here
-   |
-LL |     require_(&1u16);
-   |              +
-LL |     require_(&mut 1u16);
-   |              ++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.