diff options
| author | Makai <m4kai410@gmail.com> | 2025-04-05 18:23:07 +0800 |
|---|---|---|
| committer | Makai <m4kai410@gmail.com> | 2025-04-05 18:23:07 +0800 |
| commit | 707d356d004029a7e5300ce51e5aed330aa4a1a7 (patch) | |
| tree | 8cc166ca3855dfdc724dbbafcd6955a113683ecb /compiler/stable_mir | |
| parent | 1e008dd5d83e782ad37fc9cf6824733f824cc8cd (diff) | |
| download | rust-707d356d004029a7e5300ce51e5aed330aa4a1a7.tar.gz rust-707d356d004029a7e5300ce51e5aed330aa4a1a7.zip | |
let `rustc_smir` host `stable_mir` for refactoring
Diffstat (limited to 'compiler/stable_mir')
| -rw-r--r-- | compiler/stable_mir/Cargo.toml | 3 | ||||
| -rw-r--r-- | compiler/stable_mir/src/abi.rs | 456 | ||||
| -rw-r--r-- | compiler/stable_mir/src/compiler_interface.rs | 286 | ||||
| -rw-r--r-- | compiler/stable_mir/src/crate_def.rs | 174 | ||||
| -rw-r--r-- | compiler/stable_mir/src/error.rs | 85 | ||||
| -rw-r--r-- | compiler/stable_mir/src/lib.rs | 234 | ||||
| -rw-r--r-- | compiler/stable_mir/src/mir.rs | 8 | ||||
| -rw-r--r-- | compiler/stable_mir/src/mir/alloc.rs | 87 | ||||
| -rw-r--r-- | compiler/stable_mir/src/mir/body.rs | 1108 | ||||
| -rw-r--r-- | compiler/stable_mir/src/mir/mono.rs | 307 | ||||
| -rw-r--r-- | compiler/stable_mir/src/mir/pretty.rs | 462 | ||||
| -rw-r--r-- | compiler/stable_mir/src/mir/visit.rs | 586 | ||||
| -rw-r--r-- | compiler/stable_mir/src/target.rs | 60 | ||||
| -rw-r--r-- | compiler/stable_mir/src/ty.rs | 1622 | ||||
| -rw-r--r-- | compiler/stable_mir/src/visitor.rs | 224 |
15 files changed, 6 insertions, 5696 deletions
diff --git a/compiler/stable_mir/Cargo.toml b/compiler/stable_mir/Cargo.toml index d691a0e4f22..3a01ee5783e 100644 --- a/compiler/stable_mir/Cargo.toml +++ b/compiler/stable_mir/Cargo.toml @@ -4,5 +4,4 @@ version = "0.1.0-preview" edition = "2024" [dependencies] -scoped-tls = "1.0" -serde = { version = "1.0.125", features = [ "derive" ] } +rustc_smir = { path = "../rustc_smir" } diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs deleted file mode 100644 index 091f3e1a95e..00000000000 --- a/compiler/stable_mir/src/abi.rs +++ /dev/null @@ -1,456 +0,0 @@ -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, IndexedVal, 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 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 [crate::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, - - // Target-specific calling conventions. - ArmAapcs, - CCmseNonSecureCall, - CCmseNonSecureEntry, - - Msp430Intr, - - PtxKernel, - - GpuKernel, - - X86Fastcall, - X86Intr, - X86Stdcall, - X86ThisCall, - X86VectorCall, - - X86_64SysV, - X86_64Win64, - - AvrInterrupt, - AvrNonBlockingInterrupt, - - RiscvInterrupt, -} diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs deleted file mode 100644 index 46154da36ca..00000000000 --- a/compiler/stable_mir/src/compiler_interface.rs +++ /dev/null @@ -1,286 +0,0 @@ -//! Define the interface with the Rust compiler. -//! -//! StableMIR users should not use any of the items in this module directly. -//! These APIs have no stability guarantee. - -use std::cell::Cell; - -use crate::abi::{FnAbi, Layout, LayoutShape}; -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; -use crate::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, 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, -}; -use crate::{ - AssocItems, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, - ItemKind, Symbol, TraitDecls, mir, -}; - -/// This trait defines the interface between stable_mir and the Rust compiler. -/// Do not use this directly. -pub trait Context { - 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; - - /// 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; - - /// 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 representation 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; - - /// Check if this is an empty AsyncDropGlueCtor shim. - fn is_empty_async_drop_ctor_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; -} - -// A thread local variable that stores a pointer to the tables mapping between TyCtxt -// datastructures and stable MIR datastructures -scoped_tls::scoped_thread_local!(static TLV: Cell<*const ()>); - -pub fn run<F, T>(context: &dyn Context, 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 context) as _; - TLV.set(&Cell::new(ptr), || Ok(f())) - } -} - -/// Execute the given function with access the compiler [Context]. -/// -/// I.e., This function will load the current context and calls a function with it. -/// Do not nest these, as that will ICE. -pub(crate) fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R { - assert!(TLV.is_set()); - TLV.with(|tlv| { - let ptr = tlv.get(); - assert!(!ptr.is_null()); - f(unsafe { *(ptr as *const &dyn Context) }) - }) -} diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs deleted file mode 100644 index 75228135e4c..00000000000 --- a/compiler/stable_mir/src/crate_def.rs +++ /dev/null @@ -1,174 +0,0 @@ -//! Module that define a common trait for things that represent a crate definition, -//! such as, a function, a trait, an enum, and any other definitions. - -use serde::Serialize; - -use 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/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs deleted file mode 100644 index 050752e41eb..00000000000 --- a/compiler/stable_mir/src/error.rs +++ /dev/null @@ -1,85 +0,0 @@ -//! When things go wrong, we need some error handling. -//! There are a few different types of errors in StableMIR: -//! -//! - [CompilerError]: This represents errors that can be raised when invoking the compiler. -//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled. - -use std::fmt::{Debug, Display, Formatter}; -use std::{fmt, io}; - -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 Error { - pub fn new(msg: String) -> Self { - Self(msg) - } -} - -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/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index df90d3e5a08..cc0fb52433d 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -1,231 +1,7 @@ -//! The WIP stable interface to rustc internals. +//! We've temporarily moved the `stable_mir` implementation to [`rustc_smir::stable_mir`], +//! during refactoring to break the circular dependency between `rustc_smir` and `stable_mir`, //! -//! For more information see <https://github.com/rust-lang/project-stable-mir> -//! -//! # Note -//! -//! This API is still completely unstable and subject to change. - -#![doc( - html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", - test(attr(allow(unused_variables), deny(warnings))) -)] -//! -//! This crate shall contain all type definitions and APIs that we expect third-party tools to invoke to -//! interact with the compiler. -//! -//! The goal is to eventually be published on -//! [crates.io](https://crates.io). - -use std::fmt::Debug; -use std::{fmt, io}; - -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, IndexedVal, Span, TraitDef, Ty}; - -pub mod abi; -#[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) - } -} +//! This is a transitional measure as described in [PR #139319](https://github.com/rust-lang/rust/pull/139319). +//! Once the refactoring is complete, the `stable_mir` implementation will be moved back here. -pub fn opaque<T: Debug>(value: &T) -> Opaque { - Opaque(format!("{value:?}")) -} +pub use rustc_smir::stable_mir::*; diff --git a/compiler/stable_mir/src/mir.rs b/compiler/stable_mir/src/mir.rs deleted file mode 100644 index 413b5152bb3..00000000000 --- a/compiler/stable_mir/src/mir.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod alloc; -mod body; -pub mod mono; -pub mod pretty; -pub mod visit; - -pub use body::*; -pub use visit::{MirVisitor, MutMirVisitor}; diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs deleted file mode 100644 index 023807b76ae..00000000000 --- a/compiler/stable_mir/src/mir/alloc.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! 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, IndexedVal, Ty}; -use crate::{Error, 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), -} - -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/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs deleted file mode 100644 index 2a1c163de3c..00000000000 --- a/compiler/stable_mir/src/mir/body.rs +++ /dev/null @@ -1,1108 +0,0 @@ -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), - MisalignedPointerDereference { required: Operand, found: Operand }, - NullPointerDereference, -} - -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::BoundsCheck { .. } => Ok("index out of bounds"), - AssertMessage::MisalignedPointerDereference { .. } => { - Ok("misaligned pointer dereference") - } - AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"), - } - } -} - -#[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(stable_mir): Movability here is redundant - Coroutine(CoroutineDef, GenericArgs, Movability), - CoroutineClosure(CoroutineClosureDef, GenericArgs), - RawPtr(Ty, Mutability), -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum Operand { - Copy(Place), - Move(Place), - Constant(ConstOperand), -} - -#[derive(Clone, Eq, PartialEq, Serialize)] -pub struct Place { - pub local: Local, - /// projection out of a place (access a field, deref a pointer, etc) - pub projection: Vec<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), - // FIXME(smir-rename): change this to PointerCoercion(DynStar) - DynStar, - 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/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs deleted file mode 100644 index 22507a49411..00000000000 --- a/compiler/stable_mir/src/mir/mono.rs +++ /dev/null @@ -1,307 +0,0 @@ -use std::fmt::{Debug, Formatter}; -use std::io; - -use serde::Serialize; - -use crate::abi::FnAbi; -use crate::crate_def::CrateDef; -use crate::mir::Body; -use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; -use crate::{CrateItem, DefId, Error, 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, crate::Error> { - with(|context| { - context.resolve_instance(def, args).ok_or_else(|| { - crate::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, crate::Error> { - with(|context| { - context.resolve_for_fn_ptr(def, args).ok_or_else(|| { - crate::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, crate::Error> { - with(|context| { - context.resolve_closure(def, args, kind).ok_or_else(|| { - crate::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) || cx.is_empty_async_drop_ctor_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/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs deleted file mode 100644 index 65d9f20f0a3..00000000000 --- a/compiler/stable_mir/src/mir/pretty.rs +++ /dev/null @@ -1,462 +0,0 @@ -//! Implement methods to pretty print stable MIR body. -use std::fmt::Debug; -use std::io::Write; -use std::{fmt, io, iter}; - -use fmt::{Display, Formatter}; - -use super::{AggregateKind, AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind}; -use crate::mir::{ - Operand, Place, RawPtrKind, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents, -}; -use crate::ty::{AdtKind, AssocKind, IndexedVal, MirConst, Ty, TyConst}; -use crate::{Body, CrateDef, 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 => write!(f, "method"), - 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::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => { - 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/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs deleted file mode 100644 index 9d2368ba332..00000000000 --- a/compiler/stable_mir/src/mir/visit.rs +++ /dev/null @@ -1,586 +0,0 @@ -//! # The Stable MIR Visitor -//! -//! ## Overview -//! -//! We currently only support an immutable visitor. -//! The structure of this visitor is similar to the ones internal to `rustc`, -//! and it follows the following conventions: -//! -//! For every mir item, the trait has a `visit_<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) => { - self.visit_operand(op, location); - } - AssertMessage::ResumedAfterReturn(_) - | AssertMessage::ResumedAfterPanic(_) - | AssertMessage::NullPointerDereference => { - //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/stable_mir/src/target.rs b/compiler/stable_mir/src/target.rs deleted file mode 100644 index 32c3a2a9122..00000000000 --- a/compiler/stable_mir/src/target.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! 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/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs deleted file mode 100644 index 25ec4a440d6..00000000000 --- a/compiler/stable_mir/src/ty.rs +++ /dev/null @@ -1,1622 +0,0 @@ -use std::fmt::{self, Debug, Display, Formatter}; -use std::ops::Range; - -use serde::Serialize; - -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, 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, -} - -#[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(stable_mir): 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 => crate::target::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 => crate::target::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; -} - -crate_def! { - #[derive(Serialize)] - pub CoroutineDef; -} - -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 }) - } -} - -/// 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, - Weak, -} - -#[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 }, - RustIntrinsic, - RustCall, - Unadjusted, - RustCold, - RiscvInterruptM, - RiscvInterruptS, -} - -/// 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, - DynStar, -} - -#[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(GenericArgKind), - 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, -} - -pub trait IndexedVal { - fn to_val(index: usize) -> Self; - - fn to_index(&self) -> usize; -} - -macro_rules! index_impl { - ($name:ident) => { - impl 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 infomation 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 name: Symbol, - 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>, - - /// Whether this is a method with an explicit self - /// as its first parameter, allowing method calls. - pub fn_has_self_parameter: bool, - - /// `Some` if the associated item (an associated type) comes from the - /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` - /// provides additional information about its source. - pub opt_rpitit_info: Option<ImplTraitInTraitData>, -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum AssocKind { - Const, - Fn, - Type, -} - -#[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 { - self.opt_rpitit_info.is_some() - } -} diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs deleted file mode 100644 index 8463174f9a4..00000000000 --- a/compiler/stable_mir/src/visitor.rs +++ /dev/null @@ -1,224 +0,0 @@ -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 { - crate::ty::TyConstKind::Param(_) | crate::ty::TyConstKind::Bound(_, _) => {} - crate::ty::TyConstKind::Unevaluated(_, args) => args.visit(visitor)?, - crate::ty::TyConstKind::Value(ty, alloc) => { - alloc.visit(visitor)?; - ty.visit(visitor)?; - } - crate::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) - } -} |
