diff options
| author | Makai <m4kai410@gmail.com> | 2025-07-12 15:28:50 +0000 |
|---|---|---|
| committer | Makai <m4kai410@gmail.com> | 2025-07-14 09:25:54 +0000 |
| commit | 6598c61725abb0e8179b8a5fab7a0ed1f7fcaf5f (patch) | |
| tree | 65d506113ce17311d0346fa4089500192dd0f3ed /compiler/rustc_public | |
| parent | ad635e5d0696076b4412dd7db7b7e8c0867d6e0c (diff) | |
| download | rust-6598c61725abb0e8179b8a5fab7a0ed1f7fcaf5f.tar.gz rust-6598c61725abb0e8179b8a5fab7a0ed1f7fcaf5f.zip | |
rename `stable_mir` to `rustc_public`, and `rustc_smir` to `rustc_public_bridge`
Diffstat (limited to 'compiler/rustc_public')
29 files changed, 10886 insertions, 0 deletions
diff --git a/compiler/rustc_public/Cargo.toml b/compiler/rustc_public/Cargo.toml new file mode 100644 index 00000000000..fa782166e4f --- /dev/null +++ b/compiler/rustc_public/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "rustc_public" +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_public_bridge = { path = "../rustc_public_bridge" } +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 + +[features] +# Provides access to APIs that expose internals of the rust compiler. +# APIs enabled by this feature are unstable. They can be removed or modified +# at any point and they are not included in the crate's semantic versioning. +rustc_internal = [] diff --git a/compiler/rustc_public/README.md b/compiler/rustc_public/README.md new file mode 100644 index 00000000000..ab2546e377a --- /dev/null +++ b/compiler/rustc_public/README.md @@ -0,0 +1,46 @@ +This crate is currently developed in-tree together with the compiler. + +Our goal is to start publishing `stable_mir` into crates.io. +Until then, users will use this as any other rustc crate, by installing +the rustup component `rustc-dev`, and declaring `stable-mir` as an external crate. + +See the StableMIR ["Getting Started"](https://rust-lang.github.io/project-stable-mir/getting-started.html) +guide for more information. + +## Stable MIR Design + +The stable-mir will follow a similar approach to proc-macro2. Its +implementation is split between two main crates: + +- `stable_mir`: Public crate, to be published on crates.io, which will contain +the stable data structure as well as calls to `rustc_smir` APIs. The +translation between stable and internal constructs will also be done in this crate, +however, this is currently implemented in the `rustc_smir` crate.[^translation]. +- `rustc_smir`: This crate implements the public APIs to the compiler. +It is responsible for gathering all the information requested, and providing +the data in its unstable form. + +[^translation]: This is currently implemented in the `rustc_smir` crate, +but we are working to change that. + +I.e., +tools will depend on `stable_mir` crate, +which will invoke the compiler using APIs defined in `rustc_smir`. + +I.e.: + +``` + ┌──────────────────────────────────┐ ┌──────────────────────────────────┐ + │ External Tool ┌──────────┐ │ │ ┌──────────┐ Rust Compiler │ + │ │ │ │ │ │ │ │ + │ │stable_mir| │ │ │rustc_smir│ │ + │ │ │ ├──────────►| │ │ │ + │ │ │ │◄──────────┤ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ + │ └──────────┘ │ │ └──────────┘ │ + └──────────────────────────────────┘ └──────────────────────────────────┘ +``` + +More details can be found here: +https://hackmd.io/XhnYHKKuR6-LChhobvlT-g?view diff --git a/compiler/rustc_public/rust-toolchain.toml b/compiler/rustc_public/rust-toolchain.toml new file mode 100644 index 00000000000..d75e8e33b1c --- /dev/null +++ b/compiler/rustc_public/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2023-06-14" +components = [ "rustfmt", "rustc-dev" ] diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs new file mode 100644 index 00000000000..7b0882caf1b --- /dev/null +++ b/compiler/rustc_public/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<ArgAbi>, + + /// 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<usize>), + + /// 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<Size>, + }, +} + +impl FieldsShape { + pub fn fields_by_offset_order(&self) -> Vec<FieldIdx> { + match self { + FieldsShape::Primitive => vec![], + FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(), + FieldsShape::Arbitrary { offsets, .. } => { + let mut indices = (0..offsets.len()).collect::<Vec<_>>(); + 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<LayoutShape>, + }, +} + +#[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<VariantIdx>, + 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<bool, Error> { + 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<IntegerType>, + pub align: Option<Align>, + pub pack: Option<Align>, + pub flags: ReprFlags, +} diff --git a/compiler/rustc_public/src/alloc.rs b/compiler/rustc_public/src/alloc.rs new file mode 100644 index 00000000000..d2db6c08bbc --- /dev/null +++ b/compiler/rustc_public/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_public_bridge::alloc` to maintain stability guarantees. + +use rustc_abi::Align; +use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::AllocRange; +use rustc_public_bridge::bridge::SmirError; +use rustc_public_bridge::context::SmirCtxt; +use rustc_public_bridge::{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<Allocation, Error> { + let layout = alloc::create_ty_and_layout(cx, ty).map_err(|e| Error::from_internal(e))?; + match const_value { + ConstValue::Scalar(scalar) => { + alloc::try_new_scalar(layout, scalar, cx).map(|alloc| alloc.stable(tables, cx)) + } + ConstValue::ZeroSized => Ok(new_empty_allocation(layout.align.abi)), + ConstValue::Slice { data, meta } => { + alloc::try_new_slice(layout, data, meta, cx).map(|alloc| alloc.stable(tables, cx)) + } + ConstValue::Indirect { alloc_id, offset } => { + let alloc = alloc::try_new_indirect(alloc_id, cx); + use rustc_public_bridge::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_public/src/compiler_interface.rs b/compiler/rustc_public/src/compiler_interface.rs new file mode 100644 index 00000000000..d15438c2b80 --- /dev/null +++ b/compiler/rustc_public/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_public_bridge::context::SmirCtxt; +use rustc_public_bridge::{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_public_bridge::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<CrateItem>; + /// Retrieve all items of the local crate that have a MIR associated with them. + fn all_local_items(&self) -> CrateItems; + /// Retrieve the body of a function. + /// This function will panic if the body is not available. + fn mir_body(&self, item: DefId) -> mir::Body; + /// Check whether the body of a function is available. + fn has_body(&self, item: DefId) -> bool; + fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef>; + + /// Retrieve all functions defined in this crate. + fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef>; + + /// Retrieve all static items defined in this crate. + fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef>; + fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule; + fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef>; + fn all_trait_decls(&self) -> TraitDecls; + fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls; + fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl; + fn all_trait_impls(&self) -> ImplTraitDecls; + fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls; + fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait; + fn generics_of(&self, def_id: DefId) -> Generics; + fn predicates_of(&self, def_id: DefId) -> GenericPredicates; + fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates; + + /// Get information about the local crate. + fn local_crate(&self) -> Crate; + /// Retrieve a list of all external crates. + fn external_crates(&self) -> Vec<Crate>; + + /// Find a crate with the given name. + fn find_crates(&self, name: &str) -> Vec<Crate>; + + /// Returns the name of given `DefId` + fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol; + + /// Return registered tool attributes with the given attribute name. + /// + /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool + /// attributes will simply return an empty list. + /// + /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`. + /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. + fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute>; + + /// Get all tool attributes of a definition. + fn all_tool_attrs(&self, def_id: DefId) -> Vec<Attribute>; + + /// Returns printable, human readable form of `Span` + fn span_to_string(&self, span: Span) -> String; + + /// Return filename from given `Span`, for diagnostic purposes + fn get_filename(&self, span: &Span) -> Filename; + + /// Return lines corresponding to this `Span` + fn get_lines(&self, span: &Span) -> LineInfo; + + /// Returns the `kind` of given `DefId` + fn item_kind(&self, item: CrateItem) -> ItemKind; + + /// Returns whether this is a foreign item. + fn is_foreign_item(&self, item: DefId) -> bool; + + /// Returns the kind of a given foreign item. + fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind; + + /// Returns the kind of a given algebraic data type + fn adt_kind(&self, def: AdtDef) -> AdtKind; + + /// Returns if the ADT is a box. + fn adt_is_box(&self, def: AdtDef) -> bool; + + /// Returns whether this ADT is simd. + fn adt_is_simd(&self, def: AdtDef) -> bool; + + /// Returns whether this definition is a C string. + fn adt_is_cstr(&self, def: AdtDef) -> bool; + + /// Returns the representation options for this ADT. + fn adt_repr(&self, def: AdtDef) -> ReprOptions; + + /// Retrieve the function signature for the given generic arguments. + fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig; + + /// Retrieve the intrinsic definition if the item corresponds one. + fn intrinsic(&self, item: DefId) -> Option<IntrinsicDef>; + + /// Retrieve the plain function name of an intrinsic. + fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol; + + /// Retrieve the closure signature for the given generic arguments. + fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig; + + /// The number of variants in this ADT. + fn adt_variants_len(&self, def: AdtDef) -> usize; + + /// Discriminant for a given variant index of AdtDef. + fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr; + + /// Discriminant for a given variand index and args of a coroutine. + fn coroutine_discr_for_variant( + &self, + coroutine: CoroutineDef, + args: &GenericArgs, + variant: VariantIdx, + ) -> Discr; + + /// The name of a variant. + fn variant_name(&self, def: VariantDef) -> Symbol; + fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef>; + + /// Evaluate constant as a target usize. + fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error>; + fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error>; + + /// Create a new zero-sized constant. + fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error>; + + /// Create a new constant that represents the given string value. + fn new_const_str(&self, value: &str) -> MirConst; + + /// Create a new constant that represents the given boolean value. + fn new_const_bool(&self, value: bool) -> MirConst; + + /// Create a new constant that represents the given value. + fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error>; + fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<TyConst, Error>; + + /// Create a new type from the given kind. + fn new_rigid_ty(&self, kind: RigidTy) -> Ty; + + /// Create a new box type, `Box<T>`, for the given inner type `T`. + fn new_box_ty(&self, ty: Ty) -> Ty; + + /// Returns the type of given crate item. + fn def_ty(&self, item: DefId) -> Ty; + + /// Returns the type of given definition instantiated with the given arguments. + fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty; + + /// Returns literal value of a const as a string. + fn mir_const_pretty(&self, cnst: &MirConst) -> String; + + /// `Span` of an item + fn span_of_an_item(&self, def_id: DefId) -> Span; + + fn ty_const_pretty(&self, ct: TyConstId) -> String; + + /// Obtain the representation of a type. + fn ty_pretty(&self, ty: Ty) -> String; + + /// Obtain the kind of a type. + fn ty_kind(&self, ty: Ty) -> TyKind; + + // Get the discriminant Ty for this Ty if there's one. + fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty; + + /// Get the body of an Instance which is already monomorphized. + fn instance_body(&self, instance: InstanceDef) -> Option<Body>; + + /// Get the instance type with generic instantiations applied and lifetimes erased. + fn instance_ty(&self, instance: InstanceDef) -> Ty; + + /// Get the instantiation types. + fn instance_args(&self, def: InstanceDef) -> GenericArgs; + + /// Get the instance. + fn instance_def_id(&self, instance: InstanceDef) -> DefId; + + /// Get the instance mangled name. + fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol; + + /// Check if this is an empty DropGlue shim. + fn is_empty_drop_shim(&self, def: InstanceDef) -> bool; + + /// Convert a non-generic crate item into an instance. + /// This function will panic if the item is generic. + fn mono_instance(&self, def_id: DefId) -> Instance; + + /// Item requires monomorphization. + fn requires_monomorphization(&self, def_id: DefId) -> bool; + + /// Resolve an instance from the given function definition and generic arguments. + fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>; + + /// Resolve an instance for drop_in_place for the given type. + fn resolve_drop_in_place(&self, ty: Ty) -> Instance; + + /// Resolve instance for a function pointer. + fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>; + + /// Resolve instance for a closure with the requested type. + fn resolve_closure( + &self, + def: ClosureDef, + args: &GenericArgs, + kind: ClosureKind, + ) -> Option<Instance>; + + /// Evaluate a static's initializer. + fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error>; + + /// Try to evaluate an instance into a constant. + fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error>; + + /// Retrieve global allocation for the given allocation ID. + fn global_alloc(&self, id: AllocId) -> GlobalAlloc; + + /// Retrieve the id for the virtual table. + fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>; + fn krate(&self, def_id: DefId) -> Crate; + fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol; + + /// Return information about the target machine. + fn target_info(&self) -> MachineInfo; + + /// Get an instance ABI. + fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error>; + + /// Get the ABI of a function pointer. + fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error>; + + /// Get the layout of a type. + fn ty_layout(&self, ty: Ty) -> Result<Layout, Error>; + + /// Get the layout shape. + fn layout_shape(&self, id: Layout) -> LayoutShape; + + /// Get a debug string representation of a place. + fn place_pretty(&self, place: &Place) -> String; + + /// Get the resulting type of binary operation. + fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty; + + /// Get the resulting type of unary operation. + fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty; + + /// Get all associated items of a definition. + fn associated_items(&self, def_id: DefId) -> AssocItems; +} + +impl<'tcx> SmirInterface for SmirContainer<'tcx, BridgeTys> { + fn entry_fn(&self) -> Option<CrateItem> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let did = cx.entry_fn(); + Some(tables.crate_item(did?)) + } + + /// Retrieve all items of the local crate that have a MIR associated with them. + 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<ForeignModuleDef> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + cx.foreign_modules(crate_num.internal(&mut *tables, cx.tcx)) + .iter() + .map(|did| tables.foreign_module_def(*did)) + .collect() + } + + /// Retrieve all functions defined in this crate. + fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let krate = crate_num.internal(&mut *tables, cx.tcx); + cx.crate_functions(krate).iter().map(|did| tables.fn_def(*did)).collect() + } + + /// Retrieve all static items defined in this crate. + fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let krate = crate_num.internal(&mut *tables, cx.tcx); + cx.crate_statics(krate).iter().map(|did| tables.static_def(*did)).collect() + } + + 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<ForeignDef> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let did = tables[mod_def.def_id()]; + cx.foreign_items(did).iter().map(|did| tables.foreign_def(*did)).collect() + } + + 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<Crate> { + let cx = &*self.cx.borrow(); + cx.external_crates().iter().map(|crate_num| smir_crate(cx, *crate_num)).collect() + } + + /// Find a crate with the given name. + fn find_crates(&self, name: &str) -> Vec<Crate> { + let cx = &*self.cx.borrow(); + cx.find_crates(name).iter().map(|crate_num| smir_crate(cx, *crate_num)).collect() + } + + /// Returns the name of given `DefId`. + 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<Attribute> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let did = tables[def_id]; + cx.tool_attrs(did, attr) + .into_iter() + .map(|(attr_str, span)| Attribute::new(attr_str, span.stable(&mut *tables, cx))) + .collect() + } + + /// Get all tool attributes of a definition. + fn all_tool_attrs(&self, def_id: DefId) -> Vec<Attribute> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let did = tables[def_id]; + cx.all_tool_attrs(did) + .into_iter() + .map(|(attr_str, span)| Attribute::new(attr_str, span.stable(&mut *tables, cx))) + .collect() + } + + /// Returns printable, human readable form of `Span`. + 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_public_bridge::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<IntrinsicDef> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let def_id = item.internal(&mut *tables, cx.tcx); + cx.intrinsic(def_id).map(|_| IntrinsicDef(item)) + } + + /// Retrieve the plain function name of an intrinsic. + 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<FieldDef> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + def.internal(&mut *tables, cx.tcx) + .fields + .iter() + .map(|f| f.stable(&mut *tables, cx)) + .collect() + } + + /// Evaluate constant as a target usize. + fn eval_target_usize(&self, mir_const: &MirConst) -> Result<u64, Error> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let cnst = mir_const.internal(&mut *tables, cx.tcx); + cx.eval_target_usize(cnst) + } + + fn eval_target_usize_ty(&self, ty_const: &TyConst) -> Result<u64, Error> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let cnst = ty_const.internal(&mut *tables, cx.tcx); + cx.eval_target_usize_ty(cnst) + } + + /// Create a new zero-sized constant. + fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let ty_internal = ty.internal(&mut *tables, cx.tcx); + cx.try_new_const_zst(ty_internal).map(|cnst| cnst.stable(&mut *tables, cx)) + } + + /// Create a new constant that represents the given string value. + 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<MirConst, Error> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let ty = cx.ty_new_uint(uint_ty.internal(&mut *tables, cx.tcx)); + cx.try_new_const_uint(value, ty).map(|cnst| cnst.stable(&mut *tables, cx)) + } + + fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<TyConst, Error> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let ty = cx.ty_new_uint(uint_ty.internal(&mut *tables, cx.tcx)); + cx.try_new_ty_const_uint(value, ty).map(|cnst| cnst.stable(&mut *tables, cx)) + } + + /// Create a new type from the given kind. + fn new_rigid_ty(&self, kind: RigidTy) -> Ty { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let internal_kind = kind.internal(&mut *tables, cx.tcx); + cx.new_rigid_ty(internal_kind).stable(&mut *tables, cx) + } + + /// Create a new box type, `Box<T>`, for the given inner type `T`. + 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<Body> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let instance = tables.instances[instance]; + cx.instance_body(instance).map(|body| body.stable(&mut *tables, cx)) + } + + /// Get the instance type with generic instantiations applied and lifetimes erased. + 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<Instance> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let def_id = def.0.internal(&mut *tables, cx.tcx); + let args_ref = args.internal(&mut *tables, cx.tcx); + cx.resolve_instance(def_id, args_ref).map(|inst| inst.stable(&mut *tables, cx)) + } + + /// Resolve an instance for drop_in_place for the given type. + 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<Instance> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let def_id = def.0.internal(&mut *tables, cx.tcx); + let args_ref = args.internal(&mut *tables, cx.tcx); + cx.resolve_for_fn_ptr(def_id, args_ref).stable(&mut *tables, cx) + } + + /// Resolve instance for a closure with the requested type. + fn resolve_closure( + &self, + def: ClosureDef, + args: &GenericArgs, + kind: ClosureKind, + ) -> Option<Instance> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let def_id = def.0.internal(&mut *tables, cx.tcx); + let args_ref = args.internal(&mut *tables, cx.tcx); + 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<Allocation, Error> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let def_id = def.0.internal(&mut *tables, cx.tcx); + + cx.eval_static_initializer(def_id).stable(&mut *tables, cx) + } + + /// Try to evaluate an instance into a constant. + fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> { + let mut tables = self.tables.borrow_mut(); + let instance = tables.instances[def]; + let cx = &*self.cx.borrow(); + let const_ty = const_ty.internal(&mut *tables, cx.tcx); + cx.eval_instance(instance) + .map(|const_val| alloc::try_new_allocation(const_ty, const_val, &mut *tables, cx)) + .map_err(|e| e.stable(&mut *tables, cx))? + } + + /// Retrieve global allocation for the given allocation ID. + 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<AllocId> { + let mut tables = self.tables.borrow_mut(); + let GlobalAlloc::VTable(ty, trait_ref) = global_alloc else { + return None; + }; + let cx = &*self.cx.borrow(); + let ty = ty.internal(&mut *tables, cx.tcx); + let trait_ref = trait_ref.internal(&mut *tables, cx.tcx); + let alloc_id = cx.vtable_allocation(ty, trait_ref); + Some(alloc_id.stable(&mut *tables, cx)) + } + + 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<FnAbi, Error> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let instance = tables.instances[def]; + cx.instance_abi(instance).map(|fn_abi| fn_abi.stable(&mut *tables, cx)) + } + + /// Get the ABI of a function pointer. + fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let sig = fn_ptr.internal(&mut *tables, cx.tcx); + cx.fn_ptr_abi(sig).map(|fn_abi| fn_abi.stable(&mut *tables, cx)) + } + + /// Get the layout of a type. + fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> { + let mut tables = self.tables.borrow_mut(); + let cx = &*self.cx.borrow(); + let internal_ty = ty.internal(&mut *tables, cx.tcx); + cx.ty_layout(internal_ty).map(|layout| layout.stable(&mut *tables, cx)) + } + + /// Get the layout shape. + 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<F, T>(interface: &dyn SmirInterface, f: F) -> Result<T, Error> +where + F: FnOnce() -> T, +{ + if TLV.is_set() { + Err(Error::from("StableMIR already running")) + } else { + let ptr: *const () = (&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<R>(f: impl FnOnce(&dyn SmirInterface) -> R) -> R { + assert!(TLV.is_set()); + TLV.with(|tlv| { + let ptr = tlv.get(); + assert!(!ptr.is_null()); + f(unsafe { *(ptr as *const &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_public/src/crate_def.rs b/compiler/rustc_public/src/crate_def.rs new file mode 100644 index 00000000000..75228135e4c --- /dev/null +++ b/compiler/rustc_public/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<Attribute> { + 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<Attribute> { + 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_public/src/error.rs b/compiler/rustc_public/src/error.rs new file mode 100644 index 00000000000..bc2124d1716 --- /dev/null +++ b/compiler/rustc_public/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_public_bridge::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<T> { + /// 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<T: Debug>(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<T> Display for CompilerError<T> +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<T> Debug for CompilerError<T> +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<T> std::error::Error for CompilerError<T> where T: Display + Debug {} + +impl From<io::Error> for Error { + fn from(value: io::Error) -> Self { + Error(value.to_string()) + } +} diff --git a/compiler/rustc_public/src/lib.rs b/compiler/rustc_public/src/lib.rs new file mode 100644 index 00000000000..e320c4eca71 --- /dev/null +++ b/compiler/rustc_public/src/lib.rs @@ -0,0 +1,302 @@ +//! The WIP public interface to rustc internals. +//! +//! For more information see <https://github.com/rust-lang/project-stable-mir> +//! +//! # 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_public_bridge::IndexedVal; +use rustc_public_bridge::Tables; +use rustc_public_bridge::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 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<CrateItem>; + +/// A list of trait decls. +pub type TraitDecls = Vec<TraitDef>; + +/// A list of impl trait decls. +pub type ImplTraitDecls = Vec<ImplDef>; + +/// A list of associated items. +pub type AssocItems = Vec<AssocItem>; + +/// 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<ForeignModuleDef> { + 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<FnDef> { + 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<StaticDef> { + 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<mir::Body> { + 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<W: io::Write>(&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<CrateItem> { + 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<Crate> { + with(|cx| cx.find_crates(name)) +} + +/// Try to find a crate with the given name. +pub fn external_crates() -> Vec<Crate> { + 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<T: Debug>(value: &T) -> Opaque { + Opaque(format!("{value:?}")) +} + +macro_rules! bridge_impl { + ($name: ident, $ty: ty) => { + impl rustc_public_bridge::bridge::$name<compiler_interface::BridgeTys> 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_public_bridge::bridge::Prov<compiler_interface::BridgeTys> for crate::ty::Prov { + fn new(aid: crate::mir::alloc::AllocId) -> Self { + Self(aid) + } +} + +impl rustc_public_bridge::bridge::Allocation<compiler_interface::BridgeTys> + for crate::ty::Allocation +{ + fn new<'tcx>( + bytes: Vec<Option<u8>>, + ptrs: Vec<(usize, rustc_middle::mir::interpret::AllocId)>, + align: u64, + mutability: rustc_middle::mir::Mutability, + tables: &mut Tables<'tcx, compiler_interface::BridgeTys>, + cx: &SmirCtxt<'tcx, compiler_interface::BridgeTys>, + ) -> Self { + Self { + bytes, + provenance: ProvenanceMap { + ptrs: ptrs.iter().map(|(i, aid)| (*i, tables.prov(*aid))).collect(), + }, + align, + mutability: mutability.stable(tables, cx), + } + } +} diff --git a/compiler/rustc_public/src/mir.rs b/compiler/rustc_public/src/mir.rs new file mode 100644 index 00000000000..413b5152bb3 --- /dev/null +++ b/compiler/rustc_public/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/rustc_public/src/mir/alloc.rs b/compiler/rustc_public/src/mir/alloc.rs new file mode 100644 index 00000000000..9a94551f3ec --- /dev/null +++ b/compiler/rustc_public/src/mir/alloc.rs @@ -0,0 +1,90 @@ +//! 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<Binder<ExistentialTraitRef>>), + /// 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), + /// The first pointer-sized segment of a type id. On 64 bit systems, the 128 bit type id + /// is split into two segments, on 32 bit systems there are 4 segments, and so on. + TypeId { ty: Ty }, +} + +impl From<AllocId> 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<AllocId> { + 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<u128, Error> { + let mut buf = [0u8; size_of::<u128>()]; + 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<i128, Error> { + let mut buf = [0u8; size_of::<i128>()]; + 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_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs new file mode 100644 index 00000000000..28a7aa6e758 --- /dev/null +++ b/compiler/rustc_public/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<BasicBlock>, + + /// 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<VarDebugInfo>, + + /// 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<Local>, + + /// 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<BasicBlock>, + locals: LocalDecls, + arg_count: usize, + var_debug_info: Vec<VarDebugInfo>, + spread_arg: Option<Local>, + 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<Item = (Local, &LocalDecl)> { + self.locals.iter().enumerate() + } + + /// Emit the body using the provided name for the signature. + pub fn dump<W: io::Write>(&self, w: &mut W, fn_name: &str) -> io::Result<()> { + function_body(w, self, fn_name) + } + + pub fn spread_arg(&self) -> Option<Local> { + self.spread_arg + } +} + +type LocalDecls = Vec<LocalDecl>; + +#[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<Statement>, + 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<BasicBlockIdx>; + +#[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<Operand>, + destination: Place, + target: Option<BasicBlockIdx>, + unwind: UnwindAction, + }, + Assert { + cond: Operand, + expected: bool, + msg: AssertMessage, + target: BasicBlockIdx, + unwind: UnwindAction, + }, + InlineAsm { + template: String, + operands: Vec<InlineAsmOperand>, + options: String, + line_spans: String, + destination: Option<BasicBlockIdx>, + 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<Operand>, + pub out_place: Option<Place>, + // 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<Operand>), + + /// * `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<T>`. + /// + /// 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<Ty, Error> { + 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::<Result<Vec<_>, _>>()?, + )), + 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<UserTypeAnnotationIndex>, Option<FieldIdx>), + Closure(ClosureDef, GenericArgs), + // FIXME(rustc_public): 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<ProjectionElem>, +} + +impl From<Local> 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<UserTypeAnnotationIndex>, + 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<VarDebugInfoFragment>, + + /// 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<u16>, +} + +impl VarDebugInfo { + /// Return a local variable if this info is related to one. + pub fn local(&self) -> Option<Local> { + 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<ProjectionElem>, +} + +#[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<Local, Ty>) 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<Item = (u128, BasicBlockIdx)> { + 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<Ty, Error> { + 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<Ty, Error> { + 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<Ty, Error> { + 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, Error> { + 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<Ty, Error> { + 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<Ty, Error> { + 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_public/src/mir/mono.rs b/compiler/rustc_public/src/mir/mono.rs new file mode 100644 index 00000000000..c85f0fa36f7 --- /dev/null +++ b/compiler/rustc_public/src/mir/mono.rs @@ -0,0 +1,305 @@ +use std::fmt::{Debug, Formatter}; +use std::io; + +use rustc_public_bridge::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<Body> { + 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 <https://github.com/rust-lang/rust/issues/93145>. + /// + /// 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<FnAbi, Error> { + 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<u8>::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<Symbol> { + 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<Instance, Error> { + 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<Instance, Error> { + 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<Instance, Error> { + 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<Allocation, Error> { + with(|cx| cx.eval_instance(self.def, const_ty)) + } + + /// Emit the body of this instance if it has one. + pub fn emit_mir<W: io::Write>(&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<CrateItem> for Instance { + type Error = crate::Error; + + fn try_from(item: CrateItem) -> Result<Self, Self::Error> { + 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<Instance> for CrateItem { + type Error = crate::Error; + + fn try_from(value: Instance) -> Result<Self, Self::Error> { + 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<Instance> for MonoItem { + fn from(value: Instance) -> Self { + MonoItem::Fn(value) + } +} + +impl From<StaticDef> for MonoItem { + fn from(value: StaticDef) -> Self { + MonoItem::Static(value) + } +} + +impl From<StaticDef> 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<CrateItem> for StaticDef { + type Error = crate::Error; + + fn try_from(value: CrateItem) -> Result<Self, Self::Error> { + if matches!(value.kind(), ItemKind::Static) { + Ok(StaticDef(value.0)) + } else { + Err(Error::new(format!("Expected a static item, but found: {value:?}"))) + } + } +} + +impl TryFrom<Instance> for StaticDef { + type Error = crate::Error; + + fn try_from(value: Instance) -> Result<Self, Self::Error> { + StaticDef::try_from(CrateItem::try_from(value)?) + } +} + +impl From<StaticDef> 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<Allocation, Error> { + 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_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs new file mode 100644 index 00000000000..f496d80053e --- /dev/null +++ b/compiler/rustc_public/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<W: Write>(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::<Vec<_>>(); + pretty_terminator(writer, &block.terminator.kind)?; + writeln!(writer, " }}").unwrap(); + Ok(()) + }) + .collect::<Result<Vec<_>, _>>()?; + writeln!(writer, "}}")?; + Ok(()) +} + +fn pretty_statement<W: Write>(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<W: Write>(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<W: Write>(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<String> { + 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<W: Write>(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<W: Write>(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<W: Write>( + writer: &mut W, + aggregate_kind: &AggregateKind, + operands: &Vec<Operand>, +) -> 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_public/src/mir/visit.rs b/compiler/rustc_public/src/mir/visit.rs new file mode 100644 index 00000000000..7dc99d1d1e1 --- /dev/null +++ b/compiler/rustc_public/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_<item>` and a `super_<item>` method. +//! - `visit_<item>`, by default, calls `super_<item>` +//! - `super_<item>`, by default, destructures the `<item>` and calls `visit_<sub_item>` 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_<CONSTRUCT>` 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<Ty, Error> { + 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_public/src/rustc_internal/mod.rs b/compiler/rustc_public/src/rustc_internal/mod.rs new file mode 100644 index 00000000000..5d7c8256d5b --- /dev/null +++ b/compiler/rustc_public/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_public_bridge::context::SmirCtxt; +use rustc_public_bridge::{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<R, B: Bridge>( + f: impl for<'tcx> FnOnce(&mut Tables<'tcx, B>, &SmirCtxt<'tcx, B>) -> R, +) -> R { + assert!(TLV.is_set()); + TLV.with(|tlv| { + let ptr = tlv.get(); + assert!(!ptr.is_null()); + let 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<F, T>(tcx: TyCtxt<'_>, f: F) -> Result<T, Error> +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<B, C>` +/// ```ignore(needs-extern-crate) +/// # extern crate rustc_driver; +/// # extern crate rustc_interface; +/// # extern crate rustc_middle; +/// # #[macro_use] +/// # extern crate rustc_public; +/// # +/// # fn main() { +/// # use std::ops::ControlFlow; +/// # use rustc_public::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_public; +/// # +/// # fn main() { +/// # use std::ops::ControlFlow; +/// # use rustc_public::CompilerError; +/// fn analyze_code(extra_args: Vec<String>) -> 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_public::rustc_internal; + use rustc_public::CompilerError; + use std::ops::ControlFlow; + + pub struct StableMir<B = (), C = (), F = fn($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C>> + where + B: Send, + C: Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send, + { + callback: Option<F>, + result: Option<ControlFlow<B, C>>, + } + + impl<B, C, F> StableMir<B, C, F> + where + B: Send, + C: Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + 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<C, CompilerError<B>> { + 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<B, C, F> Callbacks for StableMir<B, C, F> + where + B: Send, + C: Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + 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_public/src/rustc_internal/pretty.rs b/compiler/rustc_public/src/rustc_internal/pretty.rs new file mode 100644 index 00000000000..28c5280fe04 --- /dev/null +++ b/compiler/rustc_public/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::<Vec<_>>(); + }); + Ok(()) +} diff --git a/compiler/rustc_public/src/target.rs b/compiler/rustc_public/src/target.rs new file mode 100644 index 00000000000..32c3a2a9122 --- /dev/null +++ b/compiler/rustc_public/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<u128> { + (self.num_bits <= 128).then(|| u128::MAX >> (128 - self.bits())) + } +} diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs new file mode 100644 index 00000000000..bc67a2f987d --- /dev/null +++ b/compiler/rustc_public/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<Ty, Error> { + 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<T>`, 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<Layout, Error> { + 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<TyConst>, end: Option<TyConst>, 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<Self, Error> { + 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<u64, Error> { + 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<u64, Error> { + 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<MirConst, Error> { + 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<MirConst, Error> { + 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<BoundRegion>), + 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<T> { + 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<Binder<ExistentialTraitRef>> { + 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<Ty> { + 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<TypeAndMut> { + 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<PolyFnSig> { + 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<Ty> { + 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(rustc_public): Movability here is redundant + Coroutine(CoroutineDef, GenericArgs, Movability), + CoroutineClosure(CoroutineClosureDef, GenericArgs), + Dynamic(Vec<Binder<ExistentialPredicate>>, Region, DynKind), + Never, + Tuple(Vec<Ty>), + 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<RigidTy> 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<ForeignDef> { + 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<Body> { + 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<IntrinsicDef> { + 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<IntrinsicDef> 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<Body> { + 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<Body> { + 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<VariantDef> { + self.variants_iter().collect() + } + + /// Iterate over the variants in this ADT. + pub fn variants_iter(&self) -> impl Iterator<Item = VariantDef> { + (0..self.num_variants()) + .map(|idx| VariantDef { idx: VariantIdx::to_val(idx), adt_def: *self }) + } + + pub fn variant(&self, idx: VariantIdx) -> Option<VariantDef> { + (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<FieldDef> { + 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<GenericArgKind>); + +impl std::ops::Index<ParamTy> for GenericArgs { + type Output = Ty; + + fn index(&self, index: ParamTy) -> &Self::Output { + self.0[index.index as usize].expect_ty() + } +} + +impl std::ops::Index<ParamConst> 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<FnSig>; + +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<FnAbi, Error> { + with(|cx| cx.fn_ptr_abi(self)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +pub struct FnSig { + pub inputs_and_output: Vec<Ty>, + 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<T> { + pub value: T, + pub bound_vars: Vec<BoundVariableKind>, +} + +impl<T> Binder<T> { + /// Create a new binder with the given bound vars. + pub fn bind_with_vars(value: T, bound_vars: Vec<BoundVariableKind>) -> 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<F, U>(&self, f: F) -> Binder<U> + 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<F, U>(self, f: F) -> Binder<U> + 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<T> { + 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<ExistentialTraitRef> { + pub fn with_self_ty(&self, self_ty: Ty) -> Binder<TraitRef> { + 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<Option<u8>>; + +/// 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<u64>; + +/// 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<Vec<u8>, Error> { + self.bytes + .iter() + .copied() + .collect::<Option<Vec<_>>>() + .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<usize>) -> Result<u128, Error> { + 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::<Option<Vec<_>>>() + .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<u128, Error> { + 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<i128, Error> { + 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<bool, Error> { + 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<bool, Error> { + 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<Promoted>, +} + +#[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<Vec<Ident>>, + 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<TraitRef>; + +/// 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<TraitRef, ()> { + 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<GenericDef>, + pub parent_count: usize, + pub params: Vec<GenericParamDef>, + pub param_def_id_to_index: Vec<(GenericDef, u32)>, + pub has_self: bool, + pub has_late_bound_regions: Option<Span>, +} + +#[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<TraitDef>, + 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<A, B>(pub A, pub B); + +pub type RegionOutlivesPredicate = OutlivesPredicate<Region, Region>; +pub type TypeOutlivesPredicate = OutlivesPredicate<Ty, Region>; + +#[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<AssocDef>, +} + +#[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_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs new file mode 100644 index 00000000000..8a6238413b0 --- /dev/null +++ b/compiler/rustc_public/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 rustc_public 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_public_bridge::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<T> RustcInternal for Binder<T> +where + T: RustcInternal, + for<'tcx> T::T<'tcx>: rustc_ty::TypeVisitable<rustc_ty::TyCtxt<'tcx>>, +{ + 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<T> 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<T> RustcInternal for Option<T> +where + T: RustcInternal, +{ + type T<'tcx> = Option<T::T<'tcx>>; + + fn internal<'tcx>( + &self, + tables: &mut Tables<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + self.as_ref().map(|inner| inner.internal(tables, tcx)) + } +} + +impl<T> RustcInternal for Vec<T> +where + T: RustcInternal, +{ + type T<'tcx> = Vec<T::T<'tcx>>; + + fn internal<'tcx>( + &self, + tables: &mut Tables<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx> { + self.iter().map(|e| e.internal(tables, tcx)).collect() + } +} diff --git a/compiler/rustc_public/src/unstable/convert/mod.rs b/compiler/rustc_public/src/unstable/convert/mod.rs new file mode 100644 index 00000000000..85a71e09c3e --- /dev/null +++ b/compiler/rustc_public/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_public_bridge functions. +//! +//! For contributors, please make sure to avoid calling rustc's internal functions and queries. +//! These should be done via `rustc_public_bridge` APIs, but it's possible to access ADT fields directly. + +use std::ops::RangeInclusive; + +use rustc_public_bridge::Tables; +use rustc_public_bridge::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<T> +where + T: Stable<'tcx>, +{ + type T = Option<T::T>; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + self.as_ref().map(|value| value.stable(tables, cx)) + } +} + +impl<'tcx, T, E> Stable<'tcx> for Result<T, E> +where + T: Stable<'tcx>, + E: Stable<'tcx>, +{ + type T = Result<T::T, E::T>; + + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + match self { + Ok(val) => Ok(val.stable(tables, cx)), + Err(error) => Err(error.stable(tables, cx)), + } + } +} + +impl<'tcx, T> Stable<'tcx> for &[T] +where + T: Stable<'tcx>, +{ + type T = Vec<T::T>; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + self.iter().map(|e| e.stable(tables, cx)).collect() + } +} + +impl<'tcx, T, U> Stable<'tcx> for (T, U) +where + T: Stable<'tcx>, + U: Stable<'tcx>, +{ + type T = (T::T, U::T); + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + (self.0.stable(tables, cx), self.1.stable(tables, cx)) + } +} + +impl<'tcx, T> Stable<'tcx> for RangeInclusive<T> +where + T: Stable<'tcx>, +{ + type T = RangeInclusive<T::T>; + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T { + RangeInclusive::new(self.start().stable(tables, cx), self.end().stable(tables, cx)) + } +} diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs new file mode 100644 index 00000000000..40a8bf614e1 --- /dev/null +++ b/compiler/rustc_public/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_public_bridge::Tables; +use rustc_public_bridge::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<rustc_abi::FieldIdx, rustc_abi::VariantIdx> { + 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<rustc_abi::FieldIdx> { + 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<rustc_abi::FieldIdx, rustc_abi::VariantIdx> { + 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<rustc_abi::VariantIdx> { + 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_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs new file mode 100644 index 00000000000..bd7d4807152 --- /dev/null +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -0,0 +1,936 @@ +//! Conversion of internal Rust compiler `mir` items to stable ones. + +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::{bug, mir}; +use rustc_public_bridge::Tables; +use rustc_public_bridge::bridge::SmirError; +use rustc_public_bridge::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<Symbol>` 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<Symbol>` argument is therefore + // dropped when converting to Stable MIR. A brief justification for this decision can be + // found at https://github.com/rust-lang/rust/pull/117517#issuecomment-1811683486 + Downcast(_, idx) => 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_public_bridge::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)) + } + mir::interpret::GlobalAlloc::TypeId { ty } => { + GlobalAlloc::TypeId { ty: ty.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/rustc_public/src/unstable/convert/stable/mod.rs b/compiler/rustc_public/src/unstable/convert/stable/mod.rs new file mode 100644 index 00000000000..ea78ca50eb3 --- /dev/null +++ b/compiler/rustc_public/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_public_bridge::Tables; +use rustc_public_bridge::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/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs new file mode 100644 index 00000000000..75c29788787 --- /dev/null +++ b/compiler/rustc_public/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_public_bridge::Tables; +use rustc_public_bridge::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<V>; + + 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<V>; + + 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<T::T, Region>; + + 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/rustc_public/src/unstable/internal_cx/mod.rs b/compiler/rustc_public/src/unstable/internal_cx/mod.rs new file mode 100644 index 00000000000..6b0a06e304c --- /dev/null +++ b/compiler/rustc_public/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<T: ty::Lift<TyCtxt<'tcx>>>(self, value: T) -> Option<T::Lifted> { + TyCtxt::lift(self, value) + } + + fn mk_args_from_iter<I, T>(self, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: ty::CollectAndApply<ty::GenericArg<'tcx>, ty::GenericArgsRef<'tcx>>, + { + TyCtxt::mk_args_from_iter(self, iter) + } + + fn mk_pat(self, v: ty::PatternKind<'tcx>) -> ty::Pattern<'tcx> { + TyCtxt::mk_pat(self, v) + } + + fn mk_poly_existential_predicates( + self, + eps: &[ty::PolyExistentialPredicate<'tcx>], + ) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> { + TyCtxt::mk_poly_existential_predicates(self, eps) + } + + fn mk_type_list(self, v: &[Ty<'tcx>]) -> &'tcx List<Ty<'tcx>> { + TyCtxt::mk_type_list(self, v) + } + + fn lifetimes_re_erased(self) -> ty::Region<'tcx> { + self.lifetimes.re_erased + } + + fn mk_bound_variable_kinds_from_iter<I, T>(self, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: ty::CollectAndApply<ty::BoundVariableKind, &'tcx List<ty::BoundVariableKind>>, + { + TyCtxt::mk_bound_variable_kinds_from_iter(self, iter) + } + + fn mk_place_elems(self, v: &[mir::PlaceElem<'tcx>]) -> &'tcx List<mir::PlaceElem<'tcx>> { + TyCtxt::mk_place_elems(self, v) + } + + fn adt_def(self, def_id: rustc_hir::def_id::DefId) -> ty::AdtDef<'tcx> { + self.adt_def(def_id) + } +} diff --git a/compiler/rustc_public/src/unstable/internal_cx/traits.rs b/compiler/rustc_public/src/unstable/internal_cx/traits.rs new file mode 100644 index 00000000000..da443cd78f1 --- /dev/null +++ b/compiler/rustc_public/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/rustc_public/src/unstable/mod.rs b/compiler/rustc_public/src/unstable/mod.rs new file mode 100644 index 00000000000..ce7c41a64fa --- /dev/null +++ b/compiler/rustc_public/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_public_bridge::Tables; +use rustc_public_bridge::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_public_bridge::context::SmirCtxt`]. +pub trait InternalCx<'tcx>: Copy + Clone { + fn tcx(self) -> TyCtxt<'tcx>; + + fn lift<T: ty::Lift<TyCtxt<'tcx>>>(self, value: T) -> Option<T::Lifted>; + + fn mk_args_from_iter<I, T>(self, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: ty::CollectAndApply<ty::GenericArg<'tcx>, ty::GenericArgsRef<'tcx>>; + + fn mk_pat(self, v: ty::PatternKind<'tcx>) -> ty::Pattern<'tcx>; + + fn mk_poly_existential_predicates( + self, + eps: &[ty::PolyExistentialPredicate<'tcx>], + ) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>>; + + fn mk_type_list(self, v: &[Ty<'tcx>]) -> &'tcx List<Ty<'tcx>>; + + fn lifetimes_re_erased(self) -> ty::Region<'tcx>; + + fn mk_bound_variable_kinds_from_iter<I, T>(self, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: ty::CollectAndApply<ty::BoundVariableKind, &'tcx List<ty::BoundVariableKind>>; + + fn mk_place_elems(self, v: &[mir::PlaceElem<'tcx>]) -> &'tcx List<mir::PlaceElem<'tcx>>; + + fn adt_def(self, def_id: rustc_hir::def_id::DefId) -> ty::AdtDef<'tcx>; +} + +/// Trait used to convert between an internal MIR type to a Stable MIR type. +/// +/// This trait is currently exposed to users so they can have interoperability between internal MIR +/// and StableMIR constructs. However, they should be used seldom and they have no influence +/// in this crate semver. +#[doc(hidden)] +pub trait Stable<'tcx>: PointeeSized { + /// The stable representation of the type implementing Stable. + type T; + /// Converts an object to the equivalent Stable MIR representation. + fn stable<'cx>( + &self, + tables: &mut Tables<'cx, BridgeTys>, + cx: &SmirCtxt<'cx, BridgeTys>, + ) -> Self::T; +} + +/// Trait used to translate a stable construct to its rustc counterpart. +/// +/// This is basically a mirror of [Stable]. +/// +/// This trait is currently exposed to users so they can have interoperability between internal MIR +/// and StableMIR constructs. They should be used seldom as they have no stability guarantees. +#[doc(hidden)] +pub trait RustcInternal { + type T<'tcx>; + fn internal<'tcx>( + &self, + tables: &mut Tables<'_, BridgeTys>, + tcx: impl InternalCx<'tcx>, + ) -> Self::T<'tcx>; +} + +pub(crate) fn new_item_kind(kind: DefKind) -> ItemKind { + match kind { + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::ConstParam + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::OpaqueTy + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::Impl { .. } + | DefKind::GlobalAsm => { + unreachable!("Not a valid item kind: {kind:?}"); + } + DefKind::Closure | DefKind::AssocFn | DefKind::Fn | DefKind::SyntheticCoroutineBody => { + ItemKind::Fn + } + DefKind::Const | DefKind::InlineConst | DefKind::AssocConst | DefKind::AnonConst => { + ItemKind::Const + } + DefKind::Static { .. } => ItemKind::Static, + DefKind::Ctor(_, rustc_hir::def::CtorKind::Const) => ItemKind::Ctor(CtorKind::Const), + DefKind::Ctor(_, rustc_hir::def::CtorKind::Fn) => ItemKind::Ctor(CtorKind::Fn), + } +} diff --git a/compiler/rustc_public/src/visitor.rs b/compiler/rustc_public/src/visitor.rs new file mode 100644 index 00000000000..45e2a815470 --- /dev/null +++ b/compiler/rustc_public/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<Self::Break> { + ty.super_visit(self) + } + fn visit_const(&mut self, c: &TyConst) -> ControlFlow<Self::Break> { + c.super_visit(self) + } + fn visit_reg(&mut self, reg: &Region) -> ControlFlow<Self::Break> { + reg.super_visit(self) + } +} + +pub trait Visitable { + fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + self.super_visit(visitor) + } + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break>; +} + +impl Visitable for Ty { + fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + visitor.visit_ty(self) + } + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + 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<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + visitor.visit_const(self) + } + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + 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<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + self.super_visit(visitor) + } + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + 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<V: Visitor>(&self, _visitor: &mut V) -> ControlFlow<V::Break> { + ControlFlow::Continue(()) + } +} + +impl Visitable for Allocation { + fn super_visit<V: Visitor>(&self, _visitor: &mut V) -> ControlFlow<V::Break> { + ControlFlow::Continue(()) + } +} + +impl Visitable for UnevaluatedConst { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + let UnevaluatedConst { def, args, promoted } = self; + def.visit(visitor)?; + args.visit(visitor)?; + promoted.visit(visitor) + } +} + +impl Visitable for ConstDef { + fn super_visit<V: Visitor>(&self, _visitor: &mut V) -> ControlFlow<V::Break> { + ControlFlow::Continue(()) + } +} + +impl<T: Visitable> Visitable for Option<T> { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + match self { + Some(val) => val.visit(visitor), + None => ControlFlow::Continue(()), + } + } +} + +impl Visitable for Promoted { + fn super_visit<V: Visitor>(&self, _visitor: &mut V) -> ControlFlow<V::Break> { + ControlFlow::Continue(()) + } +} + +impl Visitable for GenericArgs { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + self.0.visit(visitor) + } +} + +impl Visitable for Region { + fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + visitor.visit_reg(self) + } + + fn super_visit<V: Visitor>(&self, _: &mut V) -> ControlFlow<V::Break> { + ControlFlow::Continue(()) + } +} + +impl Visitable for GenericArgKind { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + 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<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + 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<T: Visitable> Visitable for Vec<T> { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + for arg in self { + arg.visit(visitor)?; + } + ControlFlow::Continue(()) + } +} + +impl<T: Visitable> Visitable for Binder<T> { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + self.value.visit(visitor) + } +} + +impl Visitable for ExistentialPredicate { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + 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<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + match self { + TermKind::Type(t) => t.visit(visitor), + TermKind::Const(c) => c.visit(visitor), + } + } +} + +impl Visitable for FnSig { + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + self.inputs_and_output.visit(visitor) + } +} |
