diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
commit | d1b2d29528b7794b41e66fc2136e395a02f8529b (patch) | |
tree | a4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_smir | |
parent | Releasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip |
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_smir')
-rw-r--r-- | compiler/rustc_smir/Cargo.toml | 6 | ||||
-rw-r--r-- | compiler/rustc_smir/rust-toolchain.toml | 2 | ||||
-rw-r--r-- | compiler/rustc_smir/src/lib.rs | 15 | ||||
-rw-r--r-- | compiler/rustc_smir/src/rustc_internal/mod.rs | 110 | ||||
-rw-r--r-- | compiler/rustc_smir/src/rustc_smir/mod.rs | 1120 | ||||
-rw-r--r-- | compiler/rustc_smir/src/stable_mir/mir/body.rs | 322 | ||||
-rw-r--r-- | compiler/rustc_smir/src/stable_mir/mod.rs | 28 | ||||
-rw-r--r-- | compiler/rustc_smir/src/stable_mir/ty.rs | 414 |
8 files changed, 1848 insertions, 169 deletions
diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index a6e6de5f7..80d4e7ed0 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -4,14 +4,18 @@ version = "0.0.0" edition = "2021" [dependencies] -rustc_hir = { path = "../rustc_hir" } +# Use optional dependencies for rustc_* in order to support building this crate separately. +rustc_hir = { path = "../rustc_hir", optional = true } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } +rustc_target = { path = "../rustc_target", optional = true } tracing = "0.1" scoped-tls = "1.0" [features] default = [ + "rustc_hir", "rustc_middle", "rustc_span", + "rustc_target", ] diff --git a/compiler/rustc_smir/rust-toolchain.toml b/compiler/rustc_smir/rust-toolchain.toml index 157dfd620..d75e8e33b 100644 --- a/compiler/rustc_smir/rust-toolchain.toml +++ b/compiler/rustc_smir/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-02-28" +channel = "nightly-2023-06-14" components = [ "rustfmt", "rustc-dev" ] diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index fb03633b9..8cb533c8d 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -1,6 +1,6 @@ //! The WIP stable interface to rustc internals. //! -//! For more information see https://github.com/rust-lang/project-stable-mir +//! For more information see <https://github.com/rust-lang/project-stable-mir> //! //! # Note //! @@ -11,8 +11,19 @@ test(attr(allow(unused_variables), deny(warnings))) )] #![cfg_attr(not(feature = "default"), feature(rustc_private))] -#![feature(local_key_cell_methods)] #![feature(ptr_metadata)] +#![feature(type_alias_impl_trait)] // Used to define opaque types. +#![feature(intra_doc_pointers)] + +// Declare extern rustc_* crates to enable building this crate separately from the compiler. +#[cfg(not(feature = "default"))] +extern crate rustc_hir; +#[cfg(not(feature = "default"))] +extern crate rustc_middle; +#[cfg(not(feature = "default"))] +extern crate rustc_span; +#[cfg(not(feature = "default"))] +extern crate rustc_target; pub mod rustc_internal; pub mod stable_mir; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 609a04d26..078ff6744 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -3,6 +3,9 @@ //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs //! until stable MIR is complete. +use std::fmt::Debug; +use std::string::ToString; + use crate::{ rustc_smir::Tables, stable_mir::{self, with}, @@ -24,21 +27,117 @@ pub fn crate_item(did: DefId) -> stable_mir::CrateItem { with_tables(|t| t.crate_item(did)) } +pub fn adt_def(did: DefId) -> stable_mir::ty::AdtDef { + with_tables(|t| t.adt_def(did)) +} + +pub fn foreign_def(did: DefId) -> stable_mir::ty::ForeignDef { + with_tables(|t| t.foreign_def(did)) +} + +pub fn fn_def(did: DefId) -> stable_mir::ty::FnDef { + with_tables(|t| t.fn_def(did)) +} + +pub fn closure_def(did: DefId) -> stable_mir::ty::ClosureDef { + with_tables(|t| t.closure_def(did)) +} + +pub fn generator_def(did: DefId) -> stable_mir::ty::GeneratorDef { + with_tables(|t| t.generator_def(did)) +} + +pub fn alias_def(did: DefId) -> stable_mir::ty::AliasDef { + with_tables(|t| t.alias_def(did)) +} + +pub fn param_def(did: DefId) -> stable_mir::ty::ParamDef { + with_tables(|t| t.param_def(did)) +} + +pub fn br_named_def(did: DefId) -> stable_mir::ty::BrNamedDef { + with_tables(|t| t.br_named_def(did)) +} + +pub fn trait_def(did: DefId) -> stable_mir::ty::TraitDef { + with_tables(|t| t.trait_def(did)) +} + +pub fn impl_def(did: DefId) -> stable_mir::ty::ImplDef { + with_tables(|t| t.impl_def(did)) +} + impl<'tcx> Tables<'tcx> { pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId { self.def_ids[item.0] } + pub fn trait_def_id(&self, trait_def: &stable_mir::ty::TraitDef) -> DefId { + self.def_ids[trait_def.0] + } + + pub fn impl_trait_def_id(&self, impl_def: &stable_mir::ty::ImplDef) -> DefId { + self.def_ids[impl_def.0] + } + pub fn crate_item(&mut self, did: DefId) -> stable_mir::CrateItem { + stable_mir::CrateItem(self.create_def_id(did)) + } + + pub fn adt_def(&mut self, did: DefId) -> stable_mir::ty::AdtDef { + stable_mir::ty::AdtDef(self.create_def_id(did)) + } + + pub fn foreign_def(&mut self, did: DefId) -> stable_mir::ty::ForeignDef { + stable_mir::ty::ForeignDef(self.create_def_id(did)) + } + + pub fn fn_def(&mut self, did: DefId) -> stable_mir::ty::FnDef { + stable_mir::ty::FnDef(self.create_def_id(did)) + } + + pub fn closure_def(&mut self, did: DefId) -> stable_mir::ty::ClosureDef { + stable_mir::ty::ClosureDef(self.create_def_id(did)) + } + + pub fn generator_def(&mut self, did: DefId) -> stable_mir::ty::GeneratorDef { + stable_mir::ty::GeneratorDef(self.create_def_id(did)) + } + + pub fn alias_def(&mut self, did: DefId) -> stable_mir::ty::AliasDef { + stable_mir::ty::AliasDef(self.create_def_id(did)) + } + + pub fn param_def(&mut self, did: DefId) -> stable_mir::ty::ParamDef { + stable_mir::ty::ParamDef(self.create_def_id(did)) + } + + pub fn br_named_def(&mut self, did: DefId) -> stable_mir::ty::BrNamedDef { + stable_mir::ty::BrNamedDef(self.create_def_id(did)) + } + + pub fn trait_def(&mut self, did: DefId) -> stable_mir::ty::TraitDef { + stable_mir::ty::TraitDef(self.create_def_id(did)) + } + + pub fn const_def(&mut self, did: DefId) -> stable_mir::ty::ConstDef { + stable_mir::ty::ConstDef(self.create_def_id(did)) + } + + pub fn impl_def(&mut self, did: DefId) -> stable_mir::ty::ImplDef { + stable_mir::ty::ImplDef(self.create_def_id(did)) + } + + fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId { // FIXME: this becomes inefficient when we have too many ids for (i, &d) in self.def_ids.iter().enumerate() { if d == did { - return stable_mir::CrateItem(i); + return i; } } let id = self.def_ids.len(); self.def_ids.push(did); - stable_mir::CrateItem(id) + id } } @@ -49,3 +148,10 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) { crate::stable_mir::run(Tables { tcx, def_ids: vec![], types: vec![] }, f); } + +/// A type that provides internal information but that can still be used for debug purpose. +pub type Opaque = impl Debug + ToString + Clone; + +pub(crate) fn opaque<T: Debug>(value: &T) -> Opaque { + format!("{value:?}") +} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 85d5bb00c..06b37008e 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -7,11 +7,19 @@ //! //! For now, we are developing everything inside `rustc`, thus, we keep this module private. -use crate::stable_mir::ty::{FloatTy, IntTy, RigidTy, TyKind, UintTy}; +use crate::rustc_internal::{self, opaque}; +use crate::stable_mir::mir::{CopyNonOverlapping, UserTypeProjection, VariantIdx}; +use crate::stable_mir::ty::{ + allocation_filter, new_allocation, Const, FloatTy, IntTy, Movability, RigidTy, TyKind, UintTy, +}; use crate::stable_mir::{self, Context}; -use rustc_middle::mir; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_hir as hir; +use rustc_middle::mir::coverage::CodeRegion; +use rustc_middle::mir::interpret::alloc_range; +use rustc_middle::mir::{self, ConstantKind}; +use rustc_middle::ty::{self, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_target::abi::FieldIdx; use tracing::debug; impl<'tcx> Context for Tables<'tcx> { @@ -36,6 +44,35 @@ impl<'tcx> Context for Tables<'tcx> { fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> { Some(self.crate_item(self.tcx.entry_fn(())?.0)) } + + fn all_trait_decls(&mut self) -> stable_mir::TraitDecls { + self.tcx + .traits(LOCAL_CRATE) + .iter() + .map(|trait_def_id| self.trait_def(*trait_def_id)) + .collect() + } + + fn trait_decl(&mut self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl { + let def_id = self.trait_def_id(trait_def); + let trait_def = self.tcx.trait_def(def_id); + trait_def.stable(self) + } + + fn all_trait_impls(&mut self) -> stable_mir::ImplTraitDecls { + self.tcx + .trait_impls_in_crate(LOCAL_CRATE) + .iter() + .map(|impl_def_id| self.impl_def(*impl_def_id)) + .collect() + } + + fn trait_impl(&mut self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait { + let def_id = self.impl_trait_def_id(impl_def); + let impl_trait = self.tcx.impl_trait_ref(def_id).unwrap(); + impl_trait.stable(self) + } + fn mir_body(&mut self, item: &stable_mir::CrateItem) -> stable_mir::mir::Body { let def_id = self.item_def_id(item); let mir = self.tcx.optimized_mir(def_id); @@ -44,8 +81,12 @@ impl<'tcx> Context for Tables<'tcx> { .basic_blocks .iter() .map(|block| stable_mir::mir::BasicBlock { - terminator: block.terminator().stable(), - statements: block.statements.iter().map(mir::Statement::stable).collect(), + terminator: block.terminator().stable(self), + statements: block + .statements + .iter() + .map(|statement| statement.stable(self)) + .collect(), }) .collect(), locals: mir.local_decls.iter().map(|decl| self.intern_ty(decl.ty)).collect(), @@ -57,7 +98,8 @@ impl<'tcx> Context for Tables<'tcx> { } fn ty_kind(&mut self, ty: crate::stable_mir::ty::Ty) -> TyKind { - self.rustc_ty_to_ty(self.types[ty.0]) + let ty = self.types[ty.0]; + ty.stable(self) } } @@ -68,57 +110,6 @@ pub struct Tables<'tcx> { } impl<'tcx> Tables<'tcx> { - fn rustc_ty_to_ty(&mut self, ty: Ty<'tcx>) -> TyKind { - match ty.kind() { - ty::Bool => TyKind::RigidTy(RigidTy::Bool), - ty::Char => TyKind::RigidTy(RigidTy::Char), - ty::Int(int_ty) => match int_ty { - ty::IntTy::Isize => TyKind::RigidTy(RigidTy::Int(IntTy::Isize)), - ty::IntTy::I8 => TyKind::RigidTy(RigidTy::Int(IntTy::I8)), - ty::IntTy::I16 => TyKind::RigidTy(RigidTy::Int(IntTy::I16)), - ty::IntTy::I32 => TyKind::RigidTy(RigidTy::Int(IntTy::I32)), - ty::IntTy::I64 => TyKind::RigidTy(RigidTy::Int(IntTy::I64)), - ty::IntTy::I128 => TyKind::RigidTy(RigidTy::Int(IntTy::I128)), - }, - ty::Uint(uint_ty) => match uint_ty { - ty::UintTy::Usize => TyKind::RigidTy(RigidTy::Uint(UintTy::Usize)), - ty::UintTy::U8 => TyKind::RigidTy(RigidTy::Uint(UintTy::U8)), - ty::UintTy::U16 => TyKind::RigidTy(RigidTy::Uint(UintTy::U16)), - ty::UintTy::U32 => TyKind::RigidTy(RigidTy::Uint(UintTy::U32)), - ty::UintTy::U64 => TyKind::RigidTy(RigidTy::Uint(UintTy::U64)), - ty::UintTy::U128 => TyKind::RigidTy(RigidTy::Uint(UintTy::U128)), - }, - ty::Float(float_ty) => match float_ty { - ty::FloatTy::F32 => TyKind::RigidTy(RigidTy::Float(FloatTy::F32)), - ty::FloatTy::F64 => TyKind::RigidTy(RigidTy::Float(FloatTy::F64)), - }, - ty::Adt(_, _) => todo!(), - ty::Foreign(_) => todo!(), - ty::Str => todo!(), - ty::Array(_, _) => todo!(), - ty::Slice(_) => todo!(), - ty::RawPtr(_) => todo!(), - ty::Ref(_, _, _) => todo!(), - ty::FnDef(_, _) => todo!(), - ty::FnPtr(_) => todo!(), - ty::Placeholder(..) => todo!(), - ty::Dynamic(_, _, _) => todo!(), - ty::Closure(_, _) => todo!(), - ty::Generator(_, _, _) => todo!(), - ty::GeneratorWitness(_) => todo!(), - ty::GeneratorWitnessMIR(_, _) => todo!(), - ty::Never => todo!(), - ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple( - fields.iter().map(|ty| self.intern_ty(ty)).collect(), - )), - ty::Alias(_, _) => todo!(), - ty::Param(_) => todo!(), - ty::Bound(_, _) => todo!(), - ty::Infer(_) => todo!(), - ty::Error(_) => todo!(), - } - } - fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty { if let Some(id) = self.types.iter().position(|&t| t == ty) { return stable_mir::ty::Ty(id); @@ -137,78 +128,343 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate { stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local } } -pub trait Stable { +/// Trait used to convert between an internal MIR type to a Stable MIR type. +pub(crate) trait Stable<'tcx> { + /// The stable representation of the type implementing Stable. type T; - fn stable(&self) -> Self::T; + /// Converts an object to the equivalent Stable MIR representation. + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T; } -impl<'tcx> Stable for mir::Statement<'tcx> { +impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> { type T = stable_mir::mir::Statement; - fn stable(&self) -> Self::T { + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use rustc_middle::mir::StatementKind::*; match &self.kind { Assign(assign) => { - stable_mir::mir::Statement::Assign(assign.0.stable(), assign.1.stable()) - } - FakeRead(_) => todo!(), - SetDiscriminant { .. } => todo!(), - Deinit(_) => todo!(), - StorageLive(_) => todo!(), - StorageDead(_) => todo!(), - Retag(_, _) => todo!(), - PlaceMention(_) => todo!(), - AscribeUserType(_, _) => todo!(), - Coverage(_) => todo!(), - Intrinsic(_) => todo!(), - ConstEvalCounter => todo!(), + stable_mir::mir::Statement::Assign(assign.0.stable(tables), assign.1.stable(tables)) + } + FakeRead(fake_read_place) => stable_mir::mir::Statement::FakeRead( + fake_read_place.0.stable(tables), + fake_read_place.1.stable(tables), + ), + SetDiscriminant { place: plc, variant_index: idx } => { + stable_mir::mir::Statement::SetDiscriminant { + place: plc.as_ref().stable(tables), + variant_index: idx.stable(tables), + } + } + Deinit(place) => stable_mir::mir::Statement::Deinit(place.stable(tables)), + StorageLive(place) => stable_mir::mir::Statement::StorageLive(place.stable(tables)), + StorageDead(place) => stable_mir::mir::Statement::StorageDead(place.stable(tables)), + Retag(retag, place) => { + stable_mir::mir::Statement::Retag(retag.stable(tables), place.stable(tables)) + } + PlaceMention(place) => stable_mir::mir::Statement::PlaceMention(place.stable(tables)), + AscribeUserType(place_projection, variance) => { + stable_mir::mir::Statement::AscribeUserType { + place: place_projection.as_ref().0.stable(tables), + projections: place_projection.as_ref().1.stable(tables), + variance: variance.stable(tables), + } + } + Coverage(coverage) => stable_mir::mir::Statement::Coverage(stable_mir::mir::Coverage { + kind: coverage.kind.stable(tables), + code_region: coverage.code_region.as_ref().map(|reg| reg.stable(tables)), + }), + Intrinsic(intrinstic) => { + stable_mir::mir::Statement::Intrinsic(intrinstic.stable(tables)) + } + ConstEvalCounter => stable_mir::mir::Statement::ConstEvalCounter, Nop => stable_mir::mir::Statement::Nop, } } } -impl<'tcx> Stable for mir::Rvalue<'tcx> { +impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { type T = stable_mir::mir::Rvalue; - fn stable(&self) -> Self::T { + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use mir::Rvalue::*; match self { - Use(op) => stable_mir::mir::Rvalue::Use(op.stable()), - Repeat(_, _) => todo!(), - Ref(_, _, _) => todo!(), - ThreadLocalRef(_) => todo!(), - AddressOf(_, _) => todo!(), - Len(_) => todo!(), - Cast(_, _, _) => todo!(), - BinaryOp(_, _) => todo!(), + Use(op) => stable_mir::mir::Rvalue::Use(op.stable(tables)), + Repeat(op, len) => { + let cnst = ConstantKind::from_const(*len, tables.tcx); + let len = Const { literal: cnst.stable(tables) }; + stable_mir::mir::Rvalue::Repeat(op.stable(tables), len) + } + Ref(region, kind, place) => stable_mir::mir::Rvalue::Ref( + opaque(region), + kind.stable(tables), + place.stable(tables), + ), + ThreadLocalRef(def_id) => { + stable_mir::mir::Rvalue::ThreadLocalRef(rustc_internal::crate_item(*def_id)) + } + AddressOf(mutability, place) => { + stable_mir::mir::Rvalue::AddressOf(mutability.stable(tables), place.stable(tables)) + } + Len(place) => stable_mir::mir::Rvalue::Len(place.stable(tables)), + Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast( + cast_kind.stable(tables), + op.stable(tables), + tables.intern_ty(*ty), + ), + BinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::BinaryOp( + bin_op.stable(tables), + ops.0.stable(tables), + ops.1.stable(tables), + ), CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp( - bin_op.stable(), - ops.0.stable(), - ops.1.stable(), + bin_op.stable(tables), + ops.0.stable(tables), + ops.1.stable(tables), + ), + NullaryOp(null_op, ty) => { + stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), tables.intern_ty(*ty)) + } + UnaryOp(un_op, op) => { + stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables), op.stable(tables)) + } + Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable(tables)), + Aggregate(agg_kind, operands) => { + let operands = operands.iter().map(|op| op.stable(tables)).collect(); + stable_mir::mir::Rvalue::Aggregate(agg_kind.stable(tables), operands) + } + ShallowInitBox(op, ty) => { + stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), tables.intern_ty(*ty)) + } + CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::Mutability { + type T = stable_mir::mir::Mutability; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use mir::Mutability::*; + match *self { + Not => stable_mir::mir::Mutability::Not, + Mut => stable_mir::mir::Mutability::Mut, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::BorrowKind { + type T = stable_mir::mir::BorrowKind; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use mir::BorrowKind::*; + match *self { + Shared => stable_mir::mir::BorrowKind::Shared, + Shallow => stable_mir::mir::BorrowKind::Shallow, + Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables) }, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::MutBorrowKind { + type T = stable_mir::mir::MutBorrowKind; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use mir::MutBorrowKind::*; + match *self { + Default => stable_mir::mir::MutBorrowKind::Default, + TwoPhaseBorrow => stable_mir::mir::MutBorrowKind::TwoPhaseBorrow, + ClosureCapture => stable_mir::mir::MutBorrowKind::ClosureCapture, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { + type T = stable_mir::mir::NullOp; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use mir::NullOp::*; + match self { + SizeOf => stable_mir::mir::NullOp::SizeOf, + AlignOf => stable_mir::mir::NullOp::AlignOf, + OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf( + indices.iter().map(|idx| idx.stable(tables)).collect(), ), - NullaryOp(_, _) => todo!(), - UnaryOp(un_op, op) => stable_mir::mir::Rvalue::UnaryOp(un_op.stable(), op.stable()), - Discriminant(_) => todo!(), - Aggregate(_, _) => todo!(), - ShallowInitBox(_, _) => todo!(), - CopyForDeref(_) => todo!(), } } } -impl<'tcx> Stable for mir::Operand<'tcx> { +impl<'tcx> Stable<'tcx> for mir::CastKind { + type T = stable_mir::mir::CastKind; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use mir::CastKind::*; + match self { + PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress, + PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress, + PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)), + DynStar => stable_mir::mir::CastKind::DynStar, + IntToInt => stable_mir::mir::CastKind::IntToInt, + FloatToInt => stable_mir::mir::CastKind::FloatToInt, + FloatToFloat => stable_mir::mir::CastKind::FloatToFloat, + IntToFloat => stable_mir::mir::CastKind::IntToFloat, + PtrToPtr => stable_mir::mir::CastKind::PtrToPtr, + FnPtrToPtr => stable_mir::mir::CastKind::FnPtrToPtr, + Transmute => stable_mir::mir::CastKind::Transmute, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::AliasKind { + type T = stable_mir::ty::AliasKind; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use ty::AliasKind::*; + match self { + Projection => stable_mir::ty::AliasKind::Projection, + Inherent => stable_mir::ty::AliasKind::Inherent, + Opaque => stable_mir::ty::AliasKind::Opaque, + Weak => stable_mir::ty::AliasKind::Weak, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::AliasTy<'tcx> { + type T = stable_mir::ty::AliasTy; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + let ty::AliasTy { args, def_id, .. } = self; + stable_mir::ty::AliasTy { def_id: tables.alias_def(*def_id), args: args.stable(tables) } + } +} + +impl<'tcx> Stable<'tcx> for ty::DynKind { + type T = stable_mir::ty::DynKind; + + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use ty::DynKind; + match self { + DynKind::Dyn => stable_mir::ty::DynKind::Dyn, + DynKind::DynStar => stable_mir::ty::DynKind::DynStar, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> { + type T = stable_mir::ty::ExistentialPredicate; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::ExistentialPredicate::*; + match self { + ty::ExistentialPredicate::Trait(existential_trait_ref) => { + Trait(existential_trait_ref.stable(tables)) + } + ty::ExistentialPredicate::Projection(existential_projection) => { + Projection(existential_projection.stable(tables)) + } + ty::ExistentialPredicate::AutoTrait(def_id) => AutoTrait(tables.trait_def(*def_id)), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> { + type T = stable_mir::ty::ExistentialTraitRef; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + let ty::ExistentialTraitRef { def_id, args } = self; + stable_mir::ty::ExistentialTraitRef { + def_id: tables.trait_def(*def_id), + generic_args: args.stable(tables), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> { + type T = stable_mir::ty::TermKind; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::TermKind; + match self { + ty::TermKind::Ty(ty) => TermKind::Type(tables.intern_ty(*ty)), + ty::TermKind::Const(cnst) => { + let cnst = ConstantKind::from_const(*cnst, tables.tcx); + let cnst = Const { literal: cnst.stable(tables) }; + TermKind::Const(cnst) + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> { + type T = stable_mir::ty::ExistentialProjection; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + let ty::ExistentialProjection { def_id, args, term } = self; + stable_mir::ty::ExistentialProjection { + def_id: tables.trait_def(*def_id), + generic_args: args.stable(tables), + term: term.unpack().stable(tables), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion { + type T = stable_mir::mir::PointerCoercion; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use ty::adjustment::PointerCoercion; + match self { + PointerCoercion::ReifyFnPointer => stable_mir::mir::PointerCoercion::ReifyFnPointer, + PointerCoercion::UnsafeFnPointer => stable_mir::mir::PointerCoercion::UnsafeFnPointer, + PointerCoercion::ClosureFnPointer(unsafety) => { + stable_mir::mir::PointerCoercion::ClosureFnPointer(unsafety.stable(tables)) + } + PointerCoercion::MutToConstPointer => { + stable_mir::mir::PointerCoercion::MutToConstPointer + } + PointerCoercion::ArrayToPointer => stable_mir::mir::PointerCoercion::ArrayToPointer, + PointerCoercion::Unsize => stable_mir::mir::PointerCoercion::Unsize, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_hir::Unsafety { + type T = stable_mir::mir::Safety; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + match self { + rustc_hir::Unsafety::Unsafe => stable_mir::mir::Safety::Unsafe, + rustc_hir::Unsafety::Normal => stable_mir::mir::Safety::Normal, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::FakeReadCause { + type T = stable_mir::mir::FakeReadCause; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use mir::FakeReadCause::*; + match self { + ForMatchGuard => stable_mir::mir::FakeReadCause::ForMatchGuard, + ForMatchedPlace(local_def_id) => { + stable_mir::mir::FakeReadCause::ForMatchedPlace(opaque(local_def_id)) + } + ForGuardBinding => stable_mir::mir::FakeReadCause::ForGuardBinding, + ForLet(local_def_id) => stable_mir::mir::FakeReadCause::ForLet(opaque(local_def_id)), + ForIndex => stable_mir::mir::FakeReadCause::ForIndex, + } + } +} + +impl<'tcx> Stable<'tcx> for FieldIdx { + type T = usize; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + self.as_usize() + } +} + +impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { type T = stable_mir::mir::Operand; - fn stable(&self) -> Self::T { + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use mir::Operand::*; match self { - Copy(place) => stable_mir::mir::Operand::Copy(place.stable()), - Move(place) => stable_mir::mir::Operand::Move(place.stable()), + Copy(place) => stable_mir::mir::Operand::Copy(place.stable(tables)), + Move(place) => stable_mir::mir::Operand::Move(place.stable(tables)), Constant(c) => stable_mir::mir::Operand::Constant(c.to_string()), } } } -impl<'tcx> Stable for mir::Place<'tcx> { +impl<'tcx> Stable<'tcx> for mir::Place<'tcx> { type T = stable_mir::mir::Place; - fn stable(&self) -> Self::T { + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { stable_mir::mir::Place { local: self.local.as_usize(), projection: format!("{:?}", self.projection), @@ -216,9 +472,113 @@ impl<'tcx> Stable for mir::Place<'tcx> { } } -impl Stable for mir::UnwindAction { +impl<'tcx> Stable<'tcx> for mir::coverage::CoverageKind { + type T = stable_mir::mir::CoverageKind; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use rustc_middle::mir::coverage::CoverageKind; + match self { + CoverageKind::Counter { function_source_hash, id } => { + stable_mir::mir::CoverageKind::Counter { + function_source_hash: *function_source_hash as usize, + id: opaque(id), + } + } + CoverageKind::Expression { id, lhs, op, rhs } => { + stable_mir::mir::CoverageKind::Expression { + id: opaque(id), + lhs: opaque(lhs), + op: op.stable(tables), + rhs: opaque(rhs), + } + } + CoverageKind::Unreachable => stable_mir::mir::CoverageKind::Unreachable, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::UserTypeProjection { + type T = stable_mir::mir::UserTypeProjection; + + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + UserTypeProjection { base: self.base.as_usize(), projection: format!("{:?}", self.projs) } + } +} + +impl<'tcx> Stable<'tcx> for mir::coverage::Op { + type T = stable_mir::mir::Op; + + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use rustc_middle::mir::coverage::Op::*; + match self { + Subtract => stable_mir::mir::Op::Subtract, + Add => stable_mir::mir::Op::Add, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::Local { + type T = stable_mir::mir::Local; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + self.as_usize() + } +} + +impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx { + type T = VariantIdx; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + self.as_usize() + } +} + +impl<'tcx> Stable<'tcx> for Variance { + type T = stable_mir::mir::Variance; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + match self { + Variance::Bivariant => stable_mir::mir::Variance::Bivariant, + Variance::Contravariant => stable_mir::mir::Variance::Contravariant, + Variance::Covariant => stable_mir::mir::Variance::Covariant, + Variance::Invariant => stable_mir::mir::Variance::Invariant, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::RetagKind { + type T = stable_mir::mir::RetagKind; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use rustc_middle::mir::RetagKind; + match self { + RetagKind::FnEntry => stable_mir::mir::RetagKind::FnEntry, + RetagKind::TwoPhase => stable_mir::mir::RetagKind::TwoPhase, + RetagKind::Raw => stable_mir::mir::RetagKind::Raw, + RetagKind::Default => stable_mir::mir::RetagKind::Default, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex { + type T = usize; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + self.as_usize() + } +} + +impl<'tcx> Stable<'tcx> for CodeRegion { + type T = stable_mir::mir::CodeRegion; + + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + stable_mir::mir::CodeRegion { + file_name: self.file_name.as_str().to_string(), + start_line: self.start_line as usize, + start_col: self.start_col as usize, + end_line: self.end_line as usize, + end_col: self.end_col as usize, + } + } +} + +impl<'tcx> Stable<'tcx> for mir::UnwindAction { type T = stable_mir::mir::UnwindAction; - fn stable(&self) -> Self::T { + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { use rustc_middle::mir::UnwindAction; match self { UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue, @@ -229,42 +589,68 @@ impl Stable for mir::UnwindAction { } } -fn rustc_assert_msg_to_msg<'tcx>( - assert_message: &rustc_middle::mir::AssertMessage<'tcx>, -) -> stable_mir::mir::AssertMessage { - use rustc_middle::mir::AssertKind; - match assert_message { - AssertKind::BoundsCheck { len, index } => { - stable_mir::mir::AssertMessage::BoundsCheck { len: len.stable(), index: index.stable() } - } - AssertKind::Overflow(bin_op, op1, op2) => { - stable_mir::mir::AssertMessage::Overflow(bin_op.stable(), op1.stable(), op2.stable()) - } - AssertKind::OverflowNeg(op) => stable_mir::mir::AssertMessage::OverflowNeg(op.stable()), - AssertKind::DivisionByZero(op) => { - stable_mir::mir::AssertMessage::DivisionByZero(op.stable()) - } - AssertKind::RemainderByZero(op) => { - stable_mir::mir::AssertMessage::RemainderByZero(op.stable()) - } - AssertKind::ResumedAfterReturn(generator) => { - stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable()) - } - AssertKind::ResumedAfterPanic(generator) => { - stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable()) +impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> { + type T = stable_mir::mir::NonDivergingIntrinsic; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use rustc_middle::mir::NonDivergingIntrinsic; + match self { + NonDivergingIntrinsic::Assume(op) => { + stable_mir::mir::NonDivergingIntrinsic::Assume(op.stable(tables)) + } + NonDivergingIntrinsic::CopyNonOverlapping(copy_non_overlapping) => { + stable_mir::mir::NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + src: copy_non_overlapping.src.stable(tables), + dst: copy_non_overlapping.dst.stable(tables), + count: copy_non_overlapping.count.stable(tables), + }) + } } - AssertKind::MisalignedPointerDereference { required, found } => { - stable_mir::mir::AssertMessage::MisalignedPointerDereference { - required: required.stable(), - found: found.stable(), + } +} + +impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> { + type T = stable_mir::mir::AssertMessage; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use rustc_middle::mir::AssertKind; + match self { + AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck { + len: len.stable(tables), + index: index.stable(tables), + }, + AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow( + bin_op.stable(tables), + op1.stable(tables), + op2.stable(tables), + ), + AssertKind::OverflowNeg(op) => { + stable_mir::mir::AssertMessage::OverflowNeg(op.stable(tables)) + } + AssertKind::DivisionByZero(op) => { + stable_mir::mir::AssertMessage::DivisionByZero(op.stable(tables)) + } + AssertKind::RemainderByZero(op) => { + stable_mir::mir::AssertMessage::RemainderByZero(op.stable(tables)) + } + AssertKind::ResumedAfterReturn(generator) => { + stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable(tables)) + } + AssertKind::ResumedAfterPanic(generator) => { + stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable(tables)) + } + AssertKind::MisalignedPointerDereference { required, found } => { + stable_mir::mir::AssertMessage::MisalignedPointerDereference { + required: required.stable(tables), + found: found.stable(tables), + } } } } } -impl Stable for mir::BinOp { +impl<'tcx> Stable<'tcx> for mir::BinOp { type T = stable_mir::mir::BinOp; - fn stable(&self) -> Self::T { + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { use mir::BinOp; match self { BinOp::Add => stable_mir::mir::BinOp::Add, @@ -293,9 +679,9 @@ impl Stable for mir::BinOp { } } -impl Stable for mir::UnOp { +impl<'tcx> Stable<'tcx> for mir::UnOp { type T = stable_mir::mir::UnOp; - fn stable(&self) -> Self::T { + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { use mir::UnOp; match self { UnOp::Not => stable_mir::mir::UnOp::Not, @@ -304,9 +690,43 @@ impl Stable for mir::UnOp { } } -impl Stable for rustc_hir::GeneratorKind { +impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { + type T = stable_mir::mir::AggregateKind; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + mir::AggregateKind::Array(ty) => { + stable_mir::mir::AggregateKind::Array(tables.intern_ty(*ty)) + } + mir::AggregateKind::Tuple => stable_mir::mir::AggregateKind::Tuple, + mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => { + stable_mir::mir::AggregateKind::Adt( + rustc_internal::adt_def(*def_id), + var_idx.index(), + generic_arg.stable(tables), + user_ty_index.map(|idx| idx.index()), + field_idx.map(|idx| idx.index()), + ) + } + mir::AggregateKind::Closure(def_id, generic_arg) => { + stable_mir::mir::AggregateKind::Closure( + rustc_internal::closure_def(*def_id), + generic_arg.stable(tables), + ) + } + mir::AggregateKind::Generator(def_id, generic_arg, movability) => { + stable_mir::mir::AggregateKind::Generator( + rustc_internal::generator_def(*def_id), + generic_arg.stable(tables), + movability.stable(tables), + ) + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_hir::GeneratorKind { type T = stable_mir::mir::GeneratorKind; - fn stable(&self) -> Self::T { + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; match self { GeneratorKind::Async(async_gen) => { @@ -322,35 +742,35 @@ impl Stable for rustc_hir::GeneratorKind { } } -impl<'tcx> Stable for mir::InlineAsmOperand<'tcx> { +impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> { type T = stable_mir::mir::InlineAsmOperand; - fn stable(&self) -> Self::T { + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use rustc_middle::mir::InlineAsmOperand; let (in_value, out_place) = match self { - InlineAsmOperand::In { value, .. } => (Some(value.stable()), None), - InlineAsmOperand::Out { place, .. } => (None, place.map(|place| place.stable())), + InlineAsmOperand::In { value, .. } => (Some(value.stable(tables)), None), + InlineAsmOperand::Out { place, .. } => (None, place.map(|place| place.stable(tables))), InlineAsmOperand::InOut { in_value, out_place, .. } => { - (Some(in_value.stable()), out_place.map(|place| place.stable())) + (Some(in_value.stable(tables)), out_place.map(|place| place.stable(tables))) } InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } => (None, None), }; - stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{:?}", self) } + stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{self:?}") } } } -impl<'tcx> Stable for mir::Terminator<'tcx> { +impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> { type T = stable_mir::mir::Terminator; - fn stable(&self) -> Self::T { + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use rustc_middle::mir::TerminatorKind::*; use stable_mir::mir::Terminator; match &self.kind { Goto { target } => Terminator::Goto { target: target.as_usize() }, SwitchInt { discr, targets } => Terminator::SwitchInt { - discr: discr.stable(), + discr: discr.stable(tables), targets: targets .iter() .map(|(value, target)| stable_mir::mir::SwitchTarget { @@ -365,37 +785,423 @@ impl<'tcx> Stable for mir::Terminator<'tcx> { Return => Terminator::Return, Unreachable => Terminator::Unreachable, Drop { place, target, unwind, replace: _ } => Terminator::Drop { - place: place.stable(), + place: place.stable(tables), target: target.as_usize(), - unwind: unwind.stable(), + unwind: unwind.stable(tables), }, Call { func, args, destination, target, unwind, call_source: _, fn_span: _ } => { Terminator::Call { - func: func.stable(), - args: args.iter().map(|arg| arg.stable()).collect(), - destination: destination.stable(), + func: func.stable(tables), + args: args.iter().map(|arg| arg.stable(tables)).collect(), + destination: destination.stable(tables), target: target.map(|t| t.as_usize()), - unwind: unwind.stable(), + unwind: unwind.stable(tables), } } Assert { cond, expected, msg, target, unwind } => Terminator::Assert { - cond: cond.stable(), + cond: cond.stable(tables), expected: *expected, - msg: rustc_assert_msg_to_msg(msg), + msg: msg.stable(tables), target: target.as_usize(), - unwind: unwind.stable(), + unwind: unwind.stable(tables), }, InlineAsm { template, operands, options, line_spans, destination, unwind } => { Terminator::InlineAsm { - template: format!("{:?}", template), - operands: operands.iter().map(|operand| operand.stable()).collect(), - options: format!("{:?}", options), - line_spans: format!("{:?}", line_spans), + template: format!("{template:?}"), + operands: operands.iter().map(|operand| operand.stable(tables)).collect(), + options: format!("{options:?}"), + line_spans: format!("{line_spans:?}"), destination: destination.map(|d| d.as_usize()), - unwind: unwind.stable(), + unwind: unwind.stable(tables), } } Yield { .. } | GeneratorDrop | FalseEdge { .. } | FalseUnwind { .. } => unreachable!(), } } } + +impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> { + type T = stable_mir::ty::GenericArgs; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::GenericArgs; + + GenericArgs(self.iter().map(|arg| arg.unpack().stable(tables)).collect()) + } +} + +impl<'tcx> Stable<'tcx> for ty::GenericArgKind<'tcx> { + type T = stable_mir::ty::GenericArgKind; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::GenericArgKind; + match self { + ty::GenericArgKind::Lifetime(region) => GenericArgKind::Lifetime(opaque(region)), + ty::GenericArgKind::Type(ty) => GenericArgKind::Type(tables.intern_ty(*ty)), + ty::GenericArgKind::Const(cnst) => { + let cnst = ConstantKind::from_const(*cnst, tables.tcx); + GenericArgKind::Const(stable_mir::ty::Const { literal: cnst.stable(tables) }) + } + } + } +} + +impl<'tcx, S, V> Stable<'tcx> for ty::Binder<'tcx, S> +where + S: Stable<'tcx, T = V>, +{ + type T = stable_mir::ty::Binder<V>; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::Binder; + + Binder { + value: self.as_ref().skip_binder().stable(tables), + bound_vars: self + .bound_vars() + .iter() + .map(|bound_var| bound_var.stable(tables)) + .collect(), + } + } +} + +impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<S> +where + S: Stable<'tcx, T = V>, +{ + type T = stable_mir::ty::EarlyBinder<V>; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::EarlyBinder; + + EarlyBinder { value: self.as_ref().skip_binder().stable(tables) } + } +} + +impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> { + type T = stable_mir::ty::FnSig; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use rustc_target::spec::abi; + use stable_mir::ty::{Abi, FnSig}; + + FnSig { + inputs_and_output: self + .inputs_and_output + .iter() + .map(|ty| tables.intern_ty(ty)) + .collect(), + c_variadic: self.c_variadic, + unsafety: self.unsafety.stable(tables), + abi: match self.abi { + abi::Abi::Rust => Abi::Rust, + abi::Abi::C { unwind } => Abi::C { unwind }, + abi::Abi::Cdecl { unwind } => Abi::Cdecl { unwind }, + abi::Abi::Stdcall { unwind } => Abi::Stdcall { unwind }, + abi::Abi::Fastcall { unwind } => Abi::Fastcall { unwind }, + abi::Abi::Vectorcall { unwind } => Abi::Vectorcall { unwind }, + abi::Abi::Thiscall { unwind } => Abi::Thiscall { unwind }, + abi::Abi::Aapcs { unwind } => Abi::Aapcs { unwind }, + abi::Abi::Win64 { unwind } => Abi::Win64 { unwind }, + abi::Abi::SysV64 { unwind } => Abi::SysV64 { unwind }, + abi::Abi::PtxKernel => Abi::PtxKernel, + abi::Abi::Msp430Interrupt => Abi::Msp430Interrupt, + abi::Abi::X86Interrupt => Abi::X86Interrupt, + abi::Abi::AmdGpuKernel => Abi::AmdGpuKernel, + abi::Abi::EfiApi => Abi::EfiApi, + abi::Abi::AvrInterrupt => Abi::AvrInterrupt, + abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, + abi::Abi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, + abi::Abi::Wasm => Abi::Wasm, + abi::Abi::System { unwind } => Abi::System { unwind }, + abi::Abi::RustIntrinsic => Abi::RustIntrinsic, + abi::Abi::RustCall => Abi::RustCall, + abi::Abi::PlatformIntrinsic => Abi::PlatformIntrinsic, + abi::Abi::Unadjusted => Abi::Unadjusted, + abi::Abi::RustCold => Abi::RustCold, + abi::Abi::RiscvInterruptM => Abi::RiscvInterruptM, + abi::Abi::RiscvInterruptS => Abi::RiscvInterruptS, + }, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::BoundTyKind { + type T = stable_mir::ty::BoundTyKind; + + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::BoundTyKind; + + match self { + ty::BoundTyKind::Anon => BoundTyKind::Anon, + ty::BoundTyKind::Param(def_id, symbol) => { + BoundTyKind::Param(rustc_internal::param_def(*def_id), symbol.to_string()) + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::BoundRegionKind { + type T = stable_mir::ty::BoundRegionKind; + + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::BoundRegionKind; + + match self { + ty::BoundRegionKind::BrAnon(option_span) => { + BoundRegionKind::BrAnon(option_span.map(|span| opaque(&span))) + } + ty::BoundRegionKind::BrNamed(def_id, symbol) => { + BoundRegionKind::BrNamed(rustc_internal::br_named_def(*def_id), symbol.to_string()) + } + ty::BoundRegionKind::BrEnv => BoundRegionKind::BrEnv, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::BoundVariableKind { + type T = stable_mir::ty::BoundVariableKind; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::BoundVariableKind; + + match self { + ty::BoundVariableKind::Ty(bound_ty_kind) => { + BoundVariableKind::Ty(bound_ty_kind.stable(tables)) + } + ty::BoundVariableKind::Region(bound_region_kind) => { + BoundVariableKind::Region(bound_region_kind.stable(tables)) + } + ty::BoundVariableKind::Const => BoundVariableKind::Const, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::IntTy { + type T = IntTy; + + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + match self { + ty::IntTy::Isize => IntTy::Isize, + ty::IntTy::I8 => IntTy::I8, + ty::IntTy::I16 => IntTy::I16, + ty::IntTy::I32 => IntTy::I32, + ty::IntTy::I64 => IntTy::I64, + ty::IntTy::I128 => IntTy::I128, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::UintTy { + type T = UintTy; + + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + match self { + ty::UintTy::Usize => UintTy::Usize, + ty::UintTy::U8 => UintTy::U8, + ty::UintTy::U16 => UintTy::U16, + ty::UintTy::U32 => UintTy::U32, + ty::UintTy::U64 => UintTy::U64, + ty::UintTy::U128 => UintTy::U128, + } + } +} + +impl<'tcx> Stable<'tcx> for ty::FloatTy { + type T = FloatTy; + + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + match self { + ty::FloatTy::F32 => FloatTy::F32, + ty::FloatTy::F64 => FloatTy::F64, + } + } +} + +impl<'tcx> Stable<'tcx> for hir::Movability { + type T = Movability; + + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + match self { + hir::Movability::Static => Movability::Static, + hir::Movability::Movable => Movability::Movable, + } + } +} + +impl<'tcx> Stable<'tcx> for Ty<'tcx> { + type T = stable_mir::ty::TyKind; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self.kind() { + ty::Bool => TyKind::RigidTy(RigidTy::Bool), + ty::Char => TyKind::RigidTy(RigidTy::Char), + ty::Int(int_ty) => TyKind::RigidTy(RigidTy::Int(int_ty.stable(tables))), + ty::Uint(uint_ty) => TyKind::RigidTy(RigidTy::Uint(uint_ty.stable(tables))), + ty::Float(float_ty) => TyKind::RigidTy(RigidTy::Float(float_ty.stable(tables))), + ty::Adt(adt_def, generic_args) => TyKind::RigidTy(RigidTy::Adt( + rustc_internal::adt_def(adt_def.did()), + generic_args.stable(tables), + )), + ty::Foreign(def_id) => { + TyKind::RigidTy(RigidTy::Foreign(rustc_internal::foreign_def(*def_id))) + } + ty::Str => TyKind::RigidTy(RigidTy::Str), + ty::Array(ty, constant) => { + let cnst = ConstantKind::from_const(*constant, tables.tcx); + let cnst = stable_mir::ty::Const { literal: cnst.stable(tables) }; + TyKind::RigidTy(RigidTy::Array(tables.intern_ty(*ty), cnst)) + } + ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(tables.intern_ty(*ty))), + ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => { + TyKind::RigidTy(RigidTy::RawPtr(tables.intern_ty(*ty), mutbl.stable(tables))) + } + ty::Ref(region, ty, mutbl) => TyKind::RigidTy(RigidTy::Ref( + opaque(region), + tables.intern_ty(*ty), + mutbl.stable(tables), + )), + ty::FnDef(def_id, generic_args) => TyKind::RigidTy(RigidTy::FnDef( + rustc_internal::fn_def(*def_id), + generic_args.stable(tables), + )), + ty::FnPtr(poly_fn_sig) => TyKind::RigidTy(RigidTy::FnPtr(poly_fn_sig.stable(tables))), + ty::Dynamic(existential_predicates, region, dyn_kind) => { + TyKind::RigidTy(RigidTy::Dynamic( + existential_predicates + .iter() + .map(|existential_predicate| existential_predicate.stable(tables)) + .collect(), + opaque(region), + dyn_kind.stable(tables), + )) + } + ty::Closure(def_id, generic_args) => TyKind::RigidTy(RigidTy::Closure( + rustc_internal::closure_def(*def_id), + generic_args.stable(tables), + )), + ty::Generator(def_id, generic_args, movability) => TyKind::RigidTy(RigidTy::Generator( + rustc_internal::generator_def(*def_id), + generic_args.stable(tables), + movability.stable(tables), + )), + ty::Never => TyKind::RigidTy(RigidTy::Never), + ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple( + fields.iter().map(|ty| tables.intern_ty(ty)).collect(), + )), + ty::Alias(alias_kind, alias_ty) => { + TyKind::Alias(alias_kind.stable(tables), alias_ty.stable(tables)) + } + ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables)), + ty::Bound(debruijn_idx, bound_ty) => { + TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables)) + } + ty::Placeholder(..) + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(_, _) + | ty::Infer(_) + | ty::Error(_) => { + unreachable!(); + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::ParamTy { + type T = stable_mir::ty::ParamTy; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::ParamTy; + ParamTy { index: self.index, name: self.name.to_string() } + } +} + +impl<'tcx> Stable<'tcx> for ty::BoundTy { + type T = stable_mir::ty::BoundTy; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::BoundTy; + BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables) } + } +} + +impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { + type T = stable_mir::ty::Allocation; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + allocation_filter(self, alloc_range(rustc_target::abi::Size::ZERO, self.size()), tables) + } +} + +impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind { + type T = stable_mir::ty::TraitSpecializationKind; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::TraitSpecializationKind; + + match self { + ty::trait_def::TraitSpecializationKind::None => TraitSpecializationKind::None, + ty::trait_def::TraitSpecializationKind::Marker => TraitSpecializationKind::Marker, + ty::trait_def::TraitSpecializationKind::AlwaysApplicable => { + TraitSpecializationKind::AlwaysApplicable + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::TraitDef { + type T = stable_mir::ty::TraitDecl; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::TraitDecl; + + TraitDecl { + def_id: rustc_internal::trait_def(self.def_id), + unsafety: self.unsafety.stable(tables), + paren_sugar: self.paren_sugar, + has_auto_impl: self.has_auto_impl, + is_marker: self.is_marker, + is_coinductive: self.is_coinductive, + skip_array_during_method_dispatch: self.skip_array_during_method_dispatch, + specialization_kind: self.specialization_kind.stable(tables), + must_implement_one_of: self + .must_implement_one_of + .as_ref() + .map(|idents| idents.iter().map(|ident| opaque(ident)).collect()), + implement_via_object: self.implement_via_object, + deny_explicit_impl: self.deny_explicit_impl, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> { + type T = stable_mir::ty::ConstantKind; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + ConstantKind::Ty(c) => match c.kind() { + ty::Value(val) => { + let const_val = tables.tcx.valtree_to_const_val((c.ty(), val)); + stable_mir::ty::ConstantKind::Allocated(new_allocation(self, const_val, tables)) + } + ty::ParamCt(param) => stable_mir::ty::ConstantKind::ParamCt(opaque(¶m)), + ty::ErrorCt(_) => unreachable!(), + _ => unimplemented!(), + }, + ConstantKind::Unevaluated(unev_const, ty) => { + stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { + ty: tables.intern_ty(*ty), + def: tables.const_def(unev_const.def), + args: unev_const.args.stable(tables), + promoted: unev_const.promoted.map(|u| u.as_u32()), + }) + } + ConstantKind::Val(val, _) => { + stable_mir::ty::ConstantKind::Allocated(new_allocation(self, *val, tables)) + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> { + type T = stable_mir::ty::TraitRef; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::TraitRef; + + TraitRef { def_id: rustc_internal::trait_def(self.def_id), args: self.args.stable(tables) } + } +} diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index 468e915d1..c16bd6cbd 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -1,4 +1,8 @@ -use crate::stable_mir::ty::Ty; +use crate::rustc_internal::Opaque; +use crate::stable_mir::ty::{ + AdtDef, ClosureDef, Const, GeneratorDef, GenericArgs, Movability, Region, +}; +use crate::stable_mir::{self, ty::Ty}; #[derive(Clone, Debug)] pub struct Body { @@ -130,18 +134,225 @@ pub enum AsyncGeneratorKind { Fn, } +pub(crate) type LocalDefId = Opaque; +pub(crate) type CounterValueReference = Opaque; +pub(crate) type InjectedExpressionId = Opaque; +pub(crate) type ExpressionOperandId = Opaque; + +/// The FakeReadCause describes the type of pattern why a FakeRead statement exists. +#[derive(Clone, Debug)] +pub enum FakeReadCause { + ForMatchGuard, + ForMatchedPlace(LocalDefId), + ForGuardBinding, + ForLet(LocalDefId), + ForIndex, +} + +/// Describes what kind of retag is to be performed +#[derive(Clone, Debug)] +pub enum RetagKind { + FnEntry, + TwoPhase, + Raw, + Default, +} + +#[derive(Clone, Debug)] +pub enum Variance { + Covariant, + Invariant, + Contravariant, + Bivariant, +} + +#[derive(Clone, Debug)] +pub enum Op { + Subtract, + Add, +} + +#[derive(Clone, Debug)] +pub enum CoverageKind { + Counter { + function_source_hash: usize, + id: CounterValueReference, + }, + Expression { + id: InjectedExpressionId, + lhs: ExpressionOperandId, + op: Op, + rhs: ExpressionOperandId, + }, + Unreachable, +} + +#[derive(Clone, Debug)] +pub struct CodeRegion { + pub file_name: String, + pub start_line: usize, + pub start_col: usize, + pub end_line: usize, + pub end_col: usize, +} + +#[derive(Clone, Debug)] +pub struct Coverage { + pub kind: CoverageKind, + pub code_region: Option<CodeRegion>, +} + +#[derive(Clone, Debug)] +pub struct CopyNonOverlapping { + pub src: Operand, + pub dst: Operand, + pub count: Operand, +} + +#[derive(Clone, Debug)] +pub enum NonDivergingIntrinsic { + Assume(Operand), + CopyNonOverlapping(CopyNonOverlapping), +} + #[derive(Clone, Debug)] pub enum Statement { 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, } -// FIXME this is incomplete #[derive(Clone, Debug)] pub enum Rvalue { - Use(Operand), + /// 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(Mutability, 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 `Generator`. After + /// generator lowering, `Generator` aggregate kinds are disallowed too. + Aggregate(AggregateKind, Vec<Operand>), + + /// * `Offset` has the same semantics as [`offset`](pointer::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 of type + /// [`discriminant_ty`]. 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; use [`discriminant_for_variant`] to convert. + /// + /// [`discriminant_ty`]: rustc_middle::ty::Ty::discriminant_ty + /// [#91095]: https://github.com/rust-lang/rust/issues/91095 + /// [`discriminant_for_variant`]: rustc_middle::ty::Ty::discriminant_for_variant + 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, Const), + + /// 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(stable_mir::CrateItem), + + /// Computes a value as described by the operation. + NullaryOp(NullOp, Ty), + + /// Exactly like `BinaryOp`, but less operands. + /// + /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; + /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds + /// return a value with the same type as their operand. UnaryOp(UnOp, Operand), + + /// Yields the operand unchanged + Use(Operand), +} + +#[derive(Clone, Debug)] +pub enum AggregateKind { + Array(Ty), + Tuple, + Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>), + Closure(ClosureDef, GenericArgs), + Generator(GeneratorDef, GenericArgs, Movability), } #[derive(Clone, Debug)] @@ -153,12 +364,115 @@ pub enum Operand { #[derive(Clone, Debug)] pub struct Place { - pub local: usize, + pub local: Local, pub projection: String, } #[derive(Clone, Debug)] +pub struct UserTypeProjection { + pub base: UserTypeAnnotationIndex, + pub projection: String, +} + +pub type Local = usize; + +type FieldIdx = usize; + +/// The source-order index of a variant in a type. +pub type VariantIdx = usize; + +type UserTypeAnnotationIndex = usize; + +#[derive(Clone, Debug)] pub struct SwitchTarget { pub value: u128, pub target: usize, } + +#[derive(Clone, Debug)] +pub enum BorrowKind { + /// Data must be immutable and is aliasable. + Shared, + + /// The immediately borrowed place must be immutable, but projections from + /// it don't need to be. For example, a shallow borrow of `a.b` doesn't + /// conflict with a mutable borrow of `a.b.c`. + Shallow, + + /// Data is mutable and not aliasable. + Mut { + /// `true` if this borrow arose from method-call auto-ref + kind: MutBorrowKind, + }, +} + +#[derive(Clone, Debug)] +pub enum MutBorrowKind { + Default, + TwoPhaseBorrow, + ClosureCapture, +} + +#[derive(Clone, Debug)] +pub enum Mutability { + Not, + Mut, +} + +#[derive(Clone, Debug)] +pub enum Safety { + Unsafe, + Normal, +} + +#[derive(Clone, Debug)] +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 an 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 fat pointer. + /// This will do things like convert thin pointers to fat + /// pointers, or convert structs containing thin pointers to + /// structs containing fat pointers, or convert between fat + /// pointers. + Unsize, +} + +#[derive(Clone, Debug)] +pub enum CastKind { + PointerExposeAddress, + PointerFromExposedAddress, + PointerCoercion(PointerCoercion), + DynStar, + IntToInt, + FloatToInt, + FloatToFloat, + IntToFloat, + PtrToPtr, + FnPtrToPtr, + Transmute, +} + +#[derive(Clone, Debug)] +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<FieldIdx>), +} diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs index 5e599a77b..19061742b 100644 --- a/compiler/rustc_smir/src/stable_mir/mod.rs +++ b/compiler/rustc_smir/src/stable_mir/mod.rs @@ -15,7 +15,7 @@ use std::cell::Cell; use crate::rustc_smir::Tables; -use self::ty::{Ty, TyKind}; +use self::ty::{ImplDef, ImplTrait, TraitDecl, TraitDef, Ty, TyKind}; pub mod mir; pub mod ty; @@ -32,6 +32,12 @@ pub type DefId = usize; /// 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>; + /// Holds information about a crate. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Crate { @@ -79,11 +85,31 @@ 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 trait_decl(trait_def: &TraitDef) -> TraitDecl { + with(|cx| cx.trait_decl(trait_def)) +} + +pub fn all_trait_impls() -> ImplTraitDecls { + with(|cx| cx.all_trait_impls()) +} + +pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait { + with(|cx| cx.trait_impl(trait_impl)) +} + pub trait Context { fn entry_fn(&mut self) -> Option<CrateItem>; /// Retrieve all items of the local crate that have a MIR associated with them. fn all_local_items(&mut self) -> CrateItems; fn mir_body(&mut self, item: &CrateItem) -> mir::Body; + fn all_trait_decls(&mut self) -> TraitDecls; + fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl; + fn all_trait_impls(&mut self) -> ImplTraitDecls; + fn trait_impl(&mut self, trait_impl: &ImplDef) -> ImplTrait; /// Get information about the local crate. fn local_crate(&self) -> Crate; /// Retrieve a list of all external crates. diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 3181af46e..7a6601f09 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1,4 +1,10 @@ -use super::with; +use rustc_middle::mir::interpret::{alloc_range, AllocRange, ConstValue, Pointer}; + +use super::{mir::Mutability, mir::Safety, with, DefId}; +use crate::{ + rustc_internal::{opaque, Opaque}, + rustc_smir::{Stable, Tables}, +}; #[derive(Copy, Clone, Debug)] pub struct Ty(pub usize); @@ -9,9 +15,21 @@ impl Ty { } } +#[derive(Debug, Clone)] +pub struct Const { + pub literal: ConstantKind, +} + +type Ident = Opaque; +pub(crate) type Region = Opaque; +type Span = Opaque; + #[derive(Clone, Debug)] pub enum TyKind { RigidTy(RigidTy), + Alias(AliasKind, AliasTy), + Param(ParamTy), + Bound(usize, BoundTy), } #[derive(Clone, Debug)] @@ -21,6 +39,19 @@ pub enum RigidTy { Int(IntTy), Uint(UintTy), Float(FloatTy), + Adt(AdtDef, GenericArgs), + Foreign(ForeignDef), + Str, + Array(Ty, Const), + Slice(Ty), + RawPtr(Ty, Mutability), + Ref(Region, Ty, Mutability), + FnDef(FnDef, GenericArgs), + FnPtr(PolyFnSig), + Closure(ClosureDef, GenericArgs), + Generator(GeneratorDef, GenericArgs, Movability), + Dynamic(Vec<Binder<ExistentialPredicate>>, Region, DynKind), + Never, Tuple(Vec<Ty>), } @@ -49,3 +80,384 @@ pub enum FloatTy { F32, F64, } + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Movability { + Static, + Movable, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ForeignDef(pub(crate) DefId); + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FnDef(pub(crate) DefId); + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ClosureDef(pub(crate) DefId); + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct GeneratorDef(pub(crate) DefId); + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ParamDef(pub(crate) DefId); + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct BrNamedDef(pub(crate) DefId); + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct AdtDef(pub(crate) DefId); + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct AliasDef(pub(crate) DefId); + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct TraitDef(pub(crate) DefId); + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ConstDef(pub(crate) DefId); + +impl TraitDef { + pub fn trait_decl(&self) -> TraitDecl { + with(|cx| cx.trait_decl(self)) + } +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ImplDef(pub(crate) DefId); + +impl ImplDef { + pub fn trait_impl(&self) -> ImplTrait { + with(|cx| cx.trait_impl(self)) + } +} + +#[derive(Clone, Debug)] +pub struct GenericArgs(pub Vec<GenericArgKind>); + +#[derive(Clone, Debug)] +pub enum GenericArgKind { + Lifetime(Region), + Type(Ty), + Const(Const), +} + +#[derive(Clone, Debug)] +pub enum TermKind { + Type(Ty), + Const(Const), +} + +#[derive(Clone, Debug)] +pub enum AliasKind { + Projection, + Inherent, + Opaque, + Weak, +} + +#[derive(Clone, Debug)] +pub struct AliasTy { + pub def_id: AliasDef, + pub args: GenericArgs, +} + +pub type PolyFnSig = Binder<FnSig>; + +#[derive(Clone, Debug)] +pub struct FnSig { + pub inputs_and_output: Vec<Ty>, + pub c_variadic: bool, + pub unsafety: Safety, + pub abi: Abi, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +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, + AmdGpuKernel, + EfiApi, + AvrInterrupt, + AvrNonBlockingInterrupt, + CCmseNonSecureCall, + Wasm, + System { unwind: bool }, + RustIntrinsic, + RustCall, + PlatformIntrinsic, + Unadjusted, + RustCold, + RiscvInterruptM, + RiscvInterruptS, +} + +#[derive(Clone, Debug)] +pub struct Binder<T> { + pub value: T, + pub bound_vars: Vec<BoundVariableKind>, +} + +#[derive(Clone, Debug)] +pub struct EarlyBinder<T> { + pub value: T, +} + +#[derive(Clone, Debug)] +pub enum BoundVariableKind { + Ty(BoundTyKind), + Region(BoundRegionKind), + Const, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum BoundTyKind { + Anon, + Param(ParamDef, String), +} + +#[derive(Clone, Debug)] +pub enum BoundRegionKind { + BrAnon(Option<Span>), + BrNamed(BrNamedDef, String), + BrEnv, +} + +#[derive(Clone, Debug)] +pub enum DynKind { + Dyn, + DynStar, +} + +#[derive(Clone, Debug)] +pub enum ExistentialPredicate { + Trait(ExistentialTraitRef), + Projection(ExistentialProjection), + AutoTrait(TraitDef), +} + +#[derive(Clone, Debug)] +pub struct ExistentialTraitRef { + pub def_id: TraitDef, + pub generic_args: GenericArgs, +} + +#[derive(Clone, Debug)] +pub struct ExistentialProjection { + pub def_id: TraitDef, + pub generic_args: GenericArgs, + pub term: TermKind, +} + +#[derive(Clone, Debug)] +pub struct ParamTy { + pub index: u32, + pub name: String, +} + +#[derive(Clone, Debug)] +pub struct BoundTy { + pub var: usize, + pub kind: BoundTyKind, +} + +pub type Bytes = Vec<Option<u8>>; +pub type Size = usize; +pub type Prov = Opaque; +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)] +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)] +pub struct Allocation { + pub bytes: Bytes, + pub provenance: ProvenanceMap, + pub align: Align, + pub mutability: Mutability, +} + +impl Allocation { + /// Creates new empty `Allocation` from given `Align`. + fn new_empty_allocation(align: rustc_target::abi::Align) -> Allocation { + Allocation { + bytes: Vec::new(), + provenance: ProvenanceMap { ptrs: Vec::new() }, + align: align.bytes(), + mutability: Mutability::Not, + } + } +} + +// We need this method instead of a Stable implementation +// because we need to get `Ty` of the const we are trying to create, to do that +// we need to have access to `ConstantKind` but we can't access that inside Stable impl. +pub fn new_allocation<'tcx>( + const_kind: &rustc_middle::mir::ConstantKind<'tcx>, + const_value: ConstValue<'tcx>, + tables: &mut Tables<'tcx>, +) -> Allocation { + match const_value { + ConstValue::Scalar(scalar) => { + let size = scalar.size(); + let align = tables + .tcx + .layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(const_kind.ty())) + .unwrap() + .align; + let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi); + allocation + .write_scalar(&tables.tcx, alloc_range(rustc_target::abi::Size::ZERO, size), scalar) + .unwrap(); + allocation.stable(tables) + } + ConstValue::ZeroSized => { + let align = tables + .tcx + .layout_of(rustc_middle::ty::ParamEnv::empty().and(const_kind.ty())) + .unwrap() + .align; + Allocation::new_empty_allocation(align.abi) + } + ConstValue::Slice { data, start, end } => { + let alloc_id = tables.tcx.create_memory_alloc(data); + let ptr = Pointer::new(alloc_id, rustc_target::abi::Size::from_bytes(start)); + let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx); + let scalar_len = rustc_middle::mir::interpret::Scalar::from_target_usize( + (end - start) as u64, + &tables.tcx, + ); + let layout = tables + .tcx + .layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(const_kind.ty())) + .unwrap(); + let mut allocation = + rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi); + allocation + .write_scalar( + &tables.tcx, + alloc_range(rustc_target::abi::Size::ZERO, tables.tcx.data_layout.pointer_size), + scalar_ptr, + ) + .unwrap(); + allocation + .write_scalar( + &tables.tcx, + alloc_range(tables.tcx.data_layout.pointer_size, scalar_len.size()), + scalar_len, + ) + .unwrap(); + allocation.stable(tables) + } + ConstValue::ByRef { alloc, offset } => { + let ty_size = tables + .tcx + .layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(const_kind.ty())) + .unwrap() + .size; + allocation_filter(&alloc.0, alloc_range(offset, ty_size), tables) + } + } +} + +/// Creates an `Allocation` only from information within the `AllocRange`. +pub fn allocation_filter<'tcx>( + alloc: &rustc_middle::mir::interpret::Allocation, + alloc_range: AllocRange, + tables: &mut Tables<'tcx>, +) -> Allocation { + let mut bytes: Vec<Option<u8>> = alloc + .inspect_with_uninit_and_ptr_outside_interpreter( + alloc_range.start.bytes_usize()..alloc_range.end().bytes_usize(), + ) + .iter() + .copied() + .map(Some) + .collect(); + for (i, b) in bytes.iter_mut().enumerate() { + if !alloc + .init_mask() + .get(rustc_target::abi::Size::from_bytes(i + alloc_range.start.bytes_usize())) + { + *b = None; + } + } + let mut ptrs = Vec::new(); + for (offset, prov) in alloc + .provenance() + .ptrs() + .iter() + .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end()) + { + ptrs.push((offset.bytes_usize() - alloc_range.start.bytes_usize(), opaque(prov))); + } + Allocation { + bytes: bytes, + provenance: ProvenanceMap { ptrs }, + align: alloc.align.bytes(), + mutability: alloc.mutability.stable(tables), + } +} + +#[derive(Clone, Debug)] +pub enum ConstantKind { + Allocated(Allocation), + Unevaluated(UnevaluatedConst), + ParamCt(Opaque), +} + +#[derive(Clone, Debug)] +pub struct UnevaluatedConst { + pub ty: Ty, + pub def: ConstDef, + pub args: GenericArgs, + pub promoted: Option<Promoted>, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum TraitSpecializationKind { + None, + Marker, + AlwaysApplicable, +} + +#[derive(Clone, Debug)] +pub struct TraitDecl { + pub def_id: TraitDef, + pub unsafety: 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 specialization_kind: TraitSpecializationKind, + pub must_implement_one_of: Option<Vec<Ident>>, + pub implement_via_object: bool, + pub deny_explicit_impl: bool, +} + +pub type ImplTrait = EarlyBinder<TraitRef>; + +#[derive(Clone, Debug)] +pub struct TraitRef { + pub def_id: TraitDef, + pub args: GenericArgs, +} |