From c42a9ac6029e8a2b6b76564240e1f89850992b21 Mon Sep 17 00:00:00 2001 From: Makai Date: Sat, 5 Jul 2025 15:28:03 +0000 Subject: move `stable_mir` back to its own crate and move `rustc_internal` to the`stable_mir` crate As part of this reorganization, some traits need to be moved from `rustc_smir::context::traits` to `stable_mir::unstable::internal_cx`. These traits are specifically designed for `InternalCx` to clarify the behavior of different functions that share the same name. This move is necessary to avoid orphan rule violations. --- Cargo.lock | 12 +- compiler/rustc_smir/Cargo.toml | 3 - compiler/rustc_smir/src/alloc.rs | 104 ++ compiler/rustc_smir/src/bridge.rs | 59 + compiler/rustc_smir/src/builder.rs | 77 + compiler/rustc_smir/src/context/impls.rs | 759 +++++++++ compiler/rustc_smir/src/context/mod.rs | 79 + compiler/rustc_smir/src/context/traits.rs | 21 + compiler/rustc_smir/src/lib.rs | 288 +++- compiler/rustc_smir/src/rustc_internal/mod.rs | 273 ---- compiler/rustc_smir/src/rustc_internal/pretty.rs | 22 - compiler/rustc_smir/src/rustc_smir/alloc.rs | 104 -- compiler/rustc_smir/src/rustc_smir/bridge.rs | 59 - compiler/rustc_smir/src/rustc_smir/builder.rs | 77 - .../rustc_smir/src/rustc_smir/context/impls.rs | 762 --------- compiler/rustc_smir/src/rustc_smir/context/mod.rs | 79 - .../rustc_smir/src/rustc_smir/context/traits.rs | 46 - compiler/rustc_smir/src/rustc_smir/mod.rs | 286 ---- compiler/rustc_smir/src/stable_mir/abi.rs | 494 ------ compiler/rustc_smir/src/stable_mir/alloc.rs | 77 - .../src/stable_mir/compiler_interface.rs | 1100 ------------- compiler/rustc_smir/src/stable_mir/crate_def.rs | 175 --- compiler/rustc_smir/src/stable_mir/error.rs | 93 -- compiler/rustc_smir/src/stable_mir/mir.rs | 8 - compiler/rustc_smir/src/stable_mir/mir/alloc.rs | 88 -- compiler/rustc_smir/src/stable_mir/mir/body.rs | 1128 ------------- compiler/rustc_smir/src/stable_mir/mir/mono.rs | 306 ---- compiler/rustc_smir/src/stable_mir/mir/pretty.rs | 470 ------ compiler/rustc_smir/src/stable_mir/mir/visit.rs | 590 ------- compiler/rustc_smir/src/stable_mir/mod.rs | 304 ---- compiler/rustc_smir/src/stable_mir/target.rs | 61 - compiler/rustc_smir/src/stable_mir/ty.rs | 1656 -------------------- .../src/stable_mir/unstable/convert/internal.rs | 824 ---------- .../src/stable_mir/unstable/convert/mod.rs | 111 -- .../src/stable_mir/unstable/convert/stable/abi.rs | 411 ----- .../src/stable_mir/unstable/convert/stable/mir.rs | 950 ----------- .../src/stable_mir/unstable/convert/stable/mod.rs | 96 -- .../src/stable_mir/unstable/convert/stable/ty.rs | 1151 -------------- compiler/rustc_smir/src/stable_mir/unstable/mod.rs | 210 --- compiler/rustc_smir/src/stable_mir/visitor.rs | 226 --- compiler/stable_mir/Cargo.toml | 11 + compiler/stable_mir/src/abi.rs | 493 ++++++ compiler/stable_mir/src/alloc.rs | 76 + compiler/stable_mir/src/compiler_interface.rs | 1099 +++++++++++++ compiler/stable_mir/src/crate_def.rs | 174 ++ compiler/stable_mir/src/error.rs | 91 ++ compiler/stable_mir/src/lib.rs | 301 +++- compiler/stable_mir/src/mir.rs | 8 + compiler/stable_mir/src/mir/alloc.rs | 87 + compiler/stable_mir/src/mir/body.rs | 1127 +++++++++++++ compiler/stable_mir/src/mir/mono.rs | 305 ++++ compiler/stable_mir/src/mir/pretty.rs | 469 ++++++ compiler/stable_mir/src/mir/visit.rs | 588 +++++++ compiler/stable_mir/src/rustc_internal/mod.rs | 270 ++++ compiler/stable_mir/src/rustc_internal/pretty.rs | 21 + compiler/stable_mir/src/target.rs | 60 + compiler/stable_mir/src/ty.rs | 1655 +++++++++++++++++++ .../stable_mir/src/unstable/convert/internal.rs | 823 ++++++++++ compiler/stable_mir/src/unstable/convert/mod.rs | 110 ++ .../stable_mir/src/unstable/convert/stable/abi.rs | 410 +++++ .../stable_mir/src/unstable/convert/stable/mir.rs | 933 +++++++++++ .../stable_mir/src/unstable/convert/stable/mod.rs | 95 ++ .../stable_mir/src/unstable/convert/stable/ty.rs | 1139 ++++++++++++++ .../stable_mir/src/unstable/internal_cx/mod.rs | 93 ++ .../stable_mir/src/unstable/internal_cx/traits.rs | 31 + compiler/stable_mir/src/unstable/mod.rs | 124 ++ compiler/stable_mir/src/visitor.rs | 224 +++ 67 files changed, 12203 insertions(+), 12253 deletions(-) create mode 100644 compiler/rustc_smir/src/alloc.rs create mode 100644 compiler/rustc_smir/src/bridge.rs create mode 100644 compiler/rustc_smir/src/builder.rs create mode 100644 compiler/rustc_smir/src/context/impls.rs create mode 100644 compiler/rustc_smir/src/context/mod.rs create mode 100644 compiler/rustc_smir/src/context/traits.rs delete mode 100644 compiler/rustc_smir/src/rustc_internal/mod.rs delete mode 100644 compiler/rustc_smir/src/rustc_internal/pretty.rs delete mode 100644 compiler/rustc_smir/src/rustc_smir/alloc.rs delete mode 100644 compiler/rustc_smir/src/rustc_smir/bridge.rs delete mode 100644 compiler/rustc_smir/src/rustc_smir/builder.rs delete mode 100644 compiler/rustc_smir/src/rustc_smir/context/impls.rs delete mode 100644 compiler/rustc_smir/src/rustc_smir/context/mod.rs delete mode 100644 compiler/rustc_smir/src/rustc_smir/context/traits.rs delete mode 100644 compiler/rustc_smir/src/rustc_smir/mod.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/abi.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/alloc.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/compiler_interface.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/crate_def.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/error.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/mir.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/mir/alloc.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/mir/body.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/mir/mono.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/mir/pretty.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/mir/visit.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/mod.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/target.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/ty.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/unstable/convert/mod.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/unstable/convert/stable/abi.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mir.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mod.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/unstable/mod.rs delete mode 100644 compiler/rustc_smir/src/stable_mir/visitor.rs create mode 100644 compiler/stable_mir/src/abi.rs create mode 100644 compiler/stable_mir/src/alloc.rs create mode 100644 compiler/stable_mir/src/compiler_interface.rs create mode 100644 compiler/stable_mir/src/crate_def.rs create mode 100644 compiler/stable_mir/src/error.rs create mode 100644 compiler/stable_mir/src/mir.rs create mode 100644 compiler/stable_mir/src/mir/alloc.rs create mode 100644 compiler/stable_mir/src/mir/body.rs create mode 100644 compiler/stable_mir/src/mir/mono.rs create mode 100644 compiler/stable_mir/src/mir/pretty.rs create mode 100644 compiler/stable_mir/src/mir/visit.rs create mode 100644 compiler/stable_mir/src/rustc_internal/mod.rs create mode 100644 compiler/stable_mir/src/rustc_internal/pretty.rs create mode 100644 compiler/stable_mir/src/target.rs create mode 100644 compiler/stable_mir/src/ty.rs create mode 100644 compiler/stable_mir/src/unstable/convert/internal.rs create mode 100644 compiler/stable_mir/src/unstable/convert/mod.rs create mode 100644 compiler/stable_mir/src/unstable/convert/stable/abi.rs create mode 100644 compiler/stable_mir/src/unstable/convert/stable/mir.rs create mode 100644 compiler/stable_mir/src/unstable/convert/stable/mod.rs create mode 100644 compiler/stable_mir/src/unstable/convert/stable/ty.rs create mode 100644 compiler/stable_mir/src/unstable/internal_cx/mod.rs create mode 100644 compiler/stable_mir/src/unstable/internal_cx/traits.rs create mode 100644 compiler/stable_mir/src/unstable/mod.rs create mode 100644 compiler/stable_mir/src/visitor.rs diff --git a/Cargo.lock b/Cargo.lock index 34fc0860a4b..886eb2dabbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4540,9 +4540,6 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", - "scoped-tls", - "serde", - "tracing", ] [[package]] @@ -5095,7 +5092,16 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "stable_mir" version = "0.1.0-preview" dependencies = [ + "rustc_abi", + "rustc_hir", + "rustc_middle", + "rustc_session", "rustc_smir", + "rustc_span", + "rustc_target", + "scoped-tls", + "serde", + "tracing", ] [[package]] diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index fc9f411ac3c..b7ea478f731 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -13,7 +13,4 @@ rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -scoped-tls = "1.0" -serde = { version = "1.0.125", features = [ "derive" ] } -tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_smir/src/alloc.rs b/compiler/rustc_smir/src/alloc.rs new file mode 100644 index 00000000000..cad643f3709 --- /dev/null +++ b/compiler/rustc_smir/src/alloc.rs @@ -0,0 +1,104 @@ +//! 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 rustc_abi::{Size, TyAndLayout}; +use rustc_middle::mir::interpret::{ + AllocId, AllocInit, AllocRange, Allocation, ConstAllocation, Pointer, Scalar, alloc_range, +}; +use rustc_middle::ty::{Ty, layout}; + +use super::{SmirCtxt, Tables}; +use crate::bridge::Allocation as _; +use crate::{Bridge, SmirError}; + +pub fn create_ty_and_layout<'tcx, B: Bridge>( + cx: &SmirCtxt<'tcx, B>, + ty: Ty<'tcx>, +) -> Result>, &'tcx layout::LayoutError<'tcx>> { + use crate::context::SmirTypingEnv; + cx.tcx.layout_of(cx.fully_monomorphized().as_query_input(ty)) +} + +pub fn try_new_scalar<'tcx, B: Bridge>( + layout: TyAndLayout<'tcx, Ty<'tcx>>, + scalar: Scalar, + cx: &SmirCtxt<'tcx, B>, +) -> Result { + 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) +} + +pub fn try_new_slice<'tcx, B: Bridge>( + layout: TyAndLayout<'tcx, Ty<'tcx>>, + data: ConstAllocation<'tcx>, + meta: u64, + cx: &SmirCtxt<'tcx, B>, +) -> Result { + 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 fn allocation_filter<'tcx, B: Bridge>( + alloc: &rustc_middle::mir::interpret::Allocation, + alloc_range: AllocRange, + tables: &mut Tables<'tcx, B>, + cx: &SmirCtxt<'tcx, B>, +) -> B::Allocation { + let mut bytes: Vec> = alloc + .inspect_with_uninit_and_ptr_outside_interpreter( + alloc_range.start.bytes_usize()..alloc_range.end().bytes_usize(), + ) + .iter() + .copied() + .map(Some) + .collect(); + for (i, b) in bytes.iter_mut().enumerate() { + if !alloc.init_mask().get(Size::from_bytes(i + alloc_range.start.bytes_usize())) { + *b = None; + } + } + let mut ptrs = Vec::new(); + for (offset, prov) in alloc + .provenance() + .ptrs() + .iter() + .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end()) + { + 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/bridge.rs b/compiler/rustc_smir/src/bridge.rs new file mode 100644 index 00000000000..a31eb93d0e8 --- /dev/null +++ b/compiler/rustc_smir/src/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(err: T) -> Self; +} + +pub trait Prov { + fn new(aid: B::AllocId) -> Self; +} + +pub trait Allocation { + fn new<'tcx>( + bytes: Vec>, + 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 { + 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/builder.rs b/compiler/rustc_smir/src/builder.rs new file mode 100644 index 00000000000..2141053d09a --- /dev/null +++ b/compiler/rustc_smir/src/builder.rs @@ -0,0 +1,77 @@ +//! Logic required to produce a monomorphic stable body. +//! +//! We first retrieve and monomorphize the rustc body representation, i.e., we generate a +//! monomorphic body using internal representation. +//! After that, we convert the internal representation into a stable one. + +use rustc_hir::def::DefKind; +use rustc_middle::mir; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::ty::{self, TyCtxt}; + +/// Builds a monomorphic body for a given instance. +pub(crate) struct BodyBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, +} + +impl<'tcx> BodyBuilder<'tcx> { + pub(crate) fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { + let instance = match instance.def { + // To get the fallback body of an intrinsic, we need to convert it to an item. + ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new_raw(def_id, instance.args), + _ => instance, + }; + BodyBuilder { tcx, instance } + } + + /// 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) -> 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 + // generic_const_exprs + || self.tcx.def_kind(self.instance.def_id()) != DefKind::AnonConst + { + let mut mono_body = self.instance.instantiate_mir_and_normalize_erasing_regions( + self.tcx, + ty::TypingEnv::fully_monomorphized(), + ty::EarlyBinder::bind(body), + ); + self.visit_body(&mut mono_body); + mono_body + } else { + // Already monomorphic. + body + }; + + mono_body + } +} + +impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { + fn visit_const_operand( + &mut self, + constant: &mut mir::ConstOperand<'tcx>, + location: mir::Location, + ) { + let const_ = constant.const_; + let val = match const_.eval(self.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) { + Ok(v) => v, + Err(mir::interpret::ErrorHandled::Reported(..)) => return, + Err(mir::interpret::ErrorHandled::TooGeneric(..)) => { + unreachable!("Failed to evaluate instance constant: {:?}", const_) + } + }; + let ty = constant.ty(); + constant.const_ = mir::Const::Val(val, ty); + self.super_const_operand(constant, location); + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} diff --git a/compiler/rustc_smir/src/context/impls.rs b/compiler/rustc_smir/src/context/impls.rs new file mode 100644 index 00000000000..9faadabe489 --- /dev/null +++ b/compiler/rustc_smir/src/context/impls.rs @@ -0,0 +1,759 @@ +//! 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::builder::BodyBuilder; +use crate::{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>>(&self, value: T) -> Option { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + self.tcx.all_traits_including_private() + } + + pub fn trait_decls(&self, crate_num: CrateNum) -> Vec { + 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 { + 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 { + 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, 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, 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 { + 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 { + let crates: Vec = [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 { + 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 { + use crate::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 { + cnst.try_to_target_usize(self.tcx) + .ok_or_else(|| B::Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) + } + + pub fn try_new_const_zst(&self, ty_internal: Ty<'tcx>) -> Result, 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, 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, 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`, 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> { + 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> { + 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::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> { + 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, 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, 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>>, + ) -> 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::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, 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 { + 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/context/mod.rs b/compiler/rustc_smir/src/context/mod.rs new file mode 100644 index 00000000000..da20be2a4b3 --- /dev/null +++ b/compiler/rustc_smir/src/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::{Bridge, SmirError}; + +mod impls; +mod traits; + +pub use traits::*; + +/// Provides direct access to rustc's internal queries. +/// +/// `SmirInterface` must go through +/// this context to obtain rustc-level information. +pub struct SmirCtxt<'tcx, B: Bridge> { + pub tcx: TyCtxt<'tcx>, + _marker: PhantomData, +} + +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, 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/context/traits.rs b/compiler/rustc_smir/src/context/traits.rs new file mode 100644 index 00000000000..8483bee4aad --- /dev/null +++ b/compiler/rustc_smir/src/context/traits.rs @@ -0,0 +1,21 @@ +//! 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 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/lib.rs b/compiler/rustc_smir/src/lib.rs index 067adda791d..fbebf98df7d 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -1,4 +1,9 @@ -//! The WIP stable interface to rustc internals. +//! Crate that implements what will become the rustc side of Stable MIR. +//! +//! This crate is responsible for building Stable MIR components from internal components. +//! +//! This crate is not intended to be invoked directly by users. +//! This crate is the public API of rustc that will be invoked by the `stable_mir` crate. //! //! For more information see //! @@ -18,8 +23,283 @@ #![feature(sized_hierarchy)] // tidy-alphabetical-end -pub mod rustc_internal; +use std::cell::RefCell; +use std::fmt::Debug; +use std::hash::Hash; +use std::ops::Index; + +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, Ty, TyCtxt}; +use rustc_span::Span; +use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; + +pub mod alloc; +pub mod bridge; +mod builder; +pub mod context; + +#[deprecated(note = "please use `stable_mir::rustc_internal` instead")] +pub mod rustc_internal {} + +/// A container which is used for TLS. +pub struct SmirContainer<'tcx, B: Bridge> { + pub tables: RefCell>, + pub cx: RefCell>, +} + +pub struct Tables<'tcx, B: Bridge> { + pub def_ids: IndexMap, + pub alloc_ids: IndexMap, + pub spans: IndexMap, + pub types: IndexMap, B::Ty>, + pub instances: IndexMap, B::InstanceDef>, + pub ty_consts: IndexMap, B::TyConstId>, + pub mir_consts: IndexMap, B::MirConstId>, + pub layouts: IndexMap, 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, B: Bridge> Index 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 fn intern_ty_const(&mut self, ct: ty::Const<'tcx>) -> B::TyConstId { + self.ty_consts.create_or_fetch(ct) + } + + pub fn intern_mir_const(&mut self, constant: mir::Const<'tcx>) -> B::MirConstId { + self.mir_consts.create_or_fetch(constant) + } + + pub fn create_def_id(&mut self, did: DefId) -> B::DefId { + self.def_ids.create_or_fetch(did) + } + + pub fn create_alloc_id(&mut self, aid: AllocId) -> B::AllocId { + self.alloc_ids.create_or_fetch(aid) + } + + pub fn create_span(&mut self, span: Span) -> B::Span { + self.spans.create_or_fetch(span) + } + + pub fn instance_def(&mut self, instance: ty::Instance<'tcx>) -> B::InstanceDef { + self.instances.create_or_fetch(instance) + } + + pub fn layout_id(&mut self, layout: rustc_abi::Layout<'tcx>) -> B::Layout { + self.layouts.create_or_fetch(layout) + } + + pub fn crate_item(&mut self, did: rustc_span::def_id::DefId) -> B::CrateItem { + B::CrateItem::new(self.create_def_id(did)) + } + + pub fn adt_def(&mut self, did: rustc_span::def_id::DefId) -> B::AdtDef { + B::AdtDef::new(self.create_def_id(did)) + } + + pub fn foreign_module_def(&mut self, did: rustc_span::def_id::DefId) -> B::ForeignModuleDef { + B::ForeignModuleDef::new(self.create_def_id(did)) + } + + 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)) + } + + 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)) + } +} + +/// 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; + + type Error: SmirError; + type CrateItem: CrateItem; + type AdtDef: AdtDef; + type ForeignModuleDef: ForeignModuleDef; + type ForeignDef: ForeignDef; + type FnDef: FnDef; + type ClosureDef: ClosureDef; + type CoroutineDef: CoroutineDef; + type CoroutineClosureDef: CoroutineClosureDef; + type AliasDef: AliasDef; + type ParamDef: ParamDef; + type BrNamedDef: BrNamedDef; + type TraitDef: TraitDef; + type GenericDef: GenericDef; + type ConstDef: ConstDef; + type ImplDef: ImplDef; + type RegionDef: RegionDef; + type CoroutineWitnessDef: CoroutineWitnessDef; + type AssocDef: AssocDef; + type OpaqueDef: OpaqueDef; + type Prov: Prov; + type StaticDef: StaticDef; + + type Allocation: Allocation; +} + +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 { + index_map: fx::FxIndexMap, +} + +impl Default for IndexMap { + fn default() -> Self { + Self { index_map: FxIndexMap::default() } + } +} + +impl IndexMap { + 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 Index + for IndexMap +{ + type Output = K; -pub mod rustc_smir; + 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 + } +} -pub mod stable_mir; +/// Iterate over the definitions of the given crate. +pub(crate) fn filter_def_ids(tcx: TyCtxt<'_>, krate: CrateNum, mut func: F) -> Vec +where + F: FnMut(DefId) -> Option, +{ + 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/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs deleted file mode 100644 index dcdc77b76c2..00000000000 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ /dev/null @@ -1,273 +0,0 @@ -//! Module that implements the bridge between Stable MIR and internal compiler MIR. -//! -//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs -//! until stable MIR is complete. - -use std::cell::{Cell, RefCell}; - -use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::CrateNum; -use scoped_tls::scoped_thread_local; -use stable_mir::Error; -use stable_mir::unstable::{RustcInternal, Stable}; - -use crate::rustc_smir::context::SmirCtxt; -use crate::rustc_smir::{Bridge, SmirContainer, Tables}; -use crate::stable_mir; - -pub mod pretty; - -/// Convert an internal Rust compiler item into its stable counterpart, if one exists. -/// -/// # Warning -/// -/// This function is unstable, and its behavior may change at any point. -/// E.g.: Items that were previously supported, may no longer be supported, or its translation may -/// change. -/// -/// # Panics -/// -/// This function will panic if StableMIR has not been properly initialized. -pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T { - with_container(|tables, cx| item.stable(tables, cx)) -} - -/// Convert a stable item into its internal Rust compiler counterpart, if one exists. -/// -/// # Warning -/// -/// This function is unstable, and it's behavior may change at any point. -/// Not every stable item can be converted to an internal one. -/// Furthermore, items that were previously supported, may no longer be supported in newer versions. -/// -/// # Panics -/// -/// This function will panic if StableMIR has not been properly initialized. -pub fn internal<'tcx, S>(tcx: TyCtxt<'tcx>, item: S) -> S::T<'tcx> -where - S: RustcInternal, -{ - // The tcx argument ensures that the item won't outlive the type context. - // 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 { - item.id.into() -} - -// A thread local variable that stores a pointer to the tables mapping between TyCtxt -// datastructures and stable MIR datastructures -scoped_thread_local! (static TLV: Cell<*const ()>); - -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 = 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_container( - 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 container = ptr as *const SmirContainer<'_, B>; - let mut tables = unsafe { (*container).tables.borrow_mut() }; - let cx = unsafe { (*container).cx.borrow() }; - f(&mut *tables, &*cx) - }) -} - -pub fn run(tcx: TyCtxt<'_>, f: F) -> Result -where - F: FnOnce() -> T, -{ - let smir_cx = RefCell::new(SmirCtxt::new(tcx)); - let container = SmirContainer { tables: RefCell::new(Tables::default()), cx: smir_cx }; - - stable_mir::compiler_interface::run(&container, || init(&container, f)) -} - -/// Instantiate and run the compiler with the provided arguments and callback. -/// -/// The callback will be invoked after the compiler ran all its analyses, but before code generation. -/// Note that this macro accepts two different formats for the callback: -/// 1. An ident that resolves to a function that accepts no argument and returns `ControlFlow` -/// ```ignore(needs-extern-crate) -/// # extern crate rustc_driver; -/// # extern crate rustc_interface; -/// # extern crate rustc_middle; -/// # #[macro_use] -/// # extern crate rustc_smir; -/// # extern crate stable_mir; -/// # -/// # fn main() { -/// # use std::ops::ControlFlow; -/// # use stable_mir::CompilerError; -/// fn analyze_code() -> ControlFlow<(), ()> { -/// // Your code goes in here. -/// # ControlFlow::Continue(()) -/// } -/// # let args = &["--verbose".to_string()]; -/// let result = run!(args, analyze_code); -/// # assert_eq!(result, Err(CompilerError::Skipped)) -/// # } -/// ``` -/// 2. A closure expression: -/// ```ignore(needs-extern-crate) -/// # extern crate rustc_driver; -/// # extern crate rustc_interface; -/// # extern crate rustc_middle; -/// # #[macro_use] -/// # extern crate rustc_smir; -/// # extern crate stable_mir; -/// # -/// # fn main() { -/// # use std::ops::ControlFlow; -/// # use stable_mir::CompilerError; -/// fn analyze_code(extra_args: Vec) -> ControlFlow<(), ()> { -/// # let _ = extra_args; -/// // Your code goes in here. -/// # ControlFlow::Continue(()) -/// } -/// # let args = &["--verbose".to_string()]; -/// # let extra_args = vec![]; -/// let result = run!(args, || analyze_code(extra_args)); -/// # assert_eq!(result, Err(CompilerError::Skipped)) -/// # } -/// ``` -#[macro_export] -macro_rules! run { - ($args:expr, $callback_fn:ident) => { - run_driver!($args, || $callback_fn()) - }; - ($args:expr, $callback:expr) => { - run_driver!($args, $callback) - }; -} - -/// Instantiate and run the compiler with the provided arguments and callback. -/// -/// This is similar to `run` but it invokes the callback with the compiler's `TyCtxt`, -/// which can be used to invoke internal APIs. -#[macro_export] -macro_rules! run_with_tcx { - ($args:expr, $callback_fn:ident) => { - run_driver!($args, |tcx| $callback_fn(tcx), with_tcx) - }; - ($args:expr, $callback:expr) => { - run_driver!($args, $callback, with_tcx) - }; -} - -/// Optionally include an ident. This is needed due to macro hygiene. -#[macro_export] -#[doc(hidden)] -macro_rules! optional { - (with_tcx $ident:ident) => { - $ident - }; -} - -/// Prefer using [run!] and [run_with_tcx] instead. -/// -/// This macro implements the instantiation of a StableMIR driver, and it will invoke -/// the given callback after the compiler analyses. -/// -/// The third argument determines whether the callback requires `tcx` as an argument. -#[macro_export] -#[doc(hidden)] -macro_rules! run_driver { - ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{ - use rustc_driver::{Callbacks, Compilation, run_compiler}; - use rustc_middle::ty::TyCtxt; - use rustc_interface::interface; - use rustc_smir::rustc_internal; - use stable_mir::CompilerError; - use std::ops::ControlFlow; - - pub struct StableMir ControlFlow> - where - B: Send, - C: Send, - F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, - { - callback: Option, - result: Option>, - } - - impl StableMir - where - B: Send, - C: Send, - F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, - { - /// Creates a new `StableMir` instance, with given test_function and arguments. - pub fn new(callback: F) -> Self { - StableMir { callback: Some(callback), result: None } - } - - /// Runs the compiler against given target and tests it with `test_function` - pub fn run(&mut self, args: &[String]) -> Result> { - let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> { - run_compiler(&args, self); - Ok(()) - }); - match (compiler_result, self.result.take()) { - (Ok(Ok(())), Some(ControlFlow::Continue(value))) => Ok(value), - (Ok(Ok(())), Some(ControlFlow::Break(value))) => { - Err(CompilerError::Interrupted(value)) - } - (Ok(Ok(_)), None) => Err(CompilerError::Skipped), - // Two cases here: - // - `run` finished normally and returned `Err` - // - `run` panicked with `FatalErr` - // You might think that normal compile errors cause the former, and - // ICEs cause the latter. But some normal compiler errors also cause - // the latter. So we can't meaningfully distinguish them, and group - // them together. - (Ok(Err(_)), _) | (Err(_), _) => Err(CompilerError::Failed), - } - } - } - - impl Callbacks for StableMir - where - B: Send, - C: Send, - F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, - { - /// Called after analysis. Return value instructs the compiler whether to - /// continue the compilation afterwards (defaults to `Compilation::Continue`) - fn after_analysis<'tcx>( - &mut self, - _compiler: &interface::Compiler, - tcx: TyCtxt<'tcx>, - ) -> Compilation { - if let Some(callback) = self.callback.take() { - rustc_internal::run(tcx, || { - self.result = Some(callback($(optional!($with_tcx tcx))?)); - }) - .unwrap(); - if self.result.as_ref().is_some_and(|val| val.is_continue()) { - Compilation::Continue - } else { - Compilation::Stop - } - } else { - Compilation::Continue - } - } - } - - StableMir::new($callback).run($args) - }}; -} diff --git a/compiler/rustc_smir/src/rustc_internal/pretty.rs b/compiler/rustc_smir/src/rustc_internal/pretty.rs deleted file mode 100644 index 0710c18746a..00000000000 --- a/compiler/rustc_smir/src/rustc_internal/pretty.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::io; - -use rustc_middle::ty::TyCtxt; - -use super::run; -use crate::stable_mir; - -pub fn write_smir_pretty<'tcx, W: io::Write>(tcx: TyCtxt<'tcx>, w: &mut W) -> io::Result<()> { - writeln!( - w, - "// WARNING: This is highly experimental output it's intended for stable-mir developers only." - )?; - writeln!( - w, - "// If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir." - )?; - let _ = run(tcx, || { - let items = stable_mir::all_local_items(); - let _ = items.iter().map(|item| -> io::Result<()> { item.emit_mir(w) }).collect::>(); - }); - Ok(()) -} diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs deleted file mode 100644 index ecaf3571896..00000000000 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! 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 rustc_abi::{Size, TyAndLayout}; -use rustc_middle::mir::interpret::{ - AllocId, AllocInit, AllocRange, Allocation, ConstAllocation, Pointer, Scalar, alloc_range, -}; -use rustc_middle::ty::{Ty, layout}; - -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>, &'tcx layout::LayoutError<'tcx>> { - use crate::rustc_smir::context::SmirTypingEnv; - cx.tcx.layout_of(cx.fully_monomorphized().as_query_input(ty)) -} - -pub fn try_new_scalar<'tcx, B: Bridge>( - layout: TyAndLayout<'tcx, Ty<'tcx>>, - scalar: Scalar, - cx: &SmirCtxt<'tcx, B>, -) -> Result { - 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) -} - -pub fn try_new_slice<'tcx, B: Bridge>( - layout: TyAndLayout<'tcx, Ty<'tcx>>, - data: ConstAllocation<'tcx>, - meta: u64, - cx: &SmirCtxt<'tcx, B>, -) -> Result { - 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 fn allocation_filter<'tcx, B: Bridge>( - alloc: &rustc_middle::mir::interpret::Allocation, - alloc_range: AllocRange, - tables: &mut Tables<'tcx, B>, - cx: &SmirCtxt<'tcx, B>, -) -> B::Allocation { - let mut bytes: Vec> = alloc - .inspect_with_uninit_and_ptr_outside_interpreter( - alloc_range.start.bytes_usize()..alloc_range.end().bytes_usize(), - ) - .iter() - .copied() - .map(Some) - .collect(); - for (i, b) in bytes.iter_mut().enumerate() { - if !alloc.init_mask().get(Size::from_bytes(i + alloc_range.start.bytes_usize())) { - *b = None; - } - } - let mut ptrs = Vec::new(); - for (offset, prov) in alloc - .provenance() - .ptrs() - .iter() - .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end()) - { - 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 deleted file mode 100644 index a31eb93d0e8..00000000000 --- a/compiler/rustc_smir/src/rustc_smir/bridge.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! 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(err: T) -> Self; -} - -pub trait Prov { - fn new(aid: B::AllocId) -> Self; -} - -pub trait Allocation { - fn new<'tcx>( - bytes: Vec>, - 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 { - 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 deleted file mode 100644 index 2141053d09a..00000000000 --- a/compiler/rustc_smir/src/rustc_smir/builder.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! Logic required to produce a monomorphic stable body. -//! -//! We first retrieve and monomorphize the rustc body representation, i.e., we generate a -//! monomorphic body using internal representation. -//! After that, we convert the internal representation into a stable one. - -use rustc_hir::def::DefKind; -use rustc_middle::mir; -use rustc_middle::mir::visit::MutVisitor; -use rustc_middle::ty::{self, TyCtxt}; - -/// Builds a monomorphic body for a given instance. -pub(crate) struct BodyBuilder<'tcx> { - tcx: TyCtxt<'tcx>, - instance: ty::Instance<'tcx>, -} - -impl<'tcx> BodyBuilder<'tcx> { - pub(crate) fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { - let instance = match instance.def { - // To get the fallback body of an intrinsic, we need to convert it to an item. - ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new_raw(def_id, instance.args), - _ => instance, - }; - BodyBuilder { tcx, instance } - } - - /// 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) -> 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 - // generic_const_exprs - || self.tcx.def_kind(self.instance.def_id()) != DefKind::AnonConst - { - let mut mono_body = self.instance.instantiate_mir_and_normalize_erasing_regions( - self.tcx, - ty::TypingEnv::fully_monomorphized(), - ty::EarlyBinder::bind(body), - ); - self.visit_body(&mut mono_body); - mono_body - } else { - // Already monomorphic. - body - }; - - mono_body - } -} - -impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { - fn visit_const_operand( - &mut self, - constant: &mut mir::ConstOperand<'tcx>, - location: mir::Location, - ) { - let const_ = constant.const_; - let val = match const_.eval(self.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) { - Ok(v) => v, - Err(mir::interpret::ErrorHandled::Reported(..)) => return, - Err(mir::interpret::ErrorHandled::TooGeneric(..)) => { - unreachable!("Failed to evaluate instance constant: {:?}", const_) - } - }; - let ty = constant.ty(); - constant.const_ = mir::Const::Val(val, ty); - self.super_const_operand(constant, location); - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } -} diff --git a/compiler/rustc_smir/src/rustc_smir/context/impls.rs b/compiler/rustc_smir/src/rustc_smir/context/impls.rs deleted file mode 100644 index 89ae47143ef..00000000000 --- a/compiler/rustc_smir/src/rustc_smir/context/impls.rs +++ /dev/null @@ -1,762 +0,0 @@ -//! 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>>(&self, value: T) -> Option { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - self.tcx.all_traits_including_private() - } - - pub fn trait_decls(&self, crate_num: CrateNum) -> Vec { - 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 { - 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 { - 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, 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, 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 { - 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 { - let crates: Vec = [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 { - 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 { - 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 { - 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, 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, 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, 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`, 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> { - 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> { - 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::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> { - 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, 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, 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>>, - ) -> 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::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, 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 { - 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 deleted file mode 100644 index 38743e5f7d3..00000000000 --- a/compiler/rustc_smir/src/rustc_smir/context/mod.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! 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, -} - -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, 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 deleted file mode 100644 index 19e09016cdd..00000000000 --- a/compiler/rustc_smir/src/rustc_smir/context/traits.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! 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/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs deleted file mode 100644 index e8b7a3fec09..00000000000 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ /dev/null @@ -1,286 +0,0 @@ -//! Module that implements what will become the rustc side of Stable MIR. - -//! This module is responsible for building Stable MIR components from internal components. -//! -//! This module is not intended to be invoked directly by users. It will eventually -//! become the public API of rustc that will be invoked by the `stable_mir` crate. -//! -//! For now, we are developing everything inside `rustc`, thus, we keep this module private. - -use std::cell::RefCell; -use std::fmt::Debug; -use std::hash::Hash; -use std::ops::Index; - -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, Ty, TyCtxt}; -use rustc_span::Span; -use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; - -pub mod alloc; -pub mod bridge; -mod builder; -pub mod context; - -/// A container which is used for TLS. -pub struct SmirContainer<'tcx, B: Bridge> { - pub tables: RefCell>, - pub cx: RefCell>, -} - -pub struct Tables<'tcx, B: Bridge> { - pub def_ids: IndexMap, - pub alloc_ids: IndexMap, - pub spans: IndexMap, - pub types: IndexMap, B::Ty>, - pub instances: IndexMap, B::InstanceDef>, - pub ty_consts: IndexMap, B::TyConstId>, - pub mir_consts: IndexMap, B::MirConstId>, - pub layouts: IndexMap, 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, B: Bridge> Index 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 fn intern_ty_const(&mut self, ct: ty::Const<'tcx>) -> B::TyConstId { - self.ty_consts.create_or_fetch(ct) - } - - pub fn intern_mir_const(&mut self, constant: mir::Const<'tcx>) -> B::MirConstId { - self.mir_consts.create_or_fetch(constant) - } - - pub fn create_def_id(&mut self, did: DefId) -> B::DefId { - self.def_ids.create_or_fetch(did) - } - - pub fn create_alloc_id(&mut self, aid: AllocId) -> B::AllocId { - self.alloc_ids.create_or_fetch(aid) - } - - pub fn create_span(&mut self, span: Span) -> B::Span { - self.spans.create_or_fetch(span) - } - - pub fn instance_def(&mut self, instance: ty::Instance<'tcx>) -> B::InstanceDef { - self.instances.create_or_fetch(instance) - } - - pub fn layout_id(&mut self, layout: rustc_abi::Layout<'tcx>) -> B::Layout { - self.layouts.create_or_fetch(layout) - } - - pub fn crate_item(&mut self, did: rustc_span::def_id::DefId) -> B::CrateItem { - B::CrateItem::new(self.create_def_id(did)) - } - - pub fn adt_def(&mut self, did: rustc_span::def_id::DefId) -> B::AdtDef { - B::AdtDef::new(self.create_def_id(did)) - } - - pub fn foreign_module_def(&mut self, did: rustc_span::def_id::DefId) -> B::ForeignModuleDef { - B::ForeignModuleDef::new(self.create_def_id(did)) - } - - 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)) - } - - 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)) - } -} - -/// 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; - - type Error: SmirError; - type CrateItem: CrateItem; - type AdtDef: AdtDef; - type ForeignModuleDef: ForeignModuleDef; - type ForeignDef: ForeignDef; - type FnDef: FnDef; - type ClosureDef: ClosureDef; - type CoroutineDef: CoroutineDef; - type CoroutineClosureDef: CoroutineClosureDef; - type AliasDef: AliasDef; - type ParamDef: ParamDef; - type BrNamedDef: BrNamedDef; - type TraitDef: TraitDef; - type GenericDef: GenericDef; - type ConstDef: ConstDef; - type ImplDef: ImplDef; - type RegionDef: RegionDef; - type CoroutineWitnessDef: CoroutineWitnessDef; - type AssocDef: AssocDef; - type OpaqueDef: OpaqueDef; - type Prov: Prov; - type StaticDef: StaticDef; - - type Allocation: Allocation; -} - -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 { - index_map: fx::FxIndexMap, -} - -impl Default for IndexMap { - fn default() -> Self { - Self { index_map: FxIndexMap::default() } - } -} - -impl IndexMap { - 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 Index - for IndexMap -{ - 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 - } -} - -/// Iterate over the definitions of the given crate. -pub(crate) fn filter_def_ids(tcx: TyCtxt<'_>, krate: CrateNum, mut func: F) -> Vec -where - F: FnMut(DefId) -> Option, -{ - 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 deleted file mode 100644 index 369d08e444e..00000000000 --- a/compiler/rustc_smir/src/stable_mir/abi.rs +++ /dev/null @@ -1,494 +0,0 @@ -use std::fmt::{self, Debug}; -use std::num::NonZero; -use std::ops::RangeInclusive; - -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, Ty, VariantIdx}; -use stable_mir::{Error, Opaque, error}; - -use crate::stable_mir; - -/// A function ABI definition. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub struct FnAbi { - /// The types of each argument. - pub args: Vec, - - /// The expected return type. - pub ret: ArgAbi, - - /// The count of non-variadic arguments. - /// - /// Should only be different from `args.len()` when a function is a C variadic function. - pub fixed_count: u32, - - /// The ABI convention. - pub conv: CallConvention, - - /// Whether this is a variadic C function, - pub c_variadic: bool, -} - -/// Information about the ABI of a function's argument, or return value. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub struct ArgAbi { - pub ty: Ty, - pub layout: Layout, - pub mode: PassMode, -} - -/// How a function argument should be passed in to the target function. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub enum PassMode { - /// Ignore the argument. - /// - /// The argument is either uninhabited or a ZST. - Ignore, - /// Pass the argument directly. - /// - /// The argument has a layout abi of `Scalar` or `Vector`. - Direct(Opaque), - /// Pass a pair's elements directly in two arguments. - /// - /// The argument has a layout abi of `ScalarPair`. - Pair(Opaque, Opaque), - /// Pass the argument after casting it. - Cast { pad_i32: bool, cast: Opaque }, - /// Pass the argument indirectly via a hidden pointer. - Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool }, -} - -/// The layout of a type, alongside the type itself. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub struct TyAndLayout { - pub ty: Ty, - pub layout: Layout, -} - -/// The layout of a type in memory. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub struct LayoutShape { - /// The fields location within the layout - pub fields: FieldsShape, - - /// Encodes information about multi-variant layouts. - /// Even with `Multiple` variants, a layout still has its own fields! Those are then - /// shared between all variants. - /// - /// To access all fields of this layout, both `fields` and the fields of the active variant - /// must be taken into account. - pub variants: VariantsShape, - - /// The `abi` defines how this data is passed between functions. - pub abi: ValueAbi, - - /// The ABI mandated alignment in bytes. - pub abi_align: Align, - - /// The size of this layout in bytes. - pub size: Size, -} - -impl LayoutShape { - /// Returns `true` if the layout corresponds to an unsized type. - #[inline] - pub fn is_unsized(&self) -> bool { - self.abi.is_unsized() - } - - #[inline] - pub fn is_sized(&self) -> bool { - !self.abi.is_unsized() - } - - /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). - pub fn is_1zst(&self) -> bool { - self.is_sized() && self.size.bits() == 0 && self.abi_align == 1 - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub struct Layout(usize); - -impl Layout { - pub fn shape(self) -> LayoutShape { - with(|cx| cx.layout_shape(self)) - } -} - -impl stable_mir::IndexedVal for Layout { - fn to_val(index: usize) -> Self { - Layout(index) - } - fn to_index(&self) -> usize { - self.0 - } -} - -/// Describes how the fields of a type are shaped in memory. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub enum FieldsShape { - /// Scalar primitives and `!`, which never have fields. - Primitive, - - /// All fields start at no offset. The `usize` is the field count. - Union(NonZero), - - /// Array/vector-like placement, with all fields of identical types. - Array { stride: Size, count: u64 }, - - /// Struct-like placement, with precomputed offsets. - /// - /// Fields are guaranteed to not overlap, but note that gaps - /// before, between and after all the fields are NOT always - /// padding, and as such their contents may not be discarded. - /// For example, enum variants leave a gap at the start, - /// where the discriminant field in the enum layout goes. - Arbitrary { - /// Offsets for the first byte of each field, - /// ordered to match the source definition order. - /// I.e.: It follows the same order as [super::ty::VariantDef::fields()]. - /// This vector does not go in increasing order. - offsets: Vec, - }, -} - -impl FieldsShape { - pub fn fields_by_offset_order(&self) -> Vec { - match self { - FieldsShape::Primitive => vec![], - FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(), - FieldsShape::Arbitrary { offsets, .. } => { - let mut indices = (0..offsets.len()).collect::>(); - indices.sort_by_key(|idx| offsets[*idx]); - indices - } - } - } - - pub fn count(&self) -> usize { - match self { - FieldsShape::Primitive => 0, - FieldsShape::Union(count) => count.get(), - FieldsShape::Array { count, .. } => *count as usize, - FieldsShape::Arbitrary { offsets, .. } => offsets.len(), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub enum VariantsShape { - /// A type with no valid variants. Must be uninhabited. - Empty, - - /// Single enum variants, structs/tuples, unions, and all non-ADTs. - Single { index: VariantIdx }, - - /// Enum-likes with more than one inhabited variant: each variant comes with - /// a *discriminant* (usually the same as the variant index but the user can - /// assign explicit discriminant values). That discriminant is encoded - /// as a *tag* on the machine. The layout of each variant is - /// a struct, and they all have space reserved for the tag. - /// For enums, the tag is the sole field of the layout. - Multiple { - tag: Scalar, - tag_encoding: TagEncoding, - tag_field: usize, - variants: Vec, - }, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub enum TagEncoding { - /// The tag directly stores the discriminant, but possibly with a smaller layout - /// (so converting the tag to the discriminant can require sign extension). - Direct, - - /// Niche (values invalid for a type) encoding the discriminant: - /// Discriminant and variant index coincide. - /// The variant `untagged_variant` contains a niche at an arbitrary - /// offset (field `tag_field` of the enum), which for a variant with - /// discriminant `d` is set to - /// `(d - niche_variants.start).wrapping_add(niche_start)`. - /// - /// For example, `Option<(usize, &T)>` is represented such that - /// `None` has a null pointer for the second tuple field, and - /// `Some` is the identity function (with a non-null reference). - Niche { - untagged_variant: VariantIdx, - niche_variants: RangeInclusive, - niche_start: u128, - }, -} - -/// Describes how values of the type are passed by target ABIs, -/// in terms of categories of C types there are ABI rules for. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub enum ValueAbi { - Scalar(Scalar), - ScalarPair(Scalar, Scalar), - Vector { - element: Scalar, - count: u64, - }, - Aggregate { - /// If true, the size is exact, otherwise it's only a lower bound. - sized: bool, - }, -} - -impl ValueAbi { - /// Returns `true` if the layout corresponds to an unsized type. - pub fn is_unsized(&self) -> bool { - match *self { - ValueAbi::Scalar(_) | ValueAbi::ScalarPair(..) | ValueAbi::Vector { .. } => false, - ValueAbi::Aggregate { sized } => !sized, - } - } -} - -/// Information about one scalar component of a Rust type. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)] -pub enum Scalar { - Initialized { - /// The primitive type used to represent this value. - value: Primitive, - /// The range that represents valid values. - /// The range must be valid for the `primitive` size. - valid_range: WrappingRange, - }, - Union { - /// Unions never have niches, so there is no `valid_range`. - /// Even for unions, we need to use the correct registers for the kind of - /// values inside the union, so we keep the `Primitive` type around. - /// It is also used to compute the size of the scalar. - value: Primitive, - }, -} - -impl Scalar { - pub fn has_niche(&self, target: &MachineInfo) -> bool { - match self { - Scalar::Initialized { value, valid_range } => { - !valid_range.is_full(value.size(target)).unwrap() - } - Scalar::Union { .. } => false, - } - } -} - -/// Fundamental unit of memory access and layout. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize)] -pub enum Primitive { - /// The `bool` is the signedness of the `Integer` type. - /// - /// One would think we would not care about such details this low down, - /// but some ABIs are described in terms of C types and ISAs where the - /// integer arithmetic is done on {sign,zero}-extended registers, e.g. - /// a negative integer passed by zero-extension will appear positive in - /// the callee, and most operations on it will produce the wrong values. - Int { - length: IntegerLength, - signed: bool, - }, - Float { - length: FloatLength, - }, - Pointer(AddressSpace), -} - -impl Primitive { - pub fn size(self, target: &MachineInfo) -> Size { - match self { - Primitive::Int { length, .. } => Size::from_bits(length.bits()), - Primitive::Float { length } => Size::from_bits(length.bits()), - Primitive::Pointer(_) => target.pointer_width, - } - } -} - -/// Enum representing the existing integer lengths. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] -pub enum IntegerLength { - I8, - I16, - I32, - I64, - I128, -} - -/// Enum representing the existing float lengths. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] -pub enum FloatLength { - F16, - F32, - F64, - F128, -} - -impl IntegerLength { - pub fn bits(self) -> usize { - match self { - IntegerLength::I8 => 8, - IntegerLength::I16 => 16, - IntegerLength::I32 => 32, - IntegerLength::I64 => 64, - IntegerLength::I128 => 128, - } - } -} - -impl FloatLength { - pub fn bits(self) -> usize { - match self { - FloatLength::F16 => 16, - FloatLength::F32 => 32, - FloatLength::F64 => 64, - FloatLength::F128 => 128, - } - } -} - -/// An identifier that specifies the address space that some operation -/// should operate on. Special address spaces have an effect on code generation, -/// depending on the target and the address spaces it implements. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] -pub struct AddressSpace(pub u32); - -impl AddressSpace { - /// The default address space, corresponding to data space. - pub const DATA: Self = AddressSpace(0); -} - -/// Inclusive wrap-around range of valid values (bitwise representation), that is, if -/// start > end, it represents `start..=MAX`, followed by `0..=end`. -/// -/// That is, for an i8 primitive, a range of `254..=2` means following -/// sequence: -/// -/// 254 (-2), 255 (-1), 0, 1, 2 -#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)] -pub struct WrappingRange { - pub start: u128, - pub end: u128, -} - -impl WrappingRange { - /// Returns `true` if `size` completely fills the range. - #[inline] - pub fn is_full(&self, size: Size) -> Result { - let Some(max_value) = size.unsigned_int_max() else { - return Err(error!("Expected size <= 128 bits, but found {} instead", size.bits())); - }; - if self.start <= max_value && self.end <= max_value { - Ok(self.start == (self.end.wrapping_add(1) & max_value)) - } else { - Err(error!("Range `{self:?}` out of bounds for size `{}` bits.", size.bits())) - } - } - - /// Returns `true` if `v` is contained in the range. - #[inline(always)] - pub fn contains(&self, v: u128) -> bool { - if self.wraps_around() { - self.start <= v || v <= self.end - } else { - self.start <= v && v <= self.end - } - } - - /// Returns `true` if the range wraps around. - /// I.e., the range represents the union of `self.start..=MAX` and `0..=self.end`. - /// Returns `false` if this is a non-wrapping range, i.e.: `self.start..=self.end`. - #[inline] - pub fn wraps_around(&self) -> bool { - self.start > self.end - } -} - -impl Debug for WrappingRange { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.start > self.end { - write!(fmt, "(..={}) | ({}..)", self.end, self.start)?; - } else { - write!(fmt, "{}..={}", self.start, self.end)?; - } - Ok(()) - } -} - -/// General language calling conventions. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub enum CallConvention { - C, - Rust, - - Cold, - PreserveMost, - PreserveAll, - - Custom, - - // Target-specific calling conventions. - ArmAapcs, - CCmseNonSecureCall, - CCmseNonSecureEntry, - - Msp430Intr, - - PtxKernel, - - GpuKernel, - - X86Fastcall, - X86Intr, - X86Stdcall, - X86ThisCall, - X86VectorCall, - - X86_64SysV, - X86_64Win64, - - AvrInterrupt, - AvrNonBlockingInterrupt, - - RiscvInterrupt, -} - -#[non_exhaustive] -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] -pub struct ReprFlags { - pub is_simd: bool, - pub is_c: bool, - pub is_transparent: bool, - pub is_linear: bool, -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] -pub enum IntegerType { - /// Pointer-sized integer type, i.e. `isize` and `usize`. - Pointer { - /// Signedness. e.g. `true` for `isize` - is_signed: bool, - }, - /// Fixed-sized integer type, e.g. `i8`, `u32`, `i128`. - Fixed { - /// Length of this integer type. e.g. `IntegerLength::I8` for `u8`. - length: IntegerLength, - /// Signedness. e.g. `false` for `u8` - is_signed: bool, - }, -} - -/// Representation options provided by the user -#[non_exhaustive] -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] -pub struct ReprOptions { - pub int: Option, - pub align: Option, - pub pack: Option, - pub flags: ReprFlags, -} diff --git a/compiler/rustc_smir/src/stable_mir/alloc.rs b/compiler/rustc_smir/src/stable_mir/alloc.rs deleted file mode 100644 index 120cb4404b9..00000000000 --- a/compiler/rustc_smir/src/stable_mir/alloc.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! 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 { - 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 deleted file mode 100644 index a19968d2ab7..00000000000 --- a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs +++ /dev/null @@ -1,1100 +0,0 @@ -//! Define the interface with the Rust compiler. -//! -//! StableMIR users should not use any of the items in this module directly. -//! These APIs have no stability guarantee. - -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, 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, 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 [`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) trait SmirInterface { - fn entry_fn(&self) -> Option; - /// 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; - - /// Retrieve all functions defined in this crate. - fn crate_functions(&self, crate_num: CrateNum) -> Vec; - - /// Retrieve all static items defined in this crate. - fn crate_statics(&self, crate_num: CrateNum) -> Vec; - fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule; - fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec; - 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; - - /// Find a crate with the given name. - fn find_crates(&self, name: &str) -> Vec; - - /// 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; - - /// Get all tool attributes of a definition. - fn all_tool_attrs(&self, def_id: DefId) -> Vec; - - /// 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; - - /// 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; - - /// Evaluate constant as a target usize. - fn eval_target_usize(&self, cnst: &MirConst) -> Result; - fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result; - - /// Create a new zero-sized constant. - fn try_new_const_zst(&self, ty: Ty) -> Result; - - /// 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; - fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result; - - /// Create a new type from the given kind. - fn new_rigid_ty(&self, kind: RigidTy) -> Ty; - - /// Create a new box type, `Box`, 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; - - /// 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; - - /// 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; - - /// Resolve instance for a closure with the requested type. - fn resolve_closure( - &self, - def: ClosureDef, - args: &GenericArgs, - kind: ClosureKind, - ) -> Option; - - /// Evaluate a static's initializer. - fn eval_static_initializer(&self, def: StaticDef) -> Result; - - /// Try to evaluate an instance into a constant. - fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result; - - /// 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; - 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; - - /// Get the ABI of a function pointer. - fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result; - - /// Get the layout of a type. - fn ty_layout(&self, ty: Ty) -> Result; - - /// 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 for SmirContainer<'tcx, BridgeTys> { - fn entry_fn(&self) -> Option { - 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. - 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. - 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. - 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) - } - - fn foreign_modules(&self, crate_num: CrateNum) -> Vec { - 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. - fn crate_functions(&self, crate_num: CrateNum) -> Vec { - 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. - fn crate_statics(&self, crate_num: CrateNum) -> Vec { - 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() - } - - 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) - } - - fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec { - 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() - } - - 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() - } - - 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() - } - - 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) - } - - 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() - } - - 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() - } - - 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) - } - - 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) - } - - 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(), - } - } - - 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. - fn local_crate(&self) -> Crate { - let cx = &*self.cx.borrow(); - smir_crate(cx, cx.local_crate_num()) - } - - /// Retrieve a list of all external crates. - fn external_crates(&self) -> Vec { - 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. - fn find_crates(&self, name: &str) -> Vec { - 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`. - 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. - /// - /// 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 { - 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. - fn all_tool_attrs(&self, def_id: DefId) -> Vec { - 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`. - 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. - 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`. - 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`. - 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. - 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. - 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. - 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. - 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. - 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. - 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 - 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. - 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. - fn intrinsic(&self, item: DefId) -> Option { - 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. - 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. - 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. - 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. - 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. - fn coroutine_discr_for_variant( - &self, - coroutine: CoroutineDef, - args: &GenericArgs, - variant: VariantIdx, - ) -> Discr { - 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. - 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)) - } - - fn variant_fields(&self, def: VariantDef) -> Vec { - 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. - fn eval_target_usize(&self, mir_const: &MirConst) -> Result { - 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) - } - - fn eval_target_usize_ty(&self, ty_const: &TyConst) -> Result { - 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. - fn try_new_const_zst(&self, ty: Ty) -> Result { - 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. - 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. - 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. - fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { - 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)) - } - - fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { - 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. - 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`, for the given inner type `T`. - 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. - 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. - 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. - 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. - 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) - } - - 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. - 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 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. - 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. - fn instance_body(&self, instance: InstanceDef) -> Option { - 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. - 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. - 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. - 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. - 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. - 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. - 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. - 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. - fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option { - 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. - 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. - fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option { - 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. - fn resolve_closure( - &self, - def: ClosureDef, - args: &GenericArgs, - kind: ClosureKind, - ) -> Option { - 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. - fn eval_static_initializer(&self, def: StaticDef) -> Result { - 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. - fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result { - 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. - 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. - fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option { - 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)) - } - - fn krate(&self, def_id: DefId) -> Crate { - let tables = self.tables.borrow(); - let cx = &*self.cx.borrow(); - smir_crate(cx, tables[def_id].krate) - } - - 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. - 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. - fn instance_abi(&self, def: InstanceDef) -> Result { - 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. - fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { - 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. - fn ty_layout(&self, ty: Ty) -> Result { - 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. - 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. - 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. - 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. - 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. - 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(interface: &dyn SmirInterface, f: F) -> Result -where - F: FnOnce() -> T, -{ - if TLV.is_set() { - Err(Error::from("StableMIR already running")) - } else { - let ptr: *const () = (&raw const interface) as _; - TLV.set(&Cell::new(ptr), || Ok(f())) - } -} - -/// Execute the given function with access the [`SmirInterface`]. -/// -/// 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(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 &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/crate_def.rs b/compiler/rustc_smir/src/stable_mir/crate_def.rs deleted file mode 100644 index 64f7ef9b314..00000000000 --- a/compiler/rustc_smir/src/stable_mir/crate_def.rs +++ /dev/null @@ -1,175 +0,0 @@ -//! Module that define a common trait for things that represent a crate definition, -//! such as, a function, a trait, an enum, and any other definitions. - -use serde::Serialize; -use stable_mir::ty::{GenericArgs, Span, Ty}; -use stable_mir::{AssocItems, Crate, Symbol, with}; - -use crate::stable_mir; - -/// A unique identification number for each item accessible for the current compilation unit. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)] -pub struct DefId(pub(crate) usize); - -impl DefId { - /// Return fully qualified name of this definition - pub fn name(&self) -> Symbol { - with(|cx| cx.def_name(*self, false)) - } - - /// Return a trimmed name of this definition. - /// - /// This can be used to print more user friendly diagnostic messages. - /// - /// If a symbol name can only be imported from one place for a type, and as - /// long as it was not glob-imported anywhere in the current crate, we trim its - /// path and print only the name. - /// - /// For example, this function may shorten `std::vec::Vec` to just `Vec`, - /// as long as there is no other `Vec` importable anywhere. - pub fn trimmed_name(&self) -> Symbol { - with(|cx| cx.def_name(*self, true)) - } -} - -/// A trait for retrieving information about a particular definition. -/// -/// Implementors must provide the implementation of `def_id` which will be used to retrieve -/// information about a crate's definition. -pub trait CrateDef { - /// Retrieve the unique identifier for the current definition. - fn def_id(&self) -> DefId; - - /// Return the fully qualified name of the current definition. - /// - /// See [`DefId::name`] for more details - fn name(&self) -> Symbol { - self.def_id().name() - } - - /// Return a trimmed name of this definition. - /// - /// See [`DefId::trimmed_name`] for more details - fn trimmed_name(&self) -> Symbol { - self.def_id().trimmed_name() - } - - /// Return information about the crate where this definition is declared. - /// - /// This will return the crate number and its name. - fn krate(&self) -> Crate { - let def_id = self.def_id(); - with(|cx| cx.krate(def_id)) - } - - /// Return the span of this definition. - fn span(&self) -> Span { - let def_id = self.def_id(); - with(|cx| cx.span_of_an_item(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()]`. - fn tool_attrs(&self, attr: &[Symbol]) -> Vec { - let def_id = self.def_id(); - with(|cx| cx.tool_attrs(def_id, attr)) - } - - /// Return all tool attributes of this definition. - fn all_tool_attrs(&self) -> Vec { - let def_id = self.def_id(); - with(|cx| cx.all_tool_attrs(def_id)) - } -} - -/// A trait that can be used to retrieve a definition's type. -/// -/// Note that not every CrateDef has a type `Ty`. They should not implement this trait. -pub trait CrateDefType: CrateDef { - /// Returns the type of this crate item. - fn ty(&self) -> Ty { - with(|cx| cx.def_ty(self.def_id())) - } - - /// Retrieve the type of this definition by instantiating and normalizing it with `args`. - /// - /// This will panic if instantiation fails. - fn ty_with_args(&self, args: &GenericArgs) -> Ty { - with(|cx| cx.def_ty_with_args(self.def_id(), args)) - } -} - -/// A trait for retrieving all items from a definition within a crate. -pub trait CrateDefItems: CrateDef { - /// Retrieve all associated items from a definition. - fn associated_items(&self) -> AssocItems { - with(|cx| cx.associated_items(self.def_id())) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Attribute { - value: String, - span: Span, -} - -impl Attribute { - pub fn new(value: String, span: Span) -> Attribute { - Attribute { value, span } - } - - /// Get the span of this attribute. - pub fn span(&self) -> Span { - self.span - } - - /// Get the string representation of this attribute. - pub fn as_str(&self) -> &str { - &self.value - } -} - -macro_rules! crate_def { - ( $(#[$attr:meta])* - $vis:vis $name:ident $(;)? - ) => { - $(#[$attr])* - #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] - $vis struct $name(pub DefId); - - impl CrateDef for $name { - fn def_id(&self) -> DefId { - self.0 - } - } - }; -} - -macro_rules! crate_def_with_ty { - ( $(#[$attr:meta])* - $vis:vis $name:ident $(;)? - ) => { - $(#[$attr])* - #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] - $vis struct $name(pub DefId); - - impl CrateDef for $name { - fn def_id(&self) -> DefId { - self.0 - } - } - - impl CrateDefType for $name {} - }; -} - -macro_rules! impl_crate_def_items { - ( $name:ident $(;)? ) => { - impl CrateDefItems for $name {} - }; -} diff --git a/compiler/rustc_smir/src/stable_mir/error.rs b/compiler/rustc_smir/src/stable_mir/error.rs deleted file mode 100644 index 3f9d67954b9..00000000000 --- a/compiler/rustc_smir/src/stable_mir/error.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! When things go wrong, we need some error handling. -//! There are a few different types of errors in StableMIR: -//! -//! - [CompilerError]: This represents errors that can be raised when invoking the compiler. -//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled. - -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)*)) }; -} - -pub(crate) use error; - -/// An error type used to represent an error that has already been reported by the compiler. -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum CompilerError { - /// Compilation failed, either due to normal errors or ICE. - Failed, - /// Compilation was interrupted. - Interrupted(T), - /// Compilation skipped. This happens when users invoke rustc to retrieve information such as - /// --version. - Skipped, -} - -/// A generic error to represent an API request that cannot be fulfilled. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Error(pub(crate) String); - -impl SmirError for Error { - fn new(msg: String) -> Self { - Self(msg) - } - - fn from_internal(err: T) -> Self { - Self(format!("{err:?}")) - } -} - -impl From<&str> for Error { - fn from(value: &str) -> Self { - Self(value.into()) - } -} - -impl Display for Error { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - Display::fmt(&self.0, f) - } -} - -impl Display for CompilerError -where - T: Display, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - CompilerError::Failed => write!(f, "Compilation Failed"), - CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason}"), - CompilerError::Skipped => write!(f, "Compilation Skipped"), - } - } -} - -impl Debug for CompilerError -where - T: Debug, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - CompilerError::Failed => write!(f, "Compilation Failed"), - CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason:?}"), - CompilerError::Skipped => write!(f, "Compilation Skipped"), - } - } -} - -impl std::error::Error for Error {} - -impl std::error::Error for CompilerError where T: Display + Debug {} - -impl From for Error { - fn from(value: io::Error) -> Self { - Error(value.to_string()) - } -} diff --git a/compiler/rustc_smir/src/stable_mir/mir.rs b/compiler/rustc_smir/src/stable_mir/mir.rs deleted file mode 100644 index 413b5152bb3..00000000000 --- a/compiler/rustc_smir/src/stable_mir/mir.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod alloc; -mod body; -pub mod mono; -pub mod pretty; -pub mod visit; - -pub use body::*; -pub use visit::{MirVisitor, MutMirVisitor}; diff --git a/compiler/rustc_smir/src/stable_mir/mir/alloc.rs b/compiler/rustc_smir/src/stable_mir/mir/alloc.rs deleted file mode 100644 index 26f30898a9c..00000000000 --- a/compiler/rustc_smir/src/stable_mir/mir/alloc.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! This module provides methods to retrieve allocation information, such as static variables. - -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, Ty}; -use stable_mir::{Error, IndexedVal, with}; - -use crate::stable_mir; - -/// An allocation in the SMIR global memory can be either a function pointer, -/// a static, or a "real" allocation with some data in it. -#[derive(Debug, Clone, Eq, PartialEq, Serialize)] -pub enum GlobalAlloc { - /// The alloc ID is used as a function pointer. - Function(Instance), - /// This alloc ID points to a symbolic (not-reified) vtable. - /// The `None` trait ref is used to represent auto traits. - VTable(Ty, Option>), - /// The alloc ID points to a "lazy" static variable that did not get computed (yet). - /// This is also used to break the cycle in recursive statics. - Static(StaticDef), - /// The alloc ID points to memory. - Memory(Allocation), -} - -impl From for GlobalAlloc { - fn from(value: AllocId) -> Self { - with(|cx| cx.global_alloc(value)) - } -} - -impl GlobalAlloc { - /// Retrieve the allocation id for a global allocation if it exists. - /// - /// For `[GlobalAlloc::VTable]`, this will return the allocation for the VTable of the given - /// type for the optional trait if the type implements the trait. - /// - /// This method will always return `None` for allocations other than `[GlobalAlloc::VTable]`. - pub fn vtable_allocation(&self) -> Option { - with(|cx| cx.vtable_allocation(self)) - } -} - -/// A unique identification number for each provenance -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] -pub struct AllocId(usize); - -impl IndexedVal for AllocId { - fn to_val(index: usize) -> Self { - AllocId(index) - } - fn to_index(&self) -> usize { - self.0 - } -} - -/// Utility function used to read an allocation data into a unassigned integer. -pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result { - let mut buf = [0u8; size_of::()]; - match MachineInfo::target_endianness() { - Endian::Little => { - bytes.read_exact(&mut buf[..bytes.len()])?; - Ok(u128::from_le_bytes(buf)) - } - Endian::Big => { - bytes.read_exact(&mut buf[16 - bytes.len()..])?; - Ok(u128::from_be_bytes(buf)) - } - } -} - -/// Utility function used to read an allocation data into an assigned integer. -pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result { - let mut buf = [0u8; size_of::()]; - match MachineInfo::target_endianness() { - Endian::Little => { - bytes.read_exact(&mut buf[..bytes.len()])?; - Ok(i128::from_le_bytes(buf)) - } - Endian::Big => { - bytes.read_exact(&mut buf[16 - bytes.len()..])?; - Ok(i128::from_be_bytes(buf)) - } - } -} diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs deleted file mode 100644 index 90d4a06b177..00000000000 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ /dev/null @@ -1,1128 +0,0 @@ -use std::io; - -use serde::Serialize; -use stable_mir::compiler_interface::with; -use stable_mir::mir::pretty::function_body; -use stable_mir::ty::{ - AdtDef, ClosureDef, CoroutineClosureDef, CoroutineDef, GenericArgs, MirConst, Movability, - Region, RigidTy, Ty, TyConst, TyKind, VariantIdx, -}; -use stable_mir::{Error, Opaque, Span, Symbol}; - -use crate::stable_mir; - -/// The SMIR representation of a single function. -#[derive(Clone, Debug, Serialize)] -pub struct Body { - pub blocks: Vec, - - /// Declarations of locals within the function. - /// - /// The first local is the return value pointer, followed by `arg_count` - /// locals for the function arguments, followed by any user-declared - /// variables and temporaries. - pub(super) locals: LocalDecls, - - /// The number of arguments this function takes. - pub(super) arg_count: usize, - - /// Debug information pertaining to user variables, including captures. - pub var_debug_info: Vec, - - /// Mark an argument (which must be a tuple) as getting passed as its individual components. - /// - /// This is used for the "rust-call" ABI such as closures. - pub(super) spread_arg: Option, - - /// The span that covers the entire function body. - pub span: Span, -} - -pub type BasicBlockIdx = usize; - -impl Body { - /// Constructs a `Body`. - /// - /// A constructor is required to build a `Body` from outside the crate - /// because the `arg_count` and `locals` fields are private. - pub fn new( - blocks: Vec, - locals: LocalDecls, - arg_count: usize, - var_debug_info: Vec, - spread_arg: Option, - span: Span, - ) -> Self { - // If locals doesn't contain enough entries, it can lead to panics in - // `ret_local`, `arg_locals`, and `inner_locals`. - assert!( - locals.len() > arg_count, - "A Body must contain at least a local for the return value and each of the function's arguments" - ); - Self { blocks, locals, arg_count, var_debug_info, spread_arg, span } - } - - /// Return local that holds this function's return value. - pub fn ret_local(&self) -> &LocalDecl { - &self.locals[RETURN_LOCAL] - } - - /// Locals in `self` that correspond to this function's arguments. - pub fn arg_locals(&self) -> &[LocalDecl] { - &self.locals[1..][..self.arg_count] - } - - /// Inner locals for this function. These are the locals that are - /// neither the return local nor the argument locals. - pub fn inner_locals(&self) -> &[LocalDecl] { - &self.locals[self.arg_count + 1..] - } - - /// Returns a mutable reference to the local that holds this function's return value. - pub(crate) fn ret_local_mut(&mut self) -> &mut LocalDecl { - &mut self.locals[RETURN_LOCAL] - } - - /// Returns a mutable slice of locals corresponding to this function's arguments. - pub(crate) fn arg_locals_mut(&mut self) -> &mut [LocalDecl] { - &mut self.locals[1..][..self.arg_count] - } - - /// Returns a mutable slice of inner locals for this function. - /// Inner locals are those that are neither the return local nor the argument locals. - pub(crate) fn inner_locals_mut(&mut self) -> &mut [LocalDecl] { - &mut self.locals[self.arg_count + 1..] - } - - /// Convenience function to get all the locals in this function. - /// - /// Locals are typically accessed via the more specific methods `ret_local`, - /// `arg_locals`, and `inner_locals`. - pub fn locals(&self) -> &[LocalDecl] { - &self.locals - } - - /// Get the local declaration for this local. - pub fn local_decl(&self, local: Local) -> Option<&LocalDecl> { - self.locals.get(local) - } - - /// Get an iterator for all local declarations. - pub fn local_decls(&self) -> impl Iterator { - self.locals.iter().enumerate() - } - - /// Emit the body using the provided name for the signature. - pub fn dump(&self, w: &mut W, fn_name: &str) -> io::Result<()> { - function_body(w, self, fn_name) - } - - pub fn spread_arg(&self) -> Option { - self.spread_arg - } -} - -type LocalDecls = Vec; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct LocalDecl { - pub ty: Ty, - pub span: Span, - pub mutability: Mutability, -} - -#[derive(Clone, PartialEq, Eq, Debug, Serialize)] -pub struct BasicBlock { - pub statements: Vec, - pub terminator: Terminator, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct Terminator { - pub kind: TerminatorKind, - pub span: Span, -} - -impl Terminator { - pub fn successors(&self) -> Successors { - self.kind.successors() - } -} - -pub type Successors = Vec; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum TerminatorKind { - Goto { - target: BasicBlockIdx, - }, - SwitchInt { - discr: Operand, - targets: SwitchTargets, - }, - Resume, - Abort, - Return, - Unreachable, - Drop { - place: Place, - target: BasicBlockIdx, - unwind: UnwindAction, - }, - Call { - func: Operand, - args: Vec, - destination: Place, - target: Option, - unwind: UnwindAction, - }, - Assert { - cond: Operand, - expected: bool, - msg: AssertMessage, - target: BasicBlockIdx, - unwind: UnwindAction, - }, - InlineAsm { - template: String, - operands: Vec, - options: String, - line_spans: String, - destination: Option, - unwind: UnwindAction, - }, -} - -impl TerminatorKind { - pub fn successors(&self) -> Successors { - use self::TerminatorKind::*; - match *self { - Call { target: Some(t), unwind: UnwindAction::Cleanup(u), .. } - | Drop { target: t, unwind: UnwindAction::Cleanup(u), .. } - | Assert { target: t, unwind: UnwindAction::Cleanup(u), .. } - | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(u), .. } => { - vec![t, u] - } - Goto { target: t } - | Call { target: None, unwind: UnwindAction::Cleanup(t), .. } - | Call { target: Some(t), unwind: _, .. } - | Drop { target: t, unwind: _, .. } - | Assert { target: t, unwind: _, .. } - | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. } - | InlineAsm { destination: Some(t), unwind: _, .. } => { - vec![t] - } - - Return - | Resume - | Abort - | Unreachable - | Call { target: None, unwind: _, .. } - | InlineAsm { destination: None, unwind: _, .. } => { - vec![] - } - SwitchInt { ref targets, .. } => targets.all_targets(), - } - } - - pub fn unwind(&self) -> Option<&UnwindAction> { - match *self { - TerminatorKind::Goto { .. } - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::SwitchInt { .. } => None, - TerminatorKind::Call { ref unwind, .. } - | TerminatorKind::Assert { ref unwind, .. } - | TerminatorKind::Drop { ref unwind, .. } - | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind), - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct InlineAsmOperand { - pub in_value: Option, - pub out_place: Option, - // This field has a raw debug representation of MIR's InlineAsmOperand. - // For now we care about place/operand + the rest in a debug format. - pub raw_rpr: String, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum UnwindAction { - Continue, - Unreachable, - Terminate, - Cleanup(BasicBlockIdx), -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum AssertMessage { - BoundsCheck { len: Operand, index: Operand }, - Overflow(BinOp, Operand, Operand), - OverflowNeg(Operand), - DivisionByZero(Operand), - RemainderByZero(Operand), - ResumedAfterReturn(CoroutineKind), - ResumedAfterPanic(CoroutineKind), - ResumedAfterDrop(CoroutineKind), - MisalignedPointerDereference { required: Operand, found: Operand }, - NullPointerDereference, - InvalidEnumConstruction(Operand), -} - -impl AssertMessage { - pub fn description(&self) -> Result<&'static str, Error> { - match self { - AssertMessage::Overflow(BinOp::Add, _, _) => Ok("attempt to add with overflow"), - AssertMessage::Overflow(BinOp::Sub, _, _) => Ok("attempt to subtract with overflow"), - AssertMessage::Overflow(BinOp::Mul, _, _) => Ok("attempt to multiply with overflow"), - AssertMessage::Overflow(BinOp::Div, _, _) => Ok("attempt to divide with overflow"), - AssertMessage::Overflow(BinOp::Rem, _, _) => { - Ok("attempt to calculate the remainder with overflow") - } - AssertMessage::OverflowNeg(_) => Ok("attempt to negate with overflow"), - AssertMessage::Overflow(BinOp::Shr, _, _) => Ok("attempt to shift right with overflow"), - AssertMessage::Overflow(BinOp::Shl, _, _) => Ok("attempt to shift left with overflow"), - AssertMessage::Overflow(op, _, _) => Err(error!("`{:?}` cannot overflow", op)), - AssertMessage::DivisionByZero(_) => Ok("attempt to divide by zero"), - AssertMessage::RemainderByZero(_) => { - Ok("attempt to calculate the remainder with a divisor of zero") - } - AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine(_)) => { - Ok("coroutine resumed after completion") - } - AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared( - CoroutineDesugaring::Async, - _, - )) => Ok("`async fn` resumed after completion"), - AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared( - CoroutineDesugaring::Gen, - _, - )) => Ok("`async gen fn` resumed after completion"), - AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared( - CoroutineDesugaring::AsyncGen, - _, - )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"), - AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine(_)) => { - Ok("coroutine resumed after panicking") - } - AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared( - CoroutineDesugaring::Async, - _, - )) => Ok("`async fn` resumed after panicking"), - AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared( - CoroutineDesugaring::Gen, - _, - )) => Ok("`async gen fn` resumed after panicking"), - AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared( - CoroutineDesugaring::AsyncGen, - _, - )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking"), - - AssertMessage::ResumedAfterDrop(CoroutineKind::Coroutine(_)) => { - Ok("coroutine resumed after async drop") - } - AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared( - CoroutineDesugaring::Async, - _, - )) => Ok("`async fn` resumed after async drop"), - AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared( - CoroutineDesugaring::Gen, - _, - )) => Ok("`async gen fn` resumed after async drop"), - AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared( - CoroutineDesugaring::AsyncGen, - _, - )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after async drop"), - - AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"), - AssertMessage::MisalignedPointerDereference { .. } => { - Ok("misaligned pointer dereference") - } - AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"), - AssertMessage::InvalidEnumConstruction(_) => { - Ok("trying to construct an enum from an invalid value") - } - } - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum BinOp { - Add, - AddUnchecked, - Sub, - SubUnchecked, - Mul, - MulUnchecked, - Div, - Rem, - BitXor, - BitAnd, - BitOr, - Shl, - ShlUnchecked, - Shr, - ShrUnchecked, - Eq, - Lt, - Le, - Ne, - Ge, - Gt, - Cmp, - Offset, -} - -impl BinOp { - /// Return the type of this operation for the given input Ty. - /// This function does not perform type checking, and it currently doesn't handle SIMD. - pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty { - with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty)) - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum UnOp { - Not, - Neg, - PtrMetadata, -} - -impl UnOp { - /// Return the type of this operation for the given input Ty. - /// This function does not perform type checking, and it currently doesn't handle SIMD. - pub fn ty(&self, arg_ty: Ty) -> Ty { - with(|ctx| ctx.unop_ty(*self, arg_ty)) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum CoroutineKind { - Desugared(CoroutineDesugaring, CoroutineSource), - Coroutine(Movability), -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum CoroutineSource { - Block, - Closure, - Fn, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum CoroutineDesugaring { - Async, - - Gen, - - AsyncGen, -} - -pub(crate) type LocalDefId = Opaque; -/// The rustc coverage data structures are heavily tied to internal details of the -/// coverage implementation that are likely to change, and are unlikely to be -/// useful to third-party tools for the foreseeable future. -pub(crate) type Coverage = Opaque; - -/// The FakeReadCause describes the type of pattern why a FakeRead statement exists. -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum FakeReadCause { - ForMatchGuard, - ForMatchedPlace(LocalDefId), - ForGuardBinding, - ForLet(LocalDefId), - ForIndex, -} - -/// Describes what kind of retag is to be performed -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] -pub enum RetagKind { - FnEntry, - TwoPhase, - Raw, - Default, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] -pub enum Variance { - Covariant, - Invariant, - Contravariant, - Bivariant, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct CopyNonOverlapping { - pub src: Operand, - pub dst: Operand, - pub count: Operand, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum NonDivergingIntrinsic { - Assume(Operand), - CopyNonOverlapping(CopyNonOverlapping), -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct Statement { - pub kind: StatementKind, - pub span: Span, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum StatementKind { - Assign(Place, Rvalue), - FakeRead(FakeReadCause, Place), - SetDiscriminant { place: Place, variant_index: VariantIdx }, - Deinit(Place), - StorageLive(Local), - StorageDead(Local), - Retag(RetagKind, Place), - PlaceMention(Place), - AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance }, - Coverage(Coverage), - Intrinsic(NonDivergingIntrinsic), - ConstEvalCounter, - Nop, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum Rvalue { - /// Creates a pointer with the indicated mutability to the place. - /// - /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like - /// `&raw v` or `addr_of!(v)`. - AddressOf(RawPtrKind, Place), - - /// Creates an aggregate value, like a tuple or struct. - /// - /// This is needed because dataflow analysis needs to distinguish - /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo` - /// has a destructor. - /// - /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Coroutine`. After - /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too. - Aggregate(AggregateKind, Vec), - - /// * `Offset` has the same semantics as `<*const T>::offset`, except that the second - /// parameter may be a `usize` as well. - /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, - /// raw pointers, or function pointers and return a `bool`. The types of the operands must be - /// matching, up to the usual caveat of the lifetimes in function pointers. - /// * Left and right shift operations accept signed or unsigned integers not necessarily of the - /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is - /// truncated as needed. - /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching - /// types and return a value of that type. - /// * The remaining operations accept signed integers, unsigned integers, or floats with - /// matching types and return a value of that type. - BinaryOp(BinOp, Operand, Operand), - - /// Performs essentially all of the casts that can be performed via `as`. - /// - /// This allows for casts from/to a variety of types. - Cast(CastKind, Operand, Ty), - - /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. - /// - /// For addition, subtraction, and multiplication on integers the error condition is set when - /// the infinite precision result would not be equal to the actual result. - CheckedBinaryOp(BinOp, Operand, Operand), - - /// A CopyForDeref is equivalent to a read from a place. - /// When such a read happens, it is guaranteed that the only use of the returned value is a - /// deref operation, immediately followed by one or more projections. - CopyForDeref(Place), - - /// Computes the discriminant of the place, returning it as an integer. - /// Returns zero for types without discriminant. - /// - /// The validity requirements for the underlying value are undecided for this rvalue, see - /// [#91095]. Note too that the value of the discriminant is not the same thing as the - /// variant index; - /// - /// [#91095]: https://github.com/rust-lang/rust/issues/91095 - Discriminant(Place), - - /// Yields the length of the place, as a `usize`. - /// - /// If the type of the place is an array, this is the array length. For slices (`[T]`, not - /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is - /// ill-formed for places of other types. - Len(Place), - - /// Creates a reference to the place. - Ref(Region, BorrowKind, Place), - - /// Creates an array where each element is the value of the operand. - /// - /// This is the cause of a bug in the case where the repetition count is zero because the value - /// is not dropped, see [#74836]. - /// - /// Corresponds to source code like `[x; 32]`. - /// - /// [#74836]: https://github.com/rust-lang/rust/issues/74836 - Repeat(Operand, TyConst), - - /// Transmutes a `*mut u8` into shallow-initialized `Box`. - /// - /// This is different from a normal transmute because dataflow analysis will treat the box as - /// initialized but its content as uninitialized. Like other pointer casts, this in general - /// affects alias analysis. - ShallowInitBox(Operand, Ty), - - /// Creates a pointer/reference to the given thread local. - /// - /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a - /// `*const T`, and if neither of those apply a `&T`. - /// - /// **Note:** This is a runtime operation that actually executes code and is in this sense more - /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to - /// SIGILL for some reason that I (JakobDegen) never got a chance to look into. - /// - /// **Needs clarification**: Are there weird additional semantics here related to the runtime - /// nature of this operation? - ThreadLocalRef(stable_mir::CrateItem), - - /// Computes a value as described by the operation. - NullaryOp(NullOp, Ty), - - /// Exactly like `BinaryOp`, but less operands. - /// - /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; - /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds - /// return a value with the same type as their operand. - UnaryOp(UnOp, Operand), - - /// Yields the operand unchanged - Use(Operand), -} - -impl Rvalue { - pub fn ty(&self, locals: &[LocalDecl]) -> Result { - match self { - Rvalue::Use(operand) => operand.ty(locals), - Rvalue::Repeat(operand, count) => { - Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone())) - } - Rvalue::ThreadLocalRef(did) => Ok(did.ty()), - Rvalue::Ref(reg, bk, place) => { - let place_ty = place.ty(locals)?; - Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy())) - } - Rvalue::AddressOf(mutability, place) => { - let place_ty = place.ty(locals)?; - Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy())) - } - Rvalue::Len(..) => Ok(Ty::usize_ty()), - Rvalue::Cast(.., ty) => Ok(*ty), - Rvalue::BinaryOp(op, lhs, rhs) => { - let lhs_ty = lhs.ty(locals)?; - let rhs_ty = rhs.ty(locals)?; - Ok(op.ty(lhs_ty, rhs_ty)) - } - Rvalue::CheckedBinaryOp(op, lhs, rhs) => { - let lhs_ty = lhs.ty(locals)?; - let rhs_ty = rhs.ty(locals)?; - let ty = op.ty(lhs_ty, rhs_ty); - Ok(Ty::new_tuple(&[ty, Ty::bool_ty()])) - } - Rvalue::UnaryOp(op, operand) => { - let arg_ty = operand.ty(locals)?; - Ok(op.ty(arg_ty)) - } - Rvalue::Discriminant(place) => { - let place_ty = place.ty(locals)?; - place_ty - .kind() - .discriminant_ty() - .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}")) - } - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { - Ok(Ty::usize_ty()) - } - Rvalue::NullaryOp(NullOp::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()), - Rvalue::Aggregate(ak, ops) => match *ak { - AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64), - AggregateKind::Tuple => Ok(Ty::new_tuple( - &ops.iter().map(|op| op.ty(locals)).collect::, _>>()?, - )), - AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)), - AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())), - AggregateKind::Coroutine(def, ref args, mov) => { - Ok(Ty::new_coroutine(def, args.clone(), mov)) - } - AggregateKind::CoroutineClosure(def, ref args) => { - Ok(Ty::new_coroutine_closure(def, args.clone())) - } - AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)), - }, - Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)), - Rvalue::CopyForDeref(place) => place.ty(locals), - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum AggregateKind { - Array(Ty), - Tuple, - Adt(AdtDef, VariantIdx, GenericArgs, Option, Option), - Closure(ClosureDef, GenericArgs), - // FIXME(stable_mir): Movability here is redundant - Coroutine(CoroutineDef, GenericArgs, Movability), - CoroutineClosure(CoroutineClosureDef, GenericArgs), - RawPtr(Ty, Mutability), -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum Operand { - Copy(Place), - Move(Place), - Constant(ConstOperand), -} - -#[derive(Clone, Eq, PartialEq, Serialize)] -pub struct Place { - pub local: Local, - /// projection out of a place (access a field, deref a pointer, etc) - pub projection: Vec, -} - -impl From for Place { - fn from(local: Local) -> Self { - Place { local, projection: vec![] } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct ConstOperand { - pub span: Span, - pub user_ty: Option, - pub const_: MirConst, -} - -/// Debug information pertaining to a user variable. -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct VarDebugInfo { - /// The variable name. - pub name: Symbol, - - /// Source info of the user variable, including the scope - /// within which the variable is visible (to debuginfo). - pub source_info: SourceInfo, - - /// The user variable's data is split across several fragments, - /// each described by a `VarDebugInfoFragment`. - pub composite: Option, - - /// Where the data for this user variable is to be found. - pub value: VarDebugInfoContents, - - /// When present, indicates what argument number this variable is in the function that it - /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the - /// argument number in the original function before it was inlined. - pub argument_index: Option, -} - -impl VarDebugInfo { - /// Return a local variable if this info is related to one. - pub fn local(&self) -> Option { - match &self.value { - VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local), - VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None, - } - } - - /// Return a constant if this info is related to one. - pub fn constant(&self) -> Option<&ConstOperand> { - match &self.value { - VarDebugInfoContents::Place(_) => None, - VarDebugInfoContents::Const(const_op) => Some(const_op), - } - } -} - -pub type SourceScope = u32; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct SourceInfo { - pub span: Span, - pub scope: SourceScope, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct VarDebugInfoFragment { - pub ty: Ty, - pub projection: Vec, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum VarDebugInfoContents { - Place(Place), - Const(ConstOperand), -} - -// In MIR ProjectionElem is parameterized on the second Field argument and the Index argument. This -// is so it can be used for both Places (for which the projection elements are of type -// ProjectionElem) and user-provided type annotations (for which the projection elements -// are of type ProjectionElem<(), ()>). In SMIR we don't need this generality, so we just use -// ProjectionElem for Places. -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum ProjectionElem { - /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place. - Deref, - - /// A field projection (e.g., `f` in `_1.f`) project to a field in the base place. The field is - /// referenced by source-order index rather than the name of the field. The fields type is also - /// given. - Field(FieldIdx, Ty), - - /// Index into a slice/array. The value of the index is computed at runtime using the `V` - /// argument. - /// - /// Note that this does not also dereference, and so it does not exactly correspond to slice - /// indexing in Rust. In other words, in the below Rust code: - /// - /// ```rust - /// let x = &[1, 2, 3, 4]; - /// let i = 2; - /// x[i]; - /// ``` - /// - /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same - /// thing is true of the `ConstantIndex` and `Subslice` projections below. - Index(Local), - - /// Index into a slice/array given by offsets. - /// - /// These indices are generated by slice patterns. Easiest to explain by example: - /// - /// ```ignore (illustrative) - /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, - /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, - /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, - /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, - /// ``` - ConstantIndex { - /// index or -index (in Python terms), depending on from_end - offset: u64, - /// The thing being indexed must be at least this long -- otherwise, the - /// projection is UB. - /// - /// For arrays this is always the exact length. - min_length: u64, - /// Counting backwards from end? This is always false when indexing an - /// array. - from_end: bool, - }, - - /// Projects a slice from the base place. - /// - /// These indices are generated by slice patterns. If `from_end` is true, this represents - /// `slice[from..slice.len() - to]`. Otherwise it represents `array[from..to]`. - Subslice { - from: u64, - to: u64, - /// Whether `to` counts from the start or end of the array/slice. - from_end: bool, - }, - - /// "Downcast" to a variant of an enum or a coroutine. - Downcast(VariantIdx), - - /// Like an explicit cast from an opaque type to a concrete type, but without - /// requiring an intermediate variable. - OpaqueCast(Ty), - - /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where - /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping - /// explicit during optimizations and codegen. - /// - /// This projection doesn't impact the runtime behavior of the program except for potentially changing - /// some type metadata of the interpreter or codegen backend. - Subtype(Ty), -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct UserTypeProjection { - pub base: UserTypeAnnotationIndex, - - pub projection: Opaque, -} - -pub type Local = usize; - -pub const RETURN_LOCAL: Local = 0; - -/// The source-order index of a field in a variant. -/// -/// For example, in the following types, -/// ```ignore(illustrative) -/// enum Demo1 { -/// Variant0 { a: bool, b: i32 }, -/// Variant1 { c: u8, d: u64 }, -/// } -/// struct Demo2 { e: u8, f: u16, g: u8 } -/// ``` -/// `a`'s `FieldIdx` is `0`, -/// `b`'s `FieldIdx` is `1`, -/// `c`'s `FieldIdx` is `0`, and -/// `g`'s `FieldIdx` is `2`. -pub type FieldIdx = usize; - -type UserTypeAnnotationIndex = usize; - -/// The possible branch sites of a [TerminatorKind::SwitchInt]. -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct SwitchTargets { - /// The conditional branches where the first element represents the value that guards this - /// branch, and the second element is the branch target. - branches: Vec<(u128, BasicBlockIdx)>, - /// The `otherwise` branch which will be taken in case none of the conditional branches are - /// satisfied. - otherwise: BasicBlockIdx, -} - -impl SwitchTargets { - /// All possible targets including the `otherwise` target. - pub fn all_targets(&self) -> Successors { - self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect() - } - - /// The `otherwise` branch target. - pub fn otherwise(&self) -> BasicBlockIdx { - self.otherwise - } - - /// The conditional targets which are only taken if the pattern matches the given value. - pub fn branches(&self) -> impl Iterator { - self.branches.iter().copied() - } - - /// The number of targets including `otherwise`. - pub fn len(&self) -> usize { - self.branches.len() + 1 - } - - /// Create a new SwitchTargets from the given branches and `otherwise` target. - pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets { - SwitchTargets { branches, otherwise } - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum BorrowKind { - /// Data must be immutable and is aliasable. - Shared, - - /// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either - /// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]). - Fake(FakeBorrowKind), - - /// Data is mutable and not aliasable. - Mut { - /// `true` if this borrow arose from method-call auto-ref - kind: MutBorrowKind, - }, -} - -impl BorrowKind { - pub fn to_mutable_lossy(self) -> Mutability { - match self { - BorrowKind::Mut { .. } => Mutability::Mut, - BorrowKind::Shared => Mutability::Not, - // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation. - BorrowKind::Fake(_) => Mutability::Not, - } - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum RawPtrKind { - Mut, - Const, - FakeForPtrMetadata, -} - -impl RawPtrKind { - pub fn to_mutable_lossy(self) -> Mutability { - match self { - RawPtrKind::Mut { .. } => Mutability::Mut, - RawPtrKind::Const => Mutability::Not, - // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation. - RawPtrKind::FakeForPtrMetadata => Mutability::Not, - } - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum MutBorrowKind { - Default, - TwoPhaseBorrow, - ClosureCapture, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum FakeBorrowKind { - /// A shared (deep) borrow. Data must be immutable and is aliasable. - Deep, - /// The immediately borrowed place must be immutable, but projections from - /// it don't need to be. This is used to prevent match guards from replacing - /// the scrutinee. For example, a fake borrow of `a.b` doesn't - /// conflict with a mutable borrow of `a.b.c`. - Shallow, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub enum Mutability { - Not, - Mut, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum Safety { - Safe, - Unsafe, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum PointerCoercion { - /// Go from a fn-item type to a fn-pointer type. - ReifyFnPointer, - - /// Go from a safe fn pointer to an unsafe fn pointer. - UnsafeFnPointer, - - /// Go from a non-capturing closure to a fn pointer or an unsafe fn pointer. - /// It cannot convert a closure that requires unsafe. - ClosureFnPointer(Safety), - - /// Go from a mut raw pointer to a const raw pointer. - MutToConstPointer, - - /// Go from `*const [T; N]` to `*const T` - ArrayToPointer, - - /// Unsize a pointer/reference value, e.g., `&[T; n]` to - /// `&[T]`. Note that the source could be a thin or wide pointer. - /// This will do things like convert thin pointers to wide - /// pointers, or convert structs containing thin pointers to - /// structs containing wide pointers, or convert between wide - /// pointers. - Unsize, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub enum CastKind { - // FIXME(smir-rename): rename this to PointerExposeProvenance - PointerExposeAddress, - PointerWithExposedProvenance, - PointerCoercion(PointerCoercion), - IntToInt, - FloatToInt, - FloatToFloat, - IntToFloat, - PtrToPtr, - FnPtrToPtr, - Transmute, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum NullOp { - /// Returns the size of a value of that type. - SizeOf, - /// Returns the minimum alignment of a type. - AlignOf, - /// Returns the offset of a field. - OffsetOf(Vec<(VariantIdx, FieldIdx)>), - /// cfg!(ub_checks), but at codegen time - UbChecks, - /// cfg!(contract_checks), but at codegen time - ContractChecks, -} - -impl Operand { - /// Get the type of an operand relative to the local declaration. - /// - /// In order to retrieve the correct type, the `locals` argument must match the list of all - /// locals from the function body where this operand originates from. - /// - /// Errors indicate a malformed operand or incompatible locals list. - pub fn ty(&self, locals: &[LocalDecl]) -> Result { - match self { - Operand::Copy(place) | Operand::Move(place) => place.ty(locals), - Operand::Constant(c) => Ok(c.ty()), - } - } -} - -impl ConstOperand { - pub fn ty(&self) -> Ty { - self.const_.ty() - } -} - -impl Place { - /// Resolve down the chain of projections to get the type referenced at the end of it. - /// E.g.: - /// Calling `ty()` on `var.field` should return the type of `field`. - /// - /// In order to retrieve the correct type, the `locals` argument must match the list of all - /// locals from the function body where this place originates from. - pub fn ty(&self, locals: &[LocalDecl]) -> Result { - self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty)) - } -} - -impl ProjectionElem { - /// Get the expected type after applying this projection to a given place type. - pub fn ty(&self, place_ty: Ty) -> Result { - let ty = place_ty; - match &self { - ProjectionElem::Deref => Self::deref_ty(ty), - ProjectionElem::Field(_idx, fty) => Ok(*fty), - ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty), - ProjectionElem::Subslice { from, to, from_end } => { - Self::subslice_ty(ty, *from, *to, *from_end) - } - ProjectionElem::Downcast(_) => Ok(ty), - ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty), - } - } - - fn index_ty(ty: Ty) -> Result { - ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}")) - } - - fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result { - let ty_kind = ty.kind(); - match ty_kind { - TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty), - TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array( - inner, - to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?, - ), - TyKind::RigidTy(RigidTy::Array(inner, size)) => { - let size = size.eval_target_usize()?; - let len = size - from - to; - Ty::try_new_array(inner, len) - } - _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))), - } - } - - fn deref_ty(ty: Ty) -> Result { - let deref_ty = ty - .kind() - .builtin_deref(true) - .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?; - Ok(deref_ty.ty) - } -} diff --git a/compiler/rustc_smir/src/stable_mir/mir/mono.rs b/compiler/rustc_smir/src/stable_mir/mir/mono.rs deleted file mode 100644 index 5f177416714..00000000000 --- a/compiler/rustc_smir/src/stable_mir/mir/mono.rs +++ /dev/null @@ -1,306 +0,0 @@ -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, Ty}; -use stable_mir::{CrateItem, DefId, Error, IndexedVal, ItemKind, Opaque, Symbol, with}; - -use crate::{rustc_smir, stable_mir}; - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub enum MonoItem { - Fn(Instance), - Static(StaticDef), - GlobalAsm(Opaque), -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize)] -pub struct Instance { - /// The type of instance. - pub kind: InstanceKind, - /// An ID used to get the instance definition from the compiler. - /// Do not use this field directly. - pub def: InstanceDef, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] -pub enum InstanceKind { - /// A user defined item. - Item, - /// A compiler intrinsic function. - Intrinsic, - /// A virtual function definition stored in a VTable. - /// The `idx` field indicates the position in the VTable for this instance. - Virtual { idx: usize }, - /// A compiler generated shim. - Shim, -} - -impl Instance { - /// Get the arguments this instance was instantiated with. - pub fn args(&self) -> GenericArgs { - with(|cx| cx.instance_args(self.def)) - } - - /// Get the body of an Instance. - /// - /// The body will be eagerly monomorphized and all constants will already be evaluated. - /// - /// This method will return the intrinsic fallback body if one was defined. - pub fn body(&self) -> Option { - with(|context| context.instance_body(self.def)) - } - - /// Check whether this instance has a body available. - /// - /// For intrinsics with fallback body, this will return `true`. It is up to the user to decide - /// whether to specialize the intrinsic or to use its fallback body. - /// - /// For more information on fallback body, see . - /// - /// This call is much cheaper than `instance.body().is_some()`, since it doesn't try to build - /// the StableMIR body. - pub fn has_body(&self) -> bool { - with(|cx| cx.has_body(self.def.def_id())) - } - - pub fn is_foreign_item(&self) -> bool { - with(|cx| cx.is_foreign_item(self.def.def_id())) - } - - /// Get the instance type with generic instantiations applied and lifetimes erased. - pub fn ty(&self) -> Ty { - with(|context| context.instance_ty(self.def)) - } - - /// Retrieve information about this instance binary interface. - pub fn fn_abi(&self) -> Result { - with(|cx| cx.instance_abi(self.def)) - } - - /// Retrieve the instance's mangled name used for calling the given instance. - /// - /// This will also look up the correct name of instances from upstream crates. - pub fn mangled_name(&self) -> Symbol { - with(|context| context.instance_mangled_name(self.def)) - } - - /// Retrieve the instance name for diagnostic messages. - /// - /// This will return the specialized name, e.g., `std::vec::Vec::new`. - pub fn name(&self) -> Symbol { - with(|context| context.instance_name(self.def, false)) - } - - /// Return a trimmed name of the given instance including its args. - /// - /// If a symbol name can only be imported from one place for a type, and as - /// long as it was not glob-imported anywhere in the current crate, we trim its - /// path and print only the name. - pub fn trimmed_name(&self) -> Symbol { - with(|context| context.instance_name(self.def, true)) - } - - /// Retrieve the plain intrinsic name of an instance if it's an intrinsic. - /// - /// The plain name does not include type arguments (as `trimmed_name` does), - /// which is more convenient to match with intrinsic symbols. - pub fn intrinsic_name(&self) -> Option { - match self.kind { - InstanceKind::Intrinsic => { - Some(with(|context| context.intrinsic(self.def.def_id()).unwrap().fn_name())) - } - InstanceKind::Item | InstanceKind::Virtual { .. } | InstanceKind::Shim => None, - } - } - - /// Resolve an instance starting from a function definition and generic arguments. - pub fn resolve(def: FnDef, args: &GenericArgs) -> Result { - with(|context| { - context - .resolve_instance(def, args) - .ok_or_else(|| Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))) - }) - } - - /// Resolve the drop in place for a given type. - pub fn resolve_drop_in_place(ty: Ty) -> Instance { - with(|cx| cx.resolve_drop_in_place(ty)) - } - - /// Resolve an instance for a given function pointer. - pub fn resolve_for_fn_ptr(def: FnDef, args: &GenericArgs) -> Result { - with(|context| { - context - .resolve_for_fn_ptr(def, args) - .ok_or_else(|| Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))) - }) - } - - /// Resolve a closure with the expected kind. - pub fn resolve_closure( - def: ClosureDef, - args: &GenericArgs, - kind: ClosureKind, - ) -> Result { - with(|context| { - context - .resolve_closure(def, args, kind) - .ok_or_else(|| Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))) - }) - } - - /// Check whether this instance is an empty shim. - /// - /// Allow users to check if this shim can be ignored when called directly. - /// - /// We have decided not to export different types of Shims to StableMIR users, however, this - /// is a query that can be very helpful for users when processing DropGlue. - /// - /// When generating code for a Drop terminator, users can ignore an empty drop glue. - /// These shims are only needed to generate a valid Drop call done via VTable. - pub fn is_empty_shim(&self) -> bool { - self.kind == InstanceKind::Shim && with(|cx| cx.is_empty_drop_shim(self.def)) - } - - /// Try to constant evaluate the instance into a constant with the given type. - /// - /// This can be used to retrieve a constant that represents an intrinsic return such as - /// `type_id`. - pub fn try_const_eval(&self, const_ty: Ty) -> Result { - with(|cx| cx.eval_instance(self.def, const_ty)) - } - - /// Emit the body of this instance if it has one. - pub fn emit_mir(&self, w: &mut W) -> io::Result<()> { - if let Some(body) = self.body() { body.dump(w, &self.name()) } else { Ok(()) } - } -} - -impl Debug for Instance { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Instance") - .field("kind", &self.kind) - .field("def", &self.mangled_name()) - .field("args", &self.args()) - .finish() - } -} - -/// Try to convert a crate item into an instance. -/// The item cannot be generic in order to be converted into an instance. -impl TryFrom for Instance { - type Error = stable_mir::Error; - - fn try_from(item: CrateItem) -> Result { - with(|context| { - let def_id = item.def_id(); - if !context.requires_monomorphization(def_id) { - Ok(context.mono_instance(def_id)) - } else { - Err(Error::new("Item requires monomorphization".to_string())) - } - }) - } -} - -/// Try to convert an instance into a crate item. -/// Only user defined instances can be converted. -impl TryFrom for CrateItem { - type Error = stable_mir::Error; - - fn try_from(value: Instance) -> Result { - with(|context| { - if value.kind == InstanceKind::Item && context.has_body(value.def.def_id()) { - Ok(CrateItem(context.instance_def_id(value.def))) - } else { - Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind))) - } - }) - } -} - -impl From for MonoItem { - fn from(value: Instance) -> Self { - MonoItem::Fn(value) - } -} - -impl From for MonoItem { - fn from(value: StaticDef) -> Self { - MonoItem::Static(value) - } -} - -impl From for CrateItem { - fn from(value: StaticDef) -> Self { - CrateItem(value.0) - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] -pub struct InstanceDef(usize); - -impl CrateDef for InstanceDef { - fn def_id(&self) -> DefId { - with(|context| context.instance_def_id(*self)) - } -} - -crate_def! { - /// Holds information about a static variable definition. - #[derive(Serialize)] - pub StaticDef; -} - -impl TryFrom for StaticDef { - type Error = stable_mir::Error; - - fn try_from(value: CrateItem) -> Result { - if matches!(value.kind(), ItemKind::Static) { - Ok(StaticDef(value.0)) - } else { - Err(Error::new(format!("Expected a static item, but found: {value:?}"))) - } - } -} - -impl TryFrom for StaticDef { - type Error = stable_mir::Error; - - fn try_from(value: Instance) -> Result { - StaticDef::try_from(CrateItem::try_from(value)?) - } -} - -impl From for Instance { - fn from(value: StaticDef) -> Self { - // A static definition should always be convertible to an instance. - with(|cx| cx.mono_instance(value.def_id())) - } -} - -impl StaticDef { - /// Return the type of this static definition. - pub fn ty(&self) -> Ty { - with(|cx| cx.def_ty(self.0)) - } - - /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - pub fn eval_initializer(&self) -> Result { - with(|cx| cx.eval_static_initializer(*self)) - } -} - -impl IndexedVal for InstanceDef { - fn to_val(index: usize) -> Self { - InstanceDef(index) - } - fn to_index(&self) -> usize { - self.0 - } -} diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs deleted file mode 100644 index a7347e9b021..00000000000 --- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs +++ /dev/null @@ -1,470 +0,0 @@ -//! Implement methods to pretty print stable MIR body. -use std::fmt::Debug; -use std::io::Write; -use std::{fmt, io, iter}; - -use fmt::{Display, Formatter}; -use stable_mir::mir::{ - Operand, Place, RawPtrKind, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents, -}; -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; - -impl Display for Ty { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - with(|ctx| write!(f, "{}", ctx.ty_pretty(*self))) - } -} - -impl Display for AssocKind { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - AssocKind::Fn { has_self: true, .. } => write!(f, "method"), - AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"), - AssocKind::Const { .. } => write!(f, "associated const"), - AssocKind::Type { .. } => write!(f, "associated type"), - } - } -} - -impl Debug for Place { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - with(|ctx| write!(f, "{}", ctx.place_pretty(self))) - } -} - -pub(crate) fn function_body(writer: &mut W, body: &Body, name: &str) -> io::Result<()> { - write!(writer, "fn {name}(")?; - let mut sep = ""; - for (index, local) in body.arg_locals().iter().enumerate() { - write!(writer, "{}_{}: {}", sep, index + 1, local.ty)?; - sep = ", "; - } - write!(writer, ")")?; - - let return_local = body.ret_local(); - writeln!(writer, " -> {} {{", return_local.ty)?; - - body.locals().iter().enumerate().try_for_each(|(index, local)| -> io::Result<()> { - if index == 0 || index > body.arg_count { - writeln!(writer, " let {}_{}: {};", pretty_mut(local.mutability), index, local.ty) - } else { - Ok(()) - } - })?; - - body.var_debug_info.iter().try_for_each(|info| { - let content = match &info.value { - VarDebugInfoContents::Place(place) => { - format!("{place:?}") - } - VarDebugInfoContents::Const(constant) => pretty_mir_const(&constant.const_), - }; - writeln!(writer, " debug {} => {};", info.name, content) - })?; - - body.blocks - .iter() - .enumerate() - .map(|(index, block)| -> io::Result<()> { - writeln!(writer, " bb{index}: {{")?; - let _ = block - .statements - .iter() - .map(|statement| -> io::Result<()> { - pretty_statement(writer, &statement.kind)?; - Ok(()) - }) - .collect::>(); - pretty_terminator(writer, &block.terminator.kind)?; - writeln!(writer, " }}").unwrap(); - Ok(()) - }) - .collect::, _>>()?; - writeln!(writer, "}}")?; - Ok(()) -} - -fn pretty_statement(writer: &mut W, statement: &StatementKind) -> io::Result<()> { - const INDENT: &str = " "; - match statement { - StatementKind::Assign(place, rval) => { - write!(writer, "{INDENT}{place:?} = ")?; - pretty_rvalue(writer, rval)?; - writeln!(writer, ";") - } - // FIXME: Add rest of the statements - StatementKind::FakeRead(cause, place) => { - writeln!(writer, "{INDENT}FakeRead({cause:?}, {place:?});") - } - StatementKind::SetDiscriminant { place, variant_index } => { - writeln!(writer, "{INDENT}discriminant({place:?} = {};", variant_index.to_index()) - } - StatementKind::Deinit(place) => writeln!(writer, "Deinit({place:?};"), - StatementKind::StorageLive(local) => { - writeln!(writer, "{INDENT}StorageLive(_{local});") - } - StatementKind::StorageDead(local) => { - writeln!(writer, "{INDENT}StorageDead(_{local});") - } - StatementKind::Retag(kind, place) => writeln!(writer, "Retag({kind:?}, {place:?});"), - StatementKind::PlaceMention(place) => { - writeln!(writer, "{INDENT}PlaceMention({place:?};") - } - StatementKind::ConstEvalCounter => { - writeln!(writer, "{INDENT}ConstEvalCounter;") - } - StatementKind::Nop => writeln!(writer, "{INDENT}nop;"), - StatementKind::AscribeUserType { .. } - | StatementKind::Coverage(_) - | StatementKind::Intrinsic(_) => { - // FIX-ME: Make them pretty. - writeln!(writer, "{INDENT}{statement:?};") - } - } -} - -fn pretty_terminator(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> { - pretty_terminator_head(writer, terminator)?; - let successors = terminator.successors(); - let successor_count = successors.len(); - let labels = pretty_successor_labels(terminator); - - let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_))); - let fmt_unwind = |w: &mut W| -> io::Result<()> { - write!(w, "unwind ")?; - match terminator.unwind() { - None | Some(UnwindAction::Cleanup(_)) => unreachable!(), - Some(UnwindAction::Continue) => write!(w, "continue"), - Some(UnwindAction::Unreachable) => write!(w, "unreachable"), - Some(UnwindAction::Terminate) => write!(w, "terminate"), - } - }; - - match (successor_count, show_unwind) { - (0, false) => {} - (0, true) => { - write!(writer, " -> ")?; - fmt_unwind(writer)?; - } - (1, false) => write!(writer, " -> bb{:?}", successors[0])?, - _ => { - write!(writer, " -> [")?; - for (i, target) in successors.iter().enumerate() { - if i > 0 { - write!(writer, ", ")?; - } - write!(writer, "{}: bb{:?}", labels[i], target)?; - } - if show_unwind { - write!(writer, ", ")?; - fmt_unwind(writer)?; - } - write!(writer, "]")?; - } - }; - - writeln!(writer, ";") -} - -fn pretty_terminator_head(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> { - use self::TerminatorKind::*; - const INDENT: &str = " "; - match terminator { - Goto { .. } => write!(writer, "{INDENT}goto"), - SwitchInt { discr, .. } => { - write!(writer, "{INDENT}switchInt({})", pretty_operand(discr)) - } - Resume => write!(writer, "{INDENT}resume"), - Abort => write!(writer, "{INDENT}abort"), - Return => write!(writer, "{INDENT}return"), - Unreachable => write!(writer, "{INDENT}unreachable"), - Drop { place, .. } => write!(writer, "{INDENT}drop({place:?})"), - Call { func, args, destination, .. } => { - write!(writer, "{INDENT}{:?} = {}(", destination, pretty_operand(func))?; - let mut args_iter = args.iter(); - args_iter.next().map_or(Ok(()), |arg| write!(writer, "{}", pretty_operand(arg)))?; - args_iter.try_for_each(|arg| write!(writer, ", {}", pretty_operand(arg)))?; - write!(writer, ")") - } - Assert { cond, expected, msg, target: _, unwind: _ } => { - write!(writer, "{INDENT}assert(")?; - if !expected { - write!(writer, "!")?; - } - write!(writer, "{}, ", pretty_operand(cond))?; - pretty_assert_message(writer, msg)?; - write!(writer, ")") - } - InlineAsm { .. } => write!(writer, "{INDENT}InlineAsm"), - } -} - -fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec { - use self::TerminatorKind::*; - match terminator { - Call { target: None, unwind: UnwindAction::Cleanup(_), .. } - | InlineAsm { destination: None, .. } => vec!["unwind".into()], - Resume | Abort | Return | Unreachable | Call { target: None, unwind: _, .. } => vec![], - Goto { .. } => vec!["".to_string()], - SwitchInt { targets, .. } => targets - .branches() - .map(|(val, _target)| format!("{val}")) - .chain(iter::once("otherwise".into())) - .collect(), - Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()], - Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { - vec!["return".into(), "unwind".into()] - } - Drop { unwind: _, .. } | Call { target: Some(_), unwind: _, .. } => vec!["return".into()], - Assert { unwind: UnwindAction::Cleanup(_), .. } => { - vec!["success".into(), "unwind".into()] - } - Assert { unwind: _, .. } => vec!["success".into()], - InlineAsm { destination: Some(_), .. } => vec!["goto".into(), "unwind".into()], - } -} - -fn pretty_assert_message(writer: &mut W, msg: &AssertMessage) -> io::Result<()> { - match msg { - AssertMessage::BoundsCheck { len, index } => { - let pretty_len = pretty_operand(len); - let pretty_index = pretty_operand(index); - write!( - writer, - "\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}" - ) - } - AssertMessage::Overflow(BinOp::Add, l, r) => { - let pretty_l = pretty_operand(l); - let pretty_r = pretty_operand(r); - write!( - writer, - "\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}" - ) - } - AssertMessage::Overflow(BinOp::Sub, l, r) => { - let pretty_l = pretty_operand(l); - let pretty_r = pretty_operand(r); - write!( - writer, - "\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}" - ) - } - AssertMessage::Overflow(BinOp::Mul, l, r) => { - let pretty_l = pretty_operand(l); - let pretty_r = pretty_operand(r); - write!( - writer, - "\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}" - ) - } - AssertMessage::Overflow(BinOp::Div, l, r) => { - let pretty_l = pretty_operand(l); - let pretty_r = pretty_operand(r); - write!( - writer, - "\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}" - ) - } - AssertMessage::Overflow(BinOp::Rem, l, r) => { - let pretty_l = pretty_operand(l); - let pretty_r = pretty_operand(r); - write!( - writer, - "\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}" - ) - } - AssertMessage::Overflow(BinOp::Shr, _, r) => { - let pretty_r = pretty_operand(r); - write!(writer, "\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}") - } - AssertMessage::Overflow(BinOp::Shl, _, r) => { - let pretty_r = pretty_operand(r); - write!(writer, "\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}") - } - AssertMessage::Overflow(op, _, _) => unreachable!("`{:?}` cannot overflow", op), - AssertMessage::OverflowNeg(op) => { - let pretty_op = pretty_operand(op); - write!(writer, "\"attempt to negate `{{}}`, which would overflow\", {pretty_op}") - } - AssertMessage::DivisionByZero(op) => { - let pretty_op = pretty_operand(op); - write!(writer, "\"attempt to divide `{{}}` by zero\", {pretty_op}") - } - AssertMessage::RemainderByZero(op) => { - let pretty_op = pretty_operand(op); - write!( - writer, - "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}" - ) - } - AssertMessage::MisalignedPointerDereference { required, found } => { - let pretty_required = pretty_operand(required); - let pretty_found = pretty_operand(found); - write!( - writer, - "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}" - ) - } - AssertMessage::NullPointerDereference => { - write!(writer, "\"null pointer dereference occurred\"") - } - AssertMessage::InvalidEnumConstruction(op) => { - let pretty_op = pretty_operand(op); - write!(writer, "\"trying to construct an enum from an invalid value {{}}\",{pretty_op}") - } - AssertMessage::ResumedAfterReturn(_) - | AssertMessage::ResumedAfterPanic(_) - | AssertMessage::ResumedAfterDrop(_) => { - write!(writer, "{}", msg.description().unwrap()) - } - } -} - -fn pretty_operand(operand: &Operand) -> String { - match operand { - Operand::Copy(copy) => { - format!("{copy:?}") - } - Operand::Move(mv) => { - format!("move {mv:?}") - } - Operand::Constant(cnst) => pretty_mir_const(&cnst.const_), - } -} - -fn pretty_mir_const(literal: &MirConst) -> String { - with(|cx| cx.mir_const_pretty(literal)) -} - -fn pretty_ty_const(ct: &TyConst) -> String { - with(|cx| cx.ty_const_pretty(ct.id)) -} - -fn pretty_rvalue(writer: &mut W, rval: &Rvalue) -> io::Result<()> { - match rval { - Rvalue::AddressOf(mutability, place) => { - write!(writer, "&raw {} {:?}", pretty_raw_ptr_kind(*mutability), place) - } - Rvalue::Aggregate(aggregate_kind, operands) => { - // FIXME: Add pretty_aggregate function that returns a pretty string - pretty_aggregate(writer, aggregate_kind, operands) - } - Rvalue::BinaryOp(bin, op1, op2) => { - write!(writer, "{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2)) - } - Rvalue::Cast(_, op, ty) => { - write!(writer, "{} as {}", pretty_operand(op), ty) - } - Rvalue::CheckedBinaryOp(bin, op1, op2) => { - write!(writer, "Checked{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2)) - } - Rvalue::CopyForDeref(deref) => { - write!(writer, "CopyForDeref({deref:?})") - } - Rvalue::Discriminant(place) => { - write!(writer, "discriminant({place:?})") - } - Rvalue::Len(len) => { - write!(writer, "len({len:?})") - } - Rvalue::Ref(_, borrowkind, place) => { - let kind = match borrowkind { - BorrowKind::Shared => "&", - BorrowKind::Fake(FakeBorrowKind::Deep) => "&fake ", - BorrowKind::Fake(FakeBorrowKind::Shallow) => "&fake shallow ", - BorrowKind::Mut { .. } => "&mut ", - }; - write!(writer, "{kind}{place:?}") - } - Rvalue::Repeat(op, cnst) => { - write!(writer, "[{}; {}]", pretty_operand(op), pretty_ty_const(cnst)) - } - Rvalue::ShallowInitBox(_, _) => Ok(()), - Rvalue::ThreadLocalRef(item) => { - write!(writer, "thread_local_ref{item:?}") - } - Rvalue::NullaryOp(nul, ty) => { - write!(writer, "{nul:?}::<{ty}>() \" \"") - } - Rvalue::UnaryOp(un, op) => { - write!(writer, "{:?}({})", un, pretty_operand(op)) - } - Rvalue::Use(op) => write!(writer, "{}", pretty_operand(op)), - } -} - -fn pretty_aggregate( - writer: &mut W, - aggregate_kind: &AggregateKind, - operands: &Vec, -) -> io::Result<()> { - let suffix = match aggregate_kind { - AggregateKind::Array(_) => { - write!(writer, "[")?; - "]" - } - AggregateKind::Tuple => { - write!(writer, "(")?; - ")" - } - AggregateKind::Adt(def, var, _, _, _) => { - if def.kind() == AdtKind::Enum { - write!(writer, "{}::{}", def.name(), def.variant(*var).unwrap().name())?; - } else { - write!(writer, "{}", def.variant(*var).unwrap().name())?; - } - if operands.is_empty() { - return Ok(()); - } - // FIXME: Change this once we have CtorKind in StableMIR. - write!(writer, "(")?; - ")" - } - AggregateKind::Closure(def, _) => { - write!(writer, "{{closure@{}}}(", def.span().diagnostic())?; - ")" - } - AggregateKind::Coroutine(def, _, _) => { - write!(writer, "{{coroutine@{}}}(", def.span().diagnostic())?; - ")" - } - AggregateKind::CoroutineClosure(def, _) => { - write!(writer, "{{coroutine-closure@{}}}(", def.span().diagnostic())?; - ")" - } - AggregateKind::RawPtr(ty, mutability) => { - write!( - writer, - "*{} {ty} from (", - if *mutability == Mutability::Mut { "mut" } else { "const" } - )?; - ")" - } - }; - let mut separator = ""; - for op in operands { - write!(writer, "{}{}", separator, pretty_operand(op))?; - separator = ", "; - } - write!(writer, "{suffix}") -} - -fn pretty_mut(mutability: Mutability) -> &'static str { - match mutability { - Mutability::Not => " ", - Mutability::Mut => "mut ", - } -} - -fn pretty_raw_ptr_kind(kind: RawPtrKind) -> &'static str { - match kind { - RawPtrKind::Const => "const", - RawPtrKind::Mut => "mut", - RawPtrKind::FakeForPtrMetadata => "const (fake)", - } -} diff --git a/compiler/rustc_smir/src/stable_mir/mir/visit.rs b/compiler/rustc_smir/src/stable_mir/mir/visit.rs deleted file mode 100644 index b7dd433eb09..00000000000 --- a/compiler/rustc_smir/src/stable_mir/mir/visit.rs +++ /dev/null @@ -1,590 +0,0 @@ -//! # The Stable MIR Visitor -//! -//! ## Overview -//! -//! We currently only support an immutable visitor. -//! The structure of this visitor is similar to the ones internal to `rustc`, -//! and it follows the following conventions: -//! -//! For every mir item, the trait has a `visit_` and a `super_` method. -//! - `visit_`, by default, calls `super_` -//! - `super_`, by default, destructures the `` and calls `visit_` for -//! all sub-items that compose the original item. -//! -//! In order to implement a visitor, override the `visit_*` methods for the types you are -//! interested in analyzing, and invoke (within that method call) -//! `self.super_*` to continue to the traverse. -//! Avoid calling `super` methods in other circumstances. -//! -//! For the most part, we do not destructure things external to the -//! MIR, e.g., types, spans, etc, but simply visit them and stop. -//! This avoids duplication with other visitors like `TypeFoldable`. -//! -//! ## Updating -//! -//! The code is written in a very deliberate style intended to minimize -//! the chance of things being overlooked. -//! -//! Use pattern matching to reference fields and ensure that all -//! matches are exhaustive. -//! -//! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. -//! That means you never write `..` to skip over fields, nor do you write `_` -//! to skip over variants in a `match`. -//! -//! The only place that `_` is acceptable is to match a field (or -//! variant argument) that does not require visiting. - -use stable_mir::mir::*; -use stable_mir::ty::{GenericArgs, MirConst, Region, Ty, TyConst}; -use stable_mir::{Error, Opaque, Span}; - -use crate::stable_mir; - -macro_rules! make_mir_visitor { - ($visitor_trait_name:ident, $($mutability:ident)?) => { - pub trait $visitor_trait_name { - fn visit_body(&mut self, body: &$($mutability)? Body) { - self.super_body(body) - } - - fn visit_basic_block(&mut self, bb: &$($mutability)? BasicBlock) { - self.super_basic_block(bb) - } - - fn visit_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { - self.super_ret_decl(local, decl) - } - - fn visit_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { - self.super_arg_decl(local, decl) - } - - fn visit_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { - self.super_local_decl(local, decl) - } - - fn visit_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) { - self.super_statement(stmt, location) - } - - fn visit_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) { - self.super_terminator(term, location) - } - - fn visit_span(&mut self, span: &$($mutability)? Span) { - self.super_span(span) - } - - fn visit_place(&mut self, place: &$($mutability)? Place, ptx: PlaceContext, location: Location) { - self.super_place(place, ptx, location) - } - - visit_place_fns!($($mutability)?); - - fn visit_local(&mut self, local: &$($mutability)? Local, ptx: PlaceContext, location: Location) { - let _ = (local, ptx, location); - } - - fn visit_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) { - self.super_rvalue(rvalue, location) - } - - fn visit_operand(&mut self, operand: &$($mutability)? Operand, location: Location) { - self.super_operand(operand, location) - } - - fn visit_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) { - self.super_user_type_projection(projection) - } - - fn visit_ty(&mut self, ty: &$($mutability)? Ty, location: Location) { - let _ = location; - self.super_ty(ty) - } - - fn visit_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) { - self.super_const_operand(constant, location) - } - - fn visit_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) { - self.super_mir_const(constant, location) - } - - fn visit_ty_const(&mut self, constant: &$($mutability)? TyConst, location: Location) { - let _ = location; - self.super_ty_const(constant) - } - - fn visit_region(&mut self, region: &$($mutability)? Region, location: Location) { - let _ = location; - self.super_region(region) - } - - fn visit_args(&mut self, args: &$($mutability)? GenericArgs, location: Location) { - let _ = location; - self.super_args(args) - } - - fn visit_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) { - self.super_assert_msg(msg, location) - } - - fn visit_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) { - self.super_var_debug_info(var_debug_info); - } - - fn super_body(&mut self, body: &$($mutability)? Body) { - super_body!(self, body, $($mutability)?); - } - - fn super_basic_block(&mut self, bb: &$($mutability)? BasicBlock) { - let BasicBlock { statements, terminator } = bb; - for stmt in statements { - self.visit_statement(stmt, Location(stmt.span)); - } - self.visit_terminator(terminator, Location(terminator.span)); - } - - fn super_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { - let _ = local; - let LocalDecl { ty, span, .. } = decl; - self.visit_ty(ty, Location(*span)); - } - - fn super_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { - self.super_local_decl(local, decl) - } - - fn super_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { - self.super_local_decl(local, decl) - } - - fn super_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) { - let Statement { kind, span } = stmt; - self.visit_span(span); - match kind { - StatementKind::Assign(place, rvalue) => { - self.visit_place(place, PlaceContext::MUTATING, location); - self.visit_rvalue(rvalue, location); - } - StatementKind::FakeRead(_, place) | StatementKind::PlaceMention(place) => { - self.visit_place(place, PlaceContext::NON_MUTATING, location); - } - StatementKind::SetDiscriminant { place, .. } - | StatementKind::Deinit(place) - | StatementKind::Retag(_, place) => { - self.visit_place(place, PlaceContext::MUTATING, location); - } - StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { - self.visit_local(local, PlaceContext::NON_USE, location); - } - StatementKind::AscribeUserType { place, projections, variance: _ } => { - self.visit_place(place, PlaceContext::NON_USE, location); - self.visit_user_type_projection(projections); - } - StatementKind::Coverage(coverage) => visit_opaque(coverage), - StatementKind::Intrinsic(intrisic) => match intrisic { - NonDivergingIntrinsic::Assume(operand) => { - self.visit_operand(operand, location); - } - NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { - src, - dst, - count, - }) => { - self.visit_operand(src, location); - self.visit_operand(dst, location); - self.visit_operand(count, location); - } - }, - StatementKind::ConstEvalCounter | StatementKind::Nop => {} - } - } - - fn super_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) { - let Terminator { kind, span } = term; - self.visit_span(span); - match kind { - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Unreachable => {} - TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { - self.visit_operand(cond, location); - self.visit_assert_msg(msg, location); - } - TerminatorKind::Drop { place, target: _, unwind: _ } => { - self.visit_place(place, PlaceContext::MUTATING, location); - } - TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => { - self.visit_operand(func, location); - for arg in args { - self.visit_operand(arg, location); - } - self.visit_place(destination, PlaceContext::MUTATING, location); - } - TerminatorKind::InlineAsm { operands, .. } => { - for op in operands { - let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op; - if let Some(input) = in_value { - self.visit_operand(input, location); - } - if let Some(output) = out_place { - self.visit_place(output, PlaceContext::MUTATING, location); - } - } - } - TerminatorKind::Return => { - let $($mutability)? local = RETURN_LOCAL; - self.visit_local(&$($mutability)? local, PlaceContext::NON_MUTATING, location); - } - TerminatorKind::SwitchInt { discr, targets: _ } => { - self.visit_operand(discr, location); - } - } - } - - fn super_span(&mut self, span: &$($mutability)? Span) { - let _ = span; - } - - fn super_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) { - match rvalue { - Rvalue::AddressOf(mutability, place) => { - let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut }; - self.visit_place(place, pcx, location); - } - Rvalue::Aggregate(_, operands) => { - for op in operands { - self.visit_operand(op, location); - } - } - Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { - self.visit_operand(lhs, location); - self.visit_operand(rhs, location); - } - Rvalue::Cast(_, op, ty) => { - self.visit_operand(op, location); - self.visit_ty(ty, location); - } - Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => { - self.visit_place(place, PlaceContext::NON_MUTATING, location); - } - Rvalue::Ref(region, kind, place) => { - self.visit_region(region, location); - let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) }; - self.visit_place(place, pcx, location); - } - Rvalue::Repeat(op, constant) => { - self.visit_operand(op, location); - self.visit_ty_const(constant, location); - } - Rvalue::ShallowInitBox(op, ty) => { - self.visit_ty(ty, location); - self.visit_operand(op, location) - } - Rvalue::ThreadLocalRef(_) => {} - Rvalue::NullaryOp(_, ty) => { - self.visit_ty(ty, location); - } - Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => { - self.visit_operand(op, location); - } - } - } - - fn super_operand(&mut self, operand: &$($mutability)? Operand, location: Location) { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - self.visit_place(place, PlaceContext::NON_MUTATING, location) - } - Operand::Constant(constant) => { - self.visit_const_operand(constant, location); - } - } - } - - fn super_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) { - // This is a no-op on mir::Visitor. - let _ = projection; - } - - fn super_ty(&mut self, ty: &$($mutability)? Ty) { - let _ = ty; - } - - fn super_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) { - let ConstOperand { span, user_ty: _, const_ } = constant; - self.visit_span(span); - self.visit_mir_const(const_, location); - } - - fn super_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) { - let MirConst { kind: _, ty, id: _ } = constant; - self.visit_ty(ty, location); - } - - fn super_ty_const(&mut self, constant: &$($mutability)? TyConst) { - let _ = constant; - } - - fn super_region(&mut self, region: &$($mutability)? Region) { - let _ = region; - } - - fn super_args(&mut self, args: &$($mutability)? GenericArgs) { - let _ = args; - } - - fn super_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) { - let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } = - var_debug_info; - self.visit_span(&$($mutability)? source_info.span); - let location = Location(source_info.span); - if let Some(composite) = composite { - self.visit_ty(&$($mutability)? composite.ty, location); - } - match value { - VarDebugInfoContents::Place(place) => { - self.visit_place(place, PlaceContext::NON_USE, location); - } - VarDebugInfoContents::Const(constant) => { - self.visit_mir_const(&$($mutability)? constant.const_, location); - } - } - } - - fn super_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) { - match msg { - AssertMessage::BoundsCheck { len, index } => { - self.visit_operand(len, location); - self.visit_operand(index, location); - } - AssertMessage::Overflow(_, left, right) => { - self.visit_operand(left, location); - self.visit_operand(right, location); - } - AssertMessage::OverflowNeg(op) - | AssertMessage::DivisionByZero(op) - | AssertMessage::RemainderByZero(op) - | AssertMessage::InvalidEnumConstruction(op) => { - self.visit_operand(op, location); - } - AssertMessage::ResumedAfterReturn(_) - | AssertMessage::ResumedAfterPanic(_) - | AssertMessage::NullPointerDereference - | AssertMessage::ResumedAfterDrop(_) => { - //nothing to visit - } - AssertMessage::MisalignedPointerDereference { required, found } => { - self.visit_operand(required, location); - self.visit_operand(found, location); - } - } - } - } - }; -} - -macro_rules! super_body { - ($self:ident, $body:ident, mut) => { - for bb in $body.blocks.iter_mut() { - $self.visit_basic_block(bb); - } - - $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local_mut()); - - for (idx, arg) in $body.arg_locals_mut().iter_mut().enumerate() { - $self.visit_arg_decl(idx + 1, arg) - } - - let local_start = $body.arg_count + 1; - for (idx, arg) in $body.inner_locals_mut().iter_mut().enumerate() { - $self.visit_local_decl(idx + local_start, arg) - } - - for info in $body.var_debug_info.iter_mut() { - $self.visit_var_debug_info(info); - } - - $self.visit_span(&mut $body.span) - }; - - ($self:ident, $body:ident, ) => { - let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = $body; - - for bb in blocks { - $self.visit_basic_block(bb); - } - - $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local()); - - for (idx, arg) in $body.arg_locals().iter().enumerate() { - $self.visit_arg_decl(idx + 1, arg) - } - - let local_start = arg_count + 1; - for (idx, arg) in $body.inner_locals().iter().enumerate() { - $self.visit_local_decl(idx + local_start, arg) - } - - for info in var_debug_info.iter() { - $self.visit_var_debug_info(info); - } - - $self.visit_span(span) - }; -} - -macro_rules! visit_place_fns { - (mut) => { - fn super_place(&mut self, place: &mut Place, ptx: PlaceContext, location: Location) { - self.visit_local(&mut place.local, ptx, location); - - for elem in place.projection.iter_mut() { - self.visit_projection_elem(elem, ptx, location); - } - } - - // We don't have to replicate the `process_projection()` like we did in - // `rustc_middle::mir::visit.rs` here because the `projection` field in `Place` - // of Stable-MIR is not an immutable borrow, unlike in `Place` of MIR. - fn visit_projection_elem( - &mut self, - elem: &mut ProjectionElem, - ptx: PlaceContext, - location: Location, - ) { - self.super_projection_elem(elem, ptx, location) - } - - fn super_projection_elem( - &mut self, - elem: &mut ProjectionElem, - ptx: PlaceContext, - location: Location, - ) { - match elem { - ProjectionElem::Deref => {} - ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), - ProjectionElem::Index(local) => self.visit_local(local, ptx, location), - ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {} - ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} - ProjectionElem::Downcast(_idx) => {} - ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), - ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), - } - } - }; - - () => { - fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) { - self.visit_local(&place.local, ptx, location); - - for (idx, elem) in place.projection.iter().enumerate() { - let place_ref = - PlaceRef { local: place.local, projection: &place.projection[..idx] }; - self.visit_projection_elem(place_ref, elem, ptx, location); - } - } - - fn visit_projection_elem<'a>( - &mut self, - place_ref: PlaceRef<'a>, - elem: &ProjectionElem, - ptx: PlaceContext, - location: Location, - ) { - let _ = place_ref; - self.super_projection_elem(elem, ptx, location); - } - - fn super_projection_elem( - &mut self, - elem: &ProjectionElem, - ptx: PlaceContext, - location: Location, - ) { - match elem { - ProjectionElem::Deref => {} - ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), - ProjectionElem::Index(local) => self.visit_local(local, ptx, location), - ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {} - ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} - ProjectionElem::Downcast(_idx) => {} - ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), - ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), - } - } - }; -} - -make_mir_visitor!(MirVisitor,); -make_mir_visitor!(MutMirVisitor, mut); - -/// This function is a no-op that gets used to ensure this visitor is kept up-to-date. -/// -/// The idea is that whenever we replace an Opaque type by a real type, the compiler will fail -/// when trying to invoke `visit_opaque`. -/// -/// If you are here because your compilation is broken, replace the failing call to `visit_opaque()` -/// by a `visit_` for your construct. -fn visit_opaque(_: &Opaque) {} - -/// The location of a statement / terminator in the code and the CFG. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct Location(Span); - -impl Location { - pub fn span(&self) -> Span { - self.0 - } -} - -/// Location of the statement at the given index for a given basic block. Assumes that `stmt_idx` -/// and `bb_idx` are valid for a given body. -pub fn statement_location(body: &Body, bb_idx: &BasicBlockIdx, stmt_idx: usize) -> Location { - let bb = &body.blocks[*bb_idx]; - let stmt = &bb.statements[stmt_idx]; - Location(stmt.span) -} - -/// Location of the terminator for a given basic block. Assumes that `bb_idx` is valid for a given -/// body. -pub fn terminator_location(body: &Body, bb_idx: &BasicBlockIdx) -> Location { - let bb = &body.blocks[*bb_idx]; - let terminator = &bb.terminator; - Location(terminator.span) -} - -/// Reference to a place used to represent a partial projection. -pub struct PlaceRef<'a> { - pub local: Local, - pub projection: &'a [ProjectionElem], -} - -impl PlaceRef<'_> { - /// Get the type of this place. - pub fn ty(&self, locals: &[LocalDecl]) -> Result { - self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty)) - } -} - -/// Information about a place's usage. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct PlaceContext { - /// Whether the access is mutable or not. Keep this private so we can increment the type in a - /// backward compatible manner. - is_mut: bool, -} - -impl PlaceContext { - const MUTATING: Self = PlaceContext { is_mut: true }; - const NON_MUTATING: Self = PlaceContext { is_mut: false }; - const NON_USE: Self = PlaceContext { is_mut: false }; - - pub fn is_mutating(&self) -> bool { - self.is_mut - } -} diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs deleted file mode 100644 index 70c09c12854..00000000000 --- a/compiler/rustc_smir/src/stable_mir/mod.rs +++ /dev/null @@ -1,304 +0,0 @@ -//! Module that is temporarily parasitic on the `rustc_smir` crate, -//! -//! This module is designed to resolve circular dependency that would happen -//! if we gradually invert the dependency order between `rustc_smir` and `stable_mir`. -//! -//! Once refactoring is complete, we will migrate it back to the `stable_mir` crate. - -//! The WIP stable interface to rustc internals. -//! -//! For more information see -//! -//! # Note -//! -//! This API is still completely unstable and subject to change. - -// #![doc( -// html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", -// test(attr(allow(unused_variables), deny(warnings))) -// )] -//! -//! This crate shall contain all type definitions and APIs that we expect third-party tools to invoke to -//! interact with the compiler. -//! -//! The goal is to eventually be published on -//! [crates.io](https://crates.io). - -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, ProvenanceMap, Span, TraitDef, Ty, -}; -use stable_mir::unstable::Stable; - -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; -#[macro_use] -pub mod error; -pub mod mir; -pub mod target; -pub mod ty; -pub mod visitor; - -/// Use String for now but we should replace it. -pub type Symbol = String; - -/// The number that identifies a crate. -pub type CrateNum = usize; - -impl Debug for DefId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DefId").field("id", &self.0).field("name", &self.name()).finish() - } -} - -impl IndexedVal for DefId { - fn to_val(index: usize) -> Self { - DefId(index) - } - - fn to_index(&self) -> usize { - self.0 - } -} - -/// A list of crate items. -pub type CrateItems = Vec; - -/// A list of trait decls. -pub type TraitDecls = Vec; - -/// A list of impl trait decls. -pub type ImplTraitDecls = Vec; - -/// A list of associated items. -pub type AssocItems = Vec; - -/// Holds information about a crate. -#[derive(Clone, PartialEq, Eq, Debug, Serialize)] -pub struct Crate { - pub id: CrateNum, - pub name: Symbol, - pub is_local: bool, -} - -impl Crate { - /// The list of foreign modules in this crate. - pub fn foreign_modules(&self) -> Vec { - with(|cx| cx.foreign_modules(self.id)) - } - - /// The list of traits declared in this crate. - pub fn trait_decls(&self) -> TraitDecls { - with(|cx| cx.trait_decls(self.id)) - } - - /// The list of trait implementations in this crate. - pub fn trait_impls(&self) -> ImplTraitDecls { - with(|cx| cx.trait_impls(self.id)) - } - - /// Return a list of function definitions from this crate independent on their visibility. - pub fn fn_defs(&self) -> Vec { - with(|cx| cx.crate_functions(self.id)) - } - - /// Return a list of static items defined in this crate independent on their visibility. - pub fn statics(&self) -> Vec { - with(|cx| cx.crate_statics(self.id)) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] -pub enum ItemKind { - Fn, - Static, - Const, - Ctor(CtorKind), -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] -pub enum CtorKind { - Const, - Fn, -} - -pub type Filename = String; - -crate_def_with_ty! { - /// Holds information about an item in a crate. - #[derive(Serialize)] - pub CrateItem; -} - -impl CrateItem { - /// This will return the body of an item or panic if it's not available. - pub fn expect_body(&self) -> mir::Body { - with(|cx| cx.mir_body(self.0)) - } - - /// Return the body of an item if available. - pub fn body(&self) -> Option { - with(|cx| cx.has_body(self.0).then(|| cx.mir_body(self.0))) - } - - /// Check if a body is available for this item. - pub fn has_body(&self) -> bool { - with(|cx| cx.has_body(self.0)) - } - - pub fn span(&self) -> Span { - with(|cx| cx.span_of_an_item(self.0)) - } - - pub fn kind(&self) -> ItemKind { - with(|cx| cx.item_kind(*self)) - } - - pub fn requires_monomorphization(&self) -> bool { - with(|cx| cx.requires_monomorphization(self.0)) - } - - pub fn ty(&self) -> Ty { - with(|cx| cx.def_ty(self.0)) - } - - pub fn is_foreign_item(&self) -> bool { - with(|cx| cx.is_foreign_item(self.0)) - } - - /// Emit MIR for this item body. - pub fn emit_mir(&self, w: &mut W) -> io::Result<()> { - self.body() - .ok_or_else(|| io::Error::other(format!("No body found for `{}`", self.name())))? - .dump(w, &self.name()) - } -} - -/// Return the function where execution starts if the current -/// crate defines that. This is usually `main`, but could be -/// `start` if the crate is a no-std crate. -pub fn entry_fn() -> Option { - with(|cx| cx.entry_fn()) -} - -/// Access to the local crate. -pub fn local_crate() -> Crate { - with(|cx| cx.local_crate()) -} - -/// Try to find a crate or crates if multiple crates exist from given name. -pub fn find_crates(name: &str) -> Vec { - with(|cx| cx.find_crates(name)) -} - -/// Try to find a crate with the given name. -pub fn external_crates() -> Vec { - with(|cx| cx.external_crates()) -} - -/// Retrieve all items in the local crate that have a MIR associated with them. -pub fn all_local_items() -> CrateItems { - with(|cx| cx.all_local_items()) -} - -pub fn all_trait_decls() -> TraitDecls { - with(|cx| cx.all_trait_decls()) -} - -pub fn all_trait_impls() -> ImplTraitDecls { - with(|cx| cx.all_trait_impls()) -} - -/// A type that provides internal information but that can still be used for debug purpose. -#[derive(Clone, PartialEq, Eq, Hash, Serialize)] -pub struct Opaque(String); - -impl std::fmt::Display for Opaque { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl std::fmt::Debug for Opaque { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -pub fn opaque(value: &T) -> Opaque { - Opaque(format!("{value:?}")) -} - -macro_rules! bridge_impl { - ($name: ident, $ty: ty) => { - impl rustc_smir::bridge::$name 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 for stable_mir::ty::Prov { - fn new(aid: stable_mir::mir::alloc::AllocId) -> Self { - Self(aid) - } -} - -impl rustc_smir::bridge::Allocation for stable_mir::ty::Allocation { - fn new<'tcx>( - bytes: Vec>, - 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/target.rs b/compiler/rustc_smir/src/stable_mir/target.rs deleted file mode 100644 index 6cf1e9feb01..00000000000 --- a/compiler/rustc_smir/src/stable_mir/target.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Provide information about the machine that this is being compiled into. - -use serde::Serialize; -use stable_mir::compiler_interface::with; - -use crate::stable_mir; - -/// The properties of the target machine being compiled into. -#[derive(Clone, PartialEq, Eq, Serialize)] -pub struct MachineInfo { - pub endian: Endian, - pub pointer_width: MachineSize, -} - -impl MachineInfo { - pub fn target() -> MachineInfo { - with(|cx| cx.target_info()) - } - - pub fn target_endianness() -> Endian { - with(|cx| cx.target_info().endian) - } - - pub fn target_pointer_width() -> MachineSize { - with(|cx| cx.target_info().pointer_width) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Serialize)] -pub enum Endian { - Little, - Big, -} - -/// Represent the size of a component. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] -pub struct MachineSize { - num_bits: usize, -} - -impl MachineSize { - #[inline(always)] - pub fn bytes(self) -> usize { - self.num_bits / 8 - } - - #[inline(always)] - pub fn bits(self) -> usize { - self.num_bits - } - - #[inline(always)] - pub fn from_bits(num_bits: usize) -> MachineSize { - MachineSize { num_bits } - } - - #[inline] - pub fn unsigned_int_max(self) -> Option { - (self.num_bits <= 128).then(|| u128::MAX >> (128 - self.bits())) - } -} diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs deleted file mode 100644 index 004a7c02234..00000000000 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ /dev/null @@ -1,1656 +0,0 @@ -use std::fmt::{self, Debug, Display, Formatter}; -use std::ops::Range; - -use serde::Serialize; -use stable_mir::abi::{FnAbi, Layout}; -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, IndexedVal, Opaque}; - -use super::abi::ReprOptions; -use super::mir::{Body, Mutability, Safety}; -use super::{DefId, Error, Symbol, with}; -use crate::stable_mir; - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)] -pub struct Ty(usize); - -impl Debug for Ty { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Ty").field("id", &self.0).field("kind", &self.kind()).finish() - } -} - -/// Constructors for `Ty`. -impl Ty { - /// Create a new type from a given kind. - pub fn from_rigid_kind(kind: RigidTy) -> Ty { - with(|cx| cx.new_rigid_ty(kind)) - } - - /// Create a new array type. - pub fn try_new_array(elem_ty: Ty, size: u64) -> Result { - Ok(Ty::from_rigid_kind(RigidTy::Array(elem_ty, TyConst::try_from_target_usize(size)?))) - } - - /// Create a new array type from Const length. - pub fn new_array_with_const_len(elem_ty: Ty, len: TyConst) -> Ty { - Ty::from_rigid_kind(RigidTy::Array(elem_ty, len)) - } - - /// Create a new pointer type. - pub fn new_ptr(pointee_ty: Ty, mutability: Mutability) -> Ty { - Ty::from_rigid_kind(RigidTy::RawPtr(pointee_ty, mutability)) - } - - /// Create a new reference type. - pub fn new_ref(reg: Region, pointee_ty: Ty, mutability: Mutability) -> Ty { - Ty::from_rigid_kind(RigidTy::Ref(reg, pointee_ty, mutability)) - } - - /// Create a new pointer type. - pub fn new_tuple(tys: &[Ty]) -> Ty { - Ty::from_rigid_kind(RigidTy::Tuple(Vec::from(tys))) - } - - /// Create a new closure type. - pub fn new_closure(def: ClosureDef, args: GenericArgs) -> Ty { - Ty::from_rigid_kind(RigidTy::Closure(def, args)) - } - - /// Create a new coroutine type. - pub fn new_coroutine(def: CoroutineDef, args: GenericArgs, mov: Movability) -> Ty { - Ty::from_rigid_kind(RigidTy::Coroutine(def, args, mov)) - } - - /// Create a new closure type. - pub fn new_coroutine_closure(def: CoroutineClosureDef, args: GenericArgs) -> Ty { - Ty::from_rigid_kind(RigidTy::CoroutineClosure(def, args)) - } - - /// Create a new box type that represents `Box`, for the given inner type `T`. - pub fn new_box(inner_ty: Ty) -> Ty { - with(|cx| cx.new_box_ty(inner_ty)) - } - - /// Create a type representing `usize`. - pub fn usize_ty() -> Ty { - Ty::from_rigid_kind(RigidTy::Uint(UintTy::Usize)) - } - - /// Create a type representing `bool`. - pub fn bool_ty() -> Ty { - Ty::from_rigid_kind(RigidTy::Bool) - } - - /// Create a type representing a signed integer. - pub fn signed_ty(inner: IntTy) -> Ty { - Ty::from_rigid_kind(RigidTy::Int(inner)) - } - - /// Create a type representing an unsigned integer. - pub fn unsigned_ty(inner: UintTy) -> Ty { - Ty::from_rigid_kind(RigidTy::Uint(inner)) - } - - /// Get a type layout. - pub fn layout(self) -> Result { - with(|cx| cx.ty_layout(self)) - } -} - -impl Ty { - pub fn kind(&self) -> TyKind { - with(|context| context.ty_kind(*self)) - } -} - -/// Represents a pattern in the type system -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum Pattern { - Range { start: Option, end: Option, include_end: bool }, -} - -/// Represents a constant in the type system -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct TyConst { - pub(crate) kind: TyConstKind, - pub id: TyConstId, -} - -impl TyConst { - pub fn new(kind: TyConstKind, id: TyConstId) -> TyConst { - Self { kind, id } - } - - /// Retrieve the constant kind. - pub fn kind(&self) -> &TyConstKind { - &self.kind - } - - /// Creates an interned usize constant. - pub fn try_from_target_usize(val: u64) -> Result { - with(|cx| cx.try_new_ty_const_uint(val.into(), UintTy::Usize)) - } - - /// Try to evaluate to a target `usize`. - pub fn eval_target_usize(&self) -> Result { - with(|cx| cx.eval_target_usize_ty(self)) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum TyConstKind { - Param(ParamConst), - Bound(DebruijnIndex, BoundVar), - Unevaluated(ConstDef, GenericArgs), - - // FIXME: These should be a valtree - Value(Ty, Allocation), - ZSTValue(Ty), -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] -pub struct TyConstId(usize); - -/// Represents a constant in MIR -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct MirConst { - /// The constant kind. - pub(crate) kind: ConstantKind, - /// The constant type. - pub(crate) ty: Ty, - /// Used for internal tracking of the internal constant. - pub id: MirConstId, -} - -impl MirConst { - /// Build a constant. Note that this should only be used by the compiler. - pub fn new(kind: ConstantKind, ty: Ty, id: MirConstId) -> MirConst { - MirConst { kind, ty, id } - } - - /// Retrieve the constant kind. - pub fn kind(&self) -> &ConstantKind { - &self.kind - } - - /// Get the constant type. - pub fn ty(&self) -> Ty { - self.ty - } - - /// Try to evaluate to a target `usize`. - pub fn eval_target_usize(&self) -> Result { - with(|cx| cx.eval_target_usize(self)) - } - - /// Create a constant that represents a new zero-sized constant of type T. - /// Fails if the type is not a ZST or if it doesn't have a known size. - pub fn try_new_zero_sized(ty: Ty) -> Result { - with(|cx| cx.try_new_const_zst(ty)) - } - - /// Build a new constant that represents the given string. - /// - /// Note that there is no guarantee today about duplication of the same constant. - /// I.e.: Calling this function multiple times with the same argument may or may not return - /// the same allocation. - pub fn from_str(value: &str) -> MirConst { - with(|cx| cx.new_const_str(value)) - } - - /// Build a new constant that represents the given boolean value. - pub fn from_bool(value: bool) -> MirConst { - with(|cx| cx.new_const_bool(value)) - } - - /// Build a new constant that represents the given unsigned integer. - pub fn try_from_uint(value: u128, uint_ty: UintTy) -> Result { - with(|cx| cx.try_new_const_uint(value, uint_ty)) - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] -pub struct MirConstId(usize); - -type Ident = Opaque; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct Region { - pub kind: RegionKind, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum RegionKind { - ReEarlyParam(EarlyParamRegion), - ReBound(DebruijnIndex, BoundRegion), - ReStatic, - RePlaceholder(Placeholder), - ReErased, -} - -pub(crate) type DebruijnIndex = u32; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct EarlyParamRegion { - pub index: u32, - pub name: Symbol, -} - -pub(crate) type BoundVar = u32; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct BoundRegion { - pub var: BoundVar, - pub kind: BoundRegionKind, -} - -pub(crate) type UniverseIndex = u32; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct Placeholder { - pub universe: UniverseIndex, - pub bound: T, -} - -#[derive(Clone, Copy, PartialEq, Eq, Serialize)] -pub struct Span(usize); - -impl Debug for Span { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Span") - .field("id", &self.0) - .field("repr", &with(|cx| cx.span_to_string(*self))) - .finish() - } -} - -impl Span { - /// Return filename for diagnostic purposes - pub fn get_filename(&self) -> Filename { - with(|c| c.get_filename(self)) - } - - /// Return lines that correspond to this `Span` - pub fn get_lines(&self) -> LineInfo { - with(|c| c.get_lines(self)) - } - - /// Return the span location to be printed in diagnostic messages. - /// - /// This may leak local file paths and should not be used to build artifacts that may be - /// distributed. - pub fn diagnostic(&self) -> String { - with(|c| c.span_to_string(*self)) - } -} - -#[derive(Clone, Copy, Debug, Serialize)] -/// Information you get from `Span` in a struct form. -/// Line and col start from 1. -pub struct LineInfo { - pub start_line: usize, - pub start_col: usize, - pub end_line: usize, - 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), - Alias(AliasKind, AliasTy), - Param(ParamTy), - Bound(usize, BoundTy), -} - -impl TyKind { - pub fn rigid(&self) -> Option<&RigidTy> { - if let TyKind::RigidTy(inner) = self { Some(inner) } else { None } - } - - #[inline] - pub fn is_unit(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Tuple(data)) if data.is_empty()) - } - - #[inline] - pub fn is_bool(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Bool)) - } - - #[inline] - pub fn is_char(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Char)) - } - - #[inline] - pub fn is_trait(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Dynamic(_, _, DynKind::Dyn))) - } - - #[inline] - pub fn is_enum(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Enum) - } - - #[inline] - pub fn is_struct(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Struct) - } - - #[inline] - pub fn is_union(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Union) - } - - #[inline] - pub fn is_adt(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Adt(..))) - } - - #[inline] - pub fn is_ref(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Ref(..))) - } - - #[inline] - pub fn is_fn(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::FnDef(..))) - } - - #[inline] - pub fn is_fn_ptr(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::FnPtr(..))) - } - - #[inline] - pub fn is_primitive(&self) -> bool { - matches!( - self, - TyKind::RigidTy( - RigidTy::Bool - | RigidTy::Char - | RigidTy::Int(_) - | RigidTy::Uint(_) - | RigidTy::Float(_) - ) - ) - } - - #[inline] - pub fn is_float(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Float(_))) - } - - #[inline] - pub fn is_integral(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Int(_) | RigidTy::Uint(_))) - } - - #[inline] - pub fn is_numeric(&self) -> bool { - self.is_integral() || self.is_float() - } - - #[inline] - pub fn is_signed(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Int(_))) - } - - #[inline] - pub fn is_str(&self) -> bool { - *self == TyKind::RigidTy(RigidTy::Str) - } - - #[inline] - pub fn is_cstr(&self) -> bool { - let TyKind::RigidTy(RigidTy::Adt(def, _)) = self else { - return false; - }; - with(|cx| cx.adt_is_cstr(*def)) - } - - #[inline] - pub fn is_slice(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Slice(_))) - } - - #[inline] - pub fn is_array(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Array(..))) - } - - #[inline] - pub fn is_mutable_ptr(&self) -> bool { - matches!( - self, - TyKind::RigidTy(RigidTy::RawPtr(_, Mutability::Mut)) - | TyKind::RigidTy(RigidTy::Ref(_, _, Mutability::Mut)) - ) - } - - #[inline] - pub fn is_raw_ptr(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::RawPtr(..))) - } - - /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer). - #[inline] - pub fn is_any_ptr(&self) -> bool { - self.is_ref() || self.is_raw_ptr() || self.is_fn_ptr() - } - - #[inline] - pub fn is_coroutine(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Coroutine(..))) - } - - #[inline] - pub fn is_closure(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Closure(..))) - } - - #[inline] - pub fn is_box(&self) -> bool { - match self { - TyKind::RigidTy(RigidTy::Adt(def, _)) => def.is_box(), - _ => false, - } - } - - #[inline] - pub fn is_simd(&self) -> bool { - matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.is_simd()) - } - - pub fn trait_principal(&self) -> Option> { - if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _, _)) = self { - if let Some(Binder { value: ExistentialPredicate::Trait(trait_ref), bound_vars }) = - predicates.first() - { - Some(Binder { value: trait_ref.clone(), bound_vars: bound_vars.clone() }) - } else { - None - } - } else { - None - } - } - - /// Returns the type of `ty[i]` for builtin types. - pub fn builtin_index(&self) -> Option { - match self.rigid()? { - RigidTy::Array(ty, _) | RigidTy::Slice(ty) => Some(*ty), - _ => None, - } - } - - /// Returns the type and mutability of `*ty` for builtin types. - /// - /// The parameter `explicit` indicates if this is an *explicit* dereference. - /// Some types -- notably raw ptrs -- can only be dereferenced explicitly. - pub fn builtin_deref(&self, explicit: bool) -> Option { - match self.rigid()? { - RigidTy::Adt(def, args) if def.is_box() => { - Some(TypeAndMut { ty: *args.0.first()?.ty()?, mutability: Mutability::Not }) - } - RigidTy::Ref(_, ty, mutability) => { - Some(TypeAndMut { ty: *ty, mutability: *mutability }) - } - RigidTy::RawPtr(ty, mutability) if explicit => { - Some(TypeAndMut { ty: *ty, mutability: *mutability }) - } - _ => None, - } - } - - /// Get the function signature for function like types (Fn, FnPtr, and Closure) - pub fn fn_sig(&self) -> Option { - match self { - TyKind::RigidTy(RigidTy::FnDef(def, args)) => Some(with(|cx| cx.fn_sig(*def, args))), - TyKind::RigidTy(RigidTy::FnPtr(sig)) => Some(sig.clone()), - TyKind::RigidTy(RigidTy::Closure(_def, args)) => Some(with(|cx| cx.closure_sig(args))), - _ => None, - } - } - - /// Get the discriminant type for this type. - pub fn discriminant_ty(&self) -> Option { - self.rigid().map(|ty| with(|cx| cx.rigid_ty_discriminant_ty(ty))) - } - - /// Deconstruct a function type if this is one. - pub fn fn_def(&self) -> Option<(FnDef, &GenericArgs)> { - if let TyKind::RigidTy(RigidTy::FnDef(def, args)) = self { - Some((*def, args)) - } else { - None - } - } -} - -pub struct TypeAndMut { - pub ty: Ty, - pub mutability: Mutability, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum RigidTy { - Bool, - Char, - Int(IntTy), - Uint(UintTy), - Float(FloatTy), - Adt(AdtDef, GenericArgs), - Foreign(ForeignDef), - Str, - Array(Ty, TyConst), - Pat(Ty, Pattern), - Slice(Ty), - RawPtr(Ty, Mutability), - Ref(Region, Ty, Mutability), - FnDef(FnDef, GenericArgs), - FnPtr(PolyFnSig), - Closure(ClosureDef, GenericArgs), - // FIXME(stable_mir): Movability here is redundant - Coroutine(CoroutineDef, GenericArgs, Movability), - CoroutineClosure(CoroutineClosureDef, GenericArgs), - Dynamic(Vec>, Region, DynKind), - Never, - Tuple(Vec), - CoroutineWitness(CoroutineWitnessDef, GenericArgs), -} - -impl RigidTy { - /// Get the discriminant type for this type. - pub fn discriminant_ty(&self) -> Ty { - with(|cx| cx.rigid_ty_discriminant_ty(self)) - } -} - -impl From for TyKind { - fn from(value: RigidTy) -> Self { - TyKind::RigidTy(value) - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] -pub enum IntTy { - Isize, - I8, - I16, - I32, - I64, - I128, -} - -impl IntTy { - pub fn num_bytes(self) -> usize { - match self { - IntTy::Isize => MachineInfo::target_pointer_width().bytes(), - IntTy::I8 => 1, - IntTy::I16 => 2, - IntTy::I32 => 4, - IntTy::I64 => 8, - IntTy::I128 => 16, - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] -pub enum UintTy { - Usize, - U8, - U16, - U32, - U64, - U128, -} - -impl UintTy { - pub fn num_bytes(self) -> usize { - match self { - UintTy::Usize => MachineInfo::target_pointer_width().bytes(), - UintTy::U8 => 1, - UintTy::U16 => 2, - UintTy::U32 => 4, - UintTy::U64 => 8, - UintTy::U128 => 16, - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] -pub enum FloatTy { - F16, - F32, - F64, - F128, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] -pub enum Movability { - Static, - Movable, -} - -crate_def! { - #[derive(Serialize)] - pub ForeignModuleDef; -} - -impl ForeignModuleDef { - pub fn module(&self) -> ForeignModule { - with(|cx| cx.foreign_module(*self)) - } -} - -pub struct ForeignModule { - pub def_id: ForeignModuleDef, - pub abi: Abi, -} - -impl ForeignModule { - pub fn items(&self) -> Vec { - with(|cx| cx.foreign_items(self.def_id)) - } -} - -crate_def_with_ty! { - /// Hold information about a ForeignItem in a crate. - #[derive(Serialize)] - pub ForeignDef; -} - -impl ForeignDef { - pub fn kind(&self) -> ForeignItemKind { - with(|cx| cx.foreign_item_kind(*self)) - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] -pub enum ForeignItemKind { - Fn(FnDef), - Static(StaticDef), - Type(Ty), -} - -crate_def_with_ty! { - /// Hold information about a function definition in a crate. - #[derive(Serialize)] - pub FnDef; -} - -impl FnDef { - // Get the function body if available. - pub fn body(&self) -> Option { - with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0))) - } - - // Check if the function body is available. - pub fn has_body(&self) -> bool { - with(|ctx| ctx.has_body(self.0)) - } - - /// Get the information of the intrinsic if this function is a definition of one. - pub fn as_intrinsic(&self) -> Option { - with(|cx| cx.intrinsic(self.def_id())) - } - - /// Check if the function is an intrinsic. - #[inline] - pub fn is_intrinsic(&self) -> bool { - self.as_intrinsic().is_some() - } - - /// Get the function signature for this function definition. - pub fn fn_sig(&self) -> PolyFnSig { - let kind = self.ty().kind(); - kind.fn_sig().unwrap() - } -} - -crate_def_with_ty! { - #[derive(Serialize)] - pub IntrinsicDef; -} - -impl IntrinsicDef { - /// Returns the plain name of the intrinsic. - /// e.g., `transmute` for `core::intrinsics::transmute`. - pub fn fn_name(&self) -> Symbol { - with(|cx| cx.intrinsic_name(*self)) - } - - /// Returns whether the intrinsic has no meaningful body and all backends - /// need to shim all calls to it. - pub fn must_be_overridden(&self) -> bool { - with(|cx| !cx.has_body(self.0)) - } -} - -impl From for FnDef { - fn from(def: IntrinsicDef) -> Self { - FnDef(def.0) - } -} - -crate_def! { - #[derive(Serialize)] - pub ClosureDef; -} - -impl ClosureDef { - /// Retrieves the body of the closure definition. Returns None if the body - /// isn't available. - pub fn body(&self) -> Option { - with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0))) - } -} - -crate_def! { - #[derive(Serialize)] - pub CoroutineDef; -} - -impl CoroutineDef { - /// Retrieves the body of the coroutine definition. Returns None if the body - /// isn't available. - pub fn body(&self) -> Option { - with(|cx| cx.has_body(self.0).then(|| cx.mir_body(self.0))) - } - - pub fn discriminant_for_variant(&self, args: &GenericArgs, idx: VariantIdx) -> Discr { - with(|cx| cx.coroutine_discr_for_variant(*self, args, idx)) - } -} - -crate_def! { - #[derive(Serialize)] - pub CoroutineClosureDef; -} - -crate_def! { - #[derive(Serialize)] - pub ParamDef; -} - -crate_def! { - #[derive(Serialize)] - pub BrNamedDef; -} - -crate_def! { - #[derive(Serialize)] - pub AdtDef; -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] -pub enum AdtKind { - Enum, - Union, - Struct, -} - -impl AdtDef { - pub fn kind(&self) -> AdtKind { - with(|cx| cx.adt_kind(*self)) - } - - /// Retrieve the type of this Adt. - pub fn ty(&self) -> Ty { - with(|cx| cx.def_ty(self.0)) - } - - /// Retrieve the type of this Adt by instantiating and normalizing it with the given arguments. - /// - /// This will assume the type can be instantiated with these arguments. - pub fn ty_with_args(&self, args: &GenericArgs) -> Ty { - with(|cx| cx.def_ty_with_args(self.0, args)) - } - - pub fn is_box(&self) -> bool { - with(|cx| cx.adt_is_box(*self)) - } - - pub fn is_simd(&self) -> bool { - with(|cx| cx.adt_is_simd(*self)) - } - - /// The number of variants in this ADT. - pub fn num_variants(&self) -> usize { - with(|cx| cx.adt_variants_len(*self)) - } - - /// Retrieve the variants in this ADT. - pub fn variants(&self) -> Vec { - self.variants_iter().collect() - } - - /// Iterate over the variants in this ADT. - pub fn variants_iter(&self) -> impl Iterator { - (0..self.num_variants()) - .map(|idx| VariantDef { idx: VariantIdx::to_val(idx), adt_def: *self }) - } - - pub fn variant(&self, idx: VariantIdx) -> Option { - (idx.to_index() < self.num_variants()).then_some(VariantDef { idx, adt_def: *self }) - } - - pub fn repr(&self) -> ReprOptions { - with(|cx| cx.adt_repr(*self)) - } - - pub fn discriminant_for_variant(&self, idx: VariantIdx) -> Discr { - with(|cx| cx.adt_discr_for_variant(*self, idx)) - } -} - -pub struct Discr { - pub val: u128, - pub ty: Ty, -} - -/// Definition of a variant, which can be either a struct / union field or an enum variant. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] -pub struct VariantDef { - /// The variant index. - /// - /// ## Warning - /// Do not access this field directly! - pub idx: VariantIdx, - /// The data type where this variant comes from. - /// For now, we use this to retrieve information about the variant itself so we don't need to - /// cache more information. - /// - /// ## Warning - /// Do not access this field directly! - pub adt_def: AdtDef, -} - -impl VariantDef { - pub fn name(&self) -> Symbol { - with(|cx| cx.variant_name(*self)) - } - - /// Retrieve all the fields in this variant. - // We expect user to cache this and use it directly since today it is expensive to generate all - // fields name. - pub fn fields(&self) -> Vec { - with(|cx| cx.variant_fields(*self)) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct FieldDef { - /// The field definition. - /// - /// ## Warning - /// Do not access this field directly! This is public for the compiler to have access to it. - pub def: DefId, - - /// The field name. - pub name: Symbol, -} - -impl FieldDef { - /// Retrieve the type of this field instantiating and normalizing it with the given arguments. - /// - /// This will assume the type can be instantiated with these arguments. - pub fn ty_with_args(&self, args: &GenericArgs) -> Ty { - with(|cx| cx.def_ty_with_args(self.def, args)) - } - - /// Retrieve the type of this field. - pub fn ty(&self) -> Ty { - with(|cx| cx.def_ty(self.def)) - } -} - -impl Display for AdtKind { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str(match self { - AdtKind::Enum => "enum", - AdtKind::Union => "union", - AdtKind::Struct => "struct", - }) - } -} - -impl AdtKind { - pub fn is_enum(&self) -> bool { - matches!(self, AdtKind::Enum) - } - - pub fn is_struct(&self) -> bool { - matches!(self, AdtKind::Struct) - } - - pub fn is_union(&self) -> bool { - matches!(self, AdtKind::Union) - } -} - -crate_def! { - #[derive(Serialize)] - pub AliasDef; -} - -crate_def! { - /// A trait's definition. - #[derive(Serialize)] - pub TraitDef; -} - -impl_crate_def_items! { - TraitDef; -} - -impl TraitDef { - pub fn declaration(trait_def: &TraitDef) -> TraitDecl { - with(|cx| cx.trait_decl(trait_def)) - } -} - -crate_def! { - #[derive(Serialize)] - pub GenericDef; -} - -crate_def_with_ty! { - #[derive(Serialize)] - pub ConstDef; -} - -crate_def! { - /// A trait impl definition. - #[derive(Serialize)] - pub ImplDef; -} - -impl_crate_def_items! { - ImplDef; -} - -impl ImplDef { - /// Retrieve information about this implementation. - pub fn trait_impl(&self) -> ImplTrait { - with(|cx| cx.trait_impl(self)) - } -} - -crate_def! { - #[derive(Serialize)] - pub RegionDef; -} - -crate_def! { - #[derive(Serialize)] - pub CoroutineWitnessDef; -} - -/// A list of generic arguments. -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct GenericArgs(pub Vec); - -impl std::ops::Index for GenericArgs { - type Output = Ty; - - fn index(&self, index: ParamTy) -> &Self::Output { - self.0[index.index as usize].expect_ty() - } -} - -impl std::ops::Index for GenericArgs { - type Output = TyConst; - - fn index(&self, index: ParamConst) -> &Self::Output { - self.0[index.index as usize].expect_const() - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum GenericArgKind { - Lifetime(Region), - Type(Ty), - Const(TyConst), -} - -impl GenericArgKind { - /// Panic if this generic argument is not a type, otherwise - /// return the type. - #[track_caller] - pub fn expect_ty(&self) -> &Ty { - match self { - GenericArgKind::Type(ty) => ty, - _ => panic!("{self:?}"), - } - } - - /// Panic if this generic argument is not a const, otherwise - /// return the const. - #[track_caller] - pub fn expect_const(&self) -> &TyConst { - match self { - GenericArgKind::Const(c) => c, - _ => panic!("{self:?}"), - } - } - - /// Return the generic argument type if applicable, otherwise return `None`. - pub fn ty(&self) -> Option<&Ty> { - match self { - GenericArgKind::Type(ty) => Some(ty), - _ => None, - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum TermKind { - Type(Ty), - Const(TyConst), -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum AliasKind { - Projection, - Inherent, - Opaque, - Free, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct AliasTy { - pub def_id: AliasDef, - pub args: GenericArgs, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct AliasTerm { - pub def_id: AliasDef, - pub args: GenericArgs, -} - -pub type PolyFnSig = Binder; - -impl PolyFnSig { - /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. - /// - /// NB: this doesn't handle virtual calls - those should use `Instance::fn_abi` - /// instead, where the instance is an `InstanceKind::Virtual`. - pub fn fn_ptr_abi(self) -> Result { - with(|cx| cx.fn_ptr_abi(self)) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct FnSig { - pub inputs_and_output: Vec, - pub c_variadic: bool, - pub safety: Safety, - pub abi: Abi, -} - -impl FnSig { - pub fn output(&self) -> Ty { - self.inputs_and_output[self.inputs_and_output.len() - 1] - } - - pub fn inputs(&self) -> &[Ty] { - &self.inputs_and_output[..self.inputs_and_output.len() - 1] - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Serialize)] -pub enum Abi { - Rust, - C { unwind: bool }, - Cdecl { unwind: bool }, - Stdcall { unwind: bool }, - Fastcall { unwind: bool }, - Vectorcall { unwind: bool }, - Thiscall { unwind: bool }, - Aapcs { unwind: bool }, - Win64 { unwind: bool }, - SysV64 { unwind: bool }, - PtxKernel, - Msp430Interrupt, - X86Interrupt, - GpuKernel, - EfiApi, - AvrInterrupt, - AvrNonBlockingInterrupt, - CCmseNonSecureCall, - CCmseNonSecureEntry, - System { unwind: bool }, - RustCall, - Unadjusted, - RustCold, - RiscvInterruptM, - RiscvInterruptS, - RustInvalid, - Custom, -} - -/// A binder represents a possibly generic type and its bound vars. -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct Binder { - pub value: T, - pub bound_vars: Vec, -} - -impl Binder { - /// Create a new binder with the given bound vars. - pub fn bind_with_vars(value: T, bound_vars: Vec) -> Self { - Binder { value, bound_vars } - } - - /// Create a new binder with no bounded variable. - pub fn dummy(value: T) -> Self { - Binder { value, bound_vars: vec![] } - } - - pub fn skip_binder(self) -> T { - self.value - } - - pub fn map_bound_ref(&self, f: F) -> Binder - where - F: FnOnce(&T) -> U, - { - let Binder { value, bound_vars } = self; - let new_value = f(value); - Binder { value: new_value, bound_vars: bound_vars.clone() } - } - - pub fn map_bound(self, f: F) -> Binder - where - F: FnOnce(T) -> U, - { - let Binder { value, bound_vars } = self; - let new_value = f(value); - Binder { value: new_value, bound_vars } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct EarlyBinder { - pub value: T, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum BoundVariableKind { - Ty(BoundTyKind), - Region(BoundRegionKind), - Const, -} - -#[derive(Clone, PartialEq, Eq, Debug, Serialize)] -pub enum BoundTyKind { - Anon, - Param(ParamDef, String), -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum BoundRegionKind { - BrAnon, - BrNamed(BrNamedDef, String), - BrEnv, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum DynKind { - Dyn, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum ExistentialPredicate { - Trait(ExistentialTraitRef), - Projection(ExistentialProjection), - AutoTrait(TraitDef), -} - -/// An existential reference to a trait where `Self` is not included. -/// -/// The `generic_args` will include any other known argument. -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct ExistentialTraitRef { - pub def_id: TraitDef, - pub generic_args: GenericArgs, -} - -impl Binder { - pub fn with_self_ty(&self, self_ty: Ty) -> Binder { - self.map_bound_ref(|trait_ref| trait_ref.with_self_ty(self_ty)) - } -} - -impl ExistentialTraitRef { - pub fn with_self_ty(&self, self_ty: Ty) -> TraitRef { - TraitRef::new(self.def_id, self_ty, &self.generic_args) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct ExistentialProjection { - pub def_id: TraitDef, - pub generic_args: GenericArgs, - pub term: TermKind, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct ParamTy { - pub index: u32, - pub name: String, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct BoundTy { - pub var: usize, - pub kind: BoundTyKind, -} - -pub type Bytes = Vec>; - -/// Size in bytes. -pub type Size = usize; - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] -pub struct Prov(pub AllocId); - -pub type Align = u64; -pub type Promoted = u32; -pub type InitMaskMaterialized = Vec; - -/// Stores the provenance information of pointers stored in memory. -#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] -pub struct ProvenanceMap { - /// Provenance in this map applies from the given offset for an entire pointer-size worth of - /// bytes. Two entries in this map are always at least a pointer size apart. - pub ptrs: Vec<(Size, Prov)>, -} - -#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] -pub struct Allocation { - pub bytes: Bytes, - pub provenance: ProvenanceMap, - pub align: Align, - pub mutability: Mutability, -} - -impl Allocation { - /// Get a vector of bytes for an Allocation that has been fully initialized - pub fn raw_bytes(&self) -> Result, Error> { - self.bytes - .iter() - .copied() - .collect::>>() - .ok_or_else(|| error!("Found uninitialized bytes: `{:?}`", self.bytes)) - } - - /// Read a uint value from the specified range. - pub fn read_partial_uint(&self, range: Range) -> Result { - if range.end - range.start > 16 { - return Err(error!("Allocation is bigger than largest integer")); - } - if range.end > self.bytes.len() { - return Err(error!( - "Range is out of bounds. Allocation length is `{}`, but requested range `{:?}`", - self.bytes.len(), - range - )); - } - let raw = self.bytes[range] - .iter() - .copied() - .collect::>>() - .ok_or_else(|| error!("Found uninitialized bytes: `{:?}`", self.bytes))?; - read_target_uint(&raw) - } - - /// Read this allocation and try to convert it to an unassigned integer. - pub fn read_uint(&self) -> Result { - if self.bytes.len() > 16 { - return Err(error!("Allocation is bigger than largest integer")); - } - let raw = self.raw_bytes()?; - read_target_uint(&raw) - } - - /// Read this allocation and try to convert it to a signed integer. - pub fn read_int(&self) -> Result { - if self.bytes.len() > 16 { - return Err(error!("Allocation is bigger than largest integer")); - } - let raw = self.raw_bytes()?; - read_target_int(&raw) - } - - /// Read this allocation and try to convert it to a boolean. - pub fn read_bool(&self) -> Result { - match self.read_int()? { - 0 => Ok(false), - 1 => Ok(true), - val => Err(error!("Unexpected value for bool: `{val}`")), - } - } - - /// Read this allocation as a pointer and return whether it represents a `null` pointer. - pub fn is_null(&self) -> Result { - let len = self.bytes.len(); - let ptr_len = MachineInfo::target_pointer_width().bytes(); - if len != ptr_len { - return Err(error!("Expected width of pointer (`{ptr_len}`), but found: `{len}`")); - } - Ok(self.read_uint()? == 0 && self.provenance.ptrs.is_empty()) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum ConstantKind { - Ty(TyConst), - Allocated(Allocation), - Unevaluated(UnevaluatedConst), - Param(ParamConst), - /// Store ZST constants. - /// We have to special handle these constants since its type might be generic. - ZeroSized, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct ParamConst { - pub index: u32, - pub name: String, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct UnevaluatedConst { - pub def: ConstDef, - pub args: GenericArgs, - pub promoted: Option, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] -pub enum TraitSpecializationKind { - None, - Marker, - AlwaysApplicable, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct TraitDecl { - pub def_id: TraitDef, - pub safety: Safety, - pub paren_sugar: bool, - pub has_auto_impl: bool, - pub is_marker: bool, - pub is_coinductive: bool, - pub skip_array_during_method_dispatch: bool, - pub skip_boxed_slice_during_method_dispatch: bool, - pub specialization_kind: TraitSpecializationKind, - pub must_implement_one_of: Option>, - pub implement_via_object: bool, - pub deny_explicit_impl: bool, -} - -impl TraitDecl { - pub fn generics_of(&self) -> Generics { - with(|cx| cx.generics_of(self.def_id.0)) - } - - pub fn predicates_of(&self) -> GenericPredicates { - with(|cx| cx.predicates_of(self.def_id.0)) - } - - pub fn explicit_predicates_of(&self) -> GenericPredicates { - with(|cx| cx.explicit_predicates_of(self.def_id.0)) - } -} - -pub type ImplTrait = EarlyBinder; - -/// A complete reference to a trait, i.e., one where `Self` is known. -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct TraitRef { - pub def_id: TraitDef, - /// The generic arguments for this definition. - /// The first element must always be type, and it represents `Self`. - args: GenericArgs, -} - -impl TraitRef { - pub fn new(def_id: TraitDef, self_ty: Ty, gen_args: &GenericArgs) -> TraitRef { - let mut args = vec![GenericArgKind::Type(self_ty)]; - args.extend_from_slice(&gen_args.0); - TraitRef { def_id, args: GenericArgs(args) } - } - - pub fn try_new(def_id: TraitDef, args: GenericArgs) -> Result { - match &args.0[..] { - [GenericArgKind::Type(_), ..] => Ok(TraitRef { def_id, args }), - _ => Err(()), - } - } - - pub fn args(&self) -> &GenericArgs { - &self.args - } - - pub fn self_ty(&self) -> Ty { - let GenericArgKind::Type(self_ty) = self.args.0[0] else { - panic!("Self must be a type, but found: {:?}", self.args.0[0]) - }; - self_ty - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct Generics { - pub parent: Option, - pub parent_count: usize, - pub params: Vec, - pub param_def_id_to_index: Vec<(GenericDef, u32)>, - pub has_self: bool, - pub has_late_bound_regions: Option, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum GenericParamDefKind { - Lifetime, - Type { has_default: bool, synthetic: bool }, - Const { has_default: bool }, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct GenericParamDef { - pub name: super::Symbol, - pub def_id: GenericDef, - pub index: u32, - pub pure_wrt_drop: bool, - pub kind: GenericParamDefKind, -} - -pub struct GenericPredicates { - pub parent: Option, - pub predicates: Vec<(PredicateKind, Span)>, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum PredicateKind { - Clause(ClauseKind), - DynCompatible(TraitDef), - SubType(SubtypePredicate), - Coerce(CoercePredicate), - ConstEquate(TyConst, TyConst), - Ambiguous, - AliasRelate(TermKind, TermKind, AliasRelationDirection), -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum ClauseKind { - Trait(TraitPredicate), - RegionOutlives(RegionOutlivesPredicate), - TypeOutlives(TypeOutlivesPredicate), - Projection(ProjectionPredicate), - ConstArgHasType(TyConst, Ty), - WellFormed(TermKind), - ConstEvaluatable(TyConst), -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum ClosureKind { - Fn, - FnMut, - FnOnce, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct SubtypePredicate { - pub a: Ty, - pub b: Ty, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct CoercePredicate { - pub a: Ty, - pub b: Ty, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum AliasRelationDirection { - Equate, - Subtype, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct TraitPredicate { - pub trait_ref: TraitRef, - pub polarity: PredicatePolarity, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct OutlivesPredicate(pub A, pub B); - -pub type RegionOutlivesPredicate = OutlivesPredicate; -pub type TypeOutlivesPredicate = OutlivesPredicate; - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct ProjectionPredicate { - pub projection_term: AliasTerm, - pub term: TermKind, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum ImplPolarity { - Positive, - Negative, - Reservation, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum PredicatePolarity { - Positive, - Negative, -} - -macro_rules! index_impl { - ($name:ident) => { - impl stable_mir::IndexedVal for $name { - fn to_val(index: usize) -> Self { - $name(index) - } - fn to_index(&self) -> usize { - self.0 - } - } - }; -} - -index_impl!(TyConstId); -index_impl!(MirConstId); -index_impl!(Ty); -index_impl!(Span); - -/// The source-order index of a variant in a type. -/// -/// For example, in the following types, -/// ```ignore(illustrative) -/// enum Demo1 { -/// Variant0 { a: bool, b: i32 }, -/// Variant1 { c: u8, d: u64 }, -/// } -/// struct Demo2 { e: u8, f: u16, g: u8 } -/// ``` -/// `a` is in the variant with the `VariantIdx` of `0`, -/// `c` is in the variant with the `VariantIdx` of `1`, and -/// `g` is in the variant with the `VariantIdx` of `0`. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] -pub struct VariantIdx(usize); - -index_impl!(VariantIdx); - -crate_def! { - /// Hold information about an Opaque definition, particularly useful in `RPITIT`. - #[derive(Serialize)] - pub OpaqueDef; -} - -crate_def! { - #[derive(Serialize)] - pub AssocDef; -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub struct AssocItem { - pub def_id: AssocDef, - pub kind: AssocKind, - pub container: AssocItemContainer, - - /// If this is an item in an impl of a trait then this is the `DefId` of - /// the associated item on the trait that this implements. - pub trait_item_def_id: Option, -} - -#[derive(Clone, PartialEq, Debug, Eq, Serialize)] -pub enum AssocTypeData { - Normal(Symbol), - /// The associated type comes from an RPITIT. It has no name, and the - /// `ImplTraitInTraitData` provides additional information about its - /// source. - Rpitit(ImplTraitInTraitData), -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum AssocKind { - Const { name: Symbol }, - Fn { name: Symbol, has_self: bool }, - Type { data: AssocTypeData }, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum AssocItemContainer { - Trait, - Impl, -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] -pub enum ImplTraitInTraitData { - Trait { fn_def_id: FnDef, opaque_def_id: OpaqueDef }, - Impl { fn_def_id: FnDef }, -} - -impl AssocItem { - pub fn is_impl_trait_in_trait(&self) -> bool { - matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) }) - } -} diff --git a/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs deleted file mode 100644 index 37c93af392e..00000000000 --- a/compiler/rustc_smir/src/stable_mir/unstable/convert/internal.rs +++ /dev/null @@ -1,824 +0,0 @@ -//! Module containing the translation from stable mir constructs to the rustc counterpart. -//! -//! This module will only include a few constructs to allow users to invoke internal rustc APIs -//! due to incomplete stable coverage. - -// 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}; -use rustc_smir::Tables; -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, IntTy, MirConst, Movability, Pattern, Region, RigidTy, Span, - TermKind, TraitRef, Ty, TyConst, UintTy, VariantDef, VariantIdx, -}; -use stable_mir::unstable::{InternalCx, RustcInternal}; -use stable_mir::{CrateItem, CrateNum, DefId, IndexedVal}; - -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<'_, 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<'_, 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<'_, 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<'_, 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<'_, 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(), - GenericArgKind::Const(cnst) => cnst.internal(tables, tcx).into(), - }; - tcx.lift(arg).unwrap() - } -} - -impl RustcInternal for Region { - type T<'tcx> = rustc_ty::Region<'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() - } -} - -impl RustcInternal for Ty { - type T<'tcx> = InternalTy<'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<'_, 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<'_, 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), - end: end.as_ref().unwrap().internal(tables, tcx), - }, - }) - } -} - -impl RustcInternal for RigidTy { - type T<'tcx> = rustc_ty::TyKind<'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, - RigidTy::Int(int_ty) => rustc_ty::TyKind::Int(int_ty.internal(tables, tcx)), - RigidTy::Uint(uint_ty) => rustc_ty::TyKind::Uint(uint_ty.internal(tables, tcx)), - RigidTy::Float(float_ty) => rustc_ty::TyKind::Float(float_ty.internal(tables, tcx)), - RigidTy::Never => rustc_ty::TyKind::Never, - RigidTy::Array(ty, cnst) => { - rustc_ty::TyKind::Array(ty.internal(tables, tcx), cnst.internal(tables, tcx)) - } - RigidTy::Pat(ty, pat) => { - rustc_ty::TyKind::Pat(ty.internal(tables, tcx), pat.internal(tables, tcx)) - } - RigidTy::Adt(def, args) => { - rustc_ty::TyKind::Adt(def.internal(tables, tcx), args.internal(tables, tcx)) - } - RigidTy::Str => rustc_ty::TyKind::Str, - RigidTy::Slice(ty) => rustc_ty::TyKind::Slice(ty.internal(tables, tcx)), - RigidTy::RawPtr(ty, mutability) => { - rustc_ty::TyKind::RawPtr(ty.internal(tables, tcx), mutability.internal(tables, tcx)) - } - RigidTy::Ref(region, ty, mutability) => rustc_ty::TyKind::Ref( - region.internal(tables, tcx), - ty.internal(tables, tcx), - mutability.internal(tables, tcx), - ), - RigidTy::Foreign(def) => rustc_ty::TyKind::Foreign(def.0.internal(tables, tcx)), - RigidTy::FnDef(def, args) => { - rustc_ty::TyKind::FnDef(def.0.internal(tables, tcx), args.internal(tables, tcx)) - } - RigidTy::FnPtr(sig) => { - let (sig_tys, hdr) = sig.internal(tables, tcx).split(); - rustc_ty::TyKind::FnPtr(sig_tys, hdr) - } - RigidTy::Closure(def, args) => { - rustc_ty::TyKind::Closure(def.0.internal(tables, tcx), args.internal(tables, tcx)) - } - RigidTy::Coroutine(def, args, _mov) => { - rustc_ty::TyKind::Coroutine(def.0.internal(tables, tcx), args.internal(tables, tcx)) - } - RigidTy::CoroutineClosure(def, args) => rustc_ty::TyKind::CoroutineClosure( - def.0.internal(tables, tcx), - args.internal(tables, tcx), - ), - RigidTy::CoroutineWitness(def, args) => rustc_ty::TyKind::CoroutineWitness( - def.0.internal(tables, tcx), - args.internal(tables, tcx), - ), - RigidTy::Dynamic(predicate, region, dyn_kind) => rustc_ty::TyKind::Dynamic( - tcx.mk_poly_existential_predicates(&predicate.internal(tables, tcx)), - region.internal(tables, tcx), - dyn_kind.internal(tables, tcx), - ), - RigidTy::Tuple(tys) => { - rustc_ty::TyKind::Tuple(tcx.mk_type_list(&tys.internal(tables, tcx))) - } - } - } -} - -impl RustcInternal for IntTy { - type T<'tcx> = rustc_ty::IntTy; - - 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, - IntTy::I16 => rustc_ty::IntTy::I16, - IntTy::I32 => rustc_ty::IntTy::I32, - IntTy::I64 => rustc_ty::IntTy::I64, - IntTy::I128 => rustc_ty::IntTy::I128, - } - } -} - -impl RustcInternal for UintTy { - type T<'tcx> = rustc_ty::UintTy; - - 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, - UintTy::U16 => rustc_ty::UintTy::U16, - UintTy::U32 => rustc_ty::UintTy::U32, - UintTy::U64 => rustc_ty::UintTy::U64, - UintTy::U128 => rustc_ty::UintTy::U128, - } - } -} - -impl RustcInternal for FloatTy { - type T<'tcx> = rustc_ty::FloatTy; - - 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, - FloatTy::F64 => rustc_ty::FloatTy::F64, - FloatTy::F128 => rustc_ty::FloatTy::F128, - } - } -} - -impl RustcInternal for Mutability { - type T<'tcx> = rustc_ty::Mutability; - - 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, - } - } -} - -impl RustcInternal for Movability { - type T<'tcx> = rustc_ty::Movability; - - 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, - } - } -} - -impl RustcInternal for RawPtrKind { - type T<'tcx> = rustc_middle::mir::RawPtrKind; - - 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, - RawPtrKind::FakeForPtrMetadata => rustc_middle::mir::RawPtrKind::FakeForPtrMetadata, - } - } -} - -impl RustcInternal for FnSig { - type T<'tcx> = rustc_ty::FnSig<'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, - safety: self.safety.internal(tables, tcx), - abi: self.abi.internal(tables, tcx), - }) - .unwrap() - } -} - -impl RustcInternal for VariantIdx { - type T<'tcx> = rustc_abi::VariantIdx; - - fn internal<'tcx>( - &self, - _tables: &mut Tables<'_, BridgeTys>, - _tcx: impl InternalCx<'tcx>, - ) -> Self::T<'tcx> { - rustc_abi::VariantIdx::from(self.to_index()) - } -} - -impl RustcInternal for VariantDef { - type T<'tcx> = &'tcx rustc_ty::VariantDef; - - 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<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, - ) -> Self::T<'tcx> { - let constant = tables.mir_consts[self.id]; - match constant { - rustc_middle::mir::Const::Ty(ty, ct) => { - rustc_middle::mir::Const::Ty(tcx.lift(ty).unwrap(), tcx.lift(ct).unwrap()) - } - rustc_middle::mir::Const::Unevaluated(uneval, ty) => { - rustc_middle::mir::Const::Unevaluated( - tcx.lift(uneval).unwrap(), - tcx.lift(ty).unwrap(), - ) - } - rustc_middle::mir::Const::Val(const_val, ty) => { - rustc_middle::mir::Const::Val(tcx.lift(const_val).unwrap(), tcx.lift(ty).unwrap()) - } - } - } -} - -impl RustcInternal for MonoItem { - type T<'tcx> = rustc_middle::mir::mono::MonoItem<'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)), - MonoItem::Static(def) => rustc_mono::MonoItem::Static(def.internal(tables, tcx)), - MonoItem::GlobalAsm(_) => { - unimplemented!() - } - } - } -} - -impl RustcInternal for Instance { - type T<'tcx> = rustc_ty::Instance<'tcx>; - - fn internal<'tcx>( - &self, - tables: &mut Tables<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, - ) -> Self::T<'tcx> { - tcx.lift(tables.instances[self.def]).unwrap() - } -} - -impl RustcInternal for StaticDef { - type T<'tcx> = rustc_span::def_id::DefId; - - fn internal<'tcx>( - &self, - tables: &mut Tables<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, - ) -> Self::T<'tcx> { - self.0.internal(tables, tcx) - } -} - -#[allow(rustc::usage_of_qualified_ty)] -impl RustcInternal for Binder -where - T: RustcInternal, - for<'tcx> T::T<'tcx>: rustc_ty::TypeVisitable>, -{ - type T<'tcx> = rustc_ty::Binder<'tcx, T::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( - self.bound_vars.iter().map(|bound| bound.internal(tables, tcx)), - ), - ) - } -} - -impl RustcInternal for BoundVariableKind { - type T<'tcx> = rustc_ty::BoundVariableKind; - - 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, - BoundTyKind::Param(def, _symbol) => { - rustc_ty::BoundTyKind::Param(def.0.internal(tables, tcx)) - } - }), - BoundVariableKind::Region(kind) => rustc_ty::BoundVariableKind::Region(match kind { - BoundRegionKind::BrAnon => rustc_ty::BoundRegionKind::Anon, - BoundRegionKind::BrNamed(def, _symbol) => { - rustc_ty::BoundRegionKind::Named(def.0.internal(tables, tcx)) - } - BoundRegionKind::BrEnv => rustc_ty::BoundRegionKind::ClosureEnv, - }), - BoundVariableKind::Const => rustc_ty::BoundVariableKind::Const, - } - } -} - -impl RustcInternal for DynKind { - type T<'tcx> = rustc_ty::DynKind; - - fn internal<'tcx>( - &self, - _tables: &mut Tables<'_, BridgeTys>, - _tcx: impl InternalCx<'tcx>, - ) -> Self::T<'tcx> { - match self { - DynKind::Dyn => rustc_ty::DynKind::Dyn, - } - } -} - -impl RustcInternal for ExistentialPredicate { - type T<'tcx> = rustc_ty::ExistentialPredicate<'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)) - } - ExistentialPredicate::Projection(proj) => { - rustc_ty::ExistentialPredicate::Projection(proj.internal(tables, tcx)) - } - ExistentialPredicate::AutoTrait(trait_def) => { - rustc_ty::ExistentialPredicate::AutoTrait(trait_def.0.internal(tables, tcx)) - } - } - } -} - -impl RustcInternal for ExistentialProjection { - type T<'tcx> = rustc_ty::ExistentialProjection<'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), - ) - } -} - -impl RustcInternal for TermKind { - type T<'tcx> = rustc_ty::Term<'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(), - } - } -} - -impl RustcInternal for ExistentialTraitRef { - type T<'tcx> = rustc_ty::ExistentialTraitRef<'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), - ) - } -} - -impl RustcInternal for TraitRef { - type T<'tcx> = rustc_ty::TraitRef<'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<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, - ) -> Self::T<'tcx> { - tcx.lift(tables.alloc_ids[*self]).unwrap() - } -} - -impl RustcInternal for ClosureKind { - type T<'tcx> = rustc_ty::ClosureKind; - - 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, - ClosureKind::FnOnce => rustc_ty::ClosureKind::FnOnce, - } - } -} - -impl RustcInternal for AdtDef { - type T<'tcx> = rustc_ty::AdtDef<'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<'_, BridgeTys>, - _tcx: impl InternalCx<'tcx>, - ) -> Self::T<'tcx> { - match *self { - Abi::Rust => rustc_abi::ExternAbi::Rust, - Abi::C { unwind } => rustc_abi::ExternAbi::C { unwind }, - Abi::Cdecl { unwind } => rustc_abi::ExternAbi::Cdecl { unwind }, - Abi::Stdcall { unwind } => rustc_abi::ExternAbi::Stdcall { unwind }, - Abi::Fastcall { unwind } => rustc_abi::ExternAbi::Fastcall { unwind }, - Abi::Vectorcall { unwind } => rustc_abi::ExternAbi::Vectorcall { unwind }, - Abi::Thiscall { unwind } => rustc_abi::ExternAbi::Thiscall { unwind }, - Abi::Aapcs { unwind } => rustc_abi::ExternAbi::Aapcs { unwind }, - Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CmseNonSecureCall, - Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CmseNonSecureEntry, - Abi::Win64 { unwind } => rustc_abi::ExternAbi::Win64 { unwind }, - Abi::SysV64 { unwind } => rustc_abi::ExternAbi::SysV64 { unwind }, - Abi::PtxKernel => rustc_abi::ExternAbi::PtxKernel, - Abi::Msp430Interrupt => rustc_abi::ExternAbi::Msp430Interrupt, - Abi::X86Interrupt => rustc_abi::ExternAbi::X86Interrupt, - Abi::GpuKernel => rustc_abi::ExternAbi::GpuKernel, - Abi::EfiApi => rustc_abi::ExternAbi::EfiApi, - Abi::AvrInterrupt => rustc_abi::ExternAbi::AvrInterrupt, - Abi::AvrNonBlockingInterrupt => rustc_abi::ExternAbi::AvrNonBlockingInterrupt, - Abi::System { unwind } => rustc_abi::ExternAbi::System { unwind }, - Abi::RustCall => rustc_abi::ExternAbi::RustCall, - Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted, - Abi::RustCold => rustc_abi::ExternAbi::RustCold, - Abi::RustInvalid => rustc_abi::ExternAbi::RustInvalid, - Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM, - Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS, - Abi::Custom => rustc_abi::ExternAbi::Custom, - } - } -} - -impl RustcInternal for Safety { - type T<'tcx> = rustc_hir::Safety; - - 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, - } - } -} -impl RustcInternal for Span { - type T<'tcx> = rustc_span::Span; - - 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<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, - ) -> Self::T<'tcx> { - tcx.lift(tables.layouts[*self]).unwrap() - } -} - -impl RustcInternal for Place { - type T<'tcx> = rustc_middle::mir::Place<'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)), - } - } -} - -impl RustcInternal for ProjectionElem { - type T<'tcx> = rustc_middle::mir::PlaceElem<'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) => { - rustc_middle::mir::PlaceElem::Field((*idx).into(), ty.internal(tables, tcx)) - } - ProjectionElem::Index(idx) => rustc_middle::mir::PlaceElem::Index((*idx).into()), - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - rustc_middle::mir::PlaceElem::ConstantIndex { - offset: *offset, - min_length: *min_length, - from_end: *from_end, - } - } - ProjectionElem::Subslice { from, to, from_end } => { - rustc_middle::mir::PlaceElem::Subslice { from: *from, to: *to, from_end: *from_end } - } - ProjectionElem::Downcast(idx) => { - rustc_middle::mir::PlaceElem::Downcast(None, idx.internal(tables, tcx)) - } - ProjectionElem::OpaqueCast(ty) => { - rustc_middle::mir::PlaceElem::OpaqueCast(ty.internal(tables, tcx)) - } - ProjectionElem::Subtype(ty) => { - rustc_middle::mir::PlaceElem::Subtype(ty.internal(tables, tcx)) - } - } - } -} - -impl RustcInternal for BinOp { - type T<'tcx> = rustc_middle::mir::BinOp; - - 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, - BinOp::Sub => rustc_middle::mir::BinOp::Sub, - BinOp::SubUnchecked => rustc_middle::mir::BinOp::SubUnchecked, - BinOp::Mul => rustc_middle::mir::BinOp::Mul, - BinOp::MulUnchecked => rustc_middle::mir::BinOp::MulUnchecked, - BinOp::Div => rustc_middle::mir::BinOp::Div, - BinOp::Rem => rustc_middle::mir::BinOp::Rem, - BinOp::BitXor => rustc_middle::mir::BinOp::BitXor, - BinOp::BitAnd => rustc_middle::mir::BinOp::BitAnd, - BinOp::BitOr => rustc_middle::mir::BinOp::BitOr, - BinOp::Shl => rustc_middle::mir::BinOp::Shl, - BinOp::ShlUnchecked => rustc_middle::mir::BinOp::ShlUnchecked, - BinOp::Shr => rustc_middle::mir::BinOp::Shr, - BinOp::ShrUnchecked => rustc_middle::mir::BinOp::ShrUnchecked, - BinOp::Eq => rustc_middle::mir::BinOp::Eq, - BinOp::Lt => rustc_middle::mir::BinOp::Lt, - BinOp::Le => rustc_middle::mir::BinOp::Le, - BinOp::Ne => rustc_middle::mir::BinOp::Ne, - BinOp::Ge => rustc_middle::mir::BinOp::Ge, - BinOp::Gt => rustc_middle::mir::BinOp::Gt, - BinOp::Cmp => rustc_middle::mir::BinOp::Cmp, - BinOp::Offset => rustc_middle::mir::BinOp::Offset, - } - } -} - -impl RustcInternal for UnOp { - type T<'tcx> = rustc_middle::mir::UnOp; - - 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, - UnOp::PtrMetadata => rustc_middle::mir::UnOp::PtrMetadata, - } - } -} - -impl RustcInternal for &T -where - T: RustcInternal, -{ - type T<'tcx> = T::T<'tcx>; - - fn internal<'tcx>( - &self, - tables: &mut Tables<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, - ) -> Self::T<'tcx> { - (*self).internal(tables, tcx) - } -} - -impl RustcInternal for Option -where - T: RustcInternal, -{ - type T<'tcx> = Option>; - - fn internal<'tcx>( - &self, - tables: &mut Tables<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, - ) -> Self::T<'tcx> { - self.as_ref().map(|inner| inner.internal(tables, tcx)) - } -} - -impl RustcInternal for Vec -where - T: RustcInternal, -{ - type T<'tcx> = Vec>; - - 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 deleted file mode 100644 index 6e1b85671f8..00000000000 --- a/compiler/rustc_smir/src/stable_mir/unstable/convert/mod.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! 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 -where - T: Stable<'tcx>, -{ - type T = Option; - - 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 -where - T: Stable<'tcx>, - E: Stable<'tcx>, -{ - type T = Result; - - 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; - 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 -where - T: Stable<'tcx>, -{ - type T = RangeInclusive; - 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/stable_mir/unstable/convert/stable/abi.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/abi.rs deleted file mode 100644 index d8823a0d10c..00000000000 --- a/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/abi.rs +++ /dev/null @@ -1,411 +0,0 @@ -//! Conversion of internal Rust compiler `rustc_target` and `rustc_abi` items to stable ones. - -#![allow(rustc::usage_of_qualified_ty)] - -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::compiler_interface::BridgeTys; -use stable_mir::target::MachineSize as Size; -use stable_mir::ty::{Align, VariantIdx}; -use stable_mir::unstable::Stable; -use stable_mir::{IndexedVal, opaque}; - -use crate::{rustc_smir, stable_mir}; - -impl<'tcx> Stable<'tcx> for rustc_abi::VariantIdx { - type T = VariantIdx; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - VariantIdx::to_val(self.as_usize()) - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::Endian { - type T = stable_mir::target::Endian; - - 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, - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { - type T = TyAndLayout; - - 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<'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 { - type T = LayoutShape; - - fn stable<'cx>( - &self, - tables: &mut Tables<'cx, BridgeTys>, - cx: &SmirCtxt<'cx, BridgeTys>, - ) -> Self::T { - LayoutShape { - 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), - } - } -} - -impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> { - type T = FnAbi; - - 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, cx), - ret: self.ret.stable(tables, cx), - fixed_count: self.fixed_count, - conv: self.conv.stable(tables, cx), - c_variadic: self.c_variadic, - } - } -} - -impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> { - type T = ArgAbi; - - fn stable<'cx>( - &self, - tables: &mut Tables<'cx, BridgeTys>, - cx: &SmirCtxt<'cx, BridgeTys>, - ) -> Self::T { - ArgAbi { - ty: self.layout.ty.stable(tables, cx), - layout: self.layout.layout.stable(tables, cx), - mode: self.mode.stable(tables, cx), - } - } -} - -impl<'tcx> Stable<'tcx> for CanonAbi { - type T = CallConvention; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - match self { - CanonAbi::C => CallConvention::C, - CanonAbi::Rust => CallConvention::Rust, - CanonAbi::RustCold => CallConvention::Cold, - CanonAbi::Custom => CallConvention::Custom, - CanonAbi::Arm(arm_call) => match arm_call { - ArmCall::Aapcs => CallConvention::ArmAapcs, - ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, - ArmCall::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry, - }, - CanonAbi::GpuKernel => CallConvention::GpuKernel, - CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { - InterruptKind::Avr => CallConvention::AvrInterrupt, - InterruptKind::AvrNonBlocking => CallConvention::AvrNonBlockingInterrupt, - InterruptKind::Msp430 => CallConvention::Msp430Intr, - InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => { - CallConvention::RiscvInterrupt - } - InterruptKind::X86 => CallConvention::X86Intr, - }, - CanonAbi::X86(x86_call) => match x86_call { - X86Call::Fastcall => CallConvention::X86Fastcall, - X86Call::Stdcall => CallConvention::X86Stdcall, - X86Call::SysV64 => CallConvention::X86_64SysV, - X86Call::Thiscall => CallConvention::X86ThisCall, - X86Call::Vectorcall => CallConvention::X86VectorCall, - X86Call::Win64 => CallConvention::X86_64Win64, - }, - } - } -} - -impl<'tcx> Stable<'tcx> for callconv::PassMode { - type T = PassMode; - - 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)), - callconv::PassMode::Pair(first, second) => { - PassMode::Pair(opaque(first), opaque(second)) - } - callconv::PassMode::Cast { pad_i32, cast } => { - PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) } - } - callconv::PassMode::Indirect { attrs, meta_attrs, on_stack } => PassMode::Indirect { - attrs: opaque(attrs), - meta_attrs: opaque(meta_attrs), - on_stack: *on_stack, - }, - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape { - type T = FieldsShape; - - 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, cx), count: *count } - } - rustc_abi::FieldsShape::Arbitrary { offsets, .. } => { - FieldsShape::Arbitrary { offsets: offsets.iter().as_slice().stable(tables, cx) } - } - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::Variants { - type T = VariantsShape; - - 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, cx) } - } - rustc_abi::Variants::Empty => VariantsShape::Empty, - rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => { - VariantsShape::Multiple { - 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), - } - } - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding { - type T = TagEncoding; - - 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, cx), - niche_variants: niche_variants.stable(tables, cx), - niche_start: *niche_start, - } - } - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { - type T = ValueAbi; - - 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, cx)), - rustc_abi::BackendRepr::ScalarPair(first, second) => { - ValueAbi::ScalarPair(first.stable(tables, cx), second.stable(tables, cx)) - } - rustc_abi::BackendRepr::SimdVector { element, count } => { - ValueAbi::Vector { element: element.stable(tables, cx), count } - } - rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized }, - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::Size { - type T = Size; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - Size::from_bits(self.bits_usize()) - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::Align { - type T = Align; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - self.bytes() - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::Scalar { - type T = Scalar; - - 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, cx), - valid_range: valid_range.stable(tables, cx), - }, - rustc_abi::Scalar::Union { value } => Scalar::Union { value: value.stable(tables, cx) }, - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::Primitive { - type T = Primitive; - - 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, cx), signed: *signed } - } - rustc_abi::Primitive::Float(length) => { - Primitive::Float { length: length.stable(tables, cx) } - } - rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables, cx)), - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::AddressSpace { - type T = AddressSpace; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - AddressSpace(self.0) - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::Integer { - type T = IntegerLength; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - match self { - rustc_abi::Integer::I8 => IntegerLength::I8, - rustc_abi::Integer::I16 => IntegerLength::I16, - rustc_abi::Integer::I32 => IntegerLength::I32, - rustc_abi::Integer::I64 => IntegerLength::I64, - rustc_abi::Integer::I128 => IntegerLength::I128, - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::Float { - type T = FloatLength; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - match self { - rustc_abi::Float::F16 => FloatLength::F16, - rustc_abi::Float::F32 => FloatLength::F32, - rustc_abi::Float::F64 => FloatLength::F64, - rustc_abi::Float::F128 => FloatLength::F128, - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange { - type T = WrappingRange; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - WrappingRange { start: self.start, end: self.end } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::ReprFlags { - type T = ReprFlags; - - 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), - is_transparent: self.intersects(Self::IS_TRANSPARENT), - is_linear: self.intersects(Self::IS_LINEAR), - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::IntegerType { - type T = IntegerType; - - 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, cx), is_signed: *signed } - } - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::ReprOptions { - type T = ReprOptions; - - fn stable<'cx>( - &self, - tables: &mut Tables<'cx, BridgeTys>, - cx: &SmirCtxt<'cx, BridgeTys>, - ) -> Self::T { - ReprOptions { - 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/stable_mir/unstable/convert/stable/mir.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mir.rs deleted file mode 100644 index 99f9f456567..00000000000 --- a/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mir.rs +++ /dev/null @@ -1,950 +0,0 @@ -//! Conversion of internal Rust compiler `mir` items to stable ones. - -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::unstable::Stable; -use stable_mir::{Error, alloc, opaque}; - -use crate::{rustc_smir, stable_mir}; - -impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { - type T = stable_mir::mir::Body; - - 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, cx), - statements: block - .statements - .iter() - .map(|statement| statement.stable(tables, cx)) - .collect(), - }) - .collect(), - self.local_decls - .iter() - .map(|decl| stable_mir::mir::LocalDecl { - 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, 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<'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, cx), - composite: self.composite.as_ref().map(|composite| composite.stable(tables, cx)), - value: self.value.stable(tables, cx), - argument_index: self.argument_index, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> { - type T = stable_mir::mir::Statement; - 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<'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<'cx>( - &self, - tables: &mut Tables<'cx, BridgeTys>, - cx: &SmirCtxt<'cx, BridgeTys>, - ) -> Self::T { - VarDebugInfoFragment { - 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<'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, cx)) - } - mir::VarDebugInfoContents::Const(const_operand) => { - let op = ConstOperand { - span: const_operand.span.stable(tables, cx), - user_ty: const_operand.user_ty.map(|index| index.as_usize()), - const_: const_operand.const_.stable(tables, cx), - }; - stable_mir::mir::VarDebugInfoContents::Const(op) - } - } - } -} - -impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> { - type T = stable_mir::mir::StatementKind; - 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, cx), - assign.1.stable(tables, cx), - ), - mir::StatementKind::FakeRead(fake_read_place) => { - stable_mir::mir::StatementKind::FakeRead( - 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, cx), - variant_index: variant_index.stable(tables, cx), - } - } - mir::StatementKind::Deinit(place) => { - stable_mir::mir::StatementKind::Deinit(place.stable(tables, cx)) - } - - mir::StatementKind::StorageLive(place) => { - stable_mir::mir::StatementKind::StorageLive(place.stable(tables, cx)) - } - - mir::StatementKind::StorageDead(place) => { - 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, cx)) - } - mir::StatementKind::AscribeUserType(place_projection, variance) => { - stable_mir::mir::StatementKind::AscribeUserType { - 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, cx)) - } - mir::StatementKind::ConstEvalCounter => { - stable_mir::mir::StatementKind::ConstEvalCounter - } - // BackwardIncompatibleDropHint has no semantics, so it is translated to Nop. - mir::StatementKind::BackwardIncompatibleDropHint { .. } => { - stable_mir::mir::StatementKind::Nop - } - mir::StatementKind::Nop => stable_mir::mir::StatementKind::Nop, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { - type T = stable_mir::mir::Rvalue; - 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, cx)), - Repeat(op, 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, 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, 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, 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, cx), - ops.0.stable(tables, cx), - ops.1.stable(tables, cx), - ) - } else { - stable_mir::mir::Rvalue::BinaryOp( - 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, cx), - ty.stable(tables, cx), - ), - UnaryOp(un_op, op) => { - stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables, cx), op.stable(tables, cx)) - } - Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable(tables, cx)), - Aggregate(agg_kind, 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, cx), - ty.stable(tables, cx), - ), - CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables, cx)), - WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"), - } - } -} - -impl<'tcx> Stable<'tcx> for mir::Mutability { - type T = stable_mir::mir::Mutability; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_hir::Mutability::*; - match *self { - Not => stable_mir::mir::Mutability::Not, - Mut => stable_mir::mir::Mutability::Mut, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::RawPtrKind { - type T = stable_mir::mir::RawPtrKind; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use mir::RawPtrKind::*; - match *self { - Const => stable_mir::mir::RawPtrKind::Const, - Mut => stable_mir::mir::RawPtrKind::Mut, - FakeForPtrMetadata => stable_mir::mir::RawPtrKind::FakeForPtrMetadata, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::BorrowKind { - type T = stable_mir::mir::BorrowKind; - 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, 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<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::mir::MutBorrowKind::*; - match *self { - Default => stable_mir::mir::MutBorrowKind::Default, - TwoPhaseBorrow => stable_mir::mir::MutBorrowKind::TwoPhaseBorrow, - ClosureCapture => stable_mir::mir::MutBorrowKind::ClosureCapture, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind { - type T = stable_mir::mir::FakeBorrowKind; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::mir::FakeBorrowKind::*; - match *self { - Deep => stable_mir::mir::FakeBorrowKind::Deep, - Shallow => stable_mir::mir::FakeBorrowKind::Shallow, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { - type T = stable_mir::mir::NullOp; - 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, cx)).collect(), - ), - UbChecks => stable_mir::mir::NullOp::UbChecks, - ContractChecks => stable_mir::mir::NullOp::ContractChecks, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::CastKind { - type T = stable_mir::mir::CastKind; - 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, cx)) - } - IntToInt => stable_mir::mir::CastKind::IntToInt, - FloatToInt => stable_mir::mir::CastKind::FloatToInt, - FloatToFloat => stable_mir::mir::CastKind::FloatToFloat, - IntToFloat => stable_mir::mir::CastKind::IntToFloat, - PtrToPtr => stable_mir::mir::CastKind::PtrToPtr, - FnPtrToPtr => stable_mir::mir::CastKind::FnPtrToPtr, - Transmute => stable_mir::mir::CastKind::Transmute, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::FakeReadCause { - type T = stable_mir::mir::FakeReadCause; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::mir::FakeReadCause::*; - match self { - ForMatchGuard => stable_mir::mir::FakeReadCause::ForMatchGuard, - ForMatchedPlace(local_def_id) => { - stable_mir::mir::FakeReadCause::ForMatchedPlace(opaque(local_def_id)) - } - ForGuardBinding => stable_mir::mir::FakeReadCause::ForGuardBinding, - ForLet(local_def_id) => stable_mir::mir::FakeReadCause::ForLet(opaque(local_def_id)), - ForIndex => stable_mir::mir::FakeReadCause::ForIndex, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { - type T = stable_mir::mir::Operand; - 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, cx)), - Move(place) => stable_mir::mir::Operand::Move(place.stable(tables, cx)), - Constant(c) => stable_mir::mir::Operand::Constant(c.stable(tables, cx)), - } - } -} - -impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> { - type T = stable_mir::mir::ConstOperand; - - fn stable<'cx>( - &self, - tables: &mut Tables<'cx, BridgeTys>, - cx: &SmirCtxt<'cx, BridgeTys>, - ) -> Self::T { - stable_mir::mir::ConstOperand { - span: self.span.stable(tables, cx), - user_ty: self.user_ty.map(|u| u.as_usize()).or(None), - const_: self.const_.stable(tables, cx), - } - } -} - -impl<'tcx> Stable<'tcx> for mir::Place<'tcx> { - type T = stable_mir::mir::Place; - 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, cx)).collect(), - } - } -} - -impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { - type T = stable_mir::mir::ProjectionElem; - 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, 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, - min_length: *min_length, - from_end: *from_end, - } - } - Subslice { from, to, from_end } => stable_mir::mir::ProjectionElem::Subslice { - from: *from, - to: *to, - from_end: *from_end, - }, - // MIR includes an `Option` argument for `Downcast` that is the name of the - // variant, used for printing MIR. However this information should also be accessible - // via a lookup using the `VariantIdx`. The `Option` 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, 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):"), - } - } -} - -impl<'tcx> Stable<'tcx> for mir::UserTypeProjection { - type T = stable_mir::mir::UserTypeProjection; - - 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<'_, 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<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::mir::RetagKind; - match self { - RetagKind::FnEntry => stable_mir::mir::RetagKind::FnEntry, - RetagKind::TwoPhase => stable_mir::mir::RetagKind::TwoPhase, - RetagKind::Raw => stable_mir::mir::RetagKind::Raw, - RetagKind::Default => stable_mir::mir::RetagKind::Default, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::UnwindAction { - type T = stable_mir::mir::UnwindAction; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::mir::UnwindAction; - match self { - UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue, - UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable, - UnwindAction::Terminate(_) => stable_mir::mir::UnwindAction::Terminate, - UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()), - } - } -} - -impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> { - type T = stable_mir::mir::NonDivergingIntrinsic; - - 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, cx)) - } - NonDivergingIntrinsic::CopyNonOverlapping(copy_non_overlapping) => { - stable_mir::mir::NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { - src: copy_non_overlapping.src.stable(tables, cx), - dst: copy_non_overlapping.dst.stable(tables, cx), - count: copy_non_overlapping.count.stable(tables, cx), - }) - } - } - } -} - -impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> { - type T = stable_mir::mir::AssertMessage; - 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, cx), - index: index.stable(tables, cx), - }, - AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow( - bin_op.stable(tables, cx), - op1.stable(tables, cx), - op2.stable(tables, cx), - ), - AssertKind::OverflowNeg(op) => { - stable_mir::mir::AssertMessage::OverflowNeg(op.stable(tables, cx)) - } - AssertKind::DivisionByZero(op) => { - stable_mir::mir::AssertMessage::DivisionByZero(op.stable(tables, cx)) - } - AssertKind::RemainderByZero(op) => { - stable_mir::mir::AssertMessage::RemainderByZero(op.stable(tables, cx)) - } - AssertKind::ResumedAfterReturn(coroutine) => { - stable_mir::mir::AssertMessage::ResumedAfterReturn(coroutine.stable(tables, cx)) - } - AssertKind::ResumedAfterPanic(coroutine) => { - stable_mir::mir::AssertMessage::ResumedAfterPanic(coroutine.stable(tables, cx)) - } - AssertKind::ResumedAfterDrop(coroutine) => { - stable_mir::mir::AssertMessage::ResumedAfterDrop(coroutine.stable(tables, cx)) - } - AssertKind::MisalignedPointerDereference { required, found } => { - stable_mir::mir::AssertMessage::MisalignedPointerDereference { - 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, cx)) - } - } - } -} - -impl<'tcx> Stable<'tcx> for mir::BinOp { - type T = stable_mir::mir::BinOp; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::mir::BinOp; - match self { - BinOp::Add => stable_mir::mir::BinOp::Add, - BinOp::AddUnchecked => stable_mir::mir::BinOp::AddUnchecked, - BinOp::AddWithOverflow => bug!("AddWithOverflow should have been translated already"), - BinOp::Sub => stable_mir::mir::BinOp::Sub, - BinOp::SubUnchecked => stable_mir::mir::BinOp::SubUnchecked, - BinOp::SubWithOverflow => bug!("AddWithOverflow should have been translated already"), - BinOp::Mul => stable_mir::mir::BinOp::Mul, - BinOp::MulUnchecked => stable_mir::mir::BinOp::MulUnchecked, - BinOp::MulWithOverflow => bug!("AddWithOverflow should have been translated already"), - BinOp::Div => stable_mir::mir::BinOp::Div, - BinOp::Rem => stable_mir::mir::BinOp::Rem, - BinOp::BitXor => stable_mir::mir::BinOp::BitXor, - BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd, - BinOp::BitOr => stable_mir::mir::BinOp::BitOr, - BinOp::Shl => stable_mir::mir::BinOp::Shl, - BinOp::ShlUnchecked => stable_mir::mir::BinOp::ShlUnchecked, - BinOp::Shr => stable_mir::mir::BinOp::Shr, - BinOp::ShrUnchecked => stable_mir::mir::BinOp::ShrUnchecked, - BinOp::Eq => stable_mir::mir::BinOp::Eq, - BinOp::Lt => stable_mir::mir::BinOp::Lt, - BinOp::Le => stable_mir::mir::BinOp::Le, - BinOp::Ne => stable_mir::mir::BinOp::Ne, - BinOp::Ge => stable_mir::mir::BinOp::Ge, - BinOp::Gt => stable_mir::mir::BinOp::Gt, - BinOp::Cmp => stable_mir::mir::BinOp::Cmp, - BinOp::Offset => stable_mir::mir::BinOp::Offset, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::UnOp { - type T = stable_mir::mir::UnOp; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::mir::UnOp; - match self { - UnOp::Not => stable_mir::mir::UnOp::Not, - UnOp::Neg => stable_mir::mir::UnOp::Neg, - UnOp::PtrMetadata => stable_mir::mir::UnOp::PtrMetadata, - } - } -} - -impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { - type T = stable_mir::mir::AggregateKind; - 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, 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, cx), - generic_arg.stable(tables, cx), - user_ty_index.map(|idx| idx.index()), - field_idx.map(|idx| idx.index()), - ) - } - mir::AggregateKind::Closure(def_id, generic_arg) => { - stable_mir::mir::AggregateKind::Closure( - tables.closure_def(*def_id), - 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, 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, cx), - ) - } - 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<'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, cx)), None), - InlineAsmOperand::Out { place, .. } => { - (None, place.map(|place| place.stable(tables, cx))) - } - InlineAsmOperand::InOut { in_value, out_place, .. } => { - (Some(in_value.stable(tables, cx)), out_place.map(|place| place.stable(tables, cx))) - } - InlineAsmOperand::Const { .. } - | InlineAsmOperand::SymFn { .. } - | InlineAsmOperand::SymStatic { .. } - | InlineAsmOperand::Label { .. } => (None, None), - }; - - stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{self:?}") } - } -} - -impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { - type T = stable_mir::mir::Terminator; - 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, 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<'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, cx), - targets: { - let branches = targets.iter().map(|(val, target)| (val, target.as_usize())); - stable_mir::mir::SwitchTargets::new( - branches.collect(), - targets.otherwise().as_usize(), - ) - }, - }, - mir::TerminatorKind::UnwindResume => TerminatorKind::Resume, - mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort, - mir::TerminatorKind::Return => TerminatorKind::Return, - mir::TerminatorKind::Unreachable => TerminatorKind::Unreachable, - mir::TerminatorKind::Drop { - place, - target, - unwind, - replace: _, - drop: _, - async_fut: _, - } => TerminatorKind::Drop { - place: place.stable(tables, cx), - target: target.as_usize(), - unwind: unwind.stable(tables, cx), - }, - mir::TerminatorKind::Call { - func, - args, - destination, - target, - unwind, - call_source: _, - fn_span: _, - } => TerminatorKind::Call { - 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, cx), - }, - mir::TerminatorKind::TailCall { func: _, args: _, fn_span: _ } => todo!(), - mir::TerminatorKind::Assert { cond, expected, msg, target, unwind } => { - TerminatorKind::Assert { - cond: cond.stable(tables, cx), - expected: *expected, - msg: msg.stable(tables, cx), - target: target.as_usize(), - unwind: unwind.stable(tables, cx), - } - } - mir::TerminatorKind::InlineAsm { - asm_macro: _, - template, - operands, - options, - line_spans, - targets, - unwind, - } => TerminatorKind::InlineAsm { - template: format!("{template:?}"), - 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, cx), - }, - mir::TerminatorKind::Yield { .. } - | mir::TerminatorKind::CoroutineDrop - | mir::TerminatorKind::FalseEdge { .. } - | mir::TerminatorKind::FalseUnwind { .. } => unreachable!(), - } - } -} - -impl<'tcx> Stable<'tcx> for mir::interpret::ConstAllocation<'tcx> { - type T = Allocation; - - 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<'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<'cx>( - &self, - tables: &mut Tables<'cx, BridgeTys>, - _: &SmirCtxt<'cx, BridgeTys>, - ) -> Self::T { - tables.create_alloc_id(*self) - } -} - -impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { - type T = GlobalAlloc; - - 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, cx)) - } - mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => { - // FIXME: Should we record the whole vtable? - 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, cx)) - } - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { - type T = stable_mir::ty::MirConst; - - 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, 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, cx), - promoted: unev_const.promoted.map(|u| u.as_u32()), - }); - let ty = ty.stable(tables, cx); - MirConst::new(kind, ty, id) - } - mir::Const::Val(mir::ConstValue::ZeroSized, ty) => { - let ty = ty.stable(tables, cx); - MirConst::new(ConstantKind::ZeroSized, ty, id) - } - mir::Const::Val(val, ty) => { - 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) - } - } - } -} - -impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled { - type T = Error; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - Error::new(format!("{self:?}")) - } -} - -impl<'tcx> Stable<'tcx> for MonoItem<'tcx> { - type T = stable_mir::mir::mono::MonoItem; - - 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, 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/stable_mir/unstable/convert/stable/mod.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mod.rs deleted file mode 100644 index 799917c6e17..00000000000 --- a/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/mod.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! 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 super::Stable; -use crate::{rustc_smir, stable_mir}; - -mod abi; -mod mir; -mod ty; - -impl<'tcx> Stable<'tcx> for rustc_hir::Safety { - type T = stable_mir::mir::Safety; - 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, - } - } -} - -impl<'tcx> Stable<'tcx> for FieldIdx { - type T = usize; - 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<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_hir::CoroutineSource; - match self { - CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block, - CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure, - CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn, - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { - type T = stable_mir::mir::CoroutineKind; - 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, cx), - ) - } - CoroutineKind::Desugared(CoroutineDesugaring::Gen, source) => { - stable_mir::mir::CoroutineKind::Desugared( - stable_mir::mir::CoroutineDesugaring::Gen, - source.stable(tables, cx), - ) - } - CoroutineKind::Coroutine(movability) => { - 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, cx), - ) - } - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_span::Symbol { - type T = stable_mir::Symbol; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - self.to_string() - } -} - -impl<'tcx> Stable<'tcx> for rustc_span::Span { - type T = stable_mir::ty::Span; - - 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/stable_mir/unstable/convert/stable/ty.rs b/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs deleted file mode 100644 index 596c8b96bfc..00000000000 --- a/compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs +++ /dev/null @@ -1,1151 +0,0 @@ -//! Conversion of internal Rust compiler `ty` items to stable ones. - -use rustc_middle::ty::Ty; -use rustc_middle::{bug, 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_mir}; - -impl<'tcx> Stable<'tcx> for ty::AliasTyKind { - type T = stable_mir::ty::AliasKind; - 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, - ty::Opaque => stable_mir::ty::AliasKind::Opaque, - ty::Free => stable_mir::ty::AliasKind::Free, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::AliasTy<'tcx> { - type T = stable_mir::ty::AliasTy; - 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, cx) } - } -} - -impl<'tcx> Stable<'tcx> for ty::AliasTerm<'tcx> { - type T = stable_mir::ty::AliasTerm; - 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, cx), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::DynKind { - type T = stable_mir::ty::DynKind; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - match self { - ty::Dyn => stable_mir::ty::DynKind::Dyn, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> { - type T = stable_mir::ty::ExistentialPredicate; - - 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, cx)) - } - ty::ExistentialPredicate::Projection(existential_projection) => { - Projection(existential_projection.stable(tables, cx)) - } - ty::ExistentialPredicate::AutoTrait(def_id) => AutoTrait(tables.trait_def(*def_id)), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> { - type T = stable_mir::ty::ExistentialTraitRef; - - 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, cx), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> { - type T = stable_mir::ty::TermKind; - - 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, cx)), - ty::TermKind::Const(cnst) => { - let cnst = cnst.stable(tables, cx); - TermKind::Const(cnst) - } - } - } -} - -impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> { - type T = stable_mir::ty::ExistentialProjection; - - 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, cx), - term: term.kind().stable(tables, cx), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion { - type T = stable_mir::mir::PointerCoercion; - 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, cx)) - } - PointerCoercion::MutToConstPointer => { - stable_mir::mir::PointerCoercion::MutToConstPointer - } - PointerCoercion::ArrayToPointer => stable_mir::mir::PointerCoercion::ArrayToPointer, - PointerCoercion::Unsize => stable_mir::mir::PointerCoercion::Unsize, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex { - type T = usize; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - self.as_usize() - } -} - -impl<'tcx> Stable<'tcx> for ty::AdtKind { - type T = AdtKind; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - match self { - ty::AdtKind::Struct => AdtKind::Struct, - ty::AdtKind::Union => AdtKind::Union, - ty::AdtKind::Enum => AdtKind::Enum, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::FieldDef { - type T = stable_mir::ty::FieldDef; - - 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, cx), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> { - type T = stable_mir::ty::GenericArgs; - 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<'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, cx)) - } - ty::GenericArgKind::Type(ty) => GenericArgKind::Type(ty.stable(tables, cx)), - ty::GenericArgKind::Const(cnst) => GenericArgKind::Const(cnst.stable(tables, cx)), - } - } -} - -impl<'tcx, S, V> Stable<'tcx> for ty::Binder<'tcx, S> -where - S: Stable<'tcx, T = V>, -{ - type T = stable_mir::ty::Binder; - - 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, cx), - bound_vars: self - .bound_vars() - .iter() - .map(|bound_var| bound_var.stable(tables, cx)) - .collect(), - } - } -} - -impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<'tcx, S> -where - S: Stable<'tcx, T = V>, -{ - type T = stable_mir::ty::EarlyBinder; - - 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, cx) } - } -} - -impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> { - type T = stable_mir::ty::FnSig; - 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, cx)) - .collect(), - c_variadic: self.c_variadic, - safety: self.safety.stable(tables, cx), - abi: self.abi.stable(tables, cx), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::BoundTyKind { - type T = stable_mir::ty::BoundTyKind; - - fn stable<'cx>( - &self, - tables: &mut Tables<'cx, BridgeTys>, - cx: &SmirCtxt<'cx, BridgeTys>, - ) -> Self::T { - use stable_mir::ty::BoundTyKind; - - match self { - ty::BoundTyKind::Anon => BoundTyKind::Anon, - ty::BoundTyKind::Param(def_id) => { - BoundTyKind::Param(tables.param_def(*def_id), cx.tcx.item_name(*def_id).to_string()) - } - } - } -} - -impl<'tcx> Stable<'tcx> for ty::BoundRegionKind { - type T = stable_mir::ty::BoundRegionKind; - - fn stable<'cx>( - &self, - tables: &mut Tables<'cx, BridgeTys>, - cx: &SmirCtxt<'cx, BridgeTys>, - ) -> Self::T { - use stable_mir::ty::BoundRegionKind; - - match self { - ty::BoundRegionKind::Anon => BoundRegionKind::BrAnon, - ty::BoundRegionKind::Named(def_id) => BoundRegionKind::BrNamed( - tables.br_named_def(*def_id), - cx.tcx.item_name(*def_id).to_string(), - ), - ty::BoundRegionKind::ClosureEnv => BoundRegionKind::BrEnv, - ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::BoundVariableKind { - type T = stable_mir::ty::BoundVariableKind; - - 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, cx)) - } - ty::BoundVariableKind::Region(bound_region_kind) => { - BoundVariableKind::Region(bound_region_kind.stable(tables, cx)) - } - ty::BoundVariableKind::Const => BoundVariableKind::Const, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::IntTy { - type T = IntTy; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - match self { - ty::IntTy::Isize => IntTy::Isize, - ty::IntTy::I8 => IntTy::I8, - ty::IntTy::I16 => IntTy::I16, - ty::IntTy::I32 => IntTy::I32, - ty::IntTy::I64 => IntTy::I64, - ty::IntTy::I128 => IntTy::I128, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::UintTy { - type T = UintTy; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - match self { - ty::UintTy::Usize => UintTy::Usize, - ty::UintTy::U8 => UintTy::U8, - ty::UintTy::U16 => UintTy::U16, - ty::UintTy::U32 => UintTy::U32, - ty::UintTy::U64 => UintTy::U64, - ty::UintTy::U128 => UintTy::U128, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::FloatTy { - type T = FloatTy; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - match self { - ty::FloatTy::F16 => FloatTy::F16, - ty::FloatTy::F32 => FloatTy::F32, - ty::FloatTy::F64 => FloatTy::F64, - ty::FloatTy::F128 => FloatTy::F128, - } - } -} - -impl<'tcx> Stable<'tcx> for Ty<'tcx> { - type T = stable_mir::ty::Ty; - 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<'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, 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, 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, cx), constant.stable(tables, cx))) - } - ty::Pat(ty, pat) => { - TyKind::RigidTy(RigidTy::Pat(ty.stable(tables, cx), pat.stable(tables, cx))) - } - ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables, cx))), - ty::RawPtr(ty, mutbl) => { - TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables, cx), mutbl.stable(tables, cx))) - } - ty::Ref(region, ty, mutbl) => TyKind::RigidTy(RigidTy::Ref( - 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::FnPtr(sig_tys, hdr) => { - TyKind::RigidTy(RigidTy::FnPtr(sig_tys.with(*hdr).stable(tables, cx))) - } - // FIXME(unsafe_binders): - ty::UnsafeBinder(_) => todo!(), - ty::Dynamic(existential_predicates, region, dyn_kind) => { - TyKind::RigidTy(RigidTy::Dynamic( - existential_predicates - .iter() - .map(|existential_predicate| existential_predicate.stable(tables, cx)) - .collect(), - 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, 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, 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, cx)).collect(), - )), - ty::Alias(alias_kind, alias_ty) => { - TyKind::Alias(alias_kind.stable(tables, cx), alias_ty.stable(tables, cx)) - } - 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, cx)) - } - ty::CoroutineWitness(def_id, args) => TyKind::RigidTy(RigidTy::CoroutineWitness( - tables.coroutine_witness_def(*def_id), - args.stable(tables, cx), - )), - ty::Placeholder(..) | ty::Infer(_) | ty::Error(_) => { - unreachable!(); - } - } - } -} - -impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> { - type T = stable_mir::ty::Pattern; - - 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, cx)), - end: Some(end.stable(tables, cx)), - include_end: true, - }, - ty::PatternKind::Or(_) => todo!(), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { - type T = stable_mir::ty::TyConst; - - 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 = cx.valtree_to_const_val(cv); - if matches!(const_val, mir::ConstValue::ZeroSized) { - stable_mir::ty::TyConstKind::ZSTValue(cv.ty.stable(tables, cx)) - } else { - stable_mir::ty::TyConstKind::Value( - 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, cx)) - } - ty::ConstKind::Unevaluated(uv) => stable_mir::ty::TyConstKind::Unevaluated( - tables.const_def(uv.def), - uv.args.stable(tables, cx), - ), - ty::ConstKind::Error(_) => unreachable!(), - ty::ConstKind::Infer(_) => unreachable!(), - ty::ConstKind::Bound(_, _) => unimplemented!(), - ty::ConstKind::Placeholder(_) => unimplemented!(), - ty::ConstKind::Expr(_) => unimplemented!(), - }; - let id = tables.intern_ty_const(ct); - stable_mir::ty::TyConst::new(kind, id) - } -} - -impl<'tcx> Stable<'tcx> for ty::ParamConst { - type T = stable_mir::ty::ParamConst; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use stable_mir::ty::ParamConst; - ParamConst { index: self.index, name: self.name.to_string() } - } -} - -impl<'tcx> Stable<'tcx> for ty::ParamTy { - type T = stable_mir::ty::ParamTy; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use stable_mir::ty::ParamTy; - ParamTy { index: self.index, name: self.name.to_string() } - } -} - -impl<'tcx> Stable<'tcx> for ty::BoundTy { - type T = stable_mir::ty::BoundTy; - 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, cx) } - } -} - -impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind { - type T = stable_mir::ty::TraitSpecializationKind; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use stable_mir::ty::TraitSpecializationKind; - - match self { - ty::trait_def::TraitSpecializationKind::None => TraitSpecializationKind::None, - ty::trait_def::TraitSpecializationKind::Marker => TraitSpecializationKind::Marker, - ty::trait_def::TraitSpecializationKind::AlwaysApplicable => { - TraitSpecializationKind::AlwaysApplicable - } - } - } -} - -impl<'tcx> Stable<'tcx> for ty::TraitDef { - type T = stable_mir::ty::TraitDecl; - 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, 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, cx), - must_implement_one_of: self - .must_implement_one_of - .as_ref() - .map(|idents| idents.iter().map(|ident| opaque(ident)).collect()), - implement_via_object: self.implement_via_object, - deny_explicit_impl: self.deny_explicit_impl, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> { - type T = stable_mir::ty::TraitRef; - 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, cx)).unwrap() - } -} - -impl<'tcx> Stable<'tcx> for ty::Generics { - type T = stable_mir::ty::Generics; - - 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, cx)).collect(); - let param_def_id_to_index = - params.iter().map(|param| (param.def_id, param.index)).collect(); - - Generics { - parent: self.parent.map(|did| tables.generic_def(did)), - parent_count: self.parent_count, - params, - param_def_id_to_index, - has_self: self.has_self, - has_late_bound_regions: self - .has_late_bound_regions - .as_ref() - .map(|late_bound_regions| late_bound_regions.stable(tables, cx)), - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind { - type T = stable_mir::ty::GenericParamDefKind; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use stable_mir::ty::GenericParamDefKind; - match self { - ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime, - ty::GenericParamDefKind::Type { has_default, synthetic } => { - GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic } - } - ty::GenericParamDefKind::Const { has_default, synthetic: _ } => { - GenericParamDefKind::Const { has_default: *has_default } - } - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDef { - type T = stable_mir::ty::GenericParamDef; - - 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, cx), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> { - type T = stable_mir::ty::PredicateKind; - - 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, 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, cx)) - } - PredicateKind::Coerce(coerce_predicate) => { - 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, cx), - b.kind().stable(tables, cx), - alias_relation_direction.stable(tables, cx), - ) - } - } - } -} - -impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { - type T = stable_mir::ty::ClauseKind; - - 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, cx)) - } - ClauseKind::RegionOutlives(region_outlives) => { - 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, cx), - b.stable(tables, cx), - )) - } - ClauseKind::Projection(projection_predicate) => { - stable_mir::ty::ClauseKind::Projection(projection_predicate.stable(tables, cx)) - } - ClauseKind::ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType( - const_.stable(tables, cx), - ty.stable(tables, cx), - ), - ClauseKind::WellFormed(term) => { - stable_mir::ty::ClauseKind::WellFormed(term.kind().stable(tables, cx)) - } - ClauseKind::ConstEvaluatable(const_) => { - stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables, cx)) - } - ClauseKind::HostEffect(..) => { - todo!() - } - } - } -} - -impl<'tcx> Stable<'tcx> for ty::ClosureKind { - type T = stable_mir::ty::ClosureKind; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::ty::ClosureKind::*; - match self { - Fn => stable_mir::ty::ClosureKind::Fn, - FnMut => stable_mir::ty::ClosureKind::FnMut, - FnOnce => stable_mir::ty::ClosureKind::FnOnce, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::SubtypePredicate<'tcx> { - type T = stable_mir::ty::SubtypePredicate; - - 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, cx), b: b.stable(tables, cx) } - } -} - -impl<'tcx> Stable<'tcx> for ty::CoercePredicate<'tcx> { - type T = stable_mir::ty::CoercePredicate; - - 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, cx), b: b.stable(tables, cx) } - } -} - -impl<'tcx> Stable<'tcx> for ty::AliasRelationDirection { - type T = stable_mir::ty::AliasRelationDirection; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::ty::AliasRelationDirection::*; - match self { - Equate => stable_mir::ty::AliasRelationDirection::Equate, - Subtype => stable_mir::ty::AliasRelationDirection::Subtype, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::TraitPredicate<'tcx> { - type T = stable_mir::ty::TraitPredicate; - - 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, cx), - polarity: polarity.stable(tables, cx), - } - } -} - -impl<'tcx, T> Stable<'tcx> for ty::OutlivesPredicate<'tcx, T> -where - T: Stable<'tcx>, -{ - type T = stable_mir::ty::OutlivesPredicate; - - 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, cx), b.stable(tables, cx)) - } -} - -impl<'tcx> Stable<'tcx> for ty::ProjectionPredicate<'tcx> { - type T = stable_mir::ty::ProjectionPredicate; - - 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, cx), - term: term.kind().stable(tables, cx), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::ImplPolarity { - type T = stable_mir::ty::ImplPolarity; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::ty::ImplPolarity::*; - match self { - Positive => stable_mir::ty::ImplPolarity::Positive, - Negative => stable_mir::ty::ImplPolarity::Negative, - Reservation => stable_mir::ty::ImplPolarity::Reservation, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::PredicatePolarity { - type T = stable_mir::ty::PredicatePolarity; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_middle::ty::PredicatePolarity::*; - match self { - Positive => stable_mir::ty::PredicatePolarity::Positive, - Negative => stable_mir::ty::PredicatePolarity::Negative, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::Region<'tcx> { - type T = stable_mir::ty::Region; - - 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<'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 { - index: early_reg.index, - name: early_reg.name.to_string(), - }), - 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, cx), - }, - ), - ty::ReStatic => RegionKind::ReStatic, - ty::RePlaceholder(place_holder) => { - RegionKind::RePlaceholder(stable_mir::ty::Placeholder { - universe: place_holder.universe.as_u32(), - bound: BoundRegion { - var: place_holder.bound.var.as_u32(), - kind: place_holder.bound.kind.stable(tables, cx), - }, - }) - } - ty::ReErased => RegionKind::ReErased, - _ => unreachable!("{self:?}"), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { - type T = stable_mir::mir::mono::Instance; - - 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, - ty::InstanceKind::Virtual(_def_id, idx) => { - stable_mir::mir::mono::InstanceKind::Virtual { idx } - } - ty::InstanceKind::VTableShim(..) - | ty::InstanceKind::ReifyShim(..) - | ty::InstanceKind::FnPtrAddrShim(..) - | ty::InstanceKind::ClosureOnceShim { .. } - | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } - | ty::InstanceKind::ThreadLocalShim(..) - | ty::InstanceKind::DropGlue(..) - | ty::InstanceKind::CloneShim(..) - | ty::InstanceKind::FnPtrShim(..) - | ty::InstanceKind::FutureDropPollShim(..) - | ty::InstanceKind::AsyncDropGlue(..) - | ty::InstanceKind::AsyncDropGlueCtorShim(..) => { - stable_mir::mir::mono::InstanceKind::Shim - } - }; - stable_mir::mir::mono::Instance { def, kind } - } -} - -impl<'tcx> Stable<'tcx> for ty::Variance { - type T = stable_mir::mir::Variance; - 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, - ty::Covariant => stable_mir::mir::Variance::Covariant, - ty::Invariant => stable_mir::mir::Variance::Invariant, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::Movability { - type T = stable_mir::ty::Movability; - - 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, - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { - type T = stable_mir::ty::Abi; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use rustc_abi::ExternAbi; - use stable_mir::ty::Abi; - match *self { - ExternAbi::Rust => Abi::Rust, - ExternAbi::C { unwind } => Abi::C { unwind }, - ExternAbi::Cdecl { unwind } => Abi::Cdecl { unwind }, - ExternAbi::Stdcall { unwind } => Abi::Stdcall { unwind }, - ExternAbi::Fastcall { unwind } => Abi::Fastcall { unwind }, - ExternAbi::Vectorcall { unwind } => Abi::Vectorcall { unwind }, - ExternAbi::Thiscall { unwind } => Abi::Thiscall { unwind }, - ExternAbi::Aapcs { unwind } => Abi::Aapcs { unwind }, - ExternAbi::Win64 { unwind } => Abi::Win64 { unwind }, - ExternAbi::SysV64 { unwind } => Abi::SysV64 { unwind }, - ExternAbi::PtxKernel => Abi::PtxKernel, - ExternAbi::GpuKernel => Abi::GpuKernel, - ExternAbi::Msp430Interrupt => Abi::Msp430Interrupt, - ExternAbi::X86Interrupt => Abi::X86Interrupt, - ExternAbi::EfiApi => Abi::EfiApi, - ExternAbi::AvrInterrupt => Abi::AvrInterrupt, - ExternAbi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, - ExternAbi::CmseNonSecureCall => Abi::CCmseNonSecureCall, - ExternAbi::CmseNonSecureEntry => Abi::CCmseNonSecureEntry, - ExternAbi::System { unwind } => Abi::System { unwind }, - ExternAbi::RustCall => Abi::RustCall, - ExternAbi::Unadjusted => Abi::Unadjusted, - ExternAbi::RustCold => Abi::RustCold, - ExternAbi::RustInvalid => Abi::RustInvalid, - ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM, - ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS, - ExternAbi::Custom => Abi::Custom, - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_session::cstore::ForeignModule { - type T = stable_mir::ty::ForeignModule; - - 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, cx), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::AssocKind { - type T = stable_mir::ty::AssocKind; - - 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() }, - ty::AssocKind::Fn { name, has_self } => { - AssocKind::Fn { name: name.to_string(), has_self } - } - ty::AssocKind::Type { data } => AssocKind::Type { - data: match data { - ty::AssocTypeData::Normal(name) => AssocTypeData::Normal(name.to_string()), - ty::AssocTypeData::Rpitit(rpitit) => { - AssocTypeData::Rpitit(rpitit.stable(tables, cx)) - } - }, - }, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::AssocItemContainer { - type T = stable_mir::ty::AssocItemContainer; - - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { - use stable_mir::ty::AssocItemContainer; - match self { - ty::AssocItemContainer::Trait => AssocItemContainer::Trait, - ty::AssocItemContainer::Impl => AssocItemContainer::Impl, - } - } -} - -impl<'tcx> Stable<'tcx> for ty::AssocItem { - type T = stable_mir::ty::AssocItem; - - 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, cx), - container: self.container.stable(tables, cx), - trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)), - } - } -} - -impl<'tcx> Stable<'tcx> for ty::ImplTraitInTraitData { - type T = stable_mir::ty::ImplTraitInTraitData; - - 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 } => { - ImplTraitInTraitData::Trait { - fn_def_id: tables.fn_def(*fn_def_id), - opaque_def_id: tables.opaque_def(*opaque_def_id), - } - } - ty::ImplTraitInTraitData::Impl { fn_def_id } => { - ImplTraitInTraitData::Impl { fn_def_id: tables.fn_def(*fn_def_id) } - } - } - } -} - -impl<'tcx> Stable<'tcx> for rustc_middle::ty::util::Discr<'tcx> { - type T = stable_mir::ty::Discr; - - 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 deleted file mode 100644 index 77a772019eb..00000000000 --- a/compiler/rustc_smir/src/stable_mir/unstable/mod.rs +++ /dev/null @@ -1,210 +0,0 @@ -//! 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>>(self, value: T) -> Option { - TyCtxt::lift(self, value) - } - - fn mk_args_from_iter(self, iter: I) -> T::Output - where - I: Iterator, - T: ty::CollectAndApply, 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> { - TyCtxt::mk_poly_existential_predicates(self, eps) - } - - fn mk_type_list(self, v: &[Ty<'tcx>]) -> &'tcx List> { - 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(self, iter: I) -> T::Output - where - I: Iterator, - T: ty::CollectAndApply>, - { - TyCtxt::mk_bound_variable_kinds_from_iter(self, iter) - } - - fn mk_place_elems(self, v: &[mir::PlaceElem<'tcx>]) -> &'tcx List> { - 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>>(self, value: T) -> Option; - - fn mk_args_from_iter(self, iter: I) -> T::Output - where - I: Iterator, - T: ty::CollectAndApply, 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>; - - fn mk_type_list(self, v: &[Ty<'tcx>]) -> &'tcx List>; - - fn lifetimes_re_erased(self) -> ty::Region<'tcx>; - - fn mk_bound_variable_kinds_from_iter(self, iter: I) -> T::Output - where - I: Iterator, - T: ty::CollectAndApply>; - - fn mk_place_elems(self, v: &[mir::PlaceElem<'tcx>]) -> &'tcx List>; - - 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_smir/src/stable_mir/visitor.rs b/compiler/rustc_smir/src/stable_mir/visitor.rs deleted file mode 100644 index 31a53d1b19d..00000000000 --- a/compiler/rustc_smir/src/stable_mir/visitor.rs +++ /dev/null @@ -1,226 +0,0 @@ -use std::ops::ControlFlow; - -use stable_mir::Opaque; -use stable_mir::ty::TyConst; - -use super::ty::{ - Allocation, Binder, ConstDef, ExistentialPredicate, FnSig, GenericArgKind, GenericArgs, - MirConst, Promoted, Region, RigidTy, TermKind, Ty, UnevaluatedConst, -}; -use crate::stable_mir; - -pub trait Visitor: Sized { - type Break; - fn visit_ty(&mut self, ty: &Ty) -> ControlFlow { - ty.super_visit(self) - } - fn visit_const(&mut self, c: &TyConst) -> ControlFlow { - c.super_visit(self) - } - fn visit_reg(&mut self, reg: &Region) -> ControlFlow { - reg.super_visit(self) - } -} - -pub trait Visitable { - fn visit(&self, visitor: &mut V) -> ControlFlow { - self.super_visit(visitor) - } - fn super_visit(&self, visitor: &mut V) -> ControlFlow; -} - -impl Visitable for Ty { - fn visit(&self, visitor: &mut V) -> ControlFlow { - visitor.visit_ty(self) - } - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - match self.kind() { - super::ty::TyKind::RigidTy(ty) => ty.visit(visitor)?, - super::ty::TyKind::Alias(_, alias) => alias.args.visit(visitor)?, - super::ty::TyKind::Param(_) | super::ty::TyKind::Bound(_, _) => {} - } - ControlFlow::Continue(()) - } -} - -impl Visitable for TyConst { - fn visit(&self, visitor: &mut V) -> ControlFlow { - visitor.visit_const(self) - } - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - match &self.kind { - super::ty::TyConstKind::Param(_) | super::ty::TyConstKind::Bound(_, _) => {} - super::ty::TyConstKind::Unevaluated(_, args) => args.visit(visitor)?, - super::ty::TyConstKind::Value(ty, alloc) => { - alloc.visit(visitor)?; - ty.visit(visitor)?; - } - super::ty::TyConstKind::ZSTValue(ty) => ty.visit(visitor)?, - } - ControlFlow::Continue(()) - } -} - -impl Visitable for MirConst { - fn visit(&self, visitor: &mut V) -> ControlFlow { - self.super_visit(visitor) - } - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - match &self.kind() { - super::ty::ConstantKind::Ty(ct) => ct.visit(visitor)?, - super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?, - super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?, - super::ty::ConstantKind::Param(_) | super::ty::ConstantKind::ZeroSized => {} - } - self.ty().visit(visitor) - } -} - -impl Visitable for Opaque { - fn super_visit(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::Continue(()) - } -} - -impl Visitable for Allocation { - fn super_visit(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::Continue(()) - } -} - -impl Visitable for UnevaluatedConst { - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - let UnevaluatedConst { def, args, promoted } = self; - def.visit(visitor)?; - args.visit(visitor)?; - promoted.visit(visitor) - } -} - -impl Visitable for ConstDef { - fn super_visit(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::Continue(()) - } -} - -impl Visitable for Option { - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - match self { - Some(val) => val.visit(visitor), - None => ControlFlow::Continue(()), - } - } -} - -impl Visitable for Promoted { - fn super_visit(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::Continue(()) - } -} - -impl Visitable for GenericArgs { - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - self.0.visit(visitor) - } -} - -impl Visitable for Region { - fn visit(&self, visitor: &mut V) -> ControlFlow { - visitor.visit_reg(self) - } - - fn super_visit(&self, _: &mut V) -> ControlFlow { - ControlFlow::Continue(()) - } -} - -impl Visitable for GenericArgKind { - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - match self { - GenericArgKind::Lifetime(lt) => lt.visit(visitor), - GenericArgKind::Type(t) => t.visit(visitor), - GenericArgKind::Const(c) => c.visit(visitor), - } - } -} - -impl Visitable for RigidTy { - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - match self { - RigidTy::Bool - | RigidTy::Char - | RigidTy::Int(_) - | RigidTy::Uint(_) - | RigidTy::Float(_) - | RigidTy::Never - | RigidTy::Foreign(_) - | RigidTy::Str => ControlFlow::Continue(()), - RigidTy::Array(t, c) => { - t.visit(visitor)?; - c.visit(visitor) - } - RigidTy::Pat(t, _p) => t.visit(visitor), - RigidTy::Slice(inner) => inner.visit(visitor), - RigidTy::RawPtr(ty, _) => ty.visit(visitor), - RigidTy::Ref(reg, ty, _) => { - reg.visit(visitor)?; - ty.visit(visitor) - } - RigidTy::Adt(_, args) - | RigidTy::Closure(_, args) - | RigidTy::Coroutine(_, args, _) - | RigidTy::CoroutineWitness(_, args) - | RigidTy::CoroutineClosure(_, args) - | RigidTy::FnDef(_, args) => args.visit(visitor), - RigidTy::FnPtr(sig) => sig.visit(visitor), - RigidTy::Dynamic(pred, r, _) => { - pred.visit(visitor)?; - r.visit(visitor) - } - RigidTy::Tuple(fields) => fields.visit(visitor), - } - } -} - -impl Visitable for Vec { - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - for arg in self { - arg.visit(visitor)?; - } - ControlFlow::Continue(()) - } -} - -impl Visitable for Binder { - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - self.value.visit(visitor) - } -} - -impl Visitable for ExistentialPredicate { - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - match self { - ExistentialPredicate::Trait(tr) => tr.generic_args.visit(visitor), - ExistentialPredicate::Projection(p) => { - p.term.visit(visitor)?; - p.generic_args.visit(visitor) - } - ExistentialPredicate::AutoTrait(_) => ControlFlow::Continue(()), - } - } -} - -impl Visitable for TermKind { - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - match self { - TermKind::Type(t) => t.visit(visitor), - TermKind::Const(c) => c.visit(visitor), - } - } -} - -impl Visitable for FnSig { - fn super_visit(&self, visitor: &mut V) -> ControlFlow { - self.inputs_and_output.visit(visitor) - } -} diff --git a/compiler/stable_mir/Cargo.toml b/compiler/stable_mir/Cargo.toml index 516c8e9c718..6777abce01d 100644 --- a/compiler/stable_mir/Cargo.toml +++ b/compiler/stable_mir/Cargo.toml @@ -4,7 +4,18 @@ version = "0.1.0-preview" edition = "2024" [dependencies] +# tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi" } +rustc_hir = { path = "../rustc_hir" } +rustc_middle = { path = "../rustc_middle" } +rustc_session = { path = "../rustc_session" } rustc_smir = { path = "../rustc_smir" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +scoped-tls = "1.0" +serde = { version = "1.0.125", features = [ "derive" ] } +tracing = "0.1" +# tidy-alphabetical-end [features] # Provides access to APIs that expose internals of the rust compiler. diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs new file mode 100644 index 00000000000..7b0882caf1b --- /dev/null +++ b/compiler/stable_mir/src/abi.rs @@ -0,0 +1,493 @@ +use std::fmt::{self, Debug}; +use std::num::NonZero; +use std::ops::RangeInclusive; + +use serde::Serialize; + +use crate::compiler_interface::with; +use crate::mir::FieldIdx; +use crate::target::{MachineInfo, MachineSize as Size}; +use crate::ty::{Align, Ty, VariantIdx}; +use crate::{Error, Opaque, error}; + +/// A function ABI definition. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub struct FnAbi { + /// The types of each argument. + pub args: Vec, + + /// The expected return type. + pub ret: ArgAbi, + + /// The count of non-variadic arguments. + /// + /// Should only be different from `args.len()` when a function is a C variadic function. + pub fixed_count: u32, + + /// The ABI convention. + pub conv: CallConvention, + + /// Whether this is a variadic C function, + pub c_variadic: bool, +} + +/// Information about the ABI of a function's argument, or return value. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub struct ArgAbi { + pub ty: Ty, + pub layout: Layout, + pub mode: PassMode, +} + +/// How a function argument should be passed in to the target function. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub enum PassMode { + /// Ignore the argument. + /// + /// The argument is either uninhabited or a ZST. + Ignore, + /// Pass the argument directly. + /// + /// The argument has a layout abi of `Scalar` or `Vector`. + Direct(Opaque), + /// Pass a pair's elements directly in two arguments. + /// + /// The argument has a layout abi of `ScalarPair`. + Pair(Opaque, Opaque), + /// Pass the argument after casting it. + Cast { pad_i32: bool, cast: Opaque }, + /// Pass the argument indirectly via a hidden pointer. + Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool }, +} + +/// The layout of a type, alongside the type itself. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub struct TyAndLayout { + pub ty: Ty, + pub layout: Layout, +} + +/// The layout of a type in memory. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub struct LayoutShape { + /// The fields location within the layout + pub fields: FieldsShape, + + /// Encodes information about multi-variant layouts. + /// Even with `Multiple` variants, a layout still has its own fields! Those are then + /// shared between all variants. + /// + /// To access all fields of this layout, both `fields` and the fields of the active variant + /// must be taken into account. + pub variants: VariantsShape, + + /// The `abi` defines how this data is passed between functions. + pub abi: ValueAbi, + + /// The ABI mandated alignment in bytes. + pub abi_align: Align, + + /// The size of this layout in bytes. + pub size: Size, +} + +impl LayoutShape { + /// Returns `true` if the layout corresponds to an unsized type. + #[inline] + pub fn is_unsized(&self) -> bool { + self.abi.is_unsized() + } + + #[inline] + pub fn is_sized(&self) -> bool { + !self.abi.is_unsized() + } + + /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). + pub fn is_1zst(&self) -> bool { + self.is_sized() && self.size.bits() == 0 && self.abi_align == 1 + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub struct Layout(usize); + +impl Layout { + pub fn shape(self) -> LayoutShape { + with(|cx| cx.layout_shape(self)) + } +} + +impl crate::IndexedVal for Layout { + fn to_val(index: usize) -> Self { + Layout(index) + } + fn to_index(&self) -> usize { + self.0 + } +} + +/// Describes how the fields of a type are shaped in memory. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub enum FieldsShape { + /// Scalar primitives and `!`, which never have fields. + Primitive, + + /// All fields start at no offset. The `usize` is the field count. + Union(NonZero), + + /// Array/vector-like placement, with all fields of identical types. + Array { stride: Size, count: u64 }, + + /// Struct-like placement, with precomputed offsets. + /// + /// Fields are guaranteed to not overlap, but note that gaps + /// before, between and after all the fields are NOT always + /// padding, and as such their contents may not be discarded. + /// For example, enum variants leave a gap at the start, + /// where the discriminant field in the enum layout goes. + Arbitrary { + /// Offsets for the first byte of each field, + /// ordered to match the source definition order. + /// I.e.: It follows the same order as [super::ty::VariantDef::fields()]. + /// This vector does not go in increasing order. + offsets: Vec, + }, +} + +impl FieldsShape { + pub fn fields_by_offset_order(&self) -> Vec { + match self { + FieldsShape::Primitive => vec![], + FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(), + FieldsShape::Arbitrary { offsets, .. } => { + let mut indices = (0..offsets.len()).collect::>(); + indices.sort_by_key(|idx| offsets[*idx]); + indices + } + } + } + + pub fn count(&self) -> usize { + match self { + FieldsShape::Primitive => 0, + FieldsShape::Union(count) => count.get(), + FieldsShape::Array { count, .. } => *count as usize, + FieldsShape::Arbitrary { offsets, .. } => offsets.len(), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub enum VariantsShape { + /// A type with no valid variants. Must be uninhabited. + Empty, + + /// Single enum variants, structs/tuples, unions, and all non-ADTs. + Single { index: VariantIdx }, + + /// Enum-likes with more than one inhabited variant: each variant comes with + /// a *discriminant* (usually the same as the variant index but the user can + /// assign explicit discriminant values). That discriminant is encoded + /// as a *tag* on the machine. The layout of each variant is + /// a struct, and they all have space reserved for the tag. + /// For enums, the tag is the sole field of the layout. + Multiple { + tag: Scalar, + tag_encoding: TagEncoding, + tag_field: usize, + variants: Vec, + }, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub enum TagEncoding { + /// The tag directly stores the discriminant, but possibly with a smaller layout + /// (so converting the tag to the discriminant can require sign extension). + Direct, + + /// Niche (values invalid for a type) encoding the discriminant: + /// Discriminant and variant index coincide. + /// The variant `untagged_variant` contains a niche at an arbitrary + /// offset (field `tag_field` of the enum), which for a variant with + /// discriminant `d` is set to + /// `(d - niche_variants.start).wrapping_add(niche_start)`. + /// + /// For example, `Option<(usize, &T)>` is represented such that + /// `None` has a null pointer for the second tuple field, and + /// `Some` is the identity function (with a non-null reference). + Niche { + untagged_variant: VariantIdx, + niche_variants: RangeInclusive, + niche_start: u128, + }, +} + +/// Describes how values of the type are passed by target ABIs, +/// in terms of categories of C types there are ABI rules for. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub enum ValueAbi { + Scalar(Scalar), + ScalarPair(Scalar, Scalar), + Vector { + element: Scalar, + count: u64, + }, + Aggregate { + /// If true, the size is exact, otherwise it's only a lower bound. + sized: bool, + }, +} + +impl ValueAbi { + /// Returns `true` if the layout corresponds to an unsized type. + pub fn is_unsized(&self) -> bool { + match *self { + ValueAbi::Scalar(_) | ValueAbi::ScalarPair(..) | ValueAbi::Vector { .. } => false, + ValueAbi::Aggregate { sized } => !sized, + } + } +} + +/// Information about one scalar component of a Rust type. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)] +pub enum Scalar { + Initialized { + /// The primitive type used to represent this value. + value: Primitive, + /// The range that represents valid values. + /// The range must be valid for the `primitive` size. + valid_range: WrappingRange, + }, + Union { + /// Unions never have niches, so there is no `valid_range`. + /// Even for unions, we need to use the correct registers for the kind of + /// values inside the union, so we keep the `Primitive` type around. + /// It is also used to compute the size of the scalar. + value: Primitive, + }, +} + +impl Scalar { + pub fn has_niche(&self, target: &MachineInfo) -> bool { + match self { + Scalar::Initialized { value, valid_range } => { + !valid_range.is_full(value.size(target)).unwrap() + } + Scalar::Union { .. } => false, + } + } +} + +/// Fundamental unit of memory access and layout. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize)] +pub enum Primitive { + /// The `bool` is the signedness of the `Integer` type. + /// + /// One would think we would not care about such details this low down, + /// but some ABIs are described in terms of C types and ISAs where the + /// integer arithmetic is done on {sign,zero}-extended registers, e.g. + /// a negative integer passed by zero-extension will appear positive in + /// the callee, and most operations on it will produce the wrong values. + Int { + length: IntegerLength, + signed: bool, + }, + Float { + length: FloatLength, + }, + Pointer(AddressSpace), +} + +impl Primitive { + pub fn size(self, target: &MachineInfo) -> Size { + match self { + Primitive::Int { length, .. } => Size::from_bits(length.bits()), + Primitive::Float { length } => Size::from_bits(length.bits()), + Primitive::Pointer(_) => target.pointer_width, + } + } +} + +/// Enum representing the existing integer lengths. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub enum IntegerLength { + I8, + I16, + I32, + I64, + I128, +} + +/// Enum representing the existing float lengths. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub enum FloatLength { + F16, + F32, + F64, + F128, +} + +impl IntegerLength { + pub fn bits(self) -> usize { + match self { + IntegerLength::I8 => 8, + IntegerLength::I16 => 16, + IntegerLength::I32 => 32, + IntegerLength::I64 => 64, + IntegerLength::I128 => 128, + } + } +} + +impl FloatLength { + pub fn bits(self) -> usize { + match self { + FloatLength::F16 => 16, + FloatLength::F32 => 32, + FloatLength::F64 => 64, + FloatLength::F128 => 128, + } + } +} + +/// An identifier that specifies the address space that some operation +/// should operate on. Special address spaces have an effect on code generation, +/// depending on the target and the address spaces it implements. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] +pub struct AddressSpace(pub u32); + +impl AddressSpace { + /// The default address space, corresponding to data space. + pub const DATA: Self = AddressSpace(0); +} + +/// Inclusive wrap-around range of valid values (bitwise representation), that is, if +/// start > end, it represents `start..=MAX`, followed by `0..=end`. +/// +/// That is, for an i8 primitive, a range of `254..=2` means following +/// sequence: +/// +/// 254 (-2), 255 (-1), 0, 1, 2 +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)] +pub struct WrappingRange { + pub start: u128, + pub end: u128, +} + +impl WrappingRange { + /// Returns `true` if `size` completely fills the range. + #[inline] + pub fn is_full(&self, size: Size) -> Result { + let Some(max_value) = size.unsigned_int_max() else { + return Err(error!("Expected size <= 128 bits, but found {} instead", size.bits())); + }; + if self.start <= max_value && self.end <= max_value { + Ok(self.start == (self.end.wrapping_add(1) & max_value)) + } else { + Err(error!("Range `{self:?}` out of bounds for size `{}` bits.", size.bits())) + } + } + + /// Returns `true` if `v` is contained in the range. + #[inline(always)] + pub fn contains(&self, v: u128) -> bool { + if self.wraps_around() { + self.start <= v || v <= self.end + } else { + self.start <= v && v <= self.end + } + } + + /// Returns `true` if the range wraps around. + /// I.e., the range represents the union of `self.start..=MAX` and `0..=self.end`. + /// Returns `false` if this is a non-wrapping range, i.e.: `self.start..=self.end`. + #[inline] + pub fn wraps_around(&self) -> bool { + self.start > self.end + } +} + +impl Debug for WrappingRange { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.start > self.end { + write!(fmt, "(..={}) | ({}..)", self.end, self.start)?; + } else { + write!(fmt, "{}..={}", self.start, self.end)?; + } + Ok(()) + } +} + +/// General language calling conventions. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub enum CallConvention { + C, + Rust, + + Cold, + PreserveMost, + PreserveAll, + + Custom, + + // Target-specific calling conventions. + ArmAapcs, + CCmseNonSecureCall, + CCmseNonSecureEntry, + + Msp430Intr, + + PtxKernel, + + GpuKernel, + + X86Fastcall, + X86Intr, + X86Stdcall, + X86ThisCall, + X86VectorCall, + + X86_64SysV, + X86_64Win64, + + AvrInterrupt, + AvrNonBlockingInterrupt, + + RiscvInterrupt, +} + +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub struct ReprFlags { + pub is_simd: bool, + pub is_c: bool, + pub is_transparent: bool, + pub is_linear: bool, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub enum IntegerType { + /// Pointer-sized integer type, i.e. `isize` and `usize`. + Pointer { + /// Signedness. e.g. `true` for `isize` + is_signed: bool, + }, + /// Fixed-sized integer type, e.g. `i8`, `u32`, `i128`. + Fixed { + /// Length of this integer type. e.g. `IntegerLength::I8` for `u8`. + length: IntegerLength, + /// Signedness. e.g. `false` for `u8` + is_signed: bool, + }, +} + +/// Representation options provided by the user +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub struct ReprOptions { + pub int: Option, + pub align: Option, + pub pack: Option, + pub flags: ReprFlags, +} diff --git a/compiler/stable_mir/src/alloc.rs b/compiler/stable_mir/src/alloc.rs new file mode 100644 index 00000000000..349b83231e3 --- /dev/null +++ b/compiler/stable_mir/src/alloc.rs @@ -0,0 +1,76 @@ +//! 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; + +/// 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 { + 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/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs new file mode 100644 index 00000000000..50c2f02e6ad --- /dev/null +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -0,0 +1,1099 @@ +//! Define the interface with the Rust compiler. +//! +//! StableMIR users should not use any of the items in this module directly. +//! These APIs have no stability guarantee. + +use std::cell::Cell; + +use rustc_hir::def::DefKind; +use rustc_smir::context::SmirCtxt; +use rustc_smir::{Bridge, SmirContainer}; +use tracing::debug; + +use crate::abi::{FnAbi, Layout, LayoutShape, ReprOptions}; +use crate::crate_def::Attribute; +use crate::mir::alloc::{AllocId, GlobalAlloc}; +use crate::mir::mono::{Instance, InstanceDef, StaticDef}; +use crate::mir::{BinOp, Body, Place, UnOp}; +use crate::target::{MachineInfo, MachineSize}; +use crate::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 crate::unstable::{RustcInternal, Stable, new_item_kind}; +use crate::{ + AssocItems, Crate, CrateDef, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, + ImplTraitDecls, ItemKind, Symbol, TraitDecls, alloc, mir, +}; + +pub struct BridgeTys; + +impl Bridge for BridgeTys { + type DefId = crate::DefId; + type AllocId = crate::mir::alloc::AllocId; + type Span = crate::ty::Span; + type Ty = crate::ty::Ty; + type InstanceDef = crate::mir::mono::InstanceDef; + type TyConstId = crate::ty::TyConstId; + type MirConstId = crate::ty::MirConstId; + type Layout = crate::abi::Layout; + + type Error = crate::Error; + type CrateItem = crate::CrateItem; + type AdtDef = crate::ty::AdtDef; + type ForeignModuleDef = crate::ty::ForeignModuleDef; + type ForeignDef = crate::ty::ForeignDef; + type FnDef = crate::ty::FnDef; + type ClosureDef = crate::ty::ClosureDef; + type CoroutineDef = crate::ty::CoroutineDef; + type CoroutineClosureDef = crate::ty::CoroutineClosureDef; + type AliasDef = crate::ty::AliasDef; + type ParamDef = crate::ty::ParamDef; + type BrNamedDef = crate::ty::BrNamedDef; + type TraitDef = crate::ty::TraitDef; + type GenericDef = crate::ty::GenericDef; + type ConstDef = crate::ty::ConstDef; + type ImplDef = crate::ty::ImplDef; + type RegionDef = crate::ty::RegionDef; + type CoroutineWitnessDef = crate::ty::CoroutineWitnessDef; + type AssocDef = crate::ty::AssocDef; + type OpaqueDef = crate::ty::OpaqueDef; + type Prov = crate::ty::Prov; + type StaticDef = crate::mir::mono::StaticDef; + + type Allocation = crate::ty::Allocation; +} + +/// Stable public API for querying compiler information. +/// +/// All queries are delegated to [`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) trait SmirInterface { + fn entry_fn(&self) -> Option; + /// 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; + + /// Retrieve all functions defined in this crate. + fn crate_functions(&self, crate_num: CrateNum) -> Vec; + + /// Retrieve all static items defined in this crate. + fn crate_statics(&self, crate_num: CrateNum) -> Vec; + fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule; + fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec; + 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; + + /// Find a crate with the given name. + fn find_crates(&self, name: &str) -> Vec; + + /// 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; + + /// Get all tool attributes of a definition. + fn all_tool_attrs(&self, def_id: DefId) -> Vec; + + /// 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; + + /// 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; + + /// Evaluate constant as a target usize. + fn eval_target_usize(&self, cnst: &MirConst) -> Result; + fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result; + + /// Create a new zero-sized constant. + fn try_new_const_zst(&self, ty: Ty) -> Result; + + /// 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; + fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result; + + /// Create a new type from the given kind. + fn new_rigid_ty(&self, kind: RigidTy) -> Ty; + + /// Create a new box type, `Box`, 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; + + /// 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; + + /// 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; + + /// Resolve instance for a closure with the requested type. + fn resolve_closure( + &self, + def: ClosureDef, + args: &GenericArgs, + kind: ClosureKind, + ) -> Option; + + /// Evaluate a static's initializer. + fn eval_static_initializer(&self, def: StaticDef) -> Result; + + /// Try to evaluate an instance into a constant. + fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result; + + /// 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; + 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; + + /// Get the ABI of a function pointer. + fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result; + + /// Get the layout of a type. + fn ty_layout(&self, ty: Ty) -> Result; + + /// 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 for SmirContainer<'tcx, BridgeTys> { + fn entry_fn(&self) -> Option { + 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. + 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. + 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. + 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) + } + + fn foreign_modules(&self, crate_num: CrateNum) -> Vec { + 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. + fn crate_functions(&self, crate_num: CrateNum) -> Vec { + 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. + fn crate_statics(&self, crate_num: CrateNum) -> Vec { + 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() + } + + 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) + } + + fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec { + 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() + } + + 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() + } + + 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() + } + + 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) + } + + 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() + } + + 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() + } + + 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) + } + + 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) + } + + 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); + crate::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(), + } + } + + 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); + crate::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. + fn local_crate(&self) -> Crate { + let cx = &*self.cx.borrow(); + smir_crate(cx, cx.local_crate_num()) + } + + /// Retrieve a list of all external crates. + fn external_crates(&self) -> Vec { + 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. + fn find_crates(&self, name: &str) -> Vec { + 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`. + 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. + /// + /// 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 { + 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. + fn all_tool_attrs(&self, def_id: DefId) -> Vec { + 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`. + 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. + 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`. + 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`. + 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. + 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. + 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. + 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. + 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. + 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. + 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 + 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. + 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. + fn intrinsic(&self, item: DefId) -> Option { + 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. + 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. + 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. + 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. + 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. + fn coroutine_discr_for_variant( + &self, + coroutine: CoroutineDef, + args: &GenericArgs, + variant: VariantIdx, + ) -> Discr { + 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. + 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)) + } + + fn variant_fields(&self, def: VariantDef) -> Vec { + 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. + fn eval_target_usize(&self, mir_const: &MirConst) -> Result { + 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) + } + + fn eval_target_usize_ty(&self, ty_const: &TyConst) -> Result { + 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. + fn try_new_const_zst(&self, ty: Ty) -> Result { + 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. + 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. + 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. + fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { + 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)) + } + + fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { + 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. + 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`, for the given inner type `T`. + 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. + 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. + 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. + 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. + 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) + } + + 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. + 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 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. + 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. + fn instance_body(&self, instance: InstanceDef) -> Option { + 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. + 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. + 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. + 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. + 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. + 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. + 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. + 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. + fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option { + 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. + 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. + fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option { + 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. + fn resolve_closure( + &self, + def: ClosureDef, + args: &GenericArgs, + kind: ClosureKind, + ) -> Option { + 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. + fn eval_static_initializer(&self, def: StaticDef) -> Result { + 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. + fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result { + 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. + 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. + fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option { + 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)) + } + + fn krate(&self, def_id: DefId) -> Crate { + let tables = self.tables.borrow(); + let cx = &*self.cx.borrow(); + smir_crate(cx, tables[def_id].krate) + } + + 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. + 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. + fn instance_abi(&self, def: InstanceDef) -> Result { + 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. + fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { + 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. + fn ty_layout(&self, ty: Ty) -> Result { + 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. + 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. + 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. + 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. + 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. + 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(interface: &dyn SmirInterface, f: F) -> Result +where + F: FnOnce() -> T, +{ + if TLV.is_set() { + Err(Error::from("StableMIR already running")) + } else { + let ptr: *const () = (&raw const interface) as _; + TLV.set(&Cell::new(ptr), || Ok(f())) + } +} + +/// Execute the given function with access the [`SmirInterface`]. +/// +/// 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(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 &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/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs new file mode 100644 index 00000000000..75228135e4c --- /dev/null +++ b/compiler/stable_mir/src/crate_def.rs @@ -0,0 +1,174 @@ +//! Module that define a common trait for things that represent a crate definition, +//! such as, a function, a trait, an enum, and any other definitions. + +use serde::Serialize; + +use crate::ty::{GenericArgs, Span, Ty}; +use crate::{AssocItems, Crate, Symbol, with}; + +/// A unique identification number for each item accessible for the current compilation unit. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)] +pub struct DefId(pub(crate) usize); + +impl DefId { + /// Return fully qualified name of this definition + pub fn name(&self) -> Symbol { + with(|cx| cx.def_name(*self, false)) + } + + /// Return a trimmed name of this definition. + /// + /// This can be used to print more user friendly diagnostic messages. + /// + /// If a symbol name can only be imported from one place for a type, and as + /// long as it was not glob-imported anywhere in the current crate, we trim its + /// path and print only the name. + /// + /// For example, this function may shorten `std::vec::Vec` to just `Vec`, + /// as long as there is no other `Vec` importable anywhere. + pub fn trimmed_name(&self) -> Symbol { + with(|cx| cx.def_name(*self, true)) + } +} + +/// A trait for retrieving information about a particular definition. +/// +/// Implementors must provide the implementation of `def_id` which will be used to retrieve +/// information about a crate's definition. +pub trait CrateDef { + /// Retrieve the unique identifier for the current definition. + fn def_id(&self) -> DefId; + + /// Return the fully qualified name of the current definition. + /// + /// See [`DefId::name`] for more details + fn name(&self) -> Symbol { + self.def_id().name() + } + + /// Return a trimmed name of this definition. + /// + /// See [`DefId::trimmed_name`] for more details + fn trimmed_name(&self) -> Symbol { + self.def_id().trimmed_name() + } + + /// Return information about the crate where this definition is declared. + /// + /// This will return the crate number and its name. + fn krate(&self) -> Crate { + let def_id = self.def_id(); + with(|cx| cx.krate(def_id)) + } + + /// Return the span of this definition. + fn span(&self) -> Span { + let def_id = self.def_id(); + with(|cx| cx.span_of_an_item(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()]`. + fn tool_attrs(&self, attr: &[Symbol]) -> Vec { + let def_id = self.def_id(); + with(|cx| cx.tool_attrs(def_id, attr)) + } + + /// Return all tool attributes of this definition. + fn all_tool_attrs(&self) -> Vec { + let def_id = self.def_id(); + with(|cx| cx.all_tool_attrs(def_id)) + } +} + +/// A trait that can be used to retrieve a definition's type. +/// +/// Note that not every CrateDef has a type `Ty`. They should not implement this trait. +pub trait CrateDefType: CrateDef { + /// Returns the type of this crate item. + fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.def_id())) + } + + /// Retrieve the type of this definition by instantiating and normalizing it with `args`. + /// + /// This will panic if instantiation fails. + fn ty_with_args(&self, args: &GenericArgs) -> Ty { + with(|cx| cx.def_ty_with_args(self.def_id(), args)) + } +} + +/// A trait for retrieving all items from a definition within a crate. +pub trait CrateDefItems: CrateDef { + /// Retrieve all associated items from a definition. + fn associated_items(&self) -> AssocItems { + with(|cx| cx.associated_items(self.def_id())) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Attribute { + value: String, + span: Span, +} + +impl Attribute { + pub fn new(value: String, span: Span) -> Attribute { + Attribute { value, span } + } + + /// Get the span of this attribute. + pub fn span(&self) -> Span { + self.span + } + + /// Get the string representation of this attribute. + pub fn as_str(&self) -> &str { + &self.value + } +} + +macro_rules! crate_def { + ( $(#[$attr:meta])* + $vis:vis $name:ident $(;)? + ) => { + $(#[$attr])* + #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] + $vis struct $name(pub DefId); + + impl CrateDef for $name { + fn def_id(&self) -> DefId { + self.0 + } + } + }; +} + +macro_rules! crate_def_with_ty { + ( $(#[$attr:meta])* + $vis:vis $name:ident $(;)? + ) => { + $(#[$attr])* + #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] + $vis struct $name(pub DefId); + + impl CrateDef for $name { + fn def_id(&self) -> DefId { + self.0 + } + } + + impl CrateDefType for $name {} + }; +} + +macro_rules! impl_crate_def_items { + ( $name:ident $(;)? ) => { + impl CrateDefItems for $name {} + }; +} diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs new file mode 100644 index 00000000000..702134b0c4c --- /dev/null +++ b/compiler/stable_mir/src/error.rs @@ -0,0 +1,91 @@ +//! When things go wrong, we need some error handling. +//! There are a few different types of errors in StableMIR: +//! +//! - [CompilerError]: This represents errors that can be raised when invoking the compiler. +//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled. + +use std::fmt::{Debug, Display, Formatter}; +use std::{fmt, io}; + +use rustc_smir::bridge::SmirError; + +macro_rules! error { + ($fmt: literal $(,)?) => { Error(format!($fmt)) }; + ($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg)*)) }; +} + +pub(crate) use error; + +/// An error type used to represent an error that has already been reported by the compiler. +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum CompilerError { + /// Compilation failed, either due to normal errors or ICE. + Failed, + /// Compilation was interrupted. + Interrupted(T), + /// Compilation skipped. This happens when users invoke rustc to retrieve information such as + /// --version. + Skipped, +} + +/// A generic error to represent an API request that cannot be fulfilled. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Error(pub(crate) String); + +impl SmirError for Error { + fn new(msg: String) -> Self { + Self(msg) + } + + fn from_internal(err: T) -> Self { + Self(format!("{err:?}")) + } +} + +impl From<&str> for Error { + fn from(value: &str) -> Self { + Self(value.into()) + } +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl Display for CompilerError +where + T: Display, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + CompilerError::Failed => write!(f, "Compilation Failed"), + CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason}"), + CompilerError::Skipped => write!(f, "Compilation Skipped"), + } + } +} + +impl Debug for CompilerError +where + T: Debug, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + CompilerError::Failed => write!(f, "Compilation Failed"), + CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason:?}"), + CompilerError::Skipped => write!(f, "Compilation Skipped"), + } + } +} + +impl std::error::Error for Error {} + +impl std::error::Error for CompilerError where T: Display + Debug {} + +impl From for Error { + fn from(value: io::Error) -> Self { + Error(value.to_string()) + } +} diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 688f3936b26..0a2e4e71afc 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -1,11 +1,300 @@ -//! We've temporarily moved the `stable_mir` implementation to [`rustc_smir::stable_mir`], -//! during refactoring to break the circular dependency between `rustc_smir` and `stable_mir`, +//! The WIP stable interface to rustc internals. //! -//! This is a transitional measure as described in [PR #139319](https://github.com/rust-lang/rust/pull/139319). -//! Once the refactoring is complete, the `stable_mir` implementation will be moved back here. +//! For more information see +//! +//! # Note +//! +//! This API is still completely unstable and subject to change. +#![allow(rustc::usage_of_ty_tykind)] +#![doc( + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", + test(attr(allow(unused_variables), deny(warnings))) +)] +#![feature(sized_hierarchy)] +//! +//! This crate shall contain all type definitions and APIs that we expect third-party tools to invoke to +//! interact with the compiler. +//! +//! The goal is to eventually be published on +//! [crates.io](https://crates.io). + +use std::fmt::Debug; +use std::{fmt, io}; + +pub(crate) use rustc_smir::IndexedVal; +use rustc_smir::Tables; +use rustc_smir::context::SmirCtxt; /// Export the rustc_internal APIs. Note that this module has no stability /// guarantees and it is not taken into account for semver. #[cfg(feature = "rustc_internal")] -pub use rustc_smir::rustc_internal; -pub use rustc_smir::stable_mir::*; +pub mod rustc_internal; +use serde::Serialize; + +use crate::compiler_interface::with; +pub use crate::crate_def::{CrateDef, CrateDefItems, CrateDefType, DefId}; +pub use crate::error::*; +use crate::mir::mono::StaticDef; +use crate::mir::{Body, Mutability}; +use crate::ty::{AssocItem, FnDef, ForeignModuleDef, ImplDef, ProvenanceMap, Span, TraitDef, Ty}; +use crate::unstable::Stable; + +pub mod abi; +mod alloc; +pub(crate) mod unstable; +#[macro_use] +pub mod crate_def; +pub mod compiler_interface; +#[macro_use] +pub mod error; +pub mod mir; +pub mod target; +pub mod ty; +pub mod visitor; + +/// Use String for now but we should replace it. +pub type Symbol = String; + +/// The number that identifies a crate. +pub type CrateNum = usize; + +impl Debug for DefId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DefId").field("id", &self.0).field("name", &self.name()).finish() + } +} + +impl IndexedVal for DefId { + fn to_val(index: usize) -> Self { + DefId(index) + } + + fn to_index(&self) -> usize { + self.0 + } +} + +/// A list of crate items. +pub type CrateItems = Vec; + +/// A list of trait decls. +pub type TraitDecls = Vec; + +/// A list of impl trait decls. +pub type ImplTraitDecls = Vec; + +/// A list of associated items. +pub type AssocItems = Vec; + +/// Holds information about a crate. +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] +pub struct Crate { + pub id: CrateNum, + pub name: Symbol, + pub is_local: bool, +} + +impl Crate { + /// The list of foreign modules in this crate. + pub fn foreign_modules(&self) -> Vec { + with(|cx| cx.foreign_modules(self.id)) + } + + /// The list of traits declared in this crate. + pub fn trait_decls(&self) -> TraitDecls { + with(|cx| cx.trait_decls(self.id)) + } + + /// The list of trait implementations in this crate. + pub fn trait_impls(&self) -> ImplTraitDecls { + with(|cx| cx.trait_impls(self.id)) + } + + /// Return a list of function definitions from this crate independent on their visibility. + pub fn fn_defs(&self) -> Vec { + with(|cx| cx.crate_functions(self.id)) + } + + /// Return a list of static items defined in this crate independent on their visibility. + pub fn statics(&self) -> Vec { + with(|cx| cx.crate_statics(self.id)) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] +pub enum ItemKind { + Fn, + Static, + Const, + Ctor(CtorKind), +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] +pub enum CtorKind { + Const, + Fn, +} + +pub type Filename = String; + +crate_def_with_ty! { + /// Holds information about an item in a crate. + #[derive(Serialize)] + pub CrateItem; +} + +impl CrateItem { + /// This will return the body of an item or panic if it's not available. + pub fn expect_body(&self) -> mir::Body { + with(|cx| cx.mir_body(self.0)) + } + + /// Return the body of an item if available. + pub fn body(&self) -> Option { + with(|cx| cx.has_body(self.0).then(|| cx.mir_body(self.0))) + } + + /// Check if a body is available for this item. + pub fn has_body(&self) -> bool { + with(|cx| cx.has_body(self.0)) + } + + pub fn span(&self) -> Span { + with(|cx| cx.span_of_an_item(self.0)) + } + + pub fn kind(&self) -> ItemKind { + with(|cx| cx.item_kind(*self)) + } + + pub fn requires_monomorphization(&self) -> bool { + with(|cx| cx.requires_monomorphization(self.0)) + } + + pub fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.0)) + } + + pub fn is_foreign_item(&self) -> bool { + with(|cx| cx.is_foreign_item(self.0)) + } + + /// Emit MIR for this item body. + pub fn emit_mir(&self, w: &mut W) -> io::Result<()> { + self.body() + .ok_or_else(|| io::Error::other(format!("No body found for `{}`", self.name())))? + .dump(w, &self.name()) + } +} + +/// Return the function where execution starts if the current +/// crate defines that. This is usually `main`, but could be +/// `start` if the crate is a no-std crate. +pub fn entry_fn() -> Option { + with(|cx| cx.entry_fn()) +} + +/// Access to the local crate. +pub fn local_crate() -> Crate { + with(|cx| cx.local_crate()) +} + +/// Try to find a crate or crates if multiple crates exist from given name. +pub fn find_crates(name: &str) -> Vec { + with(|cx| cx.find_crates(name)) +} + +/// Try to find a crate with the given name. +pub fn external_crates() -> Vec { + with(|cx| cx.external_crates()) +} + +/// Retrieve all items in the local crate that have a MIR associated with them. +pub fn all_local_items() -> CrateItems { + with(|cx| cx.all_local_items()) +} + +pub fn all_trait_decls() -> TraitDecls { + with(|cx| cx.all_trait_decls()) +} + +pub fn all_trait_impls() -> ImplTraitDecls { + with(|cx| cx.all_trait_impls()) +} + +/// A type that provides internal information but that can still be used for debug purpose. +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub struct Opaque(String); + +impl std::fmt::Display for Opaque { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::fmt::Debug for Opaque { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +pub fn opaque(value: &T) -> Opaque { + Opaque(format!("{value:?}")) +} + +macro_rules! bridge_impl { + ($name: ident, $ty: ty) => { + impl rustc_smir::bridge::$name for $ty { + fn new(def: crate::DefId) -> Self { + Self(def) + } + } + }; +} + +bridge_impl!(CrateItem, crate::CrateItem); +bridge_impl!(AdtDef, crate::ty::AdtDef); +bridge_impl!(ForeignModuleDef, crate::ty::ForeignModuleDef); +bridge_impl!(ForeignDef, crate::ty::ForeignDef); +bridge_impl!(FnDef, crate::ty::FnDef); +bridge_impl!(ClosureDef, crate::ty::ClosureDef); +bridge_impl!(CoroutineDef, crate::ty::CoroutineDef); +bridge_impl!(CoroutineClosureDef, crate::ty::CoroutineClosureDef); +bridge_impl!(AliasDef, crate::ty::AliasDef); +bridge_impl!(ParamDef, crate::ty::ParamDef); +bridge_impl!(BrNamedDef, crate::ty::BrNamedDef); +bridge_impl!(TraitDef, crate::ty::TraitDef); +bridge_impl!(GenericDef, crate::ty::GenericDef); +bridge_impl!(ConstDef, crate::ty::ConstDef); +bridge_impl!(ImplDef, crate::ty::ImplDef); +bridge_impl!(RegionDef, crate::ty::RegionDef); +bridge_impl!(CoroutineWitnessDef, crate::ty::CoroutineWitnessDef); +bridge_impl!(AssocDef, crate::ty::AssocDef); +bridge_impl!(OpaqueDef, crate::ty::OpaqueDef); +bridge_impl!(StaticDef, crate::mir::mono::StaticDef); + +impl rustc_smir::bridge::Prov for crate::ty::Prov { + fn new(aid: crate::mir::alloc::AllocId) -> Self { + Self(aid) + } +} + +impl rustc_smir::bridge::Allocation for crate::ty::Allocation { + fn new<'tcx>( + bytes: Vec>, + 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/stable_mir/src/mir.rs b/compiler/stable_mir/src/mir.rs new file mode 100644 index 00000000000..413b5152bb3 --- /dev/null +++ b/compiler/stable_mir/src/mir.rs @@ -0,0 +1,8 @@ +pub mod alloc; +mod body; +pub mod mono; +pub mod pretty; +pub mod visit; + +pub use body::*; +pub use visit::{MirVisitor, MutMirVisitor}; diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs new file mode 100644 index 00000000000..0d45e59885c --- /dev/null +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -0,0 +1,87 @@ +//! This module provides methods to retrieve allocation information, such as static variables. + +use std::io::Read; + +use serde::Serialize; + +use crate::mir::mono::{Instance, StaticDef}; +use crate::target::{Endian, MachineInfo}; +use crate::ty::{Allocation, Binder, ExistentialTraitRef, Ty}; +use crate::{Error, IndexedVal, with}; + +/// An allocation in the SMIR global memory can be either a function pointer, +/// a static, or a "real" allocation with some data in it. +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] +pub enum GlobalAlloc { + /// The alloc ID is used as a function pointer. + Function(Instance), + /// This alloc ID points to a symbolic (not-reified) vtable. + /// The `None` trait ref is used to represent auto traits. + VTable(Ty, Option>), + /// The alloc ID points to a "lazy" static variable that did not get computed (yet). + /// This is also used to break the cycle in recursive statics. + Static(StaticDef), + /// The alloc ID points to memory. + Memory(Allocation), +} + +impl From for GlobalAlloc { + fn from(value: AllocId) -> Self { + with(|cx| cx.global_alloc(value)) + } +} + +impl GlobalAlloc { + /// Retrieve the allocation id for a global allocation if it exists. + /// + /// For `[GlobalAlloc::VTable]`, this will return the allocation for the VTable of the given + /// type for the optional trait if the type implements the trait. + /// + /// This method will always return `None` for allocations other than `[GlobalAlloc::VTable]`. + pub fn vtable_allocation(&self) -> Option { + with(|cx| cx.vtable_allocation(self)) + } +} + +/// A unique identification number for each provenance +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] +pub struct AllocId(usize); + +impl IndexedVal for AllocId { + fn to_val(index: usize) -> Self { + AllocId(index) + } + fn to_index(&self) -> usize { + self.0 + } +} + +/// Utility function used to read an allocation data into a unassigned integer. +pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result { + let mut buf = [0u8; size_of::()]; + match MachineInfo::target_endianness() { + Endian::Little => { + bytes.read_exact(&mut buf[..bytes.len()])?; + Ok(u128::from_le_bytes(buf)) + } + Endian::Big => { + bytes.read_exact(&mut buf[16 - bytes.len()..])?; + Ok(u128::from_be_bytes(buf)) + } + } +} + +/// Utility function used to read an allocation data into an assigned integer. +pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result { + let mut buf = [0u8; size_of::()]; + match MachineInfo::target_endianness() { + Endian::Little => { + bytes.read_exact(&mut buf[..bytes.len()])?; + Ok(i128::from_le_bytes(buf)) + } + Endian::Big => { + bytes.read_exact(&mut buf[16 - bytes.len()..])?; + Ok(i128::from_be_bytes(buf)) + } + } +} diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs new file mode 100644 index 00000000000..a9fe3607232 --- /dev/null +++ b/compiler/stable_mir/src/mir/body.rs @@ -0,0 +1,1127 @@ +use std::io; + +use serde::Serialize; + +use crate::compiler_interface::with; +use crate::mir::pretty::function_body; +use crate::ty::{ + AdtDef, ClosureDef, CoroutineClosureDef, CoroutineDef, GenericArgs, MirConst, Movability, + Region, RigidTy, Ty, TyConst, TyKind, VariantIdx, +}; +use crate::{Error, Opaque, Span, Symbol}; + +/// The SMIR representation of a single function. +#[derive(Clone, Debug, Serialize)] +pub struct Body { + pub blocks: Vec, + + /// Declarations of locals within the function. + /// + /// The first local is the return value pointer, followed by `arg_count` + /// locals for the function arguments, followed by any user-declared + /// variables and temporaries. + pub(super) locals: LocalDecls, + + /// The number of arguments this function takes. + pub(super) arg_count: usize, + + /// Debug information pertaining to user variables, including captures. + pub var_debug_info: Vec, + + /// Mark an argument (which must be a tuple) as getting passed as its individual components. + /// + /// This is used for the "rust-call" ABI such as closures. + pub(super) spread_arg: Option, + + /// The span that covers the entire function body. + pub span: Span, +} + +pub type BasicBlockIdx = usize; + +impl Body { + /// Constructs a `Body`. + /// + /// A constructor is required to build a `Body` from outside the crate + /// because the `arg_count` and `locals` fields are private. + pub fn new( + blocks: Vec, + locals: LocalDecls, + arg_count: usize, + var_debug_info: Vec, + spread_arg: Option, + span: Span, + ) -> Self { + // If locals doesn't contain enough entries, it can lead to panics in + // `ret_local`, `arg_locals`, and `inner_locals`. + assert!( + locals.len() > arg_count, + "A Body must contain at least a local for the return value and each of the function's arguments" + ); + Self { blocks, locals, arg_count, var_debug_info, spread_arg, span } + } + + /// Return local that holds this function's return value. + pub fn ret_local(&self) -> &LocalDecl { + &self.locals[RETURN_LOCAL] + } + + /// Locals in `self` that correspond to this function's arguments. + pub fn arg_locals(&self) -> &[LocalDecl] { + &self.locals[1..][..self.arg_count] + } + + /// Inner locals for this function. These are the locals that are + /// neither the return local nor the argument locals. + pub fn inner_locals(&self) -> &[LocalDecl] { + &self.locals[self.arg_count + 1..] + } + + /// Returns a mutable reference to the local that holds this function's return value. + pub(crate) fn ret_local_mut(&mut self) -> &mut LocalDecl { + &mut self.locals[RETURN_LOCAL] + } + + /// Returns a mutable slice of locals corresponding to this function's arguments. + pub(crate) fn arg_locals_mut(&mut self) -> &mut [LocalDecl] { + &mut self.locals[1..][..self.arg_count] + } + + /// Returns a mutable slice of inner locals for this function. + /// Inner locals are those that are neither the return local nor the argument locals. + pub(crate) fn inner_locals_mut(&mut self) -> &mut [LocalDecl] { + &mut self.locals[self.arg_count + 1..] + } + + /// Convenience function to get all the locals in this function. + /// + /// Locals are typically accessed via the more specific methods `ret_local`, + /// `arg_locals`, and `inner_locals`. + pub fn locals(&self) -> &[LocalDecl] { + &self.locals + } + + /// Get the local declaration for this local. + pub fn local_decl(&self, local: Local) -> Option<&LocalDecl> { + self.locals.get(local) + } + + /// Get an iterator for all local declarations. + pub fn local_decls(&self) -> impl Iterator { + self.locals.iter().enumerate() + } + + /// Emit the body using the provided name for the signature. + pub fn dump(&self, w: &mut W, fn_name: &str) -> io::Result<()> { + function_body(w, self, fn_name) + } + + pub fn spread_arg(&self) -> Option { + self.spread_arg + } +} + +type LocalDecls = Vec; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct LocalDecl { + pub ty: Ty, + pub span: Span, + pub mutability: Mutability, +} + +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] +pub struct BasicBlock { + pub statements: Vec, + pub terminator: Terminator, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct Terminator { + pub kind: TerminatorKind, + pub span: Span, +} + +impl Terminator { + pub fn successors(&self) -> Successors { + self.kind.successors() + } +} + +pub type Successors = Vec; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum TerminatorKind { + Goto { + target: BasicBlockIdx, + }, + SwitchInt { + discr: Operand, + targets: SwitchTargets, + }, + Resume, + Abort, + Return, + Unreachable, + Drop { + place: Place, + target: BasicBlockIdx, + unwind: UnwindAction, + }, + Call { + func: Operand, + args: Vec, + destination: Place, + target: Option, + unwind: UnwindAction, + }, + Assert { + cond: Operand, + expected: bool, + msg: AssertMessage, + target: BasicBlockIdx, + unwind: UnwindAction, + }, + InlineAsm { + template: String, + operands: Vec, + options: String, + line_spans: String, + destination: Option, + unwind: UnwindAction, + }, +} + +impl TerminatorKind { + pub fn successors(&self) -> Successors { + use self::TerminatorKind::*; + match *self { + Call { target: Some(t), unwind: UnwindAction::Cleanup(u), .. } + | Drop { target: t, unwind: UnwindAction::Cleanup(u), .. } + | Assert { target: t, unwind: UnwindAction::Cleanup(u), .. } + | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(u), .. } => { + vec![t, u] + } + Goto { target: t } + | Call { target: None, unwind: UnwindAction::Cleanup(t), .. } + | Call { target: Some(t), unwind: _, .. } + | Drop { target: t, unwind: _, .. } + | Assert { target: t, unwind: _, .. } + | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. } + | InlineAsm { destination: Some(t), unwind: _, .. } => { + vec![t] + } + + Return + | Resume + | Abort + | Unreachable + | Call { target: None, unwind: _, .. } + | InlineAsm { destination: None, unwind: _, .. } => { + vec![] + } + SwitchInt { ref targets, .. } => targets.all_targets(), + } + } + + pub fn unwind(&self) -> Option<&UnwindAction> { + match *self { + TerminatorKind::Goto { .. } + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::SwitchInt { .. } => None, + TerminatorKind::Call { ref unwind, .. } + | TerminatorKind::Assert { ref unwind, .. } + | TerminatorKind::Drop { ref unwind, .. } + | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind), + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct InlineAsmOperand { + pub in_value: Option, + pub out_place: Option, + // This field has a raw debug representation of MIR's InlineAsmOperand. + // For now we care about place/operand + the rest in a debug format. + pub raw_rpr: String, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum UnwindAction { + Continue, + Unreachable, + Terminate, + Cleanup(BasicBlockIdx), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum AssertMessage { + BoundsCheck { len: Operand, index: Operand }, + Overflow(BinOp, Operand, Operand), + OverflowNeg(Operand), + DivisionByZero(Operand), + RemainderByZero(Operand), + ResumedAfterReturn(CoroutineKind), + ResumedAfterPanic(CoroutineKind), + ResumedAfterDrop(CoroutineKind), + MisalignedPointerDereference { required: Operand, found: Operand }, + NullPointerDereference, + InvalidEnumConstruction(Operand), +} + +impl AssertMessage { + pub fn description(&self) -> Result<&'static str, Error> { + match self { + AssertMessage::Overflow(BinOp::Add, _, _) => Ok("attempt to add with overflow"), + AssertMessage::Overflow(BinOp::Sub, _, _) => Ok("attempt to subtract with overflow"), + AssertMessage::Overflow(BinOp::Mul, _, _) => Ok("attempt to multiply with overflow"), + AssertMessage::Overflow(BinOp::Div, _, _) => Ok("attempt to divide with overflow"), + AssertMessage::Overflow(BinOp::Rem, _, _) => { + Ok("attempt to calculate the remainder with overflow") + } + AssertMessage::OverflowNeg(_) => Ok("attempt to negate with overflow"), + AssertMessage::Overflow(BinOp::Shr, _, _) => Ok("attempt to shift right with overflow"), + AssertMessage::Overflow(BinOp::Shl, _, _) => Ok("attempt to shift left with overflow"), + AssertMessage::Overflow(op, _, _) => Err(error!("`{:?}` cannot overflow", op)), + AssertMessage::DivisionByZero(_) => Ok("attempt to divide by zero"), + AssertMessage::RemainderByZero(_) => { + Ok("attempt to calculate the remainder with a divisor of zero") + } + AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine(_)) => { + Ok("coroutine resumed after completion") + } + AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + _, + )) => Ok("`async fn` resumed after completion"), + AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::Gen, + _, + )) => Ok("`async gen fn` resumed after completion"), + AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::AsyncGen, + _, + )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"), + AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine(_)) => { + Ok("coroutine resumed after panicking") + } + AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + _, + )) => Ok("`async fn` resumed after panicking"), + AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared( + CoroutineDesugaring::Gen, + _, + )) => Ok("`async gen fn` resumed after panicking"), + AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared( + CoroutineDesugaring::AsyncGen, + _, + )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking"), + + AssertMessage::ResumedAfterDrop(CoroutineKind::Coroutine(_)) => { + Ok("coroutine resumed after async drop") + } + AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + _, + )) => Ok("`async fn` resumed after async drop"), + AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared( + CoroutineDesugaring::Gen, + _, + )) => Ok("`async gen fn` resumed after async drop"), + AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared( + CoroutineDesugaring::AsyncGen, + _, + )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after async drop"), + + AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"), + AssertMessage::MisalignedPointerDereference { .. } => { + Ok("misaligned pointer dereference") + } + AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"), + AssertMessage::InvalidEnumConstruction(_) => { + Ok("trying to construct an enum from an invalid value") + } + } + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum BinOp { + Add, + AddUnchecked, + Sub, + SubUnchecked, + Mul, + MulUnchecked, + Div, + Rem, + BitXor, + BitAnd, + BitOr, + Shl, + ShlUnchecked, + Shr, + ShrUnchecked, + Eq, + Lt, + Le, + Ne, + Ge, + Gt, + Cmp, + Offset, +} + +impl BinOp { + /// Return the type of this operation for the given input Ty. + /// This function does not perform type checking, and it currently doesn't handle SIMD. + pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty { + with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty)) + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum UnOp { + Not, + Neg, + PtrMetadata, +} + +impl UnOp { + /// Return the type of this operation for the given input Ty. + /// This function does not perform type checking, and it currently doesn't handle SIMD. + pub fn ty(&self, arg_ty: Ty) -> Ty { + with(|ctx| ctx.unop_ty(*self, arg_ty)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum CoroutineKind { + Desugared(CoroutineDesugaring, CoroutineSource), + Coroutine(Movability), +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum CoroutineSource { + Block, + Closure, + Fn, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum CoroutineDesugaring { + Async, + + Gen, + + AsyncGen, +} + +pub(crate) type LocalDefId = Opaque; +/// The rustc coverage data structures are heavily tied to internal details of the +/// coverage implementation that are likely to change, and are unlikely to be +/// useful to third-party tools for the foreseeable future. +pub(crate) type Coverage = Opaque; + +/// The FakeReadCause describes the type of pattern why a FakeRead statement exists. +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum FakeReadCause { + ForMatchGuard, + ForMatchedPlace(LocalDefId), + ForGuardBinding, + ForLet(LocalDefId), + ForIndex, +} + +/// Describes what kind of retag is to be performed +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] +pub enum RetagKind { + FnEntry, + TwoPhase, + Raw, + Default, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)] +pub enum Variance { + Covariant, + Invariant, + Contravariant, + Bivariant, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct CopyNonOverlapping { + pub src: Operand, + pub dst: Operand, + pub count: Operand, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum NonDivergingIntrinsic { + Assume(Operand), + CopyNonOverlapping(CopyNonOverlapping), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct Statement { + pub kind: StatementKind, + pub span: Span, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum StatementKind { + Assign(Place, Rvalue), + FakeRead(FakeReadCause, Place), + SetDiscriminant { place: Place, variant_index: VariantIdx }, + Deinit(Place), + StorageLive(Local), + StorageDead(Local), + Retag(RetagKind, Place), + PlaceMention(Place), + AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance }, + Coverage(Coverage), + Intrinsic(NonDivergingIntrinsic), + ConstEvalCounter, + Nop, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum Rvalue { + /// Creates a pointer with the indicated mutability to the place. + /// + /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like + /// `&raw v` or `addr_of!(v)`. + AddressOf(RawPtrKind, Place), + + /// Creates an aggregate value, like a tuple or struct. + /// + /// This is needed because dataflow analysis needs to distinguish + /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo` + /// has a destructor. + /// + /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Coroutine`. After + /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too. + Aggregate(AggregateKind, Vec), + + /// * `Offset` has the same semantics as `<*const T>::offset`, except that the second + /// parameter may be a `usize` as well. + /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, + /// raw pointers, or function pointers and return a `bool`. The types of the operands must be + /// matching, up to the usual caveat of the lifetimes in function pointers. + /// * Left and right shift operations accept signed or unsigned integers not necessarily of the + /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is + /// truncated as needed. + /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching + /// types and return a value of that type. + /// * The remaining operations accept signed integers, unsigned integers, or floats with + /// matching types and return a value of that type. + BinaryOp(BinOp, Operand, Operand), + + /// Performs essentially all of the casts that can be performed via `as`. + /// + /// This allows for casts from/to a variety of types. + Cast(CastKind, Operand, Ty), + + /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. + /// + /// For addition, subtraction, and multiplication on integers the error condition is set when + /// the infinite precision result would not be equal to the actual result. + CheckedBinaryOp(BinOp, Operand, Operand), + + /// A CopyForDeref is equivalent to a read from a place. + /// When such a read happens, it is guaranteed that the only use of the returned value is a + /// deref operation, immediately followed by one or more projections. + CopyForDeref(Place), + + /// Computes the discriminant of the place, returning it as an integer. + /// Returns zero for types without discriminant. + /// + /// The validity requirements for the underlying value are undecided for this rvalue, see + /// [#91095]. Note too that the value of the discriminant is not the same thing as the + /// variant index; + /// + /// [#91095]: https://github.com/rust-lang/rust/issues/91095 + Discriminant(Place), + + /// Yields the length of the place, as a `usize`. + /// + /// If the type of the place is an array, this is the array length. For slices (`[T]`, not + /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is + /// ill-formed for places of other types. + Len(Place), + + /// Creates a reference to the place. + Ref(Region, BorrowKind, Place), + + /// Creates an array where each element is the value of the operand. + /// + /// This is the cause of a bug in the case where the repetition count is zero because the value + /// is not dropped, see [#74836]. + /// + /// Corresponds to source code like `[x; 32]`. + /// + /// [#74836]: https://github.com/rust-lang/rust/issues/74836 + Repeat(Operand, TyConst), + + /// Transmutes a `*mut u8` into shallow-initialized `Box`. + /// + /// This is different from a normal transmute because dataflow analysis will treat the box as + /// initialized but its content as uninitialized. Like other pointer casts, this in general + /// affects alias analysis. + ShallowInitBox(Operand, Ty), + + /// Creates a pointer/reference to the given thread local. + /// + /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a + /// `*const T`, and if neither of those apply a `&T`. + /// + /// **Note:** This is a runtime operation that actually executes code and is in this sense more + /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to + /// SIGILL for some reason that I (JakobDegen) never got a chance to look into. + /// + /// **Needs clarification**: Are there weird additional semantics here related to the runtime + /// nature of this operation? + ThreadLocalRef(crate::CrateItem), + + /// Computes a value as described by the operation. + NullaryOp(NullOp, Ty), + + /// Exactly like `BinaryOp`, but less operands. + /// + /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; + /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds + /// return a value with the same type as their operand. + UnaryOp(UnOp, Operand), + + /// Yields the operand unchanged + Use(Operand), +} + +impl Rvalue { + pub fn ty(&self, locals: &[LocalDecl]) -> Result { + match self { + Rvalue::Use(operand) => operand.ty(locals), + Rvalue::Repeat(operand, count) => { + Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone())) + } + Rvalue::ThreadLocalRef(did) => Ok(did.ty()), + Rvalue::Ref(reg, bk, place) => { + let place_ty = place.ty(locals)?; + Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy())) + } + Rvalue::AddressOf(mutability, place) => { + let place_ty = place.ty(locals)?; + Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy())) + } + Rvalue::Len(..) => Ok(Ty::usize_ty()), + Rvalue::Cast(.., ty) => Ok(*ty), + Rvalue::BinaryOp(op, lhs, rhs) => { + let lhs_ty = lhs.ty(locals)?; + let rhs_ty = rhs.ty(locals)?; + Ok(op.ty(lhs_ty, rhs_ty)) + } + Rvalue::CheckedBinaryOp(op, lhs, rhs) => { + let lhs_ty = lhs.ty(locals)?; + let rhs_ty = rhs.ty(locals)?; + let ty = op.ty(lhs_ty, rhs_ty); + Ok(Ty::new_tuple(&[ty, Ty::bool_ty()])) + } + Rvalue::UnaryOp(op, operand) => { + let arg_ty = operand.ty(locals)?; + Ok(op.ty(arg_ty)) + } + Rvalue::Discriminant(place) => { + let place_ty = place.ty(locals)?; + place_ty + .kind() + .discriminant_ty() + .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}")) + } + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { + Ok(Ty::usize_ty()) + } + Rvalue::NullaryOp(NullOp::ContractChecks, _) + | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()), + Rvalue::Aggregate(ak, ops) => match *ak { + AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64), + AggregateKind::Tuple => Ok(Ty::new_tuple( + &ops.iter().map(|op| op.ty(locals)).collect::, _>>()?, + )), + AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)), + AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())), + AggregateKind::Coroutine(def, ref args, mov) => { + Ok(Ty::new_coroutine(def, args.clone(), mov)) + } + AggregateKind::CoroutineClosure(def, ref args) => { + Ok(Ty::new_coroutine_closure(def, args.clone())) + } + AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)), + }, + Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)), + Rvalue::CopyForDeref(place) => place.ty(locals), + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum AggregateKind { + Array(Ty), + Tuple, + Adt(AdtDef, VariantIdx, GenericArgs, Option, Option), + Closure(ClosureDef, GenericArgs), + // FIXME(stable_mir): Movability here is redundant + Coroutine(CoroutineDef, GenericArgs, Movability), + CoroutineClosure(CoroutineClosureDef, GenericArgs), + RawPtr(Ty, Mutability), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum Operand { + Copy(Place), + Move(Place), + Constant(ConstOperand), +} + +#[derive(Clone, Eq, PartialEq, Serialize)] +pub struct Place { + pub local: Local, + /// projection out of a place (access a field, deref a pointer, etc) + pub projection: Vec, +} + +impl From for Place { + fn from(local: Local) -> Self { + Place { local, projection: vec![] } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct ConstOperand { + pub span: Span, + pub user_ty: Option, + pub const_: MirConst, +} + +/// Debug information pertaining to a user variable. +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct VarDebugInfo { + /// The variable name. + pub name: Symbol, + + /// Source info of the user variable, including the scope + /// within which the variable is visible (to debuginfo). + pub source_info: SourceInfo, + + /// The user variable's data is split across several fragments, + /// each described by a `VarDebugInfoFragment`. + pub composite: Option, + + /// Where the data for this user variable is to be found. + pub value: VarDebugInfoContents, + + /// When present, indicates what argument number this variable is in the function that it + /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the + /// argument number in the original function before it was inlined. + pub argument_index: Option, +} + +impl VarDebugInfo { + /// Return a local variable if this info is related to one. + pub fn local(&self) -> Option { + match &self.value { + VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local), + VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None, + } + } + + /// Return a constant if this info is related to one. + pub fn constant(&self) -> Option<&ConstOperand> { + match &self.value { + VarDebugInfoContents::Place(_) => None, + VarDebugInfoContents::Const(const_op) => Some(const_op), + } + } +} + +pub type SourceScope = u32; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct SourceInfo { + pub span: Span, + pub scope: SourceScope, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct VarDebugInfoFragment { + pub ty: Ty, + pub projection: Vec, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum VarDebugInfoContents { + Place(Place), + Const(ConstOperand), +} + +// In MIR ProjectionElem is parameterized on the second Field argument and the Index argument. This +// is so it can be used for both Places (for which the projection elements are of type +// ProjectionElem) and user-provided type annotations (for which the projection elements +// are of type ProjectionElem<(), ()>). In SMIR we don't need this generality, so we just use +// ProjectionElem for Places. +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum ProjectionElem { + /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place. + Deref, + + /// A field projection (e.g., `f` in `_1.f`) project to a field in the base place. The field is + /// referenced by source-order index rather than the name of the field. The fields type is also + /// given. + Field(FieldIdx, Ty), + + /// Index into a slice/array. The value of the index is computed at runtime using the `V` + /// argument. + /// + /// Note that this does not also dereference, and so it does not exactly correspond to slice + /// indexing in Rust. In other words, in the below Rust code: + /// + /// ```rust + /// let x = &[1, 2, 3, 4]; + /// let i = 2; + /// x[i]; + /// ``` + /// + /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same + /// thing is true of the `ConstantIndex` and `Subslice` projections below. + Index(Local), + + /// Index into a slice/array given by offsets. + /// + /// These indices are generated by slice patterns. Easiest to explain by example: + /// + /// ```ignore (illustrative) + /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, + /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, + /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, + /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, + /// ``` + ConstantIndex { + /// index or -index (in Python terms), depending on from_end + offset: u64, + /// The thing being indexed must be at least this long -- otherwise, the + /// projection is UB. + /// + /// For arrays this is always the exact length. + min_length: u64, + /// Counting backwards from end? This is always false when indexing an + /// array. + from_end: bool, + }, + + /// Projects a slice from the base place. + /// + /// These indices are generated by slice patterns. If `from_end` is true, this represents + /// `slice[from..slice.len() - to]`. Otherwise it represents `array[from..to]`. + Subslice { + from: u64, + to: u64, + /// Whether `to` counts from the start or end of the array/slice. + from_end: bool, + }, + + /// "Downcast" to a variant of an enum or a coroutine. + Downcast(VariantIdx), + + /// Like an explicit cast from an opaque type to a concrete type, but without + /// requiring an intermediate variable. + OpaqueCast(Ty), + + /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where + /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping + /// explicit during optimizations and codegen. + /// + /// This projection doesn't impact the runtime behavior of the program except for potentially changing + /// some type metadata of the interpreter or codegen backend. + Subtype(Ty), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct UserTypeProjection { + pub base: UserTypeAnnotationIndex, + + pub projection: Opaque, +} + +pub type Local = usize; + +pub const RETURN_LOCAL: Local = 0; + +/// The source-order index of a field in a variant. +/// +/// For example, in the following types, +/// ```ignore(illustrative) +/// enum Demo1 { +/// Variant0 { a: bool, b: i32 }, +/// Variant1 { c: u8, d: u64 }, +/// } +/// struct Demo2 { e: u8, f: u16, g: u8 } +/// ``` +/// `a`'s `FieldIdx` is `0`, +/// `b`'s `FieldIdx` is `1`, +/// `c`'s `FieldIdx` is `0`, and +/// `g`'s `FieldIdx` is `2`. +pub type FieldIdx = usize; + +type UserTypeAnnotationIndex = usize; + +/// The possible branch sites of a [TerminatorKind::SwitchInt]. +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct SwitchTargets { + /// The conditional branches where the first element represents the value that guards this + /// branch, and the second element is the branch target. + branches: Vec<(u128, BasicBlockIdx)>, + /// The `otherwise` branch which will be taken in case none of the conditional branches are + /// satisfied. + otherwise: BasicBlockIdx, +} + +impl SwitchTargets { + /// All possible targets including the `otherwise` target. + pub fn all_targets(&self) -> Successors { + self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect() + } + + /// The `otherwise` branch target. + pub fn otherwise(&self) -> BasicBlockIdx { + self.otherwise + } + + /// The conditional targets which are only taken if the pattern matches the given value. + pub fn branches(&self) -> impl Iterator { + self.branches.iter().copied() + } + + /// The number of targets including `otherwise`. + pub fn len(&self) -> usize { + self.branches.len() + 1 + } + + /// Create a new SwitchTargets from the given branches and `otherwise` target. + pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets { + SwitchTargets { branches, otherwise } + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum BorrowKind { + /// Data must be immutable and is aliasable. + Shared, + + /// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either + /// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]). + Fake(FakeBorrowKind), + + /// Data is mutable and not aliasable. + Mut { + /// `true` if this borrow arose from method-call auto-ref + kind: MutBorrowKind, + }, +} + +impl BorrowKind { + pub fn to_mutable_lossy(self) -> Mutability { + match self { + BorrowKind::Mut { .. } => Mutability::Mut, + BorrowKind::Shared => Mutability::Not, + // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation. + BorrowKind::Fake(_) => Mutability::Not, + } + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum RawPtrKind { + Mut, + Const, + FakeForPtrMetadata, +} + +impl RawPtrKind { + pub fn to_mutable_lossy(self) -> Mutability { + match self { + RawPtrKind::Mut { .. } => Mutability::Mut, + RawPtrKind::Const => Mutability::Not, + // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation. + RawPtrKind::FakeForPtrMetadata => Mutability::Not, + } + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum MutBorrowKind { + Default, + TwoPhaseBorrow, + ClosureCapture, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum FakeBorrowKind { + /// A shared (deep) borrow. Data must be immutable and is aliasable. + Deep, + /// The immediately borrowed place must be immutable, but projections from + /// it don't need to be. This is used to prevent match guards from replacing + /// the scrutinee. For example, a fake borrow of `a.b` doesn't + /// conflict with a mutable borrow of `a.b.c`. + Shallow, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub enum Mutability { + Not, + Mut, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum Safety { + Safe, + Unsafe, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum PointerCoercion { + /// Go from a fn-item type to a fn-pointer type. + ReifyFnPointer, + + /// Go from a safe fn pointer to an unsafe fn pointer. + UnsafeFnPointer, + + /// Go from a non-capturing closure to a fn pointer or an unsafe fn pointer. + /// It cannot convert a closure that requires unsafe. + ClosureFnPointer(Safety), + + /// Go from a mut raw pointer to a const raw pointer. + MutToConstPointer, + + /// Go from `*const [T; N]` to `*const T` + ArrayToPointer, + + /// Unsize a pointer/reference value, e.g., `&[T; n]` to + /// `&[T]`. Note that the source could be a thin or wide pointer. + /// This will do things like convert thin pointers to wide + /// pointers, or convert structs containing thin pointers to + /// structs containing wide pointers, or convert between wide + /// pointers. + Unsize, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub enum CastKind { + // FIXME(smir-rename): rename this to PointerExposeProvenance + PointerExposeAddress, + PointerWithExposedProvenance, + PointerCoercion(PointerCoercion), + IntToInt, + FloatToInt, + FloatToFloat, + IntToFloat, + PtrToPtr, + FnPtrToPtr, + Transmute, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum NullOp { + /// Returns the size of a value of that type. + SizeOf, + /// Returns the minimum alignment of a type. + AlignOf, + /// Returns the offset of a field. + OffsetOf(Vec<(VariantIdx, FieldIdx)>), + /// cfg!(ub_checks), but at codegen time + UbChecks, + /// cfg!(contract_checks), but at codegen time + ContractChecks, +} + +impl Operand { + /// Get the type of an operand relative to the local declaration. + /// + /// In order to retrieve the correct type, the `locals` argument must match the list of all + /// locals from the function body where this operand originates from. + /// + /// Errors indicate a malformed operand or incompatible locals list. + pub fn ty(&self, locals: &[LocalDecl]) -> Result { + match self { + Operand::Copy(place) | Operand::Move(place) => place.ty(locals), + Operand::Constant(c) => Ok(c.ty()), + } + } +} + +impl ConstOperand { + pub fn ty(&self) -> Ty { + self.const_.ty() + } +} + +impl Place { + /// Resolve down the chain of projections to get the type referenced at the end of it. + /// E.g.: + /// Calling `ty()` on `var.field` should return the type of `field`. + /// + /// In order to retrieve the correct type, the `locals` argument must match the list of all + /// locals from the function body where this place originates from. + pub fn ty(&self, locals: &[LocalDecl]) -> Result { + self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty)) + } +} + +impl ProjectionElem { + /// Get the expected type after applying this projection to a given place type. + pub fn ty(&self, place_ty: Ty) -> Result { + let ty = place_ty; + match &self { + ProjectionElem::Deref => Self::deref_ty(ty), + ProjectionElem::Field(_idx, fty) => Ok(*fty), + ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty), + ProjectionElem::Subslice { from, to, from_end } => { + Self::subslice_ty(ty, *from, *to, *from_end) + } + ProjectionElem::Downcast(_) => Ok(ty), + ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty), + } + } + + fn index_ty(ty: Ty) -> Result { + ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}")) + } + + fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result { + let ty_kind = ty.kind(); + match ty_kind { + TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty), + TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array( + inner, + to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?, + ), + TyKind::RigidTy(RigidTy::Array(inner, size)) => { + let size = size.eval_target_usize()?; + let len = size - from - to; + Ty::try_new_array(inner, len) + } + _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))), + } + } + + fn deref_ty(ty: Ty) -> Result { + let deref_ty = ty + .kind() + .builtin_deref(true) + .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?; + Ok(deref_ty.ty) + } +} diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs new file mode 100644 index 00000000000..c54fcecac9f --- /dev/null +++ b/compiler/stable_mir/src/mir/mono.rs @@ -0,0 +1,305 @@ +use std::fmt::{Debug, Formatter}; +use std::io; + +use rustc_smir::bridge::SmirError; +use serde::Serialize; + +use crate::abi::FnAbi; +use crate::crate_def::CrateDef; +use crate::mir::Body; +use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, Ty}; +use crate::{CrateItem, DefId, Error, IndexedVal, ItemKind, Opaque, Symbol, with}; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub enum MonoItem { + Fn(Instance), + Static(StaticDef), + GlobalAsm(Opaque), +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize)] +pub struct Instance { + /// The type of instance. + pub kind: InstanceKind, + /// An ID used to get the instance definition from the compiler. + /// Do not use this field directly. + pub def: InstanceDef, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] +pub enum InstanceKind { + /// A user defined item. + Item, + /// A compiler intrinsic function. + Intrinsic, + /// A virtual function definition stored in a VTable. + /// The `idx` field indicates the position in the VTable for this instance. + Virtual { idx: usize }, + /// A compiler generated shim. + Shim, +} + +impl Instance { + /// Get the arguments this instance was instantiated with. + pub fn args(&self) -> GenericArgs { + with(|cx| cx.instance_args(self.def)) + } + + /// Get the body of an Instance. + /// + /// The body will be eagerly monomorphized and all constants will already be evaluated. + /// + /// This method will return the intrinsic fallback body if one was defined. + pub fn body(&self) -> Option { + with(|context| context.instance_body(self.def)) + } + + /// Check whether this instance has a body available. + /// + /// For intrinsics with fallback body, this will return `true`. It is up to the user to decide + /// whether to specialize the intrinsic or to use its fallback body. + /// + /// For more information on fallback body, see . + /// + /// This call is much cheaper than `instance.body().is_some()`, since it doesn't try to build + /// the StableMIR body. + pub fn has_body(&self) -> bool { + with(|cx| cx.has_body(self.def.def_id())) + } + + pub fn is_foreign_item(&self) -> bool { + with(|cx| cx.is_foreign_item(self.def.def_id())) + } + + /// Get the instance type with generic instantiations applied and lifetimes erased. + pub fn ty(&self) -> Ty { + with(|context| context.instance_ty(self.def)) + } + + /// Retrieve information about this instance binary interface. + pub fn fn_abi(&self) -> Result { + with(|cx| cx.instance_abi(self.def)) + } + + /// Retrieve the instance's mangled name used for calling the given instance. + /// + /// This will also look up the correct name of instances from upstream crates. + pub fn mangled_name(&self) -> Symbol { + with(|context| context.instance_mangled_name(self.def)) + } + + /// Retrieve the instance name for diagnostic messages. + /// + /// This will return the specialized name, e.g., `std::vec::Vec::new`. + pub fn name(&self) -> Symbol { + with(|context| context.instance_name(self.def, false)) + } + + /// Return a trimmed name of the given instance including its args. + /// + /// If a symbol name can only be imported from one place for a type, and as + /// long as it was not glob-imported anywhere in the current crate, we trim its + /// path and print only the name. + pub fn trimmed_name(&self) -> Symbol { + with(|context| context.instance_name(self.def, true)) + } + + /// Retrieve the plain intrinsic name of an instance if it's an intrinsic. + /// + /// The plain name does not include type arguments (as `trimmed_name` does), + /// which is more convenient to match with intrinsic symbols. + pub fn intrinsic_name(&self) -> Option { + match self.kind { + InstanceKind::Intrinsic => { + Some(with(|context| context.intrinsic(self.def.def_id()).unwrap().fn_name())) + } + InstanceKind::Item | InstanceKind::Virtual { .. } | InstanceKind::Shim => None, + } + } + + /// Resolve an instance starting from a function definition and generic arguments. + pub fn resolve(def: FnDef, args: &GenericArgs) -> Result { + with(|context| { + context + .resolve_instance(def, args) + .ok_or_else(|| Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))) + }) + } + + /// Resolve the drop in place for a given type. + pub fn resolve_drop_in_place(ty: Ty) -> Instance { + with(|cx| cx.resolve_drop_in_place(ty)) + } + + /// Resolve an instance for a given function pointer. + pub fn resolve_for_fn_ptr(def: FnDef, args: &GenericArgs) -> Result { + with(|context| { + context + .resolve_for_fn_ptr(def, args) + .ok_or_else(|| Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))) + }) + } + + /// Resolve a closure with the expected kind. + pub fn resolve_closure( + def: ClosureDef, + args: &GenericArgs, + kind: ClosureKind, + ) -> Result { + with(|context| { + context + .resolve_closure(def, args, kind) + .ok_or_else(|| Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))) + }) + } + + /// Check whether this instance is an empty shim. + /// + /// Allow users to check if this shim can be ignored when called directly. + /// + /// We have decided not to export different types of Shims to StableMIR users, however, this + /// is a query that can be very helpful for users when processing DropGlue. + /// + /// When generating code for a Drop terminator, users can ignore an empty drop glue. + /// These shims are only needed to generate a valid Drop call done via VTable. + pub fn is_empty_shim(&self) -> bool { + self.kind == InstanceKind::Shim && with(|cx| cx.is_empty_drop_shim(self.def)) + } + + /// Try to constant evaluate the instance into a constant with the given type. + /// + /// This can be used to retrieve a constant that represents an intrinsic return such as + /// `type_id`. + pub fn try_const_eval(&self, const_ty: Ty) -> Result { + with(|cx| cx.eval_instance(self.def, const_ty)) + } + + /// Emit the body of this instance if it has one. + pub fn emit_mir(&self, w: &mut W) -> io::Result<()> { + if let Some(body) = self.body() { body.dump(w, &self.name()) } else { Ok(()) } + } +} + +impl Debug for Instance { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Instance") + .field("kind", &self.kind) + .field("def", &self.mangled_name()) + .field("args", &self.args()) + .finish() + } +} + +/// Try to convert a crate item into an instance. +/// The item cannot be generic in order to be converted into an instance. +impl TryFrom for Instance { + type Error = crate::Error; + + fn try_from(item: CrateItem) -> Result { + with(|context| { + let def_id = item.def_id(); + if !context.requires_monomorphization(def_id) { + Ok(context.mono_instance(def_id)) + } else { + Err(Error::new("Item requires monomorphization".to_string())) + } + }) + } +} + +/// Try to convert an instance into a crate item. +/// Only user defined instances can be converted. +impl TryFrom for CrateItem { + type Error = crate::Error; + + fn try_from(value: Instance) -> Result { + with(|context| { + if value.kind == InstanceKind::Item && context.has_body(value.def.def_id()) { + Ok(CrateItem(context.instance_def_id(value.def))) + } else { + Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind))) + } + }) + } +} + +impl From for MonoItem { + fn from(value: Instance) -> Self { + MonoItem::Fn(value) + } +} + +impl From for MonoItem { + fn from(value: StaticDef) -> Self { + MonoItem::Static(value) + } +} + +impl From for CrateItem { + fn from(value: StaticDef) -> Self { + CrateItem(value.0) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] +pub struct InstanceDef(usize); + +impl CrateDef for InstanceDef { + fn def_id(&self) -> DefId { + with(|context| context.instance_def_id(*self)) + } +} + +crate_def! { + /// Holds information about a static variable definition. + #[derive(Serialize)] + pub StaticDef; +} + +impl TryFrom for StaticDef { + type Error = crate::Error; + + fn try_from(value: CrateItem) -> Result { + if matches!(value.kind(), ItemKind::Static) { + Ok(StaticDef(value.0)) + } else { + Err(Error::new(format!("Expected a static item, but found: {value:?}"))) + } + } +} + +impl TryFrom for StaticDef { + type Error = crate::Error; + + fn try_from(value: Instance) -> Result { + StaticDef::try_from(CrateItem::try_from(value)?) + } +} + +impl From for Instance { + fn from(value: StaticDef) -> Self { + // A static definition should always be convertible to an instance. + with(|cx| cx.mono_instance(value.def_id())) + } +} + +impl StaticDef { + /// Return the type of this static definition. + pub fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.0)) + } + + /// Evaluate a static's initializer, returning the allocation of the initializer's memory. + pub fn eval_initializer(&self) -> Result { + with(|cx| cx.eval_static_initializer(*self)) + } +} + +impl IndexedVal for InstanceDef { + fn to_val(index: usize) -> Self { + InstanceDef(index) + } + fn to_index(&self) -> usize { + self.0 + } +} diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs new file mode 100644 index 00000000000..f496d80053e --- /dev/null +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -0,0 +1,469 @@ +//! Implement methods to pretty print stable MIR body. +use std::fmt::Debug; +use std::io::Write; +use std::{fmt, io, iter}; + +use fmt::{Display, Formatter}; + +use super::{AggregateKind, AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind}; +use crate::mir::{ + Operand, Place, RawPtrKind, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents, +}; +use crate::ty::{AdtKind, AssocKind, MirConst, Ty, TyConst}; +use crate::{Body, CrateDef, IndexedVal, Mutability, with}; + +impl Display for Ty { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + with(|ctx| write!(f, "{}", ctx.ty_pretty(*self))) + } +} + +impl Display for AssocKind { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + AssocKind::Fn { has_self: true, .. } => write!(f, "method"), + AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"), + AssocKind::Const { .. } => write!(f, "associated const"), + AssocKind::Type { .. } => write!(f, "associated type"), + } + } +} + +impl Debug for Place { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + with(|ctx| write!(f, "{}", ctx.place_pretty(self))) + } +} + +pub(crate) fn function_body(writer: &mut W, body: &Body, name: &str) -> io::Result<()> { + write!(writer, "fn {name}(")?; + let mut sep = ""; + for (index, local) in body.arg_locals().iter().enumerate() { + write!(writer, "{}_{}: {}", sep, index + 1, local.ty)?; + sep = ", "; + } + write!(writer, ")")?; + + let return_local = body.ret_local(); + writeln!(writer, " -> {} {{", return_local.ty)?; + + body.locals().iter().enumerate().try_for_each(|(index, local)| -> io::Result<()> { + if index == 0 || index > body.arg_count { + writeln!(writer, " let {}_{}: {};", pretty_mut(local.mutability), index, local.ty) + } else { + Ok(()) + } + })?; + + body.var_debug_info.iter().try_for_each(|info| { + let content = match &info.value { + VarDebugInfoContents::Place(place) => { + format!("{place:?}") + } + VarDebugInfoContents::Const(constant) => pretty_mir_const(&constant.const_), + }; + writeln!(writer, " debug {} => {};", info.name, content) + })?; + + body.blocks + .iter() + .enumerate() + .map(|(index, block)| -> io::Result<()> { + writeln!(writer, " bb{index}: {{")?; + let _ = block + .statements + .iter() + .map(|statement| -> io::Result<()> { + pretty_statement(writer, &statement.kind)?; + Ok(()) + }) + .collect::>(); + pretty_terminator(writer, &block.terminator.kind)?; + writeln!(writer, " }}").unwrap(); + Ok(()) + }) + .collect::, _>>()?; + writeln!(writer, "}}")?; + Ok(()) +} + +fn pretty_statement(writer: &mut W, statement: &StatementKind) -> io::Result<()> { + const INDENT: &str = " "; + match statement { + StatementKind::Assign(place, rval) => { + write!(writer, "{INDENT}{place:?} = ")?; + pretty_rvalue(writer, rval)?; + writeln!(writer, ";") + } + // FIXME: Add rest of the statements + StatementKind::FakeRead(cause, place) => { + writeln!(writer, "{INDENT}FakeRead({cause:?}, {place:?});") + } + StatementKind::SetDiscriminant { place, variant_index } => { + writeln!(writer, "{INDENT}discriminant({place:?} = {};", variant_index.to_index()) + } + StatementKind::Deinit(place) => writeln!(writer, "Deinit({place:?};"), + StatementKind::StorageLive(local) => { + writeln!(writer, "{INDENT}StorageLive(_{local});") + } + StatementKind::StorageDead(local) => { + writeln!(writer, "{INDENT}StorageDead(_{local});") + } + StatementKind::Retag(kind, place) => writeln!(writer, "Retag({kind:?}, {place:?});"), + StatementKind::PlaceMention(place) => { + writeln!(writer, "{INDENT}PlaceMention({place:?};") + } + StatementKind::ConstEvalCounter => { + writeln!(writer, "{INDENT}ConstEvalCounter;") + } + StatementKind::Nop => writeln!(writer, "{INDENT}nop;"), + StatementKind::AscribeUserType { .. } + | StatementKind::Coverage(_) + | StatementKind::Intrinsic(_) => { + // FIX-ME: Make them pretty. + writeln!(writer, "{INDENT}{statement:?};") + } + } +} + +fn pretty_terminator(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> { + pretty_terminator_head(writer, terminator)?; + let successors = terminator.successors(); + let successor_count = successors.len(); + let labels = pretty_successor_labels(terminator); + + let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_))); + let fmt_unwind = |w: &mut W| -> io::Result<()> { + write!(w, "unwind ")?; + match terminator.unwind() { + None | Some(UnwindAction::Cleanup(_)) => unreachable!(), + Some(UnwindAction::Continue) => write!(w, "continue"), + Some(UnwindAction::Unreachable) => write!(w, "unreachable"), + Some(UnwindAction::Terminate) => write!(w, "terminate"), + } + }; + + match (successor_count, show_unwind) { + (0, false) => {} + (0, true) => { + write!(writer, " -> ")?; + fmt_unwind(writer)?; + } + (1, false) => write!(writer, " -> bb{:?}", successors[0])?, + _ => { + write!(writer, " -> [")?; + for (i, target) in successors.iter().enumerate() { + if i > 0 { + write!(writer, ", ")?; + } + write!(writer, "{}: bb{:?}", labels[i], target)?; + } + if show_unwind { + write!(writer, ", ")?; + fmt_unwind(writer)?; + } + write!(writer, "]")?; + } + }; + + writeln!(writer, ";") +} + +fn pretty_terminator_head(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> { + use self::TerminatorKind::*; + const INDENT: &str = " "; + match terminator { + Goto { .. } => write!(writer, "{INDENT}goto"), + SwitchInt { discr, .. } => { + write!(writer, "{INDENT}switchInt({})", pretty_operand(discr)) + } + Resume => write!(writer, "{INDENT}resume"), + Abort => write!(writer, "{INDENT}abort"), + Return => write!(writer, "{INDENT}return"), + Unreachable => write!(writer, "{INDENT}unreachable"), + Drop { place, .. } => write!(writer, "{INDENT}drop({place:?})"), + Call { func, args, destination, .. } => { + write!(writer, "{INDENT}{:?} = {}(", destination, pretty_operand(func))?; + let mut args_iter = args.iter(); + args_iter.next().map_or(Ok(()), |arg| write!(writer, "{}", pretty_operand(arg)))?; + args_iter.try_for_each(|arg| write!(writer, ", {}", pretty_operand(arg)))?; + write!(writer, ")") + } + Assert { cond, expected, msg, target: _, unwind: _ } => { + write!(writer, "{INDENT}assert(")?; + if !expected { + write!(writer, "!")?; + } + write!(writer, "{}, ", pretty_operand(cond))?; + pretty_assert_message(writer, msg)?; + write!(writer, ")") + } + InlineAsm { .. } => write!(writer, "{INDENT}InlineAsm"), + } +} + +fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec { + use self::TerminatorKind::*; + match terminator { + Call { target: None, unwind: UnwindAction::Cleanup(_), .. } + | InlineAsm { destination: None, .. } => vec!["unwind".into()], + Resume | Abort | Return | Unreachable | Call { target: None, unwind: _, .. } => vec![], + Goto { .. } => vec!["".to_string()], + SwitchInt { targets, .. } => targets + .branches() + .map(|(val, _target)| format!("{val}")) + .chain(iter::once("otherwise".into())) + .collect(), + Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()], + Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { + vec!["return".into(), "unwind".into()] + } + Drop { unwind: _, .. } | Call { target: Some(_), unwind: _, .. } => vec!["return".into()], + Assert { unwind: UnwindAction::Cleanup(_), .. } => { + vec!["success".into(), "unwind".into()] + } + Assert { unwind: _, .. } => vec!["success".into()], + InlineAsm { destination: Some(_), .. } => vec!["goto".into(), "unwind".into()], + } +} + +fn pretty_assert_message(writer: &mut W, msg: &AssertMessage) -> io::Result<()> { + match msg { + AssertMessage::BoundsCheck { len, index } => { + let pretty_len = pretty_operand(len); + let pretty_index = pretty_operand(index); + write!( + writer, + "\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}" + ) + } + AssertMessage::Overflow(BinOp::Add, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + write!( + writer, + "\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}" + ) + } + AssertMessage::Overflow(BinOp::Sub, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + write!( + writer, + "\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}" + ) + } + AssertMessage::Overflow(BinOp::Mul, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + write!( + writer, + "\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}" + ) + } + AssertMessage::Overflow(BinOp::Div, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + write!( + writer, + "\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}" + ) + } + AssertMessage::Overflow(BinOp::Rem, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + write!( + writer, + "\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}" + ) + } + AssertMessage::Overflow(BinOp::Shr, _, r) => { + let pretty_r = pretty_operand(r); + write!(writer, "\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}") + } + AssertMessage::Overflow(BinOp::Shl, _, r) => { + let pretty_r = pretty_operand(r); + write!(writer, "\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}") + } + AssertMessage::Overflow(op, _, _) => unreachable!("`{:?}` cannot overflow", op), + AssertMessage::OverflowNeg(op) => { + let pretty_op = pretty_operand(op); + write!(writer, "\"attempt to negate `{{}}`, which would overflow\", {pretty_op}") + } + AssertMessage::DivisionByZero(op) => { + let pretty_op = pretty_operand(op); + write!(writer, "\"attempt to divide `{{}}` by zero\", {pretty_op}") + } + AssertMessage::RemainderByZero(op) => { + let pretty_op = pretty_operand(op); + write!( + writer, + "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}" + ) + } + AssertMessage::MisalignedPointerDereference { required, found } => { + let pretty_required = pretty_operand(required); + let pretty_found = pretty_operand(found); + write!( + writer, + "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}" + ) + } + AssertMessage::NullPointerDereference => { + write!(writer, "\"null pointer dereference occurred\"") + } + AssertMessage::InvalidEnumConstruction(op) => { + let pretty_op = pretty_operand(op); + write!(writer, "\"trying to construct an enum from an invalid value {{}}\",{pretty_op}") + } + AssertMessage::ResumedAfterReturn(_) + | AssertMessage::ResumedAfterPanic(_) + | AssertMessage::ResumedAfterDrop(_) => { + write!(writer, "{}", msg.description().unwrap()) + } + } +} + +fn pretty_operand(operand: &Operand) -> String { + match operand { + Operand::Copy(copy) => { + format!("{copy:?}") + } + Operand::Move(mv) => { + format!("move {mv:?}") + } + Operand::Constant(cnst) => pretty_mir_const(&cnst.const_), + } +} + +fn pretty_mir_const(literal: &MirConst) -> String { + with(|cx| cx.mir_const_pretty(literal)) +} + +fn pretty_ty_const(ct: &TyConst) -> String { + with(|cx| cx.ty_const_pretty(ct.id)) +} + +fn pretty_rvalue(writer: &mut W, rval: &Rvalue) -> io::Result<()> { + match rval { + Rvalue::AddressOf(mutability, place) => { + write!(writer, "&raw {} {:?}", pretty_raw_ptr_kind(*mutability), place) + } + Rvalue::Aggregate(aggregate_kind, operands) => { + // FIXME: Add pretty_aggregate function that returns a pretty string + pretty_aggregate(writer, aggregate_kind, operands) + } + Rvalue::BinaryOp(bin, op1, op2) => { + write!(writer, "{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2)) + } + Rvalue::Cast(_, op, ty) => { + write!(writer, "{} as {}", pretty_operand(op), ty) + } + Rvalue::CheckedBinaryOp(bin, op1, op2) => { + write!(writer, "Checked{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2)) + } + Rvalue::CopyForDeref(deref) => { + write!(writer, "CopyForDeref({deref:?})") + } + Rvalue::Discriminant(place) => { + write!(writer, "discriminant({place:?})") + } + Rvalue::Len(len) => { + write!(writer, "len({len:?})") + } + Rvalue::Ref(_, borrowkind, place) => { + let kind = match borrowkind { + BorrowKind::Shared => "&", + BorrowKind::Fake(FakeBorrowKind::Deep) => "&fake ", + BorrowKind::Fake(FakeBorrowKind::Shallow) => "&fake shallow ", + BorrowKind::Mut { .. } => "&mut ", + }; + write!(writer, "{kind}{place:?}") + } + Rvalue::Repeat(op, cnst) => { + write!(writer, "[{}; {}]", pretty_operand(op), pretty_ty_const(cnst)) + } + Rvalue::ShallowInitBox(_, _) => Ok(()), + Rvalue::ThreadLocalRef(item) => { + write!(writer, "thread_local_ref{item:?}") + } + Rvalue::NullaryOp(nul, ty) => { + write!(writer, "{nul:?}::<{ty}>() \" \"") + } + Rvalue::UnaryOp(un, op) => { + write!(writer, "{:?}({})", un, pretty_operand(op)) + } + Rvalue::Use(op) => write!(writer, "{}", pretty_operand(op)), + } +} + +fn pretty_aggregate( + writer: &mut W, + aggregate_kind: &AggregateKind, + operands: &Vec, +) -> io::Result<()> { + let suffix = match aggregate_kind { + AggregateKind::Array(_) => { + write!(writer, "[")?; + "]" + } + AggregateKind::Tuple => { + write!(writer, "(")?; + ")" + } + AggregateKind::Adt(def, var, _, _, _) => { + if def.kind() == AdtKind::Enum { + write!(writer, "{}::{}", def.name(), def.variant(*var).unwrap().name())?; + } else { + write!(writer, "{}", def.variant(*var).unwrap().name())?; + } + if operands.is_empty() { + return Ok(()); + } + // FIXME: Change this once we have CtorKind in StableMIR. + write!(writer, "(")?; + ")" + } + AggregateKind::Closure(def, _) => { + write!(writer, "{{closure@{}}}(", def.span().diagnostic())?; + ")" + } + AggregateKind::Coroutine(def, _, _) => { + write!(writer, "{{coroutine@{}}}(", def.span().diagnostic())?; + ")" + } + AggregateKind::CoroutineClosure(def, _) => { + write!(writer, "{{coroutine-closure@{}}}(", def.span().diagnostic())?; + ")" + } + AggregateKind::RawPtr(ty, mutability) => { + write!( + writer, + "*{} {ty} from (", + if *mutability == Mutability::Mut { "mut" } else { "const" } + )?; + ")" + } + }; + let mut separator = ""; + for op in operands { + write!(writer, "{}{}", separator, pretty_operand(op))?; + separator = ", "; + } + write!(writer, "{suffix}") +} + +fn pretty_mut(mutability: Mutability) -> &'static str { + match mutability { + Mutability::Not => " ", + Mutability::Mut => "mut ", + } +} + +fn pretty_raw_ptr_kind(kind: RawPtrKind) -> &'static str { + match kind { + RawPtrKind::Const => "const", + RawPtrKind::Mut => "mut", + RawPtrKind::FakeForPtrMetadata => "const (fake)", + } +} diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs new file mode 100644 index 00000000000..7dc99d1d1e1 --- /dev/null +++ b/compiler/stable_mir/src/mir/visit.rs @@ -0,0 +1,588 @@ +//! # The Stable MIR Visitor +//! +//! ## Overview +//! +//! We currently only support an immutable visitor. +//! The structure of this visitor is similar to the ones internal to `rustc`, +//! and it follows the following conventions: +//! +//! For every mir item, the trait has a `visit_` and a `super_` method. +//! - `visit_`, by default, calls `super_` +//! - `super_`, by default, destructures the `` and calls `visit_` for +//! all sub-items that compose the original item. +//! +//! In order to implement a visitor, override the `visit_*` methods for the types you are +//! interested in analyzing, and invoke (within that method call) +//! `self.super_*` to continue to the traverse. +//! Avoid calling `super` methods in other circumstances. +//! +//! For the most part, we do not destructure things external to the +//! MIR, e.g., types, spans, etc, but simply visit them and stop. +//! This avoids duplication with other visitors like `TypeFoldable`. +//! +//! ## Updating +//! +//! The code is written in a very deliberate style intended to minimize +//! the chance of things being overlooked. +//! +//! Use pattern matching to reference fields and ensure that all +//! matches are exhaustive. +//! +//! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. +//! That means you never write `..` to skip over fields, nor do you write `_` +//! to skip over variants in a `match`. +//! +//! The only place that `_` is acceptable is to match a field (or +//! variant argument) that does not require visiting. + +use crate::mir::*; +use crate::ty::{GenericArgs, MirConst, Region, Ty, TyConst}; +use crate::{Error, Opaque, Span}; + +macro_rules! make_mir_visitor { + ($visitor_trait_name:ident, $($mutability:ident)?) => { + pub trait $visitor_trait_name { + fn visit_body(&mut self, body: &$($mutability)? Body) { + self.super_body(body) + } + + fn visit_basic_block(&mut self, bb: &$($mutability)? BasicBlock) { + self.super_basic_block(bb) + } + + fn visit_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_ret_decl(local, decl) + } + + fn visit_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_arg_decl(local, decl) + } + + fn visit_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_local_decl(local, decl) + } + + fn visit_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) { + self.super_statement(stmt, location) + } + + fn visit_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) { + self.super_terminator(term, location) + } + + fn visit_span(&mut self, span: &$($mutability)? Span) { + self.super_span(span) + } + + fn visit_place(&mut self, place: &$($mutability)? Place, ptx: PlaceContext, location: Location) { + self.super_place(place, ptx, location) + } + + visit_place_fns!($($mutability)?); + + fn visit_local(&mut self, local: &$($mutability)? Local, ptx: PlaceContext, location: Location) { + let _ = (local, ptx, location); + } + + fn visit_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) { + self.super_rvalue(rvalue, location) + } + + fn visit_operand(&mut self, operand: &$($mutability)? Operand, location: Location) { + self.super_operand(operand, location) + } + + fn visit_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) { + self.super_user_type_projection(projection) + } + + fn visit_ty(&mut self, ty: &$($mutability)? Ty, location: Location) { + let _ = location; + self.super_ty(ty) + } + + fn visit_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) { + self.super_const_operand(constant, location) + } + + fn visit_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) { + self.super_mir_const(constant, location) + } + + fn visit_ty_const(&mut self, constant: &$($mutability)? TyConst, location: Location) { + let _ = location; + self.super_ty_const(constant) + } + + fn visit_region(&mut self, region: &$($mutability)? Region, location: Location) { + let _ = location; + self.super_region(region) + } + + fn visit_args(&mut self, args: &$($mutability)? GenericArgs, location: Location) { + let _ = location; + self.super_args(args) + } + + fn visit_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) { + self.super_assert_msg(msg, location) + } + + fn visit_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) { + self.super_var_debug_info(var_debug_info); + } + + fn super_body(&mut self, body: &$($mutability)? Body) { + super_body!(self, body, $($mutability)?); + } + + fn super_basic_block(&mut self, bb: &$($mutability)? BasicBlock) { + let BasicBlock { statements, terminator } = bb; + for stmt in statements { + self.visit_statement(stmt, Location(stmt.span)); + } + self.visit_terminator(terminator, Location(terminator.span)); + } + + fn super_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + let _ = local; + let LocalDecl { ty, span, .. } = decl; + self.visit_ty(ty, Location(*span)); + } + + fn super_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_local_decl(local, decl) + } + + fn super_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_local_decl(local, decl) + } + + fn super_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) { + let Statement { kind, span } = stmt; + self.visit_span(span); + match kind { + StatementKind::Assign(place, rvalue) => { + self.visit_place(place, PlaceContext::MUTATING, location); + self.visit_rvalue(rvalue, location); + } + StatementKind::FakeRead(_, place) | StatementKind::PlaceMention(place) => { + self.visit_place(place, PlaceContext::NON_MUTATING, location); + } + StatementKind::SetDiscriminant { place, .. } + | StatementKind::Deinit(place) + | StatementKind::Retag(_, place) => { + self.visit_place(place, PlaceContext::MUTATING, location); + } + StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { + self.visit_local(local, PlaceContext::NON_USE, location); + } + StatementKind::AscribeUserType { place, projections, variance: _ } => { + self.visit_place(place, PlaceContext::NON_USE, location); + self.visit_user_type_projection(projections); + } + StatementKind::Coverage(coverage) => visit_opaque(coverage), + StatementKind::Intrinsic(intrisic) => match intrisic { + NonDivergingIntrinsic::Assume(operand) => { + self.visit_operand(operand, location); + } + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + src, + dst, + count, + }) => { + self.visit_operand(src, location); + self.visit_operand(dst, location); + self.visit_operand(count, location); + } + }, + StatementKind::ConstEvalCounter | StatementKind::Nop => {} + } + } + + fn super_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) { + let Terminator { kind, span } = term; + self.visit_span(span); + match kind { + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Unreachable => {} + TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { + self.visit_operand(cond, location); + self.visit_assert_msg(msg, location); + } + TerminatorKind::Drop { place, target: _, unwind: _ } => { + self.visit_place(place, PlaceContext::MUTATING, location); + } + TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => { + self.visit_operand(func, location); + for arg in args { + self.visit_operand(arg, location); + } + self.visit_place(destination, PlaceContext::MUTATING, location); + } + TerminatorKind::InlineAsm { operands, .. } => { + for op in operands { + let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op; + if let Some(input) = in_value { + self.visit_operand(input, location); + } + if let Some(output) = out_place { + self.visit_place(output, PlaceContext::MUTATING, location); + } + } + } + TerminatorKind::Return => { + let $($mutability)? local = RETURN_LOCAL; + self.visit_local(&$($mutability)? local, PlaceContext::NON_MUTATING, location); + } + TerminatorKind::SwitchInt { discr, targets: _ } => { + self.visit_operand(discr, location); + } + } + } + + fn super_span(&mut self, span: &$($mutability)? Span) { + let _ = span; + } + + fn super_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) { + match rvalue { + Rvalue::AddressOf(mutability, place) => { + let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut }; + self.visit_place(place, pcx, location); + } + Rvalue::Aggregate(_, operands) => { + for op in operands { + self.visit_operand(op, location); + } + } + Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { + self.visit_operand(lhs, location); + self.visit_operand(rhs, location); + } + Rvalue::Cast(_, op, ty) => { + self.visit_operand(op, location); + self.visit_ty(ty, location); + } + Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => { + self.visit_place(place, PlaceContext::NON_MUTATING, location); + } + Rvalue::Ref(region, kind, place) => { + self.visit_region(region, location); + let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) }; + self.visit_place(place, pcx, location); + } + Rvalue::Repeat(op, constant) => { + self.visit_operand(op, location); + self.visit_ty_const(constant, location); + } + Rvalue::ShallowInitBox(op, ty) => { + self.visit_ty(ty, location); + self.visit_operand(op, location) + } + Rvalue::ThreadLocalRef(_) => {} + Rvalue::NullaryOp(_, ty) => { + self.visit_ty(ty, location); + } + Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => { + self.visit_operand(op, location); + } + } + } + + fn super_operand(&mut self, operand: &$($mutability)? Operand, location: Location) { + match operand { + Operand::Copy(place) | Operand::Move(place) => { + self.visit_place(place, PlaceContext::NON_MUTATING, location) + } + Operand::Constant(constant) => { + self.visit_const_operand(constant, location); + } + } + } + + fn super_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) { + // This is a no-op on mir::Visitor. + let _ = projection; + } + + fn super_ty(&mut self, ty: &$($mutability)? Ty) { + let _ = ty; + } + + fn super_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) { + let ConstOperand { span, user_ty: _, const_ } = constant; + self.visit_span(span); + self.visit_mir_const(const_, location); + } + + fn super_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) { + let MirConst { kind: _, ty, id: _ } = constant; + self.visit_ty(ty, location); + } + + fn super_ty_const(&mut self, constant: &$($mutability)? TyConst) { + let _ = constant; + } + + fn super_region(&mut self, region: &$($mutability)? Region) { + let _ = region; + } + + fn super_args(&mut self, args: &$($mutability)? GenericArgs) { + let _ = args; + } + + fn super_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) { + let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } = + var_debug_info; + self.visit_span(&$($mutability)? source_info.span); + let location = Location(source_info.span); + if let Some(composite) = composite { + self.visit_ty(&$($mutability)? composite.ty, location); + } + match value { + VarDebugInfoContents::Place(place) => { + self.visit_place(place, PlaceContext::NON_USE, location); + } + VarDebugInfoContents::Const(constant) => { + self.visit_mir_const(&$($mutability)? constant.const_, location); + } + } + } + + fn super_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) { + match msg { + AssertMessage::BoundsCheck { len, index } => { + self.visit_operand(len, location); + self.visit_operand(index, location); + } + AssertMessage::Overflow(_, left, right) => { + self.visit_operand(left, location); + self.visit_operand(right, location); + } + AssertMessage::OverflowNeg(op) + | AssertMessage::DivisionByZero(op) + | AssertMessage::RemainderByZero(op) + | AssertMessage::InvalidEnumConstruction(op) => { + self.visit_operand(op, location); + } + AssertMessage::ResumedAfterReturn(_) + | AssertMessage::ResumedAfterPanic(_) + | AssertMessage::NullPointerDereference + | AssertMessage::ResumedAfterDrop(_) => { + //nothing to visit + } + AssertMessage::MisalignedPointerDereference { required, found } => { + self.visit_operand(required, location); + self.visit_operand(found, location); + } + } + } + } + }; +} + +macro_rules! super_body { + ($self:ident, $body:ident, mut) => { + for bb in $body.blocks.iter_mut() { + $self.visit_basic_block(bb); + } + + $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local_mut()); + + for (idx, arg) in $body.arg_locals_mut().iter_mut().enumerate() { + $self.visit_arg_decl(idx + 1, arg) + } + + let local_start = $body.arg_count + 1; + for (idx, arg) in $body.inner_locals_mut().iter_mut().enumerate() { + $self.visit_local_decl(idx + local_start, arg) + } + + for info in $body.var_debug_info.iter_mut() { + $self.visit_var_debug_info(info); + } + + $self.visit_span(&mut $body.span) + }; + + ($self:ident, $body:ident, ) => { + let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = $body; + + for bb in blocks { + $self.visit_basic_block(bb); + } + + $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local()); + + for (idx, arg) in $body.arg_locals().iter().enumerate() { + $self.visit_arg_decl(idx + 1, arg) + } + + let local_start = arg_count + 1; + for (idx, arg) in $body.inner_locals().iter().enumerate() { + $self.visit_local_decl(idx + local_start, arg) + } + + for info in var_debug_info.iter() { + $self.visit_var_debug_info(info); + } + + $self.visit_span(span) + }; +} + +macro_rules! visit_place_fns { + (mut) => { + fn super_place(&mut self, place: &mut Place, ptx: PlaceContext, location: Location) { + self.visit_local(&mut place.local, ptx, location); + + for elem in place.projection.iter_mut() { + self.visit_projection_elem(elem, ptx, location); + } + } + + // We don't have to replicate the `process_projection()` like we did in + // `rustc_middle::mir::visit.rs` here because the `projection` field in `Place` + // of Stable-MIR is not an immutable borrow, unlike in `Place` of MIR. + fn visit_projection_elem( + &mut self, + elem: &mut ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + self.super_projection_elem(elem, ptx, location) + } + + fn super_projection_elem( + &mut self, + elem: &mut ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + match elem { + ProjectionElem::Deref => {} + ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), + ProjectionElem::Index(local) => self.visit_local(local, ptx, location), + ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {} + ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} + ProjectionElem::Downcast(_idx) => {} + ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), + ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), + } + } + }; + + () => { + fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) { + self.visit_local(&place.local, ptx, location); + + for (idx, elem) in place.projection.iter().enumerate() { + let place_ref = + PlaceRef { local: place.local, projection: &place.projection[..idx] }; + self.visit_projection_elem(place_ref, elem, ptx, location); + } + } + + fn visit_projection_elem<'a>( + &mut self, + place_ref: PlaceRef<'a>, + elem: &ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + let _ = place_ref; + self.super_projection_elem(elem, ptx, location); + } + + fn super_projection_elem( + &mut self, + elem: &ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + match elem { + ProjectionElem::Deref => {} + ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), + ProjectionElem::Index(local) => self.visit_local(local, ptx, location), + ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {} + ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} + ProjectionElem::Downcast(_idx) => {} + ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), + ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), + } + } + }; +} + +make_mir_visitor!(MirVisitor,); +make_mir_visitor!(MutMirVisitor, mut); + +/// This function is a no-op that gets used to ensure this visitor is kept up-to-date. +/// +/// The idea is that whenever we replace an Opaque type by a real type, the compiler will fail +/// when trying to invoke `visit_opaque`. +/// +/// If you are here because your compilation is broken, replace the failing call to `visit_opaque()` +/// by a `visit_` for your construct. +fn visit_opaque(_: &Opaque) {} + +/// The location of a statement / terminator in the code and the CFG. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Location(Span); + +impl Location { + pub fn span(&self) -> Span { + self.0 + } +} + +/// Location of the statement at the given index for a given basic block. Assumes that `stmt_idx` +/// and `bb_idx` are valid for a given body. +pub fn statement_location(body: &Body, bb_idx: &BasicBlockIdx, stmt_idx: usize) -> Location { + let bb = &body.blocks[*bb_idx]; + let stmt = &bb.statements[stmt_idx]; + Location(stmt.span) +} + +/// Location of the terminator for a given basic block. Assumes that `bb_idx` is valid for a given +/// body. +pub fn terminator_location(body: &Body, bb_idx: &BasicBlockIdx) -> Location { + let bb = &body.blocks[*bb_idx]; + let terminator = &bb.terminator; + Location(terminator.span) +} + +/// Reference to a place used to represent a partial projection. +pub struct PlaceRef<'a> { + pub local: Local, + pub projection: &'a [ProjectionElem], +} + +impl PlaceRef<'_> { + /// Get the type of this place. + pub fn ty(&self, locals: &[LocalDecl]) -> Result { + self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty)) + } +} + +/// Information about a place's usage. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct PlaceContext { + /// Whether the access is mutable or not. Keep this private so we can increment the type in a + /// backward compatible manner. + is_mut: bool, +} + +impl PlaceContext { + const MUTATING: Self = PlaceContext { is_mut: true }; + const NON_MUTATING: Self = PlaceContext { is_mut: false }; + const NON_USE: Self = PlaceContext { is_mut: false }; + + pub fn is_mutating(&self) -> bool { + self.is_mut + } +} diff --git a/compiler/stable_mir/src/rustc_internal/mod.rs b/compiler/stable_mir/src/rustc_internal/mod.rs new file mode 100644 index 00000000000..c1ed03ade75 --- /dev/null +++ b/compiler/stable_mir/src/rustc_internal/mod.rs @@ -0,0 +1,270 @@ +//! Module that implements the bridge between Stable MIR and internal compiler MIR. +//! +//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs +//! until stable MIR is complete. + +use std::cell::{Cell, RefCell}; + +use rustc_middle::ty::TyCtxt; +use rustc_smir::context::SmirCtxt; +use rustc_smir::{Bridge, SmirContainer, Tables}; +use rustc_span::def_id::CrateNum; +use scoped_tls::scoped_thread_local; + +use crate::Error; +use crate::unstable::{RustcInternal, Stable}; + +pub mod pretty; + +/// Convert an internal Rust compiler item into its stable counterpart, if one exists. +/// +/// # Warning +/// +/// This function is unstable, and its behavior may change at any point. +/// E.g.: Items that were previously supported, may no longer be supported, or its translation may +/// change. +/// +/// # Panics +/// +/// This function will panic if StableMIR has not been properly initialized. +pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T { + with_container(|tables, cx| item.stable(tables, cx)) +} + +/// Convert a stable item into its internal Rust compiler counterpart, if one exists. +/// +/// # Warning +/// +/// This function is unstable, and it's behavior may change at any point. +/// Not every stable item can be converted to an internal one. +/// Furthermore, items that were previously supported, may no longer be supported in newer versions. +/// +/// # Panics +/// +/// This function will panic if StableMIR has not been properly initialized. +pub fn internal<'tcx, S>(tcx: TyCtxt<'tcx>, item: S) -> S::T<'tcx> +where + S: RustcInternal, +{ + // The tcx argument ensures that the item won't outlive the type context. + // 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: &crate::Crate) -> CrateNum { + item.id.into() +} + +// A thread local variable that stores a pointer to the tables mapping between TyCtxt +// datastructures and stable MIR datastructures +scoped_thread_local! (static TLV: Cell<*const ()>); + +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 = 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_container( + 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 container = ptr as *const SmirContainer<'_, B>; + let mut tables = unsafe { (*container).tables.borrow_mut() }; + let cx = unsafe { (*container).cx.borrow() }; + f(&mut *tables, &*cx) + }) +} + +pub fn run(tcx: TyCtxt<'_>, f: F) -> Result +where + F: FnOnce() -> T, +{ + let smir_cx = RefCell::new(SmirCtxt::new(tcx)); + let container = SmirContainer { tables: RefCell::new(Tables::default()), cx: smir_cx }; + + crate::compiler_interface::run(&container, || init(&container, f)) +} + +/// Instantiate and run the compiler with the provided arguments and callback. +/// +/// The callback will be invoked after the compiler ran all its analyses, but before code generation. +/// Note that this macro accepts two different formats for the callback: +/// 1. An ident that resolves to a function that accepts no argument and returns `ControlFlow` +/// ```ignore(needs-extern-crate) +/// # extern crate rustc_driver; +/// # extern crate rustc_interface; +/// # extern crate rustc_middle; +/// # #[macro_use] +/// # extern crate stable_mir; +/// # +/// # fn main() { +/// # use std::ops::ControlFlow; +/// # use stable_mir::CompilerError; +/// fn analyze_code() -> ControlFlow<(), ()> { +/// // Your code goes in here. +/// # ControlFlow::Continue(()) +/// } +/// # let args = &["--verbose".to_string()]; +/// let result = run!(args, analyze_code); +/// # assert_eq!(result, Err(CompilerError::Skipped)) +/// # } +/// ``` +/// 2. A closure expression: +/// ```ignore(needs-extern-crate) +/// # extern crate rustc_driver; +/// # extern crate rustc_interface; +/// # extern crate rustc_middle; +/// # #[macro_use] +/// # extern crate stable_mir; +/// # +/// # fn main() { +/// # use std::ops::ControlFlow; +/// # use stable_mir::CompilerError; +/// fn analyze_code(extra_args: Vec) -> ControlFlow<(), ()> { +/// # let _ = extra_args; +/// // Your code goes in here. +/// # ControlFlow::Continue(()) +/// } +/// # let args = &["--verbose".to_string()]; +/// # let extra_args = vec![]; +/// let result = run!(args, || analyze_code(extra_args)); +/// # assert_eq!(result, Err(CompilerError::Skipped)) +/// # } +/// ``` +#[macro_export] +macro_rules! run { + ($args:expr, $callback_fn:ident) => { + run_driver!($args, || $callback_fn()) + }; + ($args:expr, $callback:expr) => { + run_driver!($args, $callback) + }; +} + +/// Instantiate and run the compiler with the provided arguments and callback. +/// +/// This is similar to `run` but it invokes the callback with the compiler's `TyCtxt`, +/// which can be used to invoke internal APIs. +#[macro_export] +macro_rules! run_with_tcx { + ($args:expr, $callback_fn:ident) => { + run_driver!($args, |tcx| $callback_fn(tcx), with_tcx) + }; + ($args:expr, $callback:expr) => { + run_driver!($args, $callback, with_tcx) + }; +} + +/// Optionally include an ident. This is needed due to macro hygiene. +#[macro_export] +#[doc(hidden)] +macro_rules! optional { + (with_tcx $ident:ident) => { + $ident + }; +} + +/// Prefer using [run!] and [run_with_tcx] instead. +/// +/// This macro implements the instantiation of a StableMIR driver, and it will invoke +/// the given callback after the compiler analyses. +/// +/// The third argument determines whether the callback requires `tcx` as an argument. +#[macro_export] +#[doc(hidden)] +macro_rules! run_driver { + ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{ + use rustc_driver::{Callbacks, Compilation, run_compiler}; + use rustc_middle::ty::TyCtxt; + use rustc_interface::interface; + use stable_mir::rustc_internal; + use stable_mir::CompilerError; + use std::ops::ControlFlow; + + pub struct StableMir ControlFlow> + where + B: Send, + C: Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, + { + callback: Option, + result: Option>, + } + + impl StableMir + where + B: Send, + C: Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, + { + /// Creates a new `StableMir` instance, with given test_function and arguments. + pub fn new(callback: F) -> Self { + StableMir { callback: Some(callback), result: None } + } + + /// Runs the compiler against given target and tests it with `test_function` + pub fn run(&mut self, args: &[String]) -> Result> { + let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> { + run_compiler(&args, self); + Ok(()) + }); + match (compiler_result, self.result.take()) { + (Ok(Ok(())), Some(ControlFlow::Continue(value))) => Ok(value), + (Ok(Ok(())), Some(ControlFlow::Break(value))) => { + Err(CompilerError::Interrupted(value)) + } + (Ok(Ok(_)), None) => Err(CompilerError::Skipped), + // Two cases here: + // - `run` finished normally and returned `Err` + // - `run` panicked with `FatalErr` + // You might think that normal compile errors cause the former, and + // ICEs cause the latter. But some normal compiler errors also cause + // the latter. So we can't meaningfully distinguish them, and group + // them together. + (Ok(Err(_)), _) | (Err(_), _) => Err(CompilerError::Failed), + } + } + } + + impl Callbacks for StableMir + where + B: Send, + C: Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, + { + /// Called after analysis. Return value instructs the compiler whether to + /// continue the compilation afterwards (defaults to `Compilation::Continue`) + fn after_analysis<'tcx>( + &mut self, + _compiler: &interface::Compiler, + tcx: TyCtxt<'tcx>, + ) -> Compilation { + if let Some(callback) = self.callback.take() { + rustc_internal::run(tcx, || { + self.result = Some(callback($(optional!($with_tcx tcx))?)); + }) + .unwrap(); + if self.result.as_ref().is_some_and(|val| val.is_continue()) { + Compilation::Continue + } else { + Compilation::Stop + } + } else { + Compilation::Continue + } + } + } + + StableMir::new($callback).run($args) + }}; +} diff --git a/compiler/stable_mir/src/rustc_internal/pretty.rs b/compiler/stable_mir/src/rustc_internal/pretty.rs new file mode 100644 index 00000000000..28c5280fe04 --- /dev/null +++ b/compiler/stable_mir/src/rustc_internal/pretty.rs @@ -0,0 +1,21 @@ +use std::io; + +use rustc_middle::ty::TyCtxt; + +use super::run; + +pub fn write_smir_pretty<'tcx, W: io::Write>(tcx: TyCtxt<'tcx>, w: &mut W) -> io::Result<()> { + writeln!( + w, + "// WARNING: This is highly experimental output it's intended for stable-mir developers only." + )?; + writeln!( + w, + "// If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir." + )?; + let _ = run(tcx, || { + let items = crate::all_local_items(); + let _ = items.iter().map(|item| -> io::Result<()> { item.emit_mir(w) }).collect::>(); + }); + Ok(()) +} diff --git a/compiler/stable_mir/src/target.rs b/compiler/stable_mir/src/target.rs new file mode 100644 index 00000000000..32c3a2a9122 --- /dev/null +++ b/compiler/stable_mir/src/target.rs @@ -0,0 +1,60 @@ +//! Provide information about the machine that this is being compiled into. + +use serde::Serialize; + +use crate::compiler_interface::with; + +/// The properties of the target machine being compiled into. +#[derive(Clone, PartialEq, Eq, Serialize)] +pub struct MachineInfo { + pub endian: Endian, + pub pointer_width: MachineSize, +} + +impl MachineInfo { + pub fn target() -> MachineInfo { + with(|cx| cx.target_info()) + } + + pub fn target_endianness() -> Endian { + with(|cx| cx.target_info().endian) + } + + pub fn target_pointer_width() -> MachineSize { + with(|cx| cx.target_info().pointer_width) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Serialize)] +pub enum Endian { + Little, + Big, +} + +/// Represent the size of a component. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub struct MachineSize { + num_bits: usize, +} + +impl MachineSize { + #[inline(always)] + pub fn bytes(self) -> usize { + self.num_bits / 8 + } + + #[inline(always)] + pub fn bits(self) -> usize { + self.num_bits + } + + #[inline(always)] + pub fn from_bits(num_bits: usize) -> MachineSize { + MachineSize { num_bits } + } + + #[inline] + pub fn unsigned_int_max(self) -> Option { + (self.num_bits <= 128).then(|| u128::MAX >> (128 - self.bits())) + } +} diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs new file mode 100644 index 00000000000..87d31cf9713 --- /dev/null +++ b/compiler/stable_mir/src/ty.rs @@ -0,0 +1,1655 @@ +use std::fmt::{self, Debug, Display, Formatter}; +use std::ops::Range; + +use serde::Serialize; + +use super::abi::ReprOptions; +use super::mir::{Body, Mutability, Safety}; +use super::{DefId, Error, Symbol, with}; +use crate::abi::{FnAbi, Layout}; +use crate::crate_def::{CrateDef, CrateDefItems, CrateDefType}; +use crate::mir::alloc::{AllocId, read_target_int, read_target_uint}; +use crate::mir::mono::StaticDef; +use crate::target::MachineInfo; +use crate::{Filename, IndexedVal, Opaque}; + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)] +pub struct Ty(usize); + +impl Debug for Ty { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Ty").field("id", &self.0).field("kind", &self.kind()).finish() + } +} + +/// Constructors for `Ty`. +impl Ty { + /// Create a new type from a given kind. + pub fn from_rigid_kind(kind: RigidTy) -> Ty { + with(|cx| cx.new_rigid_ty(kind)) + } + + /// Create a new array type. + pub fn try_new_array(elem_ty: Ty, size: u64) -> Result { + Ok(Ty::from_rigid_kind(RigidTy::Array(elem_ty, TyConst::try_from_target_usize(size)?))) + } + + /// Create a new array type from Const length. + pub fn new_array_with_const_len(elem_ty: Ty, len: TyConst) -> Ty { + Ty::from_rigid_kind(RigidTy::Array(elem_ty, len)) + } + + /// Create a new pointer type. + pub fn new_ptr(pointee_ty: Ty, mutability: Mutability) -> Ty { + Ty::from_rigid_kind(RigidTy::RawPtr(pointee_ty, mutability)) + } + + /// Create a new reference type. + pub fn new_ref(reg: Region, pointee_ty: Ty, mutability: Mutability) -> Ty { + Ty::from_rigid_kind(RigidTy::Ref(reg, pointee_ty, mutability)) + } + + /// Create a new pointer type. + pub fn new_tuple(tys: &[Ty]) -> Ty { + Ty::from_rigid_kind(RigidTy::Tuple(Vec::from(tys))) + } + + /// Create a new closure type. + pub fn new_closure(def: ClosureDef, args: GenericArgs) -> Ty { + Ty::from_rigid_kind(RigidTy::Closure(def, args)) + } + + /// Create a new coroutine type. + pub fn new_coroutine(def: CoroutineDef, args: GenericArgs, mov: Movability) -> Ty { + Ty::from_rigid_kind(RigidTy::Coroutine(def, args, mov)) + } + + /// Create a new closure type. + pub fn new_coroutine_closure(def: CoroutineClosureDef, args: GenericArgs) -> Ty { + Ty::from_rigid_kind(RigidTy::CoroutineClosure(def, args)) + } + + /// Create a new box type that represents `Box`, for the given inner type `T`. + pub fn new_box(inner_ty: Ty) -> Ty { + with(|cx| cx.new_box_ty(inner_ty)) + } + + /// Create a type representing `usize`. + pub fn usize_ty() -> Ty { + Ty::from_rigid_kind(RigidTy::Uint(UintTy::Usize)) + } + + /// Create a type representing `bool`. + pub fn bool_ty() -> Ty { + Ty::from_rigid_kind(RigidTy::Bool) + } + + /// Create a type representing a signed integer. + pub fn signed_ty(inner: IntTy) -> Ty { + Ty::from_rigid_kind(RigidTy::Int(inner)) + } + + /// Create a type representing an unsigned integer. + pub fn unsigned_ty(inner: UintTy) -> Ty { + Ty::from_rigid_kind(RigidTy::Uint(inner)) + } + + /// Get a type layout. + pub fn layout(self) -> Result { + with(|cx| cx.ty_layout(self)) + } +} + +impl Ty { + pub fn kind(&self) -> TyKind { + with(|context| context.ty_kind(*self)) + } +} + +/// Represents a pattern in the type system +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum Pattern { + Range { start: Option, end: Option, include_end: bool }, +} + +/// Represents a constant in the type system +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct TyConst { + pub(crate) kind: TyConstKind, + pub id: TyConstId, +} + +impl TyConst { + pub fn new(kind: TyConstKind, id: TyConstId) -> TyConst { + Self { kind, id } + } + + /// Retrieve the constant kind. + pub fn kind(&self) -> &TyConstKind { + &self.kind + } + + /// Creates an interned usize constant. + pub fn try_from_target_usize(val: u64) -> Result { + with(|cx| cx.try_new_ty_const_uint(val.into(), UintTy::Usize)) + } + + /// Try to evaluate to a target `usize`. + pub fn eval_target_usize(&self) -> Result { + with(|cx| cx.eval_target_usize_ty(self)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum TyConstKind { + Param(ParamConst), + Bound(DebruijnIndex, BoundVar), + Unevaluated(ConstDef, GenericArgs), + + // FIXME: These should be a valtree + Value(Ty, Allocation), + ZSTValue(Ty), +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)] +pub struct TyConstId(usize); + +/// Represents a constant in MIR +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct MirConst { + /// The constant kind. + pub(crate) kind: ConstantKind, + /// The constant type. + pub(crate) ty: Ty, + /// Used for internal tracking of the internal constant. + pub id: MirConstId, +} + +impl MirConst { + /// Build a constant. Note that this should only be used by the compiler. + pub fn new(kind: ConstantKind, ty: Ty, id: MirConstId) -> MirConst { + MirConst { kind, ty, id } + } + + /// Retrieve the constant kind. + pub fn kind(&self) -> &ConstantKind { + &self.kind + } + + /// Get the constant type. + pub fn ty(&self) -> Ty { + self.ty + } + + /// Try to evaluate to a target `usize`. + pub fn eval_target_usize(&self) -> Result { + with(|cx| cx.eval_target_usize(self)) + } + + /// Create a constant that represents a new zero-sized constant of type T. + /// Fails if the type is not a ZST or if it doesn't have a known size. + pub fn try_new_zero_sized(ty: Ty) -> Result { + with(|cx| cx.try_new_const_zst(ty)) + } + + /// Build a new constant that represents the given string. + /// + /// Note that there is no guarantee today about duplication of the same constant. + /// I.e.: Calling this function multiple times with the same argument may or may not return + /// the same allocation. + pub fn from_str(value: &str) -> MirConst { + with(|cx| cx.new_const_str(value)) + } + + /// Build a new constant that represents the given boolean value. + pub fn from_bool(value: bool) -> MirConst { + with(|cx| cx.new_const_bool(value)) + } + + /// Build a new constant that represents the given unsigned integer. + pub fn try_from_uint(value: u128, uint_ty: UintTy) -> Result { + with(|cx| cx.try_new_const_uint(value, uint_ty)) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] +pub struct MirConstId(usize); + +type Ident = Opaque; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct Region { + pub kind: RegionKind, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum RegionKind { + ReEarlyParam(EarlyParamRegion), + ReBound(DebruijnIndex, BoundRegion), + ReStatic, + RePlaceholder(Placeholder), + ReErased, +} + +pub(crate) type DebruijnIndex = u32; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct EarlyParamRegion { + pub index: u32, + pub name: Symbol, +} + +pub(crate) type BoundVar = u32; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct BoundRegion { + pub var: BoundVar, + pub kind: BoundRegionKind, +} + +pub(crate) type UniverseIndex = u32; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct Placeholder { + pub universe: UniverseIndex, + pub bound: T, +} + +#[derive(Clone, Copy, PartialEq, Eq, Serialize)] +pub struct Span(usize); + +impl Debug for Span { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Span") + .field("id", &self.0) + .field("repr", &with(|cx| cx.span_to_string(*self))) + .finish() + } +} + +impl Span { + /// Return filename for diagnostic purposes + pub fn get_filename(&self) -> Filename { + with(|c| c.get_filename(self)) + } + + /// Return lines that correspond to this `Span` + pub fn get_lines(&self) -> LineInfo { + with(|c| c.get_lines(self)) + } + + /// Return the span location to be printed in diagnostic messages. + /// + /// This may leak local file paths and should not be used to build artifacts that may be + /// distributed. + pub fn diagnostic(&self) -> String { + with(|c| c.span_to_string(*self)) + } +} + +#[derive(Clone, Copy, Debug, Serialize)] +/// Information you get from `Span` in a struct form. +/// Line and col start from 1. +pub struct LineInfo { + pub start_line: usize, + pub start_col: usize, + pub end_line: usize, + 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), + Alias(AliasKind, AliasTy), + Param(ParamTy), + Bound(usize, BoundTy), +} + +impl TyKind { + pub fn rigid(&self) -> Option<&RigidTy> { + if let TyKind::RigidTy(inner) = self { Some(inner) } else { None } + } + + #[inline] + pub fn is_unit(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Tuple(data)) if data.is_empty()) + } + + #[inline] + pub fn is_bool(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Bool)) + } + + #[inline] + pub fn is_char(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Char)) + } + + #[inline] + pub fn is_trait(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Dynamic(_, _, DynKind::Dyn))) + } + + #[inline] + pub fn is_enum(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Enum) + } + + #[inline] + pub fn is_struct(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Struct) + } + + #[inline] + pub fn is_union(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Union) + } + + #[inline] + pub fn is_adt(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Adt(..))) + } + + #[inline] + pub fn is_ref(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Ref(..))) + } + + #[inline] + pub fn is_fn(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::FnDef(..))) + } + + #[inline] + pub fn is_fn_ptr(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::FnPtr(..))) + } + + #[inline] + pub fn is_primitive(&self) -> bool { + matches!( + self, + TyKind::RigidTy( + RigidTy::Bool + | RigidTy::Char + | RigidTy::Int(_) + | RigidTy::Uint(_) + | RigidTy::Float(_) + ) + ) + } + + #[inline] + pub fn is_float(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Float(_))) + } + + #[inline] + pub fn is_integral(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Int(_) | RigidTy::Uint(_))) + } + + #[inline] + pub fn is_numeric(&self) -> bool { + self.is_integral() || self.is_float() + } + + #[inline] + pub fn is_signed(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Int(_))) + } + + #[inline] + pub fn is_str(&self) -> bool { + *self == TyKind::RigidTy(RigidTy::Str) + } + + #[inline] + pub fn is_cstr(&self) -> bool { + let TyKind::RigidTy(RigidTy::Adt(def, _)) = self else { + return false; + }; + with(|cx| cx.adt_is_cstr(*def)) + } + + #[inline] + pub fn is_slice(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Slice(_))) + } + + #[inline] + pub fn is_array(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Array(..))) + } + + #[inline] + pub fn is_mutable_ptr(&self) -> bool { + matches!( + self, + TyKind::RigidTy(RigidTy::RawPtr(_, Mutability::Mut)) + | TyKind::RigidTy(RigidTy::Ref(_, _, Mutability::Mut)) + ) + } + + #[inline] + pub fn is_raw_ptr(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::RawPtr(..))) + } + + /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer). + #[inline] + pub fn is_any_ptr(&self) -> bool { + self.is_ref() || self.is_raw_ptr() || self.is_fn_ptr() + } + + #[inline] + pub fn is_coroutine(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Coroutine(..))) + } + + #[inline] + pub fn is_closure(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Closure(..))) + } + + #[inline] + pub fn is_box(&self) -> bool { + match self { + TyKind::RigidTy(RigidTy::Adt(def, _)) => def.is_box(), + _ => false, + } + } + + #[inline] + pub fn is_simd(&self) -> bool { + matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.is_simd()) + } + + pub fn trait_principal(&self) -> Option> { + if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _, _)) = self { + if let Some(Binder { value: ExistentialPredicate::Trait(trait_ref), bound_vars }) = + predicates.first() + { + Some(Binder { value: trait_ref.clone(), bound_vars: bound_vars.clone() }) + } else { + None + } + } else { + None + } + } + + /// Returns the type of `ty[i]` for builtin types. + pub fn builtin_index(&self) -> Option { + match self.rigid()? { + RigidTy::Array(ty, _) | RigidTy::Slice(ty) => Some(*ty), + _ => None, + } + } + + /// Returns the type and mutability of `*ty` for builtin types. + /// + /// The parameter `explicit` indicates if this is an *explicit* dereference. + /// Some types -- notably raw ptrs -- can only be dereferenced explicitly. + pub fn builtin_deref(&self, explicit: bool) -> Option { + match self.rigid()? { + RigidTy::Adt(def, args) if def.is_box() => { + Some(TypeAndMut { ty: *args.0.first()?.ty()?, mutability: Mutability::Not }) + } + RigidTy::Ref(_, ty, mutability) => { + Some(TypeAndMut { ty: *ty, mutability: *mutability }) + } + RigidTy::RawPtr(ty, mutability) if explicit => { + Some(TypeAndMut { ty: *ty, mutability: *mutability }) + } + _ => None, + } + } + + /// Get the function signature for function like types (Fn, FnPtr, and Closure) + pub fn fn_sig(&self) -> Option { + match self { + TyKind::RigidTy(RigidTy::FnDef(def, args)) => Some(with(|cx| cx.fn_sig(*def, args))), + TyKind::RigidTy(RigidTy::FnPtr(sig)) => Some(sig.clone()), + TyKind::RigidTy(RigidTy::Closure(_def, args)) => Some(with(|cx| cx.closure_sig(args))), + _ => None, + } + } + + /// Get the discriminant type for this type. + pub fn discriminant_ty(&self) -> Option { + self.rigid().map(|ty| with(|cx| cx.rigid_ty_discriminant_ty(ty))) + } + + /// Deconstruct a function type if this is one. + pub fn fn_def(&self) -> Option<(FnDef, &GenericArgs)> { + if let TyKind::RigidTy(RigidTy::FnDef(def, args)) = self { + Some((*def, args)) + } else { + None + } + } +} + +pub struct TypeAndMut { + pub ty: Ty, + pub mutability: Mutability, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum RigidTy { + Bool, + Char, + Int(IntTy), + Uint(UintTy), + Float(FloatTy), + Adt(AdtDef, GenericArgs), + Foreign(ForeignDef), + Str, + Array(Ty, TyConst), + Pat(Ty, Pattern), + Slice(Ty), + RawPtr(Ty, Mutability), + Ref(Region, Ty, Mutability), + FnDef(FnDef, GenericArgs), + FnPtr(PolyFnSig), + Closure(ClosureDef, GenericArgs), + // FIXME(stable_mir): Movability here is redundant + Coroutine(CoroutineDef, GenericArgs, Movability), + CoroutineClosure(CoroutineClosureDef, GenericArgs), + Dynamic(Vec>, Region, DynKind), + Never, + Tuple(Vec), + CoroutineWitness(CoroutineWitnessDef, GenericArgs), +} + +impl RigidTy { + /// Get the discriminant type for this type. + pub fn discriminant_ty(&self) -> Ty { + with(|cx| cx.rigid_ty_discriminant_ty(self)) + } +} + +impl From for TyKind { + fn from(value: RigidTy) -> Self { + TyKind::RigidTy(value) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] +pub enum IntTy { + Isize, + I8, + I16, + I32, + I64, + I128, +} + +impl IntTy { + pub fn num_bytes(self) -> usize { + match self { + IntTy::Isize => MachineInfo::target_pointer_width().bytes(), + IntTy::I8 => 1, + IntTy::I16 => 2, + IntTy::I32 => 4, + IntTy::I64 => 8, + IntTy::I128 => 16, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] +pub enum UintTy { + Usize, + U8, + U16, + U32, + U64, + U128, +} + +impl UintTy { + pub fn num_bytes(self) -> usize { + match self { + UintTy::Usize => MachineInfo::target_pointer_width().bytes(), + UintTy::U8 => 1, + UintTy::U16 => 2, + UintTy::U32 => 4, + UintTy::U64 => 8, + UintTy::U128 => 16, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] +pub enum FloatTy { + F16, + F32, + F64, + F128, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] +pub enum Movability { + Static, + Movable, +} + +crate_def! { + #[derive(Serialize)] + pub ForeignModuleDef; +} + +impl ForeignModuleDef { + pub fn module(&self) -> ForeignModule { + with(|cx| cx.foreign_module(*self)) + } +} + +pub struct ForeignModule { + pub def_id: ForeignModuleDef, + pub abi: Abi, +} + +impl ForeignModule { + pub fn items(&self) -> Vec { + with(|cx| cx.foreign_items(self.def_id)) + } +} + +crate_def_with_ty! { + /// Hold information about a ForeignItem in a crate. + #[derive(Serialize)] + pub ForeignDef; +} + +impl ForeignDef { + pub fn kind(&self) -> ForeignItemKind { + with(|cx| cx.foreign_item_kind(*self)) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] +pub enum ForeignItemKind { + Fn(FnDef), + Static(StaticDef), + Type(Ty), +} + +crate_def_with_ty! { + /// Hold information about a function definition in a crate. + #[derive(Serialize)] + pub FnDef; +} + +impl FnDef { + // Get the function body if available. + pub fn body(&self) -> Option { + with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0))) + } + + // Check if the function body is available. + pub fn has_body(&self) -> bool { + with(|ctx| ctx.has_body(self.0)) + } + + /// Get the information of the intrinsic if this function is a definition of one. + pub fn as_intrinsic(&self) -> Option { + with(|cx| cx.intrinsic(self.def_id())) + } + + /// Check if the function is an intrinsic. + #[inline] + pub fn is_intrinsic(&self) -> bool { + self.as_intrinsic().is_some() + } + + /// Get the function signature for this function definition. + pub fn fn_sig(&self) -> PolyFnSig { + let kind = self.ty().kind(); + kind.fn_sig().unwrap() + } +} + +crate_def_with_ty! { + #[derive(Serialize)] + pub IntrinsicDef; +} + +impl IntrinsicDef { + /// Returns the plain name of the intrinsic. + /// e.g., `transmute` for `core::intrinsics::transmute`. + pub fn fn_name(&self) -> Symbol { + with(|cx| cx.intrinsic_name(*self)) + } + + /// Returns whether the intrinsic has no meaningful body and all backends + /// need to shim all calls to it. + pub fn must_be_overridden(&self) -> bool { + with(|cx| !cx.has_body(self.0)) + } +} + +impl From for FnDef { + fn from(def: IntrinsicDef) -> Self { + FnDef(def.0) + } +} + +crate_def! { + #[derive(Serialize)] + pub ClosureDef; +} + +impl ClosureDef { + /// Retrieves the body of the closure definition. Returns None if the body + /// isn't available. + pub fn body(&self) -> Option { + with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0))) + } +} + +crate_def! { + #[derive(Serialize)] + pub CoroutineDef; +} + +impl CoroutineDef { + /// Retrieves the body of the coroutine definition. Returns None if the body + /// isn't available. + pub fn body(&self) -> Option { + with(|cx| cx.has_body(self.0).then(|| cx.mir_body(self.0))) + } + + pub fn discriminant_for_variant(&self, args: &GenericArgs, idx: VariantIdx) -> Discr { + with(|cx| cx.coroutine_discr_for_variant(*self, args, idx)) + } +} + +crate_def! { + #[derive(Serialize)] + pub CoroutineClosureDef; +} + +crate_def! { + #[derive(Serialize)] + pub ParamDef; +} + +crate_def! { + #[derive(Serialize)] + pub BrNamedDef; +} + +crate_def! { + #[derive(Serialize)] + pub AdtDef; +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] +pub enum AdtKind { + Enum, + Union, + Struct, +} + +impl AdtDef { + pub fn kind(&self) -> AdtKind { + with(|cx| cx.adt_kind(*self)) + } + + /// Retrieve the type of this Adt. + pub fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.0)) + } + + /// Retrieve the type of this Adt by instantiating and normalizing it with the given arguments. + /// + /// This will assume the type can be instantiated with these arguments. + pub fn ty_with_args(&self, args: &GenericArgs) -> Ty { + with(|cx| cx.def_ty_with_args(self.0, args)) + } + + pub fn is_box(&self) -> bool { + with(|cx| cx.adt_is_box(*self)) + } + + pub fn is_simd(&self) -> bool { + with(|cx| cx.adt_is_simd(*self)) + } + + /// The number of variants in this ADT. + pub fn num_variants(&self) -> usize { + with(|cx| cx.adt_variants_len(*self)) + } + + /// Retrieve the variants in this ADT. + pub fn variants(&self) -> Vec { + self.variants_iter().collect() + } + + /// Iterate over the variants in this ADT. + pub fn variants_iter(&self) -> impl Iterator { + (0..self.num_variants()) + .map(|idx| VariantDef { idx: VariantIdx::to_val(idx), adt_def: *self }) + } + + pub fn variant(&self, idx: VariantIdx) -> Option { + (idx.to_index() < self.num_variants()).then_some(VariantDef { idx, adt_def: *self }) + } + + pub fn repr(&self) -> ReprOptions { + with(|cx| cx.adt_repr(*self)) + } + + pub fn discriminant_for_variant(&self, idx: VariantIdx) -> Discr { + with(|cx| cx.adt_discr_for_variant(*self, idx)) + } +} + +pub struct Discr { + pub val: u128, + pub ty: Ty, +} + +/// Definition of a variant, which can be either a struct / union field or an enum variant. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] +pub struct VariantDef { + /// The variant index. + /// + /// ## Warning + /// Do not access this field directly! + pub idx: VariantIdx, + /// The data type where this variant comes from. + /// For now, we use this to retrieve information about the variant itself so we don't need to + /// cache more information. + /// + /// ## Warning + /// Do not access this field directly! + pub adt_def: AdtDef, +} + +impl VariantDef { + pub fn name(&self) -> Symbol { + with(|cx| cx.variant_name(*self)) + } + + /// Retrieve all the fields in this variant. + // We expect user to cache this and use it directly since today it is expensive to generate all + // fields name. + pub fn fields(&self) -> Vec { + with(|cx| cx.variant_fields(*self)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct FieldDef { + /// The field definition. + /// + /// ## Warning + /// Do not access this field directly! This is public for the compiler to have access to it. + pub def: DefId, + + /// The field name. + pub name: Symbol, +} + +impl FieldDef { + /// Retrieve the type of this field instantiating and normalizing it with the given arguments. + /// + /// This will assume the type can be instantiated with these arguments. + pub fn ty_with_args(&self, args: &GenericArgs) -> Ty { + with(|cx| cx.def_ty_with_args(self.def, args)) + } + + /// Retrieve the type of this field. + pub fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.def)) + } +} + +impl Display for AdtKind { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(match self { + AdtKind::Enum => "enum", + AdtKind::Union => "union", + AdtKind::Struct => "struct", + }) + } +} + +impl AdtKind { + pub fn is_enum(&self) -> bool { + matches!(self, AdtKind::Enum) + } + + pub fn is_struct(&self) -> bool { + matches!(self, AdtKind::Struct) + } + + pub fn is_union(&self) -> bool { + matches!(self, AdtKind::Union) + } +} + +crate_def! { + #[derive(Serialize)] + pub AliasDef; +} + +crate_def! { + /// A trait's definition. + #[derive(Serialize)] + pub TraitDef; +} + +impl_crate_def_items! { + TraitDef; +} + +impl TraitDef { + pub fn declaration(trait_def: &TraitDef) -> TraitDecl { + with(|cx| cx.trait_decl(trait_def)) + } +} + +crate_def! { + #[derive(Serialize)] + pub GenericDef; +} + +crate_def_with_ty! { + #[derive(Serialize)] + pub ConstDef; +} + +crate_def! { + /// A trait impl definition. + #[derive(Serialize)] + pub ImplDef; +} + +impl_crate_def_items! { + ImplDef; +} + +impl ImplDef { + /// Retrieve information about this implementation. + pub fn trait_impl(&self) -> ImplTrait { + with(|cx| cx.trait_impl(self)) + } +} + +crate_def! { + #[derive(Serialize)] + pub RegionDef; +} + +crate_def! { + #[derive(Serialize)] + pub CoroutineWitnessDef; +} + +/// A list of generic arguments. +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct GenericArgs(pub Vec); + +impl std::ops::Index for GenericArgs { + type Output = Ty; + + fn index(&self, index: ParamTy) -> &Self::Output { + self.0[index.index as usize].expect_ty() + } +} + +impl std::ops::Index for GenericArgs { + type Output = TyConst; + + fn index(&self, index: ParamConst) -> &Self::Output { + self.0[index.index as usize].expect_const() + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum GenericArgKind { + Lifetime(Region), + Type(Ty), + Const(TyConst), +} + +impl GenericArgKind { + /// Panic if this generic argument is not a type, otherwise + /// return the type. + #[track_caller] + pub fn expect_ty(&self) -> &Ty { + match self { + GenericArgKind::Type(ty) => ty, + _ => panic!("{self:?}"), + } + } + + /// Panic if this generic argument is not a const, otherwise + /// return the const. + #[track_caller] + pub fn expect_const(&self) -> &TyConst { + match self { + GenericArgKind::Const(c) => c, + _ => panic!("{self:?}"), + } + } + + /// Return the generic argument type if applicable, otherwise return `None`. + pub fn ty(&self) -> Option<&Ty> { + match self { + GenericArgKind::Type(ty) => Some(ty), + _ => None, + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum TermKind { + Type(Ty), + Const(TyConst), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum AliasKind { + Projection, + Inherent, + Opaque, + Free, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct AliasTy { + pub def_id: AliasDef, + pub args: GenericArgs, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct AliasTerm { + pub def_id: AliasDef, + pub args: GenericArgs, +} + +pub type PolyFnSig = Binder; + +impl PolyFnSig { + /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. + /// + /// NB: this doesn't handle virtual calls - those should use `Instance::fn_abi` + /// instead, where the instance is an `InstanceKind::Virtual`. + pub fn fn_ptr_abi(self) -> Result { + with(|cx| cx.fn_ptr_abi(self)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct FnSig { + pub inputs_and_output: Vec, + pub c_variadic: bool, + pub safety: Safety, + pub abi: Abi, +} + +impl FnSig { + pub fn output(&self) -> Ty { + self.inputs_and_output[self.inputs_and_output.len() - 1] + } + + pub fn inputs(&self) -> &[Ty] { + &self.inputs_and_output[..self.inputs_and_output.len() - 1] + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] +pub enum Abi { + Rust, + C { unwind: bool }, + Cdecl { unwind: bool }, + Stdcall { unwind: bool }, + Fastcall { unwind: bool }, + Vectorcall { unwind: bool }, + Thiscall { unwind: bool }, + Aapcs { unwind: bool }, + Win64 { unwind: bool }, + SysV64 { unwind: bool }, + PtxKernel, + Msp430Interrupt, + X86Interrupt, + GpuKernel, + EfiApi, + AvrInterrupt, + AvrNonBlockingInterrupt, + CCmseNonSecureCall, + CCmseNonSecureEntry, + System { unwind: bool }, + RustCall, + Unadjusted, + RustCold, + RiscvInterruptM, + RiscvInterruptS, + RustInvalid, + Custom, +} + +/// A binder represents a possibly generic type and its bound vars. +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct Binder { + pub value: T, + pub bound_vars: Vec, +} + +impl Binder { + /// Create a new binder with the given bound vars. + pub fn bind_with_vars(value: T, bound_vars: Vec) -> Self { + Binder { value, bound_vars } + } + + /// Create a new binder with no bounded variable. + pub fn dummy(value: T) -> Self { + Binder { value, bound_vars: vec![] } + } + + pub fn skip_binder(self) -> T { + self.value + } + + pub fn map_bound_ref(&self, f: F) -> Binder + where + F: FnOnce(&T) -> U, + { + let Binder { value, bound_vars } = self; + let new_value = f(value); + Binder { value: new_value, bound_vars: bound_vars.clone() } + } + + pub fn map_bound(self, f: F) -> Binder + where + F: FnOnce(T) -> U, + { + let Binder { value, bound_vars } = self; + let new_value = f(value); + Binder { value: new_value, bound_vars } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct EarlyBinder { + pub value: T, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum BoundVariableKind { + Ty(BoundTyKind), + Region(BoundRegionKind), + Const, +} + +#[derive(Clone, PartialEq, Eq, Debug, Serialize)] +pub enum BoundTyKind { + Anon, + Param(ParamDef, String), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum BoundRegionKind { + BrAnon, + BrNamed(BrNamedDef, String), + BrEnv, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum DynKind { + Dyn, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum ExistentialPredicate { + Trait(ExistentialTraitRef), + Projection(ExistentialProjection), + AutoTrait(TraitDef), +} + +/// An existential reference to a trait where `Self` is not included. +/// +/// The `generic_args` will include any other known argument. +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct ExistentialTraitRef { + pub def_id: TraitDef, + pub generic_args: GenericArgs, +} + +impl Binder { + pub fn with_self_ty(&self, self_ty: Ty) -> Binder { + self.map_bound_ref(|trait_ref| trait_ref.with_self_ty(self_ty)) + } +} + +impl ExistentialTraitRef { + pub fn with_self_ty(&self, self_ty: Ty) -> TraitRef { + TraitRef::new(self.def_id, self_ty, &self.generic_args) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct ExistentialProjection { + pub def_id: TraitDef, + pub generic_args: GenericArgs, + pub term: TermKind, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct ParamTy { + pub index: u32, + pub name: String, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct BoundTy { + pub var: usize, + pub kind: BoundTyKind, +} + +pub type Bytes = Vec>; + +/// Size in bytes. +pub type Size = usize; + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] +pub struct Prov(pub AllocId); + +pub type Align = u64; +pub type Promoted = u32; +pub type InitMaskMaterialized = Vec; + +/// Stores the provenance information of pointers stored in memory. +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] +pub struct ProvenanceMap { + /// Provenance in this map applies from the given offset for an entire pointer-size worth of + /// bytes. Two entries in this map are always at least a pointer size apart. + pub ptrs: Vec<(Size, Prov)>, +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] +pub struct Allocation { + pub bytes: Bytes, + pub provenance: ProvenanceMap, + pub align: Align, + pub mutability: Mutability, +} + +impl Allocation { + /// Get a vector of bytes for an Allocation that has been fully initialized + pub fn raw_bytes(&self) -> Result, Error> { + self.bytes + .iter() + .copied() + .collect::>>() + .ok_or_else(|| error!("Found uninitialized bytes: `{:?}`", self.bytes)) + } + + /// Read a uint value from the specified range. + pub fn read_partial_uint(&self, range: Range) -> Result { + if range.end - range.start > 16 { + return Err(error!("Allocation is bigger than largest integer")); + } + if range.end > self.bytes.len() { + return Err(error!( + "Range is out of bounds. Allocation length is `{}`, but requested range `{:?}`", + self.bytes.len(), + range + )); + } + let raw = self.bytes[range] + .iter() + .copied() + .collect::>>() + .ok_or_else(|| error!("Found uninitialized bytes: `{:?}`", self.bytes))?; + read_target_uint(&raw) + } + + /// Read this allocation and try to convert it to an unassigned integer. + pub fn read_uint(&self) -> Result { + if self.bytes.len() > 16 { + return Err(error!("Allocation is bigger than largest integer")); + } + let raw = self.raw_bytes()?; + read_target_uint(&raw) + } + + /// Read this allocation and try to convert it to a signed integer. + pub fn read_int(&self) -> Result { + if self.bytes.len() > 16 { + return Err(error!("Allocation is bigger than largest integer")); + } + let raw = self.raw_bytes()?; + read_target_int(&raw) + } + + /// Read this allocation and try to convert it to a boolean. + pub fn read_bool(&self) -> Result { + match self.read_int()? { + 0 => Ok(false), + 1 => Ok(true), + val => Err(error!("Unexpected value for bool: `{val}`")), + } + } + + /// Read this allocation as a pointer and return whether it represents a `null` pointer. + pub fn is_null(&self) -> Result { + let len = self.bytes.len(); + let ptr_len = MachineInfo::target_pointer_width().bytes(); + if len != ptr_len { + return Err(error!("Expected width of pointer (`{ptr_len}`), but found: `{len}`")); + } + Ok(self.read_uint()? == 0 && self.provenance.ptrs.is_empty()) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum ConstantKind { + Ty(TyConst), + Allocated(Allocation), + Unevaluated(UnevaluatedConst), + Param(ParamConst), + /// Store ZST constants. + /// We have to special handle these constants since its type might be generic. + ZeroSized, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct ParamConst { + pub index: u32, + pub name: String, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct UnevaluatedConst { + pub def: ConstDef, + pub args: GenericArgs, + pub promoted: Option, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] +pub enum TraitSpecializationKind { + None, + Marker, + AlwaysApplicable, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct TraitDecl { + pub def_id: TraitDef, + pub safety: Safety, + pub paren_sugar: bool, + pub has_auto_impl: bool, + pub is_marker: bool, + pub is_coinductive: bool, + pub skip_array_during_method_dispatch: bool, + pub skip_boxed_slice_during_method_dispatch: bool, + pub specialization_kind: TraitSpecializationKind, + pub must_implement_one_of: Option>, + pub implement_via_object: bool, + pub deny_explicit_impl: bool, +} + +impl TraitDecl { + pub fn generics_of(&self) -> Generics { + with(|cx| cx.generics_of(self.def_id.0)) + } + + pub fn predicates_of(&self) -> GenericPredicates { + with(|cx| cx.predicates_of(self.def_id.0)) + } + + pub fn explicit_predicates_of(&self) -> GenericPredicates { + with(|cx| cx.explicit_predicates_of(self.def_id.0)) + } +} + +pub type ImplTrait = EarlyBinder; + +/// A complete reference to a trait, i.e., one where `Self` is known. +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct TraitRef { + pub def_id: TraitDef, + /// The generic arguments for this definition. + /// The first element must always be type, and it represents `Self`. + args: GenericArgs, +} + +impl TraitRef { + pub fn new(def_id: TraitDef, self_ty: Ty, gen_args: &GenericArgs) -> TraitRef { + let mut args = vec![GenericArgKind::Type(self_ty)]; + args.extend_from_slice(&gen_args.0); + TraitRef { def_id, args: GenericArgs(args) } + } + + pub fn try_new(def_id: TraitDef, args: GenericArgs) -> Result { + match &args.0[..] { + [GenericArgKind::Type(_), ..] => Ok(TraitRef { def_id, args }), + _ => Err(()), + } + } + + pub fn args(&self) -> &GenericArgs { + &self.args + } + + pub fn self_ty(&self) -> Ty { + let GenericArgKind::Type(self_ty) = self.args.0[0] else { + panic!("Self must be a type, but found: {:?}", self.args.0[0]) + }; + self_ty + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct Generics { + pub parent: Option, + pub parent_count: usize, + pub params: Vec, + pub param_def_id_to_index: Vec<(GenericDef, u32)>, + pub has_self: bool, + pub has_late_bound_regions: Option, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum GenericParamDefKind { + Lifetime, + Type { has_default: bool, synthetic: bool }, + Const { has_default: bool }, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct GenericParamDef { + pub name: super::Symbol, + pub def_id: GenericDef, + pub index: u32, + pub pure_wrt_drop: bool, + pub kind: GenericParamDefKind, +} + +pub struct GenericPredicates { + pub parent: Option, + pub predicates: Vec<(PredicateKind, Span)>, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum PredicateKind { + Clause(ClauseKind), + DynCompatible(TraitDef), + SubType(SubtypePredicate), + Coerce(CoercePredicate), + ConstEquate(TyConst, TyConst), + Ambiguous, + AliasRelate(TermKind, TermKind, AliasRelationDirection), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum ClauseKind { + Trait(TraitPredicate), + RegionOutlives(RegionOutlivesPredicate), + TypeOutlives(TypeOutlivesPredicate), + Projection(ProjectionPredicate), + ConstArgHasType(TyConst, Ty), + WellFormed(TermKind), + ConstEvaluatable(TyConst), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum ClosureKind { + Fn, + FnMut, + FnOnce, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct SubtypePredicate { + pub a: Ty, + pub b: Ty, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct CoercePredicate { + pub a: Ty, + pub b: Ty, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum AliasRelationDirection { + Equate, + Subtype, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct TraitPredicate { + pub trait_ref: TraitRef, + pub polarity: PredicatePolarity, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct OutlivesPredicate(pub A, pub B); + +pub type RegionOutlivesPredicate = OutlivesPredicate; +pub type TypeOutlivesPredicate = OutlivesPredicate; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct ProjectionPredicate { + pub projection_term: AliasTerm, + pub term: TermKind, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum ImplPolarity { + Positive, + Negative, + Reservation, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum PredicatePolarity { + Positive, + Negative, +} + +macro_rules! index_impl { + ($name:ident) => { + impl crate::IndexedVal for $name { + fn to_val(index: usize) -> Self { + $name(index) + } + fn to_index(&self) -> usize { + self.0 + } + } + }; +} + +index_impl!(TyConstId); +index_impl!(MirConstId); +index_impl!(Ty); +index_impl!(Span); + +/// The source-order index of a variant in a type. +/// +/// For example, in the following types, +/// ```ignore(illustrative) +/// enum Demo1 { +/// Variant0 { a: bool, b: i32 }, +/// Variant1 { c: u8, d: u64 }, +/// } +/// struct Demo2 { e: u8, f: u16, g: u8 } +/// ``` +/// `a` is in the variant with the `VariantIdx` of `0`, +/// `c` is in the variant with the `VariantIdx` of `1`, and +/// `g` is in the variant with the `VariantIdx` of `0`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] +pub struct VariantIdx(usize); + +index_impl!(VariantIdx); + +crate_def! { + /// Hold information about an Opaque definition, particularly useful in `RPITIT`. + #[derive(Serialize)] + pub OpaqueDef; +} + +crate_def! { + #[derive(Serialize)] + pub AssocDef; +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct AssocItem { + pub def_id: AssocDef, + pub kind: AssocKind, + pub container: AssocItemContainer, + + /// If this is an item in an impl of a trait then this is the `DefId` of + /// the associated item on the trait that this implements. + pub trait_item_def_id: Option, +} + +#[derive(Clone, PartialEq, Debug, Eq, Serialize)] +pub enum AssocTypeData { + Normal(Symbol), + /// The associated type comes from an RPITIT. It has no name, and the + /// `ImplTraitInTraitData` provides additional information about its + /// source. + Rpitit(ImplTraitInTraitData), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum AssocKind { + Const { name: Symbol }, + Fn { name: Symbol, has_self: bool }, + Type { data: AssocTypeData }, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub enum AssocItemContainer { + Trait, + Impl, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] +pub enum ImplTraitInTraitData { + Trait { fn_def_id: FnDef, opaque_def_id: OpaqueDef }, + Impl { fn_def_id: FnDef }, +} + +impl AssocItem { + pub fn is_impl_trait_in_trait(&self) -> bool { + matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) }) + } +} diff --git a/compiler/stable_mir/src/unstable/convert/internal.rs b/compiler/stable_mir/src/unstable/convert/internal.rs new file mode 100644 index 00000000000..04b2e572621 --- /dev/null +++ b/compiler/stable_mir/src/unstable/convert/internal.rs @@ -0,0 +1,823 @@ +//! Module containing the translation from stable mir constructs to the rustc counterpart. +//! +//! This module will only include a few constructs to allow users to invoke internal rustc APIs +//! due to incomplete stable coverage. + +// 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}; +use rustc_smir::Tables; + +use crate::abi::Layout; +use crate::compiler_interface::BridgeTys; +use crate::mir::alloc::AllocId; +use crate::mir::mono::{Instance, MonoItem, StaticDef}; +use crate::mir::{BinOp, Mutability, Place, ProjectionElem, RawPtrKind, Safety, UnOp}; +use crate::ty::{ + Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, DynKind, + ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig, + GenericArgKind, GenericArgs, IntTy, MirConst, Movability, Pattern, Region, RigidTy, Span, + TermKind, TraitRef, Ty, TyConst, UintTy, VariantDef, VariantIdx, +}; +use crate::unstable::{InternalCx, RustcInternal}; +use crate::{CrateItem, CrateNum, DefId, IndexedVal}; + +impl RustcInternal for CrateItem { + type T<'tcx> = rustc_span::def_id::DefId; + 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<'_, 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<'_, 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<'_, 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<'_, 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(), + GenericArgKind::Const(cnst) => cnst.internal(tables, tcx).into(), + }; + tcx.lift(arg).unwrap() + } +} + +impl RustcInternal for Region { + type T<'tcx> = rustc_ty::Region<'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() + } +} + +impl RustcInternal for Ty { + type T<'tcx> = InternalTy<'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<'_, 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<'_, 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), + end: end.as_ref().unwrap().internal(tables, tcx), + }, + }) + } +} + +impl RustcInternal for RigidTy { + type T<'tcx> = rustc_ty::TyKind<'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, + RigidTy::Int(int_ty) => rustc_ty::TyKind::Int(int_ty.internal(tables, tcx)), + RigidTy::Uint(uint_ty) => rustc_ty::TyKind::Uint(uint_ty.internal(tables, tcx)), + RigidTy::Float(float_ty) => rustc_ty::TyKind::Float(float_ty.internal(tables, tcx)), + RigidTy::Never => rustc_ty::TyKind::Never, + RigidTy::Array(ty, cnst) => { + rustc_ty::TyKind::Array(ty.internal(tables, tcx), cnst.internal(tables, tcx)) + } + RigidTy::Pat(ty, pat) => { + rustc_ty::TyKind::Pat(ty.internal(tables, tcx), pat.internal(tables, tcx)) + } + RigidTy::Adt(def, args) => { + rustc_ty::TyKind::Adt(def.internal(tables, tcx), args.internal(tables, tcx)) + } + RigidTy::Str => rustc_ty::TyKind::Str, + RigidTy::Slice(ty) => rustc_ty::TyKind::Slice(ty.internal(tables, tcx)), + RigidTy::RawPtr(ty, mutability) => { + rustc_ty::TyKind::RawPtr(ty.internal(tables, tcx), mutability.internal(tables, tcx)) + } + RigidTy::Ref(region, ty, mutability) => rustc_ty::TyKind::Ref( + region.internal(tables, tcx), + ty.internal(tables, tcx), + mutability.internal(tables, tcx), + ), + RigidTy::Foreign(def) => rustc_ty::TyKind::Foreign(def.0.internal(tables, tcx)), + RigidTy::FnDef(def, args) => { + rustc_ty::TyKind::FnDef(def.0.internal(tables, tcx), args.internal(tables, tcx)) + } + RigidTy::FnPtr(sig) => { + let (sig_tys, hdr) = sig.internal(tables, tcx).split(); + rustc_ty::TyKind::FnPtr(sig_tys, hdr) + } + RigidTy::Closure(def, args) => { + rustc_ty::TyKind::Closure(def.0.internal(tables, tcx), args.internal(tables, tcx)) + } + RigidTy::Coroutine(def, args, _mov) => { + rustc_ty::TyKind::Coroutine(def.0.internal(tables, tcx), args.internal(tables, tcx)) + } + RigidTy::CoroutineClosure(def, args) => rustc_ty::TyKind::CoroutineClosure( + def.0.internal(tables, tcx), + args.internal(tables, tcx), + ), + RigidTy::CoroutineWitness(def, args) => rustc_ty::TyKind::CoroutineWitness( + def.0.internal(tables, tcx), + args.internal(tables, tcx), + ), + RigidTy::Dynamic(predicate, region, dyn_kind) => rustc_ty::TyKind::Dynamic( + tcx.mk_poly_existential_predicates(&predicate.internal(tables, tcx)), + region.internal(tables, tcx), + dyn_kind.internal(tables, tcx), + ), + RigidTy::Tuple(tys) => { + rustc_ty::TyKind::Tuple(tcx.mk_type_list(&tys.internal(tables, tcx))) + } + } + } +} + +impl RustcInternal for IntTy { + type T<'tcx> = rustc_ty::IntTy; + + 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, + IntTy::I16 => rustc_ty::IntTy::I16, + IntTy::I32 => rustc_ty::IntTy::I32, + IntTy::I64 => rustc_ty::IntTy::I64, + IntTy::I128 => rustc_ty::IntTy::I128, + } + } +} + +impl RustcInternal for UintTy { + type T<'tcx> = rustc_ty::UintTy; + + 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, + UintTy::U16 => rustc_ty::UintTy::U16, + UintTy::U32 => rustc_ty::UintTy::U32, + UintTy::U64 => rustc_ty::UintTy::U64, + UintTy::U128 => rustc_ty::UintTy::U128, + } + } +} + +impl RustcInternal for FloatTy { + type T<'tcx> = rustc_ty::FloatTy; + + 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, + FloatTy::F64 => rustc_ty::FloatTy::F64, + FloatTy::F128 => rustc_ty::FloatTy::F128, + } + } +} + +impl RustcInternal for Mutability { + type T<'tcx> = rustc_ty::Mutability; + + 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, + } + } +} + +impl RustcInternal for Movability { + type T<'tcx> = rustc_ty::Movability; + + 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, + } + } +} + +impl RustcInternal for RawPtrKind { + type T<'tcx> = rustc_middle::mir::RawPtrKind; + + 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, + RawPtrKind::FakeForPtrMetadata => rustc_middle::mir::RawPtrKind::FakeForPtrMetadata, + } + } +} + +impl RustcInternal for FnSig { + type T<'tcx> = rustc_ty::FnSig<'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, + safety: self.safety.internal(tables, tcx), + abi: self.abi.internal(tables, tcx), + }) + .unwrap() + } +} + +impl RustcInternal for VariantIdx { + type T<'tcx> = rustc_abi::VariantIdx; + + fn internal<'tcx>( + &self, + _tables: &mut Tables<'_, BridgeTys>, + _tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + rustc_abi::VariantIdx::from(self.to_index()) + } +} + +impl RustcInternal for VariantDef { + type T<'tcx> = &'tcx rustc_ty::VariantDef; + + 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<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + let constant = tables.mir_consts[self.id]; + match constant { + rustc_middle::mir::Const::Ty(ty, ct) => { + rustc_middle::mir::Const::Ty(tcx.lift(ty).unwrap(), tcx.lift(ct).unwrap()) + } + rustc_middle::mir::Const::Unevaluated(uneval, ty) => { + rustc_middle::mir::Const::Unevaluated( + tcx.lift(uneval).unwrap(), + tcx.lift(ty).unwrap(), + ) + } + rustc_middle::mir::Const::Val(const_val, ty) => { + rustc_middle::mir::Const::Val(tcx.lift(const_val).unwrap(), tcx.lift(ty).unwrap()) + } + } + } +} + +impl RustcInternal for MonoItem { + type T<'tcx> = rustc_middle::mir::mono::MonoItem<'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)), + MonoItem::Static(def) => rustc_mono::MonoItem::Static(def.internal(tables, tcx)), + MonoItem::GlobalAsm(_) => { + unimplemented!() + } + } + } +} + +impl RustcInternal for Instance { + type T<'tcx> = rustc_ty::Instance<'tcx>; + + fn internal<'tcx>( + &self, + tables: &mut Tables<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + tcx.lift(tables.instances[self.def]).unwrap() + } +} + +impl RustcInternal for StaticDef { + type T<'tcx> = rustc_span::def_id::DefId; + + fn internal<'tcx>( + &self, + tables: &mut Tables<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + self.0.internal(tables, tcx) + } +} + +#[allow(rustc::usage_of_qualified_ty)] +impl RustcInternal for Binder +where + T: RustcInternal, + for<'tcx> T::T<'tcx>: rustc_ty::TypeVisitable>, +{ + type T<'tcx> = rustc_ty::Binder<'tcx, T::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( + self.bound_vars.iter().map(|bound| bound.internal(tables, tcx)), + ), + ) + } +} + +impl RustcInternal for BoundVariableKind { + type T<'tcx> = rustc_ty::BoundVariableKind; + + 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, + BoundTyKind::Param(def, _symbol) => { + rustc_ty::BoundTyKind::Param(def.0.internal(tables, tcx)) + } + }), + BoundVariableKind::Region(kind) => rustc_ty::BoundVariableKind::Region(match kind { + BoundRegionKind::BrAnon => rustc_ty::BoundRegionKind::Anon, + BoundRegionKind::BrNamed(def, _symbol) => { + rustc_ty::BoundRegionKind::Named(def.0.internal(tables, tcx)) + } + BoundRegionKind::BrEnv => rustc_ty::BoundRegionKind::ClosureEnv, + }), + BoundVariableKind::Const => rustc_ty::BoundVariableKind::Const, + } + } +} + +impl RustcInternal for DynKind { + type T<'tcx> = rustc_ty::DynKind; + + fn internal<'tcx>( + &self, + _tables: &mut Tables<'_, BridgeTys>, + _tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + match self { + DynKind::Dyn => rustc_ty::DynKind::Dyn, + } + } +} + +impl RustcInternal for ExistentialPredicate { + type T<'tcx> = rustc_ty::ExistentialPredicate<'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)) + } + ExistentialPredicate::Projection(proj) => { + rustc_ty::ExistentialPredicate::Projection(proj.internal(tables, tcx)) + } + ExistentialPredicate::AutoTrait(trait_def) => { + rustc_ty::ExistentialPredicate::AutoTrait(trait_def.0.internal(tables, tcx)) + } + } + } +} + +impl RustcInternal for ExistentialProjection { + type T<'tcx> = rustc_ty::ExistentialProjection<'tcx>; + + fn internal<'tcx>( + &self, + tables: &mut Tables<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + use crate::unstable::internal_cx::SmirExistentialProjection; + tcx.new_from_args( + self.def_id.0.internal(tables, tcx), + self.generic_args.internal(tables, tcx), + self.term.internal(tables, tcx), + ) + } +} + +impl RustcInternal for TermKind { + type T<'tcx> = rustc_ty::Term<'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(), + } + } +} + +impl RustcInternal for ExistentialTraitRef { + type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>; + + fn internal<'tcx>( + &self, + tables: &mut Tables<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + use crate::unstable::internal_cx::SmirExistentialTraitRef; + tcx.new_from_args( + self.def_id.0.internal(tables, tcx), + self.generic_args.internal(tables, tcx), + ) + } +} + +impl RustcInternal for TraitRef { + type T<'tcx> = rustc_ty::TraitRef<'tcx>; + + fn internal<'tcx>( + &self, + tables: &mut Tables<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + use crate::unstable::internal_cx::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<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + tcx.lift(tables.alloc_ids[*self]).unwrap() + } +} + +impl RustcInternal for ClosureKind { + type T<'tcx> = rustc_ty::ClosureKind; + + 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, + ClosureKind::FnOnce => rustc_ty::ClosureKind::FnOnce, + } + } +} + +impl RustcInternal for AdtDef { + type T<'tcx> = rustc_ty::AdtDef<'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<'_, BridgeTys>, + _tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + match *self { + Abi::Rust => rustc_abi::ExternAbi::Rust, + Abi::C { unwind } => rustc_abi::ExternAbi::C { unwind }, + Abi::Cdecl { unwind } => rustc_abi::ExternAbi::Cdecl { unwind }, + Abi::Stdcall { unwind } => rustc_abi::ExternAbi::Stdcall { unwind }, + Abi::Fastcall { unwind } => rustc_abi::ExternAbi::Fastcall { unwind }, + Abi::Vectorcall { unwind } => rustc_abi::ExternAbi::Vectorcall { unwind }, + Abi::Thiscall { unwind } => rustc_abi::ExternAbi::Thiscall { unwind }, + Abi::Aapcs { unwind } => rustc_abi::ExternAbi::Aapcs { unwind }, + Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CmseNonSecureCall, + Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CmseNonSecureEntry, + Abi::Win64 { unwind } => rustc_abi::ExternAbi::Win64 { unwind }, + Abi::SysV64 { unwind } => rustc_abi::ExternAbi::SysV64 { unwind }, + Abi::PtxKernel => rustc_abi::ExternAbi::PtxKernel, + Abi::Msp430Interrupt => rustc_abi::ExternAbi::Msp430Interrupt, + Abi::X86Interrupt => rustc_abi::ExternAbi::X86Interrupt, + Abi::GpuKernel => rustc_abi::ExternAbi::GpuKernel, + Abi::EfiApi => rustc_abi::ExternAbi::EfiApi, + Abi::AvrInterrupt => rustc_abi::ExternAbi::AvrInterrupt, + Abi::AvrNonBlockingInterrupt => rustc_abi::ExternAbi::AvrNonBlockingInterrupt, + Abi::System { unwind } => rustc_abi::ExternAbi::System { unwind }, + Abi::RustCall => rustc_abi::ExternAbi::RustCall, + Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted, + Abi::RustCold => rustc_abi::ExternAbi::RustCold, + Abi::RustInvalid => rustc_abi::ExternAbi::RustInvalid, + Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM, + Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS, + Abi::Custom => rustc_abi::ExternAbi::Custom, + } + } +} + +impl RustcInternal for Safety { + type T<'tcx> = rustc_hir::Safety; + + 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, + } + } +} +impl RustcInternal for Span { + type T<'tcx> = rustc_span::Span; + + 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<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + tcx.lift(tables.layouts[*self]).unwrap() + } +} + +impl RustcInternal for Place { + type T<'tcx> = rustc_middle::mir::Place<'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)), + } + } +} + +impl RustcInternal for ProjectionElem { + type T<'tcx> = rustc_middle::mir::PlaceElem<'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) => { + rustc_middle::mir::PlaceElem::Field((*idx).into(), ty.internal(tables, tcx)) + } + ProjectionElem::Index(idx) => rustc_middle::mir::PlaceElem::Index((*idx).into()), + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + rustc_middle::mir::PlaceElem::ConstantIndex { + offset: *offset, + min_length: *min_length, + from_end: *from_end, + } + } + ProjectionElem::Subslice { from, to, from_end } => { + rustc_middle::mir::PlaceElem::Subslice { from: *from, to: *to, from_end: *from_end } + } + ProjectionElem::Downcast(idx) => { + rustc_middle::mir::PlaceElem::Downcast(None, idx.internal(tables, tcx)) + } + ProjectionElem::OpaqueCast(ty) => { + rustc_middle::mir::PlaceElem::OpaqueCast(ty.internal(tables, tcx)) + } + ProjectionElem::Subtype(ty) => { + rustc_middle::mir::PlaceElem::Subtype(ty.internal(tables, tcx)) + } + } + } +} + +impl RustcInternal for BinOp { + type T<'tcx> = rustc_middle::mir::BinOp; + + 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, + BinOp::Sub => rustc_middle::mir::BinOp::Sub, + BinOp::SubUnchecked => rustc_middle::mir::BinOp::SubUnchecked, + BinOp::Mul => rustc_middle::mir::BinOp::Mul, + BinOp::MulUnchecked => rustc_middle::mir::BinOp::MulUnchecked, + BinOp::Div => rustc_middle::mir::BinOp::Div, + BinOp::Rem => rustc_middle::mir::BinOp::Rem, + BinOp::BitXor => rustc_middle::mir::BinOp::BitXor, + BinOp::BitAnd => rustc_middle::mir::BinOp::BitAnd, + BinOp::BitOr => rustc_middle::mir::BinOp::BitOr, + BinOp::Shl => rustc_middle::mir::BinOp::Shl, + BinOp::ShlUnchecked => rustc_middle::mir::BinOp::ShlUnchecked, + BinOp::Shr => rustc_middle::mir::BinOp::Shr, + BinOp::ShrUnchecked => rustc_middle::mir::BinOp::ShrUnchecked, + BinOp::Eq => rustc_middle::mir::BinOp::Eq, + BinOp::Lt => rustc_middle::mir::BinOp::Lt, + BinOp::Le => rustc_middle::mir::BinOp::Le, + BinOp::Ne => rustc_middle::mir::BinOp::Ne, + BinOp::Ge => rustc_middle::mir::BinOp::Ge, + BinOp::Gt => rustc_middle::mir::BinOp::Gt, + BinOp::Cmp => rustc_middle::mir::BinOp::Cmp, + BinOp::Offset => rustc_middle::mir::BinOp::Offset, + } + } +} + +impl RustcInternal for UnOp { + type T<'tcx> = rustc_middle::mir::UnOp; + + 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, + UnOp::PtrMetadata => rustc_middle::mir::UnOp::PtrMetadata, + } + } +} + +impl RustcInternal for &T +where + T: RustcInternal, +{ + type T<'tcx> = T::T<'tcx>; + + fn internal<'tcx>( + &self, + tables: &mut Tables<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + (*self).internal(tables, tcx) + } +} + +impl RustcInternal for Option +where + T: RustcInternal, +{ + type T<'tcx> = Option>; + + fn internal<'tcx>( + &self, + tables: &mut Tables<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + self.as_ref().map(|inner| inner.internal(tables, tcx)) + } +} + +impl RustcInternal for Vec +where + T: RustcInternal, +{ + type T<'tcx> = Vec>; + + 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/stable_mir/src/unstable/convert/mod.rs b/compiler/stable_mir/src/unstable/convert/mod.rs new file mode 100644 index 00000000000..aad92325861 --- /dev/null +++ b/compiler/stable_mir/src/unstable/convert/mod.rs @@ -0,0 +1,110 @@ +//! 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 super::Stable; +use crate::compiler_interface::BridgeTys; + +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 +where + T: Stable<'tcx>, +{ + type T = Option; + + 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 +where + T: Stable<'tcx>, + E: Stable<'tcx>, +{ + type T = Result; + + 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; + 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 +where + T: Stable<'tcx>, +{ + type T = RangeInclusive; + 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/stable_mir/src/unstable/convert/stable/abi.rs b/compiler/stable_mir/src/unstable/convert/stable/abi.rs new file mode 100644 index 00000000000..8fdaa69c305 --- /dev/null +++ b/compiler/stable_mir/src/unstable/convert/stable/abi.rs @@ -0,0 +1,410 @@ +//! Conversion of internal Rust compiler `rustc_target` and `rustc_abi` items to stable ones. + +#![allow(rustc::usage_of_qualified_ty)] + +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 crate::abi::{ + AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, + IntegerType, Layout, LayoutShape, PassMode, Primitive, ReprFlags, ReprOptions, Scalar, + TagEncoding, TyAndLayout, ValueAbi, VariantsShape, WrappingRange, +}; +use crate::compiler_interface::BridgeTys; +use crate::target::MachineSize as Size; +use crate::ty::{Align, VariantIdx}; +use crate::unstable::Stable; +use crate::{IndexedVal, opaque}; + +impl<'tcx> Stable<'tcx> for rustc_abi::VariantIdx { + type T = VariantIdx; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + VariantIdx::to_val(self.as_usize()) + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Endian { + type T = crate::target::Endian; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + rustc_abi::Endian::Little => crate::target::Endian::Little, + rustc_abi::Endian::Big => crate::target::Endian::Big, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { + type T = TyAndLayout; + + 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<'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 { + type T = LayoutShape; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + LayoutShape { + 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), + } + } +} + +impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> { + type T = FnAbi; + + 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, cx), + ret: self.ret.stable(tables, cx), + fixed_count: self.fixed_count, + conv: self.conv.stable(tables, cx), + c_variadic: self.c_variadic, + } + } +} + +impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> { + type T = ArgAbi; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + ArgAbi { + ty: self.layout.ty.stable(tables, cx), + layout: self.layout.layout.stable(tables, cx), + mode: self.mode.stable(tables, cx), + } + } +} + +impl<'tcx> Stable<'tcx> for CanonAbi { + type T = CallConvention; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + CanonAbi::C => CallConvention::C, + CanonAbi::Rust => CallConvention::Rust, + CanonAbi::RustCold => CallConvention::Cold, + CanonAbi::Custom => CallConvention::Custom, + CanonAbi::Arm(arm_call) => match arm_call { + ArmCall::Aapcs => CallConvention::ArmAapcs, + ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, + ArmCall::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry, + }, + CanonAbi::GpuKernel => CallConvention::GpuKernel, + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { + InterruptKind::Avr => CallConvention::AvrInterrupt, + InterruptKind::AvrNonBlocking => CallConvention::AvrNonBlockingInterrupt, + InterruptKind::Msp430 => CallConvention::Msp430Intr, + InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => { + CallConvention::RiscvInterrupt + } + InterruptKind::X86 => CallConvention::X86Intr, + }, + CanonAbi::X86(x86_call) => match x86_call { + X86Call::Fastcall => CallConvention::X86Fastcall, + X86Call::Stdcall => CallConvention::X86Stdcall, + X86Call::SysV64 => CallConvention::X86_64SysV, + X86Call::Thiscall => CallConvention::X86ThisCall, + X86Call::Vectorcall => CallConvention::X86VectorCall, + X86Call::Win64 => CallConvention::X86_64Win64, + }, + } + } +} + +impl<'tcx> Stable<'tcx> for callconv::PassMode { + type T = PassMode; + + 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)), + callconv::PassMode::Pair(first, second) => { + PassMode::Pair(opaque(first), opaque(second)) + } + callconv::PassMode::Cast { pad_i32, cast } => { + PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) } + } + callconv::PassMode::Indirect { attrs, meta_attrs, on_stack } => PassMode::Indirect { + attrs: opaque(attrs), + meta_attrs: opaque(meta_attrs), + on_stack: *on_stack, + }, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape { + type T = FieldsShape; + + 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, cx), count: *count } + } + rustc_abi::FieldsShape::Arbitrary { offsets, .. } => { + FieldsShape::Arbitrary { offsets: offsets.iter().as_slice().stable(tables, cx) } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Variants { + type T = VariantsShape; + + 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, cx) } + } + rustc_abi::Variants::Empty => VariantsShape::Empty, + rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => { + VariantsShape::Multiple { + 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), + } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding { + type T = TagEncoding; + + 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, cx), + niche_variants: niche_variants.stable(tables, cx), + niche_start: *niche_start, + } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { + type T = ValueAbi; + + 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, cx)), + rustc_abi::BackendRepr::ScalarPair(first, second) => { + ValueAbi::ScalarPair(first.stable(tables, cx), second.stable(tables, cx)) + } + rustc_abi::BackendRepr::SimdVector { element, count } => { + ValueAbi::Vector { element: element.stable(tables, cx), count } + } + rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized }, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Size { + type T = Size; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + Size::from_bits(self.bits_usize()) + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Align { + type T = Align; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + self.bytes() + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Scalar { + type T = Scalar; + + 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, cx), + valid_range: valid_range.stable(tables, cx), + }, + rustc_abi::Scalar::Union { value } => Scalar::Union { value: value.stable(tables, cx) }, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Primitive { + type T = Primitive; + + 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, cx), signed: *signed } + } + rustc_abi::Primitive::Float(length) => { + Primitive::Float { length: length.stable(tables, cx) } + } + rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables, cx)), + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::AddressSpace { + type T = AddressSpace; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + AddressSpace(self.0) + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Integer { + type T = IntegerLength; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + rustc_abi::Integer::I8 => IntegerLength::I8, + rustc_abi::Integer::I16 => IntegerLength::I16, + rustc_abi::Integer::I32 => IntegerLength::I32, + rustc_abi::Integer::I64 => IntegerLength::I64, + rustc_abi::Integer::I128 => IntegerLength::I128, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Float { + type T = FloatLength; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + rustc_abi::Float::F16 => FloatLength::F16, + rustc_abi::Float::F32 => FloatLength::F32, + rustc_abi::Float::F64 => FloatLength::F64, + rustc_abi::Float::F128 => FloatLength::F128, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange { + type T = WrappingRange; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + WrappingRange { start: self.start, end: self.end } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::ReprFlags { + type T = ReprFlags; + + 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), + is_transparent: self.intersects(Self::IS_TRANSPARENT), + is_linear: self.intersects(Self::IS_LINEAR), + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::IntegerType { + type T = IntegerType; + + 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, cx), is_signed: *signed } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::ReprOptions { + type T = ReprOptions; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + ReprOptions { + 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/stable_mir/src/unstable/convert/stable/mir.rs b/compiler/stable_mir/src/unstable/convert/stable/mir.rs new file mode 100644 index 00000000000..f6f4706e40b --- /dev/null +++ b/compiler/stable_mir/src/unstable/convert/stable/mir.rs @@ -0,0 +1,933 @@ +//! Conversion of internal Rust compiler `mir` items to stable ones. + +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 crate::compiler_interface::BridgeTys; +use crate::mir::alloc::GlobalAlloc; +use crate::mir::{ConstOperand, Statement, UserTypeProjection, VarDebugInfoFragment}; +use crate::ty::{Allocation, ConstantKind, MirConst}; +use crate::unstable::Stable; +use crate::{Error, alloc, opaque}; + +impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { + type T = crate::mir::Body; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + crate::mir::Body::new( + self.basic_blocks + .iter() + .map(|block| crate::mir::BasicBlock { + terminator: block.terminator().stable(tables, cx), + statements: block + .statements + .iter() + .map(|statement| statement.stable(tables, cx)) + .collect(), + }) + .collect(), + self.local_decls + .iter() + .map(|decl| crate::mir::LocalDecl { + 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, cx)).collect(), + self.spread_arg.stable(tables, cx), + self.span.stable(tables, cx), + ) + } +} + +impl<'tcx> Stable<'tcx> for mir::VarDebugInfo<'tcx> { + type T = crate::mir::VarDebugInfo; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + crate::mir::VarDebugInfo { + name: self.name.to_string(), + 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, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> { + type T = crate::mir::Statement; + 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 = crate::mir::SourceInfo; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + crate::mir::SourceInfo { span: self.span.stable(tables, cx), scope: self.scope.into() } + } +} + +impl<'tcx> Stable<'tcx> for mir::VarDebugInfoFragment<'tcx> { + type T = crate::mir::VarDebugInfoFragment; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + VarDebugInfoFragment { + 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 = crate::mir::VarDebugInfoContents; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + match self { + mir::VarDebugInfoContents::Place(place) => { + crate::mir::VarDebugInfoContents::Place(place.stable(tables, cx)) + } + mir::VarDebugInfoContents::Const(const_operand) => { + let op = ConstOperand { + span: const_operand.span.stable(tables, cx), + user_ty: const_operand.user_ty.map(|index| index.as_usize()), + const_: const_operand.const_.stable(tables, cx), + }; + crate::mir::VarDebugInfoContents::Const(op) + } + } + } +} + +impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> { + type T = crate::mir::StatementKind; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + match self { + mir::StatementKind::Assign(assign) => crate::mir::StatementKind::Assign( + assign.0.stable(tables, cx), + assign.1.stable(tables, cx), + ), + mir::StatementKind::FakeRead(fake_read_place) => crate::mir::StatementKind::FakeRead( + fake_read_place.0.stable(tables, cx), + fake_read_place.1.stable(tables, cx), + ), + mir::StatementKind::SetDiscriminant { place, variant_index } => { + crate::mir::StatementKind::SetDiscriminant { + place: place.as_ref().stable(tables, cx), + variant_index: variant_index.stable(tables, cx), + } + } + mir::StatementKind::Deinit(place) => { + crate::mir::StatementKind::Deinit(place.stable(tables, cx)) + } + + mir::StatementKind::StorageLive(place) => { + crate::mir::StatementKind::StorageLive(place.stable(tables, cx)) + } + + mir::StatementKind::StorageDead(place) => { + crate::mir::StatementKind::StorageDead(place.stable(tables, cx)) + } + mir::StatementKind::Retag(retag, place) => { + crate::mir::StatementKind::Retag(retag.stable(tables, cx), place.stable(tables, cx)) + } + mir::StatementKind::PlaceMention(place) => { + crate::mir::StatementKind::PlaceMention(place.stable(tables, cx)) + } + mir::StatementKind::AscribeUserType(place_projection, variance) => { + crate::mir::StatementKind::AscribeUserType { + 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) => { + crate::mir::StatementKind::Coverage(opaque(coverage)) + } + mir::StatementKind::Intrinsic(intrinstic) => { + crate::mir::StatementKind::Intrinsic(intrinstic.stable(tables, cx)) + } + mir::StatementKind::ConstEvalCounter => crate::mir::StatementKind::ConstEvalCounter, + // BackwardIncompatibleDropHint has no semantics, so it is translated to Nop. + mir::StatementKind::BackwardIncompatibleDropHint { .. } => { + crate::mir::StatementKind::Nop + } + mir::StatementKind::Nop => crate::mir::StatementKind::Nop, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { + type T = crate::mir::Rvalue; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use rustc_middle::mir::Rvalue::*; + match self { + Use(op) => crate::mir::Rvalue::Use(op.stable(tables, cx)), + Repeat(op, len) => { + let len = len.stable(tables, cx); + crate::mir::Rvalue::Repeat(op.stable(tables, cx), len) + } + Ref(region, kind, place) => crate::mir::Rvalue::Ref( + region.stable(tables, cx), + kind.stable(tables, cx), + place.stable(tables, cx), + ), + ThreadLocalRef(def_id) => { + crate::mir::Rvalue::ThreadLocalRef(tables.crate_item(*def_id)) + } + RawPtr(mutability, place) => crate::mir::Rvalue::AddressOf( + mutability.stable(tables, cx), + place.stable(tables, cx), + ), + Len(place) => crate::mir::Rvalue::Len(place.stable(tables, cx)), + Cast(cast_kind, op, ty) => crate::mir::Rvalue::Cast( + 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() { + crate::mir::Rvalue::CheckedBinaryOp( + bin_op.stable(tables, cx), + ops.0.stable(tables, cx), + ops.1.stable(tables, cx), + ) + } else { + crate::mir::Rvalue::BinaryOp( + bin_op.stable(tables, cx), + ops.0.stable(tables, cx), + ops.1.stable(tables, cx), + ) + } + } + NullaryOp(null_op, ty) => { + crate::mir::Rvalue::NullaryOp(null_op.stable(tables, cx), ty.stable(tables, cx)) + } + UnaryOp(un_op, op) => { + crate::mir::Rvalue::UnaryOp(un_op.stable(tables, cx), op.stable(tables, cx)) + } + Discriminant(place) => crate::mir::Rvalue::Discriminant(place.stable(tables, cx)), + Aggregate(agg_kind, operands) => { + let operands = operands.iter().map(|op| op.stable(tables, cx)).collect(); + crate::mir::Rvalue::Aggregate(agg_kind.stable(tables, cx), operands) + } + ShallowInitBox(op, ty) => { + crate::mir::Rvalue::ShallowInitBox(op.stable(tables, cx), ty.stable(tables, cx)) + } + CopyForDeref(place) => crate::mir::Rvalue::CopyForDeref(place.stable(tables, cx)), + WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::Mutability { + type T = crate::mir::Mutability; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_hir::Mutability::*; + match *self { + Not => crate::mir::Mutability::Not, + Mut => crate::mir::Mutability::Mut, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::RawPtrKind { + type T = crate::mir::RawPtrKind; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use mir::RawPtrKind::*; + match *self { + Const => crate::mir::RawPtrKind::Const, + Mut => crate::mir::RawPtrKind::Mut, + FakeForPtrMetadata => crate::mir::RawPtrKind::FakeForPtrMetadata, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::BorrowKind { + type T = crate::mir::BorrowKind; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use rustc_middle::mir::BorrowKind::*; + match *self { + Shared => crate::mir::BorrowKind::Shared, + Fake(kind) => crate::mir::BorrowKind::Fake(kind.stable(tables, cx)), + Mut { kind } => crate::mir::BorrowKind::Mut { kind: kind.stable(tables, cx) }, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::MutBorrowKind { + type T = crate::mir::MutBorrowKind; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::mir::MutBorrowKind::*; + match *self { + Default => crate::mir::MutBorrowKind::Default, + TwoPhaseBorrow => crate::mir::MutBorrowKind::TwoPhaseBorrow, + ClosureCapture => crate::mir::MutBorrowKind::ClosureCapture, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind { + type T = crate::mir::FakeBorrowKind; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::mir::FakeBorrowKind::*; + match *self { + Deep => crate::mir::FakeBorrowKind::Deep, + Shallow => crate::mir::FakeBorrowKind::Shallow, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { + type T = crate::mir::NullOp; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use rustc_middle::mir::NullOp::*; + match self { + SizeOf => crate::mir::NullOp::SizeOf, + AlignOf => crate::mir::NullOp::AlignOf, + OffsetOf(indices) => crate::mir::NullOp::OffsetOf( + indices.iter().map(|idx| idx.stable(tables, cx)).collect(), + ), + UbChecks => crate::mir::NullOp::UbChecks, + ContractChecks => crate::mir::NullOp::ContractChecks, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::CastKind { + type T = crate::mir::CastKind; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use rustc_middle::mir::CastKind::*; + match self { + PointerExposeProvenance => crate::mir::CastKind::PointerExposeAddress, + PointerWithExposedProvenance => crate::mir::CastKind::PointerWithExposedProvenance, + PointerCoercion(c, _) => crate::mir::CastKind::PointerCoercion(c.stable(tables, cx)), + IntToInt => crate::mir::CastKind::IntToInt, + FloatToInt => crate::mir::CastKind::FloatToInt, + FloatToFloat => crate::mir::CastKind::FloatToFloat, + IntToFloat => crate::mir::CastKind::IntToFloat, + PtrToPtr => crate::mir::CastKind::PtrToPtr, + FnPtrToPtr => crate::mir::CastKind::FnPtrToPtr, + Transmute => crate::mir::CastKind::Transmute, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::FakeReadCause { + type T = crate::mir::FakeReadCause; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::mir::FakeReadCause::*; + match self { + ForMatchGuard => crate::mir::FakeReadCause::ForMatchGuard, + ForMatchedPlace(local_def_id) => { + crate::mir::FakeReadCause::ForMatchedPlace(opaque(local_def_id)) + } + ForGuardBinding => crate::mir::FakeReadCause::ForGuardBinding, + ForLet(local_def_id) => crate::mir::FakeReadCause::ForLet(opaque(local_def_id)), + ForIndex => crate::mir::FakeReadCause::ForIndex, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { + type T = crate::mir::Operand; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use rustc_middle::mir::Operand::*; + match self { + Copy(place) => crate::mir::Operand::Copy(place.stable(tables, cx)), + Move(place) => crate::mir::Operand::Move(place.stable(tables, cx)), + Constant(c) => crate::mir::Operand::Constant(c.stable(tables, cx)), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> { + type T = crate::mir::ConstOperand; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + crate::mir::ConstOperand { + span: self.span.stable(tables, cx), + user_ty: self.user_ty.map(|u| u.as_usize()).or(None), + const_: self.const_.stable(tables, cx), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::Place<'tcx> { + type T = crate::mir::Place; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + crate::mir::Place { + local: self.local.as_usize(), + projection: self.projection.iter().map(|e| e.stable(tables, cx)).collect(), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { + type T = crate::mir::ProjectionElem; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use rustc_middle::mir::ProjectionElem::*; + match self { + Deref => crate::mir::ProjectionElem::Deref, + Field(idx, ty) => { + crate::mir::ProjectionElem::Field(idx.stable(tables, cx), ty.stable(tables, cx)) + } + Index(local) => crate::mir::ProjectionElem::Index(local.stable(tables, cx)), + ConstantIndex { offset, min_length, from_end } => { + crate::mir::ProjectionElem::ConstantIndex { + offset: *offset, + min_length: *min_length, + from_end: *from_end, + } + } + Subslice { from, to, from_end } => { + crate::mir::ProjectionElem::Subslice { from: *from, to: *to, from_end: *from_end } + } + // MIR includes an `Option` argument for `Downcast` that is the name of the + // variant, used for printing MIR. However this information should also be accessible + // via a lookup using the `VariantIdx`. The `Option` 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) => crate::mir::ProjectionElem::Downcast(idx.stable(tables, cx)), + OpaqueCast(ty) => crate::mir::ProjectionElem::OpaqueCast(ty.stable(tables, cx)), + Subtype(ty) => crate::mir::ProjectionElem::Subtype(ty.stable(tables, cx)), + UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::UserTypeProjection { + type T = crate::mir::UserTypeProjection; + + 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 = crate::mir::Local; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + self.as_usize() + } +} + +impl<'tcx> Stable<'tcx> for mir::RetagKind { + type T = crate::mir::RetagKind; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::mir::RetagKind; + match self { + RetagKind::FnEntry => crate::mir::RetagKind::FnEntry, + RetagKind::TwoPhase => crate::mir::RetagKind::TwoPhase, + RetagKind::Raw => crate::mir::RetagKind::Raw, + RetagKind::Default => crate::mir::RetagKind::Default, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::UnwindAction { + type T = crate::mir::UnwindAction; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::mir::UnwindAction; + match self { + UnwindAction::Continue => crate::mir::UnwindAction::Continue, + UnwindAction::Unreachable => crate::mir::UnwindAction::Unreachable, + UnwindAction::Terminate(_) => crate::mir::UnwindAction::Terminate, + UnwindAction::Cleanup(bb) => crate::mir::UnwindAction::Cleanup(bb.as_usize()), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> { + type T = crate::mir::NonDivergingIntrinsic; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use rustc_middle::mir::NonDivergingIntrinsic; + + use crate::mir::CopyNonOverlapping; + match self { + NonDivergingIntrinsic::Assume(op) => { + crate::mir::NonDivergingIntrinsic::Assume(op.stable(tables, cx)) + } + NonDivergingIntrinsic::CopyNonOverlapping(copy_non_overlapping) => { + crate::mir::NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + src: copy_non_overlapping.src.stable(tables, cx), + dst: copy_non_overlapping.dst.stable(tables, cx), + count: copy_non_overlapping.count.stable(tables, cx), + }) + } + } + } +} + +impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> { + type T = crate::mir::AssertMessage; + 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 } => crate::mir::AssertMessage::BoundsCheck { + len: len.stable(tables, cx), + index: index.stable(tables, cx), + }, + AssertKind::Overflow(bin_op, op1, op2) => crate::mir::AssertMessage::Overflow( + bin_op.stable(tables, cx), + op1.stable(tables, cx), + op2.stable(tables, cx), + ), + AssertKind::OverflowNeg(op) => { + crate::mir::AssertMessage::OverflowNeg(op.stable(tables, cx)) + } + AssertKind::DivisionByZero(op) => { + crate::mir::AssertMessage::DivisionByZero(op.stable(tables, cx)) + } + AssertKind::RemainderByZero(op) => { + crate::mir::AssertMessage::RemainderByZero(op.stable(tables, cx)) + } + AssertKind::ResumedAfterReturn(coroutine) => { + crate::mir::AssertMessage::ResumedAfterReturn(coroutine.stable(tables, cx)) + } + AssertKind::ResumedAfterPanic(coroutine) => { + crate::mir::AssertMessage::ResumedAfterPanic(coroutine.stable(tables, cx)) + } + AssertKind::ResumedAfterDrop(coroutine) => { + crate::mir::AssertMessage::ResumedAfterDrop(coroutine.stable(tables, cx)) + } + AssertKind::MisalignedPointerDereference { required, found } => { + crate::mir::AssertMessage::MisalignedPointerDereference { + required: required.stable(tables, cx), + found: found.stable(tables, cx), + } + } + AssertKind::NullPointerDereference => crate::mir::AssertMessage::NullPointerDereference, + AssertKind::InvalidEnumConstruction(source) => { + crate::mir::AssertMessage::InvalidEnumConstruction(source.stable(tables, cx)) + } + } + } +} + +impl<'tcx> Stable<'tcx> for mir::BinOp { + type T = crate::mir::BinOp; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::mir::BinOp; + match self { + BinOp::Add => crate::mir::BinOp::Add, + BinOp::AddUnchecked => crate::mir::BinOp::AddUnchecked, + BinOp::AddWithOverflow => bug!("AddWithOverflow should have been translated already"), + BinOp::Sub => crate::mir::BinOp::Sub, + BinOp::SubUnchecked => crate::mir::BinOp::SubUnchecked, + BinOp::SubWithOverflow => bug!("AddWithOverflow should have been translated already"), + BinOp::Mul => crate::mir::BinOp::Mul, + BinOp::MulUnchecked => crate::mir::BinOp::MulUnchecked, + BinOp::MulWithOverflow => bug!("AddWithOverflow should have been translated already"), + BinOp::Div => crate::mir::BinOp::Div, + BinOp::Rem => crate::mir::BinOp::Rem, + BinOp::BitXor => crate::mir::BinOp::BitXor, + BinOp::BitAnd => crate::mir::BinOp::BitAnd, + BinOp::BitOr => crate::mir::BinOp::BitOr, + BinOp::Shl => crate::mir::BinOp::Shl, + BinOp::ShlUnchecked => crate::mir::BinOp::ShlUnchecked, + BinOp::Shr => crate::mir::BinOp::Shr, + BinOp::ShrUnchecked => crate::mir::BinOp::ShrUnchecked, + BinOp::Eq => crate::mir::BinOp::Eq, + BinOp::Lt => crate::mir::BinOp::Lt, + BinOp::Le => crate::mir::BinOp::Le, + BinOp::Ne => crate::mir::BinOp::Ne, + BinOp::Ge => crate::mir::BinOp::Ge, + BinOp::Gt => crate::mir::BinOp::Gt, + BinOp::Cmp => crate::mir::BinOp::Cmp, + BinOp::Offset => crate::mir::BinOp::Offset, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::UnOp { + type T = crate::mir::UnOp; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::mir::UnOp; + match self { + UnOp::Not => crate::mir::UnOp::Not, + UnOp::Neg => crate::mir::UnOp::Neg, + UnOp::PtrMetadata => crate::mir::UnOp::PtrMetadata, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { + type T = crate::mir::AggregateKind; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + match self { + mir::AggregateKind::Array(ty) => { + crate::mir::AggregateKind::Array(ty.stable(tables, cx)) + } + mir::AggregateKind::Tuple => crate::mir::AggregateKind::Tuple, + mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => { + crate::mir::AggregateKind::Adt( + tables.adt_def(*def_id), + var_idx.stable(tables, cx), + generic_arg.stable(tables, cx), + user_ty_index.map(|idx| idx.index()), + field_idx.map(|idx| idx.index()), + ) + } + mir::AggregateKind::Closure(def_id, generic_arg) => crate::mir::AggregateKind::Closure( + tables.closure_def(*def_id), + generic_arg.stable(tables, cx), + ), + mir::AggregateKind::Coroutine(def_id, generic_arg) => { + crate::mir::AggregateKind::Coroutine( + tables.coroutine_def(*def_id), + generic_arg.stable(tables, cx), + cx.coroutine_movability(*def_id).stable(tables, cx), + ) + } + mir::AggregateKind::CoroutineClosure(def_id, generic_args) => { + crate::mir::AggregateKind::CoroutineClosure( + tables.coroutine_closure_def(*def_id), + generic_args.stable(tables, cx), + ) + } + mir::AggregateKind::RawPtr(ty, mutability) => crate::mir::AggregateKind::RawPtr( + ty.stable(tables, cx), + mutability.stable(tables, cx), + ), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> { + type T = crate::mir::InlineAsmOperand; + 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, cx)), None), + InlineAsmOperand::Out { place, .. } => { + (None, place.map(|place| place.stable(tables, cx))) + } + InlineAsmOperand::InOut { in_value, out_place, .. } => { + (Some(in_value.stable(tables, cx)), out_place.map(|place| place.stable(tables, cx))) + } + InlineAsmOperand::Const { .. } + | InlineAsmOperand::SymFn { .. } + | InlineAsmOperand::SymStatic { .. } + | InlineAsmOperand::Label { .. } => (None, None), + }; + + crate::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{self:?}") } + } +} + +impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { + type T = crate::mir::Terminator; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::mir::Terminator; + 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 = crate::mir::TerminatorKind; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::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, cx), + targets: { + let branches = targets.iter().map(|(val, target)| (val, target.as_usize())); + crate::mir::SwitchTargets::new( + branches.collect(), + targets.otherwise().as_usize(), + ) + }, + }, + mir::TerminatorKind::UnwindResume => TerminatorKind::Resume, + mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort, + mir::TerminatorKind::Return => TerminatorKind::Return, + mir::TerminatorKind::Unreachable => TerminatorKind::Unreachable, + mir::TerminatorKind::Drop { + place, + target, + unwind, + replace: _, + drop: _, + async_fut: _, + } => TerminatorKind::Drop { + place: place.stable(tables, cx), + target: target.as_usize(), + unwind: unwind.stable(tables, cx), + }, + mir::TerminatorKind::Call { + func, + args, + destination, + target, + unwind, + call_source: _, + fn_span: _, + } => TerminatorKind::Call { + 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, cx), + }, + mir::TerminatorKind::TailCall { func: _, args: _, fn_span: _ } => todo!(), + mir::TerminatorKind::Assert { cond, expected, msg, target, unwind } => { + TerminatorKind::Assert { + cond: cond.stable(tables, cx), + expected: *expected, + msg: msg.stable(tables, cx), + target: target.as_usize(), + unwind: unwind.stable(tables, cx), + } + } + mir::TerminatorKind::InlineAsm { + asm_macro: _, + template, + operands, + options, + line_spans, + targets, + unwind, + } => TerminatorKind::InlineAsm { + template: format!("{template:?}"), + 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, cx), + }, + mir::TerminatorKind::Yield { .. } + | mir::TerminatorKind::CoroutineDrop + | mir::TerminatorKind::FalseEdge { .. } + | mir::TerminatorKind::FalseUnwind { .. } => unreachable!(), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::interpret::ConstAllocation<'tcx> { + type T = Allocation; + + 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 = crate::ty::Allocation; + + 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 = crate::mir::alloc::AllocId; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + _: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + tables.create_alloc_id(*self) + } +} + +impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { + type T = GlobalAlloc; + + 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, cx)) + } + mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => { + // FIXME: Should we record the whole vtable? + 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, cx)) + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { + type T = crate::ty::MirConst; + + 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( + crate::ty::ConstantKind::Ty(c.stable(tables, cx)), + ty.stable(tables, cx), + id, + ), + mir::Const::Unevaluated(unev_const, ty) => { + let kind = crate::ty::ConstantKind::Unevaluated(crate::ty::UnevaluatedConst { + def: tables.const_def(unev_const.def), + args: unev_const.args.stable(tables, cx), + promoted: unev_const.promoted.map(|u| u.as_u32()), + }); + let ty = ty.stable(tables, cx); + MirConst::new(kind, ty, id) + } + mir::Const::Val(mir::ConstValue::ZeroSized, ty) => { + let ty = ty.stable(tables, cx); + MirConst::new(ConstantKind::ZeroSized, ty, id) + } + mir::Const::Val(val, ty) => { + 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) + } + } + } +} + +impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled { + type T = Error; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + Error::new(format!("{self:?}")) + } +} + +impl<'tcx> Stable<'tcx> for MonoItem<'tcx> { + type T = crate::mir::mono::MonoItem; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::mir::mono::MonoItem as StableMonoItem; + match self { + 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/stable_mir/src/unstable/convert/stable/mod.rs b/compiler/stable_mir/src/unstable/convert/stable/mod.rs new file mode 100644 index 00000000000..e7f14bbdfc8 --- /dev/null +++ b/compiler/stable_mir/src/unstable/convert/stable/mod.rs @@ -0,0 +1,95 @@ +//! Conversion of internal Rust compiler items to stable ones. + +use rustc_abi::FieldIdx; +use rustc_smir::Tables; +use rustc_smir::context::SmirCtxt; + +use super::Stable; +use crate::compiler_interface::BridgeTys; + +mod abi; +mod mir; +mod ty; + +impl<'tcx> Stable<'tcx> for rustc_hir::Safety { + type T = crate::mir::Safety; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + rustc_hir::Safety::Unsafe => crate::mir::Safety::Unsafe, + rustc_hir::Safety::Safe => crate::mir::Safety::Safe, + } + } +} + +impl<'tcx> Stable<'tcx> for FieldIdx { + type T = usize; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + self.as_usize() + } +} + +impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource { + type T = crate::mir::CoroutineSource; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_hir::CoroutineSource; + match self { + CoroutineSource::Block => crate::mir::CoroutineSource::Block, + CoroutineSource::Closure => crate::mir::CoroutineSource::Closure, + CoroutineSource::Fn => crate::mir::CoroutineSource::Fn, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { + type T = crate::mir::CoroutineKind; + 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) => { + crate::mir::CoroutineKind::Desugared( + crate::mir::CoroutineDesugaring::Async, + source.stable(tables, cx), + ) + } + CoroutineKind::Desugared(CoroutineDesugaring::Gen, source) => { + crate::mir::CoroutineKind::Desugared( + crate::mir::CoroutineDesugaring::Gen, + source.stable(tables, cx), + ) + } + CoroutineKind::Coroutine(movability) => { + crate::mir::CoroutineKind::Coroutine(movability.stable(tables, cx)) + } + CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, source) => { + crate::mir::CoroutineKind::Desugared( + crate::mir::CoroutineDesugaring::AsyncGen, + source.stable(tables, cx), + ) + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_span::Symbol { + type T = crate::Symbol; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + self.to_string() + } +} + +impl<'tcx> Stable<'tcx> for rustc_span::Span { + type T = crate::ty::Span; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + _: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + tables.create_span(*self) + } +} diff --git a/compiler/stable_mir/src/unstable/convert/stable/ty.rs b/compiler/stable_mir/src/unstable/convert/stable/ty.rs new file mode 100644 index 00000000000..366f7ea01d4 --- /dev/null +++ b/compiler/stable_mir/src/unstable/convert/stable/ty.rs @@ -0,0 +1,1139 @@ +//! Conversion of internal Rust compiler `ty` items to stable ones. + +use rustc_middle::ty::Ty; +use rustc_middle::{bug, mir, ty}; +use rustc_smir::Tables; +use rustc_smir::context::SmirCtxt; + +use crate::alloc; +use crate::compiler_interface::BridgeTys; +use crate::ty::{ + AdtKind, FloatTy, GenericArgs, GenericParamDef, IntTy, Region, RigidTy, TyKind, UintTy, +}; +use crate::unstable::Stable; + +impl<'tcx> Stable<'tcx> for ty::AliasTyKind { + type T = crate::ty::AliasKind; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + ty::Projection => crate::ty::AliasKind::Projection, + ty::Inherent => crate::ty::AliasKind::Inherent, + ty::Opaque => crate::ty::AliasKind::Opaque, + ty::Free => crate::ty::AliasKind::Free, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::AliasTy<'tcx> { + type T = crate::ty::AliasTy; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + let ty::AliasTy { args, def_id, .. } = self; + crate::ty::AliasTy { def_id: tables.alias_def(*def_id), args: args.stable(tables, cx) } + } +} + +impl<'tcx> Stable<'tcx> for ty::AliasTerm<'tcx> { + type T = crate::ty::AliasTerm; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + let ty::AliasTerm { args, def_id, .. } = self; + crate::ty::AliasTerm { def_id: tables.alias_def(*def_id), args: args.stable(tables, cx) } + } +} + +impl<'tcx> Stable<'tcx> for ty::DynKind { + type T = crate::ty::DynKind; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + ty::Dyn => crate::ty::DynKind::Dyn, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> { + type T = crate::ty::ExistentialPredicate; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::ExistentialPredicate::*; + match self { + ty::ExistentialPredicate::Trait(existential_trait_ref) => { + Trait(existential_trait_ref.stable(tables, cx)) + } + ty::ExistentialPredicate::Projection(existential_projection) => { + Projection(existential_projection.stable(tables, cx)) + } + ty::ExistentialPredicate::AutoTrait(def_id) => AutoTrait(tables.trait_def(*def_id)), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> { + type T = crate::ty::ExistentialTraitRef; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + let ty::ExistentialTraitRef { def_id, args, .. } = self; + crate::ty::ExistentialTraitRef { + def_id: tables.trait_def(*def_id), + generic_args: args.stable(tables, cx), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> { + type T = crate::ty::TermKind; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::TermKind; + match self { + ty::TermKind::Ty(ty) => TermKind::Type(ty.stable(tables, cx)), + ty::TermKind::Const(cnst) => { + let cnst = cnst.stable(tables, cx); + TermKind::Const(cnst) + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> { + type T = crate::ty::ExistentialProjection; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + let ty::ExistentialProjection { def_id, args, term, .. } = self; + crate::ty::ExistentialProjection { + def_id: tables.trait_def(*def_id), + generic_args: args.stable(tables, cx), + term: term.kind().stable(tables, cx), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion { + type T = crate::mir::PointerCoercion; + 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 => crate::mir::PointerCoercion::ReifyFnPointer, + PointerCoercion::UnsafeFnPointer => crate::mir::PointerCoercion::UnsafeFnPointer, + PointerCoercion::ClosureFnPointer(safety) => { + crate::mir::PointerCoercion::ClosureFnPointer(safety.stable(tables, cx)) + } + PointerCoercion::MutToConstPointer => crate::mir::PointerCoercion::MutToConstPointer, + PointerCoercion::ArrayToPointer => crate::mir::PointerCoercion::ArrayToPointer, + PointerCoercion::Unsize => crate::mir::PointerCoercion::Unsize, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex { + type T = usize; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + self.as_usize() + } +} + +impl<'tcx> Stable<'tcx> for ty::AdtKind { + type T = AdtKind; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + ty::AdtKind::Struct => AdtKind::Struct, + ty::AdtKind::Union => AdtKind::Union, + ty::AdtKind::Enum => AdtKind::Enum, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::FieldDef { + type T = crate::ty::FieldDef; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + crate::ty::FieldDef { + def: tables.create_def_id(self.did), + name: self.name.stable(tables, cx), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> { + type T = crate::ty::GenericArgs; + 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 = crate::ty::GenericArgKind; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::GenericArgKind; + match self { + 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)), + } + } +} + +impl<'tcx, S, V> Stable<'tcx> for ty::Binder<'tcx, S> +where + S: Stable<'tcx, T = V>, +{ + type T = crate::ty::Binder; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::Binder; + + Binder { + value: self.as_ref().skip_binder().stable(tables, cx), + bound_vars: self + .bound_vars() + .iter() + .map(|bound_var| bound_var.stable(tables, cx)) + .collect(), + } + } +} + +impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<'tcx, S> +where + S: Stable<'tcx, T = V>, +{ + type T = crate::ty::EarlyBinder; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::EarlyBinder; + + EarlyBinder { value: self.as_ref().skip_binder().stable(tables, cx) } + } +} + +impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> { + type T = crate::ty::FnSig; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::FnSig; + + FnSig { + 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, cx), + abi: self.abi.stable(tables, cx), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::BoundTyKind { + type T = crate::ty::BoundTyKind; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::BoundTyKind; + + match self { + ty::BoundTyKind::Anon => BoundTyKind::Anon, + ty::BoundTyKind::Param(def_id) => { + BoundTyKind::Param(tables.param_def(*def_id), cx.tcx.item_name(*def_id).to_string()) + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::BoundRegionKind { + type T = crate::ty::BoundRegionKind; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::BoundRegionKind; + + match self { + ty::BoundRegionKind::Anon => BoundRegionKind::BrAnon, + ty::BoundRegionKind::Named(def_id) => BoundRegionKind::BrNamed( + tables.br_named_def(*def_id), + cx.tcx.item_name(*def_id).to_string(), + ), + ty::BoundRegionKind::ClosureEnv => BoundRegionKind::BrEnv, + ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::BoundVariableKind { + type T = crate::ty::BoundVariableKind; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::BoundVariableKind; + + match self { + ty::BoundVariableKind::Ty(bound_ty_kind) => { + BoundVariableKind::Ty(bound_ty_kind.stable(tables, cx)) + } + ty::BoundVariableKind::Region(bound_region_kind) => { + BoundVariableKind::Region(bound_region_kind.stable(tables, cx)) + } + ty::BoundVariableKind::Const => BoundVariableKind::Const, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::IntTy { + type T = IntTy; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + ty::IntTy::Isize => IntTy::Isize, + ty::IntTy::I8 => IntTy::I8, + ty::IntTy::I16 => IntTy::I16, + ty::IntTy::I32 => IntTy::I32, + ty::IntTy::I64 => IntTy::I64, + ty::IntTy::I128 => IntTy::I128, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::UintTy { + type T = UintTy; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + ty::UintTy::Usize => UintTy::Usize, + ty::UintTy::U8 => UintTy::U8, + ty::UintTy::U16 => UintTy::U16, + ty::UintTy::U32 => UintTy::U32, + ty::UintTy::U64 => UintTy::U64, + ty::UintTy::U128 => UintTy::U128, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::FloatTy { + type T = FloatTy; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + ty::FloatTy::F16 => FloatTy::F16, + ty::FloatTy::F32 => FloatTy::F32, + ty::FloatTy::F64 => FloatTy::F64, + ty::FloatTy::F128 => FloatTy::F128, + } + } +} + +impl<'tcx> Stable<'tcx> for Ty<'tcx> { + type T = crate::ty::Ty; + 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 = crate::ty::TyKind; + 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, 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, 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, cx), constant.stable(tables, cx))) + } + ty::Pat(ty, pat) => { + TyKind::RigidTy(RigidTy::Pat(ty.stable(tables, cx), pat.stable(tables, cx))) + } + ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables, cx))), + ty::RawPtr(ty, mutbl) => { + TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables, cx), mutbl.stable(tables, cx))) + } + ty::Ref(region, ty, mutbl) => TyKind::RigidTy(RigidTy::Ref( + 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::FnPtr(sig_tys, hdr) => { + TyKind::RigidTy(RigidTy::FnPtr(sig_tys.with(*hdr).stable(tables, cx))) + } + // FIXME(unsafe_binders): + ty::UnsafeBinder(_) => todo!(), + ty::Dynamic(existential_predicates, region, dyn_kind) => { + TyKind::RigidTy(RigidTy::Dynamic( + existential_predicates + .iter() + .map(|existential_predicate| existential_predicate.stable(tables, cx)) + .collect(), + 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, 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, 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, cx)).collect(), + )), + ty::Alias(alias_kind, alias_ty) => { + TyKind::Alias(alias_kind.stable(tables, cx), alias_ty.stable(tables, cx)) + } + 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, cx)) + } + ty::CoroutineWitness(def_id, args) => TyKind::RigidTy(RigidTy::CoroutineWitness( + tables.coroutine_witness_def(*def_id), + args.stable(tables, cx), + )), + ty::Placeholder(..) | ty::Infer(_) | ty::Error(_) => { + unreachable!(); + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> { + type T = crate::ty::Pattern; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + match **self { + ty::PatternKind::Range { start, end } => crate::ty::Pattern::Range { + // FIXME(SMIR): update data structures to not have an Option here anymore + start: Some(start.stable(tables, cx)), + end: Some(end.stable(tables, cx)), + include_end: true, + }, + ty::PatternKind::Or(_) => todo!(), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { + type T = crate::ty::TyConst; + + 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 = cx.valtree_to_const_val(cv); + if matches!(const_val, mir::ConstValue::ZeroSized) { + crate::ty::TyConstKind::ZSTValue(cv.ty.stable(tables, cx)) + } else { + crate::ty::TyConstKind::Value( + cv.ty.stable(tables, cx), + alloc::new_allocation(cv.ty, const_val, tables, cx), + ) + } + } + ty::ConstKind::Param(param) => crate::ty::TyConstKind::Param(param.stable(tables, cx)), + ty::ConstKind::Unevaluated(uv) => crate::ty::TyConstKind::Unevaluated( + tables.const_def(uv.def), + uv.args.stable(tables, cx), + ), + ty::ConstKind::Error(_) => unreachable!(), + ty::ConstKind::Infer(_) => unreachable!(), + ty::ConstKind::Bound(_, _) => unimplemented!(), + ty::ConstKind::Placeholder(_) => unimplemented!(), + ty::ConstKind::Expr(_) => unimplemented!(), + }; + let id = tables.intern_ty_const(ct); + crate::ty::TyConst::new(kind, id) + } +} + +impl<'tcx> Stable<'tcx> for ty::ParamConst { + type T = crate::ty::ParamConst; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use crate::ty::ParamConst; + ParamConst { index: self.index, name: self.name.to_string() } + } +} + +impl<'tcx> Stable<'tcx> for ty::ParamTy { + type T = crate::ty::ParamTy; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use crate::ty::ParamTy; + ParamTy { index: self.index, name: self.name.to_string() } + } +} + +impl<'tcx> Stable<'tcx> for ty::BoundTy { + type T = crate::ty::BoundTy; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::BoundTy; + BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables, cx) } + } +} + +impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind { + type T = crate::ty::TraitSpecializationKind; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use crate::ty::TraitSpecializationKind; + + match self { + ty::trait_def::TraitSpecializationKind::None => TraitSpecializationKind::None, + ty::trait_def::TraitSpecializationKind::Marker => TraitSpecializationKind::Marker, + ty::trait_def::TraitSpecializationKind::AlwaysApplicable => { + TraitSpecializationKind::AlwaysApplicable + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::TraitDef { + type T = crate::ty::TraitDecl; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::opaque; + use crate::ty::TraitDecl; + + TraitDecl { + def_id: tables.trait_def(self.def_id), + 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, cx), + must_implement_one_of: self + .must_implement_one_of + .as_ref() + .map(|idents| idents.iter().map(|ident| opaque(ident)).collect()), + implement_via_object: self.implement_via_object, + deny_explicit_impl: self.deny_explicit_impl, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> { + type T = crate::ty::TraitRef; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::TraitRef; + + TraitRef::try_new(tables.trait_def(self.def_id), self.args.stable(tables, cx)).unwrap() + } +} + +impl<'tcx> Stable<'tcx> for ty::Generics { + type T = crate::ty::Generics; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::Generics; + + 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(); + + Generics { + parent: self.parent.map(|did| tables.generic_def(did)), + parent_count: self.parent_count, + params, + param_def_id_to_index, + has_self: self.has_self, + has_late_bound_regions: self + .has_late_bound_regions + .as_ref() + .map(|late_bound_regions| late_bound_regions.stable(tables, cx)), + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind { + type T = crate::ty::GenericParamDefKind; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use crate::ty::GenericParamDefKind; + match self { + ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime, + ty::GenericParamDefKind::Type { has_default, synthetic } => { + GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic } + } + ty::GenericParamDefKind::Const { has_default, synthetic: _ } => { + GenericParamDefKind::Const { has_default: *has_default } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDef { + type T = crate::ty::GenericParamDef; + + 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, cx), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> { + type T = crate::ty::PredicateKind; + + 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) => { + crate::ty::PredicateKind::Clause(clause_kind.stable(tables, cx)) + } + PredicateKind::DynCompatible(did) => { + crate::ty::PredicateKind::DynCompatible(tables.trait_def(*did)) + } + PredicateKind::Subtype(subtype_predicate) => { + crate::ty::PredicateKind::SubType(subtype_predicate.stable(tables, cx)) + } + PredicateKind::Coerce(coerce_predicate) => { + crate::ty::PredicateKind::Coerce(coerce_predicate.stable(tables, cx)) + } + PredicateKind::ConstEquate(a, b) => { + crate::ty::PredicateKind::ConstEquate(a.stable(tables, cx), b.stable(tables, cx)) + } + PredicateKind::Ambiguous => crate::ty::PredicateKind::Ambiguous, + PredicateKind::NormalizesTo(_pred) => unimplemented!(), + PredicateKind::AliasRelate(a, b, alias_relation_direction) => { + crate::ty::PredicateKind::AliasRelate( + a.kind().stable(tables, cx), + b.kind().stable(tables, cx), + alias_relation_direction.stable(tables, cx), + ) + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { + type T = crate::ty::ClauseKind; + + 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) => { + crate::ty::ClauseKind::Trait(trait_object.stable(tables, cx)) + } + ClauseKind::RegionOutlives(region_outlives) => { + crate::ty::ClauseKind::RegionOutlives(region_outlives.stable(tables, cx)) + } + ClauseKind::TypeOutlives(type_outlives) => { + let ty::OutlivesPredicate::<_, _>(a, b) = type_outlives; + crate::ty::ClauseKind::TypeOutlives(crate::ty::OutlivesPredicate( + a.stable(tables, cx), + b.stable(tables, cx), + )) + } + ClauseKind::Projection(projection_predicate) => { + crate::ty::ClauseKind::Projection(projection_predicate.stable(tables, cx)) + } + ClauseKind::ConstArgHasType(const_, ty) => crate::ty::ClauseKind::ConstArgHasType( + const_.stable(tables, cx), + ty.stable(tables, cx), + ), + ClauseKind::WellFormed(term) => { + crate::ty::ClauseKind::WellFormed(term.kind().stable(tables, cx)) + } + ClauseKind::ConstEvaluatable(const_) => { + crate::ty::ClauseKind::ConstEvaluatable(const_.stable(tables, cx)) + } + ClauseKind::HostEffect(..) => { + todo!() + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ClosureKind { + type T = crate::ty::ClosureKind; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::ty::ClosureKind::*; + match self { + Fn => crate::ty::ClosureKind::Fn, + FnMut => crate::ty::ClosureKind::FnMut, + FnOnce => crate::ty::ClosureKind::FnOnce, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::SubtypePredicate<'tcx> { + type T = crate::ty::SubtypePredicate; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + let ty::SubtypePredicate { a, b, a_is_expected: _ } = self; + crate::ty::SubtypePredicate { a: a.stable(tables, cx), b: b.stable(tables, cx) } + } +} + +impl<'tcx> Stable<'tcx> for ty::CoercePredicate<'tcx> { + type T = crate::ty::CoercePredicate; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + let ty::CoercePredicate { a, b } = self; + crate::ty::CoercePredicate { a: a.stable(tables, cx), b: b.stable(tables, cx) } + } +} + +impl<'tcx> Stable<'tcx> for ty::AliasRelationDirection { + type T = crate::ty::AliasRelationDirection; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::ty::AliasRelationDirection::*; + match self { + Equate => crate::ty::AliasRelationDirection::Equate, + Subtype => crate::ty::AliasRelationDirection::Subtype, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::TraitPredicate<'tcx> { + type T = crate::ty::TraitPredicate; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + let ty::TraitPredicate { trait_ref, polarity } = self; + crate::ty::TraitPredicate { + trait_ref: trait_ref.stable(tables, cx), + polarity: polarity.stable(tables, cx), + } + } +} + +impl<'tcx, T> Stable<'tcx> for ty::OutlivesPredicate<'tcx, T> +where + T: Stable<'tcx>, +{ + type T = crate::ty::OutlivesPredicate; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + let ty::OutlivesPredicate(a, b) = self; + crate::ty::OutlivesPredicate(a.stable(tables, cx), b.stable(tables, cx)) + } +} + +impl<'tcx> Stable<'tcx> for ty::ProjectionPredicate<'tcx> { + type T = crate::ty::ProjectionPredicate; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + let ty::ProjectionPredicate { projection_term, term } = self; + crate::ty::ProjectionPredicate { + projection_term: projection_term.stable(tables, cx), + term: term.kind().stable(tables, cx), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ImplPolarity { + type T = crate::ty::ImplPolarity; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::ty::ImplPolarity::*; + match self { + Positive => crate::ty::ImplPolarity::Positive, + Negative => crate::ty::ImplPolarity::Negative, + Reservation => crate::ty::ImplPolarity::Reservation, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::PredicatePolarity { + type T = crate::ty::PredicatePolarity; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_middle::ty::PredicatePolarity::*; + match self { + Positive => crate::ty::PredicatePolarity::Positive, + Negative => crate::ty::PredicatePolarity::Negative, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::Region<'tcx> { + type T = crate::ty::Region; + + 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 = crate::ty::RegionKind; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::{BoundRegion, EarlyParamRegion, RegionKind}; + match self { + ty::ReEarlyParam(early_reg) => RegionKind::ReEarlyParam(EarlyParamRegion { + index: early_reg.index, + name: early_reg.name.to_string(), + }), + 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, cx), + }, + ), + ty::ReStatic => RegionKind::ReStatic, + ty::RePlaceholder(place_holder) => RegionKind::RePlaceholder(crate::ty::Placeholder { + universe: place_holder.universe.as_u32(), + bound: BoundRegion { + var: place_holder.bound.var.as_u32(), + kind: place_holder.bound.kind.stable(tables, cx), + }, + }), + ty::ReErased => RegionKind::ReErased, + _ => unreachable!("{self:?}"), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { + type T = crate::mir::mono::Instance; + + 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(..) => crate::mir::mono::InstanceKind::Item, + ty::InstanceKind::Intrinsic(..) => crate::mir::mono::InstanceKind::Intrinsic, + ty::InstanceKind::Virtual(_def_id, idx) => { + crate::mir::mono::InstanceKind::Virtual { idx } + } + ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::ThreadLocalShim(..) + | ty::InstanceKind::DropGlue(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::FutureDropPollShim(..) + | ty::InstanceKind::AsyncDropGlue(..) + | ty::InstanceKind::AsyncDropGlueCtorShim(..) => crate::mir::mono::InstanceKind::Shim, + }; + crate::mir::mono::Instance { def, kind } + } +} + +impl<'tcx> Stable<'tcx> for ty::Variance { + type T = crate::mir::Variance; + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + ty::Bivariant => crate::mir::Variance::Bivariant, + ty::Contravariant => crate::mir::Variance::Contravariant, + ty::Covariant => crate::mir::Variance::Covariant, + ty::Invariant => crate::mir::Variance::Invariant, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::Movability { + type T = crate::ty::Movability; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + match self { + ty::Movability::Static => crate::ty::Movability::Static, + ty::Movability::Movable => crate::ty::Movability::Movable, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { + type T = crate::ty::Abi; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use rustc_abi::ExternAbi; + + use crate::ty::Abi; + match *self { + ExternAbi::Rust => Abi::Rust, + ExternAbi::C { unwind } => Abi::C { unwind }, + ExternAbi::Cdecl { unwind } => Abi::Cdecl { unwind }, + ExternAbi::Stdcall { unwind } => Abi::Stdcall { unwind }, + ExternAbi::Fastcall { unwind } => Abi::Fastcall { unwind }, + ExternAbi::Vectorcall { unwind } => Abi::Vectorcall { unwind }, + ExternAbi::Thiscall { unwind } => Abi::Thiscall { unwind }, + ExternAbi::Aapcs { unwind } => Abi::Aapcs { unwind }, + ExternAbi::Win64 { unwind } => Abi::Win64 { unwind }, + ExternAbi::SysV64 { unwind } => Abi::SysV64 { unwind }, + ExternAbi::PtxKernel => Abi::PtxKernel, + ExternAbi::GpuKernel => Abi::GpuKernel, + ExternAbi::Msp430Interrupt => Abi::Msp430Interrupt, + ExternAbi::X86Interrupt => Abi::X86Interrupt, + ExternAbi::EfiApi => Abi::EfiApi, + ExternAbi::AvrInterrupt => Abi::AvrInterrupt, + ExternAbi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, + ExternAbi::CmseNonSecureCall => Abi::CCmseNonSecureCall, + ExternAbi::CmseNonSecureEntry => Abi::CCmseNonSecureEntry, + ExternAbi::System { unwind } => Abi::System { unwind }, + ExternAbi::RustCall => Abi::RustCall, + ExternAbi::Unadjusted => Abi::Unadjusted, + ExternAbi::RustCold => Abi::RustCold, + ExternAbi::RustInvalid => Abi::RustInvalid, + ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM, + ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS, + ExternAbi::Custom => Abi::Custom, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_session::cstore::ForeignModule { + type T = crate::ty::ForeignModule; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + crate::ty::ForeignModule { + def_id: tables.foreign_module_def(self.def_id), + abi: self.abi.stable(tables, cx), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::AssocKind { + type T = crate::ty::AssocKind; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::{AssocKind, AssocTypeData}; + match *self { + ty::AssocKind::Const { name } => AssocKind::Const { name: name.to_string() }, + ty::AssocKind::Fn { name, has_self } => { + AssocKind::Fn { name: name.to_string(), has_self } + } + ty::AssocKind::Type { data } => AssocKind::Type { + data: match data { + ty::AssocTypeData::Normal(name) => AssocTypeData::Normal(name.to_string()), + ty::AssocTypeData::Rpitit(rpitit) => { + AssocTypeData::Rpitit(rpitit.stable(tables, cx)) + } + }, + }, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::AssocItemContainer { + type T = crate::ty::AssocItemContainer; + + fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &SmirCtxt<'_, BridgeTys>) -> Self::T { + use crate::ty::AssocItemContainer; + match self { + ty::AssocItemContainer::Trait => AssocItemContainer::Trait, + ty::AssocItemContainer::Impl => AssocItemContainer::Impl, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::AssocItem { + type T = crate::ty::AssocItem; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + crate::ty::AssocItem { + def_id: tables.assoc_def(self.def_id), + 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)), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ImplTraitInTraitData { + type T = crate::ty::ImplTraitInTraitData; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + _: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + use crate::ty::ImplTraitInTraitData; + match self { + ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id } => { + ImplTraitInTraitData::Trait { + fn_def_id: tables.fn_def(*fn_def_id), + opaque_def_id: tables.opaque_def(*opaque_def_id), + } + } + ty::ImplTraitInTraitData::Impl { fn_def_id } => { + ImplTraitInTraitData::Impl { fn_def_id: tables.fn_def(*fn_def_id) } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_middle::ty::util::Discr<'tcx> { + type T = crate::ty::Discr; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + crate::ty::Discr { val: self.val, ty: self.ty.stable(tables, cx) } + } +} diff --git a/compiler/stable_mir/src/unstable/internal_cx/mod.rs b/compiler/stable_mir/src/unstable/internal_cx/mod.rs new file mode 100644 index 00000000000..6b0a06e304c --- /dev/null +++ b/compiler/stable_mir/src/unstable/internal_cx/mod.rs @@ -0,0 +1,93 @@ +//! Implementation of InternalCx. + +use rustc_middle::ty::{List, Ty, TyCtxt}; +use rustc_middle::{mir, ty}; +pub(crate) use traits::*; + +use super::InternalCx; + +pub(crate) mod traits; + +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>>(self, value: T) -> Option { + TyCtxt::lift(self, value) + } + + fn mk_args_from_iter(self, iter: I) -> T::Output + where + I: Iterator, + T: ty::CollectAndApply, 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> { + TyCtxt::mk_poly_existential_predicates(self, eps) + } + + fn mk_type_list(self, v: &[Ty<'tcx>]) -> &'tcx List> { + 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(self, iter: I) -> T::Output + where + I: Iterator, + T: ty::CollectAndApply>, + { + TyCtxt::mk_bound_variable_kinds_from_iter(self, iter) + } + + fn mk_place_elems(self, v: &[mir::PlaceElem<'tcx>]) -> &'tcx List> { + 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) + } +} diff --git a/compiler/stable_mir/src/unstable/internal_cx/traits.rs b/compiler/stable_mir/src/unstable/internal_cx/traits.rs new file mode 100644 index 00000000000..da443cd78f1 --- /dev/null +++ b/compiler/stable_mir/src/unstable/internal_cx/traits.rs @@ -0,0 +1,31 @@ +//! A set of traits that define a stable interface to rustc's internals. +//! +//! These traits are primarily used to clarify the behavior of different +//! functions that share the same name across various contexts. + +use rustc_middle::ty; + +pub(crate) trait SmirExistentialProjection<'tcx> { + fn new_from_args( + &self, + def_id: rustc_span::def_id::DefId, + args: ty::GenericArgsRef<'tcx>, + term: ty::Term<'tcx>, + ) -> ty::ExistentialProjection<'tcx>; +} + +pub(crate) trait SmirExistentialTraitRef<'tcx> { + fn new_from_args( + &self, + trait_def_id: rustc_span::def_id::DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> ty::ExistentialTraitRef<'tcx>; +} + +pub(crate) trait SmirTraitRef<'tcx> { + fn new_from_args( + &self, + trait_def_id: rustc_span::def_id::DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> ty::TraitRef<'tcx>; +} diff --git a/compiler/stable_mir/src/unstable/mod.rs b/compiler/stable_mir/src/unstable/mod.rs new file mode 100644 index 00000000000..51c31e212f5 --- /dev/null +++ b/compiler/stable_mir/src/unstable/mod.rs @@ -0,0 +1,124 @@ +//! 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; + +use super::compiler_interface::BridgeTys; +use crate::{CtorKind, ItemKind}; + +pub(crate) mod convert; +mod internal_cx; + +/// 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 [`rustc_smir::context::SmirCtxt`]. +pub trait InternalCx<'tcx>: Copy + Clone { + fn tcx(self) -> TyCtxt<'tcx>; + + fn lift>>(self, value: T) -> Option; + + fn mk_args_from_iter(self, iter: I) -> T::Output + where + I: Iterator, + T: ty::CollectAndApply, 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>; + + fn mk_type_list(self, v: &[Ty<'tcx>]) -> &'tcx List>; + + fn lifetimes_re_erased(self) -> ty::Region<'tcx>; + + fn mk_bound_variable_kinds_from_iter(self, iter: I) -> T::Output + where + I: Iterator, + T: ty::CollectAndApply>; + + fn mk_place_elems(self, v: &[mir::PlaceElem<'tcx>]) -> &'tcx List>; + + 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/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs new file mode 100644 index 00000000000..45e2a815470 --- /dev/null +++ b/compiler/stable_mir/src/visitor.rs @@ -0,0 +1,224 @@ +use std::ops::ControlFlow; + +use super::ty::{ + Allocation, Binder, ConstDef, ExistentialPredicate, FnSig, GenericArgKind, GenericArgs, + MirConst, Promoted, Region, RigidTy, TermKind, Ty, UnevaluatedConst, +}; +use crate::Opaque; +use crate::ty::TyConst; + +pub trait Visitor: Sized { + type Break; + fn visit_ty(&mut self, ty: &Ty) -> ControlFlow { + ty.super_visit(self) + } + fn visit_const(&mut self, c: &TyConst) -> ControlFlow { + c.super_visit(self) + } + fn visit_reg(&mut self, reg: &Region) -> ControlFlow { + reg.super_visit(self) + } +} + +pub trait Visitable { + fn visit(&self, visitor: &mut V) -> ControlFlow { + self.super_visit(visitor) + } + fn super_visit(&self, visitor: &mut V) -> ControlFlow; +} + +impl Visitable for Ty { + fn visit(&self, visitor: &mut V) -> ControlFlow { + visitor.visit_ty(self) + } + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + match self.kind() { + super::ty::TyKind::RigidTy(ty) => ty.visit(visitor)?, + super::ty::TyKind::Alias(_, alias) => alias.args.visit(visitor)?, + super::ty::TyKind::Param(_) | super::ty::TyKind::Bound(_, _) => {} + } + ControlFlow::Continue(()) + } +} + +impl Visitable for TyConst { + fn visit(&self, visitor: &mut V) -> ControlFlow { + visitor.visit_const(self) + } + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + match &self.kind { + super::ty::TyConstKind::Param(_) | super::ty::TyConstKind::Bound(_, _) => {} + super::ty::TyConstKind::Unevaluated(_, args) => args.visit(visitor)?, + super::ty::TyConstKind::Value(ty, alloc) => { + alloc.visit(visitor)?; + ty.visit(visitor)?; + } + super::ty::TyConstKind::ZSTValue(ty) => ty.visit(visitor)?, + } + ControlFlow::Continue(()) + } +} + +impl Visitable for MirConst { + fn visit(&self, visitor: &mut V) -> ControlFlow { + self.super_visit(visitor) + } + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + match &self.kind() { + super::ty::ConstantKind::Ty(ct) => ct.visit(visitor)?, + super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?, + super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?, + super::ty::ConstantKind::Param(_) | super::ty::ConstantKind::ZeroSized => {} + } + self.ty().visit(visitor) + } +} + +impl Visitable for Opaque { + fn super_visit(&self, _visitor: &mut V) -> ControlFlow { + ControlFlow::Continue(()) + } +} + +impl Visitable for Allocation { + fn super_visit(&self, _visitor: &mut V) -> ControlFlow { + ControlFlow::Continue(()) + } +} + +impl Visitable for UnevaluatedConst { + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + let UnevaluatedConst { def, args, promoted } = self; + def.visit(visitor)?; + args.visit(visitor)?; + promoted.visit(visitor) + } +} + +impl Visitable for ConstDef { + fn super_visit(&self, _visitor: &mut V) -> ControlFlow { + ControlFlow::Continue(()) + } +} + +impl Visitable for Option { + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + match self { + Some(val) => val.visit(visitor), + None => ControlFlow::Continue(()), + } + } +} + +impl Visitable for Promoted { + fn super_visit(&self, _visitor: &mut V) -> ControlFlow { + ControlFlow::Continue(()) + } +} + +impl Visitable for GenericArgs { + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + self.0.visit(visitor) + } +} + +impl Visitable for Region { + fn visit(&self, visitor: &mut V) -> ControlFlow { + visitor.visit_reg(self) + } + + fn super_visit(&self, _: &mut V) -> ControlFlow { + ControlFlow::Continue(()) + } +} + +impl Visitable for GenericArgKind { + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + match self { + GenericArgKind::Lifetime(lt) => lt.visit(visitor), + GenericArgKind::Type(t) => t.visit(visitor), + GenericArgKind::Const(c) => c.visit(visitor), + } + } +} + +impl Visitable for RigidTy { + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + match self { + RigidTy::Bool + | RigidTy::Char + | RigidTy::Int(_) + | RigidTy::Uint(_) + | RigidTy::Float(_) + | RigidTy::Never + | RigidTy::Foreign(_) + | RigidTy::Str => ControlFlow::Continue(()), + RigidTy::Array(t, c) => { + t.visit(visitor)?; + c.visit(visitor) + } + RigidTy::Pat(t, _p) => t.visit(visitor), + RigidTy::Slice(inner) => inner.visit(visitor), + RigidTy::RawPtr(ty, _) => ty.visit(visitor), + RigidTy::Ref(reg, ty, _) => { + reg.visit(visitor)?; + ty.visit(visitor) + } + RigidTy::Adt(_, args) + | RigidTy::Closure(_, args) + | RigidTy::Coroutine(_, args, _) + | RigidTy::CoroutineWitness(_, args) + | RigidTy::CoroutineClosure(_, args) + | RigidTy::FnDef(_, args) => args.visit(visitor), + RigidTy::FnPtr(sig) => sig.visit(visitor), + RigidTy::Dynamic(pred, r, _) => { + pred.visit(visitor)?; + r.visit(visitor) + } + RigidTy::Tuple(fields) => fields.visit(visitor), + } + } +} + +impl Visitable for Vec { + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + for arg in self { + arg.visit(visitor)?; + } + ControlFlow::Continue(()) + } +} + +impl Visitable for Binder { + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + self.value.visit(visitor) + } +} + +impl Visitable for ExistentialPredicate { + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + match self { + ExistentialPredicate::Trait(tr) => tr.generic_args.visit(visitor), + ExistentialPredicate::Projection(p) => { + p.term.visit(visitor)?; + p.generic_args.visit(visitor) + } + ExistentialPredicate::AutoTrait(_) => ControlFlow::Continue(()), + } + } +} + +impl Visitable for TermKind { + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + match self { + TermKind::Type(t) => t.visit(visitor), + TermKind::Const(c) => c.visit(visitor), + } + } +} + +impl Visitable for FnSig { + fn super_visit(&self, visitor: &mut V) -> ControlFlow { + self.inputs_and_output.visit(visitor) + } +} -- cgit 1.4.1-3-g733a5 From 627cefa9930e65bc2ae4d93b8fb95b6f008f4702 Mon Sep 17 00:00:00 2001 From: Makai Date: Sun, 6 Jul 2025 11:17:12 +0000 Subject: remove `rustc_smir` from tests --- tests/ui-fulldeps/stable-mir/check_abi.rs | 3 +-- tests/ui-fulldeps/stable-mir/check_allocation.rs | 4 ++-- tests/ui-fulldeps/stable-mir/check_assoc_items.rs | 3 +-- tests/ui-fulldeps/stable-mir/check_attribute.rs | 4 ++-- tests/ui-fulldeps/stable-mir/check_binop.rs | 4 ++-- tests/ui-fulldeps/stable-mir/check_coroutine_body.rs | 4 ++-- tests/ui-fulldeps/stable-mir/check_crate_defs.rs | 4 ++-- tests/ui-fulldeps/stable-mir/check_def_ty.rs | 3 +-- tests/ui-fulldeps/stable-mir/check_defs.rs | 3 +-- tests/ui-fulldeps/stable-mir/check_foreign.rs | 3 +-- tests/ui-fulldeps/stable-mir/check_instance.rs | 3 +-- tests/ui-fulldeps/stable-mir/check_intrinsics.rs | 4 ++-- tests/ui-fulldeps/stable-mir/check_item_kind.rs | 3 +-- tests/ui-fulldeps/stable-mir/check_normalization.rs | 3 +-- tests/ui-fulldeps/stable-mir/check_trait_queries.rs | 4 ++-- tests/ui-fulldeps/stable-mir/check_transform.rs | 4 ++-- tests/ui-fulldeps/stable-mir/check_ty_fold.rs | 4 ++-- tests/ui-fulldeps/stable-mir/check_variant.rs | 4 ++-- tests/ui-fulldeps/stable-mir/closure-generic-body.rs | 4 ++-- tests/ui-fulldeps/stable-mir/closure_body.rs | 4 ++-- tests/ui-fulldeps/stable-mir/compilation-result.rs | 4 ++-- tests/ui-fulldeps/stable-mir/crate-info.rs | 4 ++-- tests/ui-fulldeps/stable-mir/projections.rs | 4 ++-- tests/ui-fulldeps/stable-mir/smir_internal.rs | 5 ++--- tests/ui-fulldeps/stable-mir/smir_serde.rs | 4 ++-- tests/ui-fulldeps/stable-mir/smir_visitor.rs | 3 +-- 26 files changed, 43 insertions(+), 53 deletions(-) diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 15ef583709b..9d83dd9ce1a 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -11,10 +11,9 @@ extern crate rustc_hir; extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use stable_mir::abi::{ diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index 64194e72888..c2d1d5d873b 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -13,10 +13,10 @@ extern crate rustc_hir; extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use std::ascii::Char; diff --git a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs index bb95bedf973..574f7797854 100644 --- a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs +++ b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs @@ -11,8 +11,7 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs index e4cc7b104b6..f234c658dfd 100644 --- a/tests/ui-fulldeps/stable-mir/check_attribute.rs +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -9,10 +9,10 @@ extern crate rustc_hir; extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use stable_mir::{CrateDef, CrateItems}; diff --git a/tests/ui-fulldeps/stable-mir/check_binop.rs b/tests/ui-fulldeps/stable-mir/check_binop.rs index f9559d9958d..748c2088a30 100644 --- a/tests/ui-fulldeps/stable-mir/check_binop.rs +++ b/tests/ui-fulldeps/stable-mir/check_binop.rs @@ -9,10 +9,10 @@ extern crate rustc_hir; extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use stable_mir::mir::mono::Instance; diff --git a/tests/ui-fulldeps/stable-mir/check_coroutine_body.rs b/tests/ui-fulldeps/stable-mir/check_coroutine_body.rs index 67773492958..2af32afc1f7 100644 --- a/tests/ui-fulldeps/stable-mir/check_coroutine_body.rs +++ b/tests/ui-fulldeps/stable-mir/check_coroutine_body.rs @@ -10,10 +10,10 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs index 6863242f225..d3929c5e48b 100644 --- a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs @@ -10,10 +10,10 @@ extern crate rustc_hir; extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use stable_mir::CrateDef; diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs index f86a8e0ae61..101e7eb9121 100644 --- a/tests/ui-fulldeps/stable-mir/check_def_ty.rs +++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs @@ -11,8 +11,7 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index ab741378bb7..65db50ee3ff 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -10,8 +10,7 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs index 398024c4ff0..2947d51b63b 100644 --- a/tests/ui-fulldeps/stable-mir/check_foreign.rs +++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs @@ -10,8 +10,7 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; extern crate rustc_span; diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index b19e5b033c4..9b1e4176531 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -10,8 +10,7 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index 52424857dc1..2fce367c7a0 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -14,10 +14,10 @@ extern crate rustc_middle; extern crate rustc_hir; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use stable_mir::mir::mono::{Instance, InstanceKind}; diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs index d1124c75a89..20b9e86ff92 100644 --- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs +++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs @@ -10,8 +10,7 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; diff --git a/tests/ui-fulldeps/stable-mir/check_normalization.rs b/tests/ui-fulldeps/stable-mir/check_normalization.rs index 16e8c0339ed..bb5cd49e1b0 100644 --- a/tests/ui-fulldeps/stable-mir/check_normalization.rs +++ b/tests/ui-fulldeps/stable-mir/check_normalization.rs @@ -9,8 +9,7 @@ #![feature(rustc_private)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs index fcf04a1fc3a..73ba0ea23c9 100644 --- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs +++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs @@ -10,10 +10,10 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use stable_mir::CrateDef; diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index 9087c1cf450..460f1b9e963 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -11,10 +11,10 @@ extern crate rustc_hir; extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use stable_mir::mir::alloc::GlobalAlloc; diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs index 18b9e32e4e8..1a21757d038 100644 --- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -11,10 +11,10 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use stable_mir::mir::{ diff --git a/tests/ui-fulldeps/stable-mir/check_variant.rs b/tests/ui-fulldeps/stable-mir/check_variant.rs index b0de3369830..4cff57308f6 100644 --- a/tests/ui-fulldeps/stable-mir/check_variant.rs +++ b/tests/ui-fulldeps/stable-mir/check_variant.rs @@ -11,10 +11,10 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/closure-generic-body.rs b/tests/ui-fulldeps/stable-mir/closure-generic-body.rs index 2a23345a9d3..6b3447e5839 100644 --- a/tests/ui-fulldeps/stable-mir/closure-generic-body.rs +++ b/tests/ui-fulldeps/stable-mir/closure-generic-body.rs @@ -10,10 +10,10 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/closure_body.rs b/tests/ui-fulldeps/stable-mir/closure_body.rs index 7ed0dabd2c3..a1c97e7549b 100644 --- a/tests/ui-fulldeps/stable-mir/closure_body.rs +++ b/tests/ui-fulldeps/stable-mir/closure_body.rs @@ -10,10 +10,10 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index 19b9c8b7de5..d577de48c55 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -10,10 +10,10 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use std::io::Write; diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 7fc4edafb93..fd7c2032b6d 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -11,10 +11,10 @@ extern crate rustc_hir; extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use rustc_hir::def::DefKind; diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index 103c97bc48e..f8104287700 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -11,10 +11,10 @@ extern crate rustc_hir; extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; +#[macro_use] extern crate stable_mir; use stable_mir::ItemKind; diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index 0519b9de680..287f4353d51 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -10,15 +10,14 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#[macro_use] -extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate rustc_middle; +#[macro_use] extern crate stable_mir; use rustc_middle::ty::TyCtxt; -use rustc_smir::rustc_internal; +use stable_mir::rustc_internal; use std::io::Write; use std::ops::ControlFlow; diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs index 0b39ec05002..c2f00e56c2c 100644 --- a/tests/ui-fulldeps/stable-mir/smir_serde.rs +++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs @@ -9,13 +9,13 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; extern crate rustc_middle; extern crate serde; extern crate serde_json; +#[macro_use] extern crate stable_mir; use rustc_middle::ty::TyCtxt; diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index caf71de2556..46f85a992ef 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -10,8 +10,7 @@ #![feature(assert_matches)] extern crate rustc_middle; -#[macro_use] -extern crate rustc_smir; + extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -- cgit 1.4.1-3-g733a5