diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index fe226ef60ed..202ca1b156a 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -11,8 +11,8 @@ use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; use stable_mir::ty::{ AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, - ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, TraitRef, - Ty, UintTy, + ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, Span, + TraitRef, Ty, UintTy, }; use stable_mir::{CrateItem, DefId}; @@ -279,6 +279,14 @@ fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { } } +impl<'tcx> RustcInternal<'tcx> for Span { + type T = rustc_span::Span; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables[*self] + } +} + impl<'tcx, T> RustcInternal<'tcx> for &T where T: RustcInternal<'tcx>, diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 8b469882cd1..9921a89eb23 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -14,6 +14,7 @@ use rustc_middle::mir; use rustc_middle::mir::interpret::{alloc_range, AllocId}; use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; use rustc_middle::ty::{self, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_target::abi::FieldIdx; @@ -28,7 +29,7 @@ EarlyParamRegion, FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, TyKind, UintTy, }; -use stable_mir::{self, opaque, Context, CrateItem, Error, Filename, ItemKind}; +use stable_mir::{self, opaque, Context, Crate, CrateItem, Error, Filename, ItemKind, Symbol}; use std::cell::RefCell; use tracing::debug; @@ -61,9 +62,18 @@ fn find_crates(&self, name: &str) -> Vec { crates } - fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String { + fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol { let tables = self.0.borrow(); - tables.tcx.def_path_str(tables[def_id]) + if trimmed { + with_forced_trimmed_paths!(tables.tcx.def_path_str(tables[def_id])) + } else { + with_no_trimmed_paths!(tables.tcx.def_path_str(tables[def_id])) + } + } + + fn krate(&self, def_id: stable_mir::DefId) -> Crate { + let tables = self.0.borrow(); + smir_crate(tables.tcx, tables[def_id].krate) } fn span_to_string(&self, span: stable_mir::ty::Span) -> String { @@ -240,10 +250,27 @@ fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { tables.create_def_id(def_id) } - fn instance_mangled_name(&self, def: InstanceDef) -> String { + fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol { + let tables = self.0.borrow_mut(); + let instance = tables.instances[instance]; + tables.tcx.symbol_name(instance).name.to_string() + } + + /// Retrieve the instance name for diagnostic messages. + /// + /// This will return the specialized name, e.g., `Vec::new`. + fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; - tables.tcx.symbol_name(instance).name.to_string() + if trimmed { + with_forced_trimmed_paths!( + tables.tcx.def_path_str_with_args(instance.def_id(), instance.args) + ) + } else { + with_no_trimmed_paths!( + tables.tcx.def_path_str_with_args(instance.def_id(), instance.args) + ) + } } fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance { diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs new file mode 100644 index 00000000000..70ca9e6825e --- /dev/null +++ b/compiler/stable_mir/src/crate_def.rs @@ -0,0 +1,69 @@ +//! 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 crate::ty::Span; +use crate::{with, Crate, Symbol}; + +/// A unique identification number for each item accessible for the current compilation unit. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct DefId(pub(crate) usize); + +/// 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. + fn name(&self) -> Symbol { + let def_id = self.def_id(); + with(|cx| cx.def_name(def_id, 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. + fn trimmed_name(&self) -> Symbol { + let def_id = self.def_id(); + with(|cx| cx.def_name(def_id, true)) + } + + /// 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)) + } +} + +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 + } + } + }; +} diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 6c1b723a8da..1b1faea4953 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -31,12 +31,16 @@ #[macro_use] extern crate scoped_tls; +#[macro_use] +pub mod crate_def; #[macro_use] pub mod error; pub mod mir; pub mod ty; pub mod visitor; +pub use crate::crate_def::CrateDef; +pub use crate::crate_def::DefId; use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::pretty::function_name; use crate::mir::Mutability; @@ -51,15 +55,11 @@ /// The number that identifies a crate. pub type CrateNum = usize; -/// A unique identification number for each item accessible for the current compilation unit. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct DefId(usize); - impl Debug for DefId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DefId") .field("id", &self.0) - .field("name", &with(|cx| cx.name_of_def_id(*self))) + .field("name", &with(|cx| cx.def_name(*self, false))) .finish() } } @@ -100,9 +100,10 @@ pub enum ItemKind { pub type Filename = String; -/// Holds information about an item in the crate. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct CrateItem(pub DefId); +crate_def! { + /// Holds information about an item in a crate. + pub CrateItem; +} impl CrateItem { pub fn body(&self) -> mir::Body { @@ -113,10 +114,6 @@ pub fn span(&self) -> Span { with(|cx| cx.span_of_an_item(self.0)) } - pub fn name(&self) -> String { - with(|cx| cx.name_of_def_id(self.0)) - } - pub fn kind(&self) -> ItemKind { with(|cx| cx.item_kind(*self)) } @@ -205,7 +202,7 @@ pub trait Context { fn find_crates(&self, name: &str) -> Vec; /// Returns the name of given `DefId` - fn name_of_def_id(&self, def_id: DefId) -> String; + fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol; /// Returns printable, human readable form of `Span` fn span_to_string(&self, span: Span) -> String; @@ -260,7 +257,7 @@ pub trait Context { fn instance_def_id(&self, instance: InstanceDef) -> DefId; /// Get the instance mangled name. - fn instance_mangled_name(&self, instance: InstanceDef) -> String; + fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol; /// Convert a non-generic crate item into an instance. /// This function will panic if the item is generic. @@ -294,6 +291,8 @@ fn resolve_closure( /// Retrieve the id for the virtual table. fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option; + fn krate(&self, def_id: DefId) -> Crate; + fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 9cec963cf84..8e884f17573 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -1,6 +1,7 @@ +use crate::crate_def::CrateDef; use crate::mir::Body; use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; -use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque}; +use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol}; use std::fmt::{Debug, Formatter}; #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -47,10 +48,29 @@ pub fn ty(&self) -> Ty { with(|context| context.instance_ty(self.def)) } - pub fn mangled_name(&self) -> String { + /// Retrieve the instance's mangled name used for calling the given instance. + /// + /// This will also look up the correct name of instances from upstream crates. + pub fn mangled_name(&self) -> Symbol { with(|context| context.instance_mangled_name(self.def)) } + /// Retrieve the instance name for diagnostic messages. + /// + /// This will return the specialized name, e.g., `std::vec::Vec::new`. + pub fn name(&self) -> Symbol { + with(|context| context.instance_name(self.def, false)) + } + + /// Return a trimmed name of the given instance including its args. + /// + /// If a symbol name can only be imported from one place for a type, and as + /// long as it was not glob-imported anywhere in the current crate, we trim its + /// path and print only the name. + pub fn trimmed_name(&self) -> Symbol { + with(|context| context.instance_name(self.def, true)) + } + /// Resolve an instance starting from a function definition and generic arguments. pub fn resolve(def: FnDef, args: &GenericArgs) -> Result { with(|context| { @@ -104,6 +124,8 @@ impl TryFrom for Instance { fn try_from(item: CrateItem) -> Result { with(|context| { + // FIXME(celinval): + // - Return `Err` if instance does not have a body. if !context.requires_monomorphization(item.0) { Ok(context.mono_instance(item)) } else { @@ -148,8 +170,10 @@ fn from(value: StaticDef) -> Self { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct InstanceDef(usize); -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub struct StaticDef(pub DefId); +crate_def! { + /// Holds information about a static variable definition. + pub StaticDef; +} impl TryFrom for StaticDef { type Error = crate::Error; diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index c7422d66c0e..c16d7ddf335 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -1,3 +1,4 @@ +use crate::crate_def::CrateDef; use crate::mir::{Operand, Rvalue, StatementKind}; use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy}; use crate::{with, Body, CrateItem, Mutability}; diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 19b7abaf2a8..80558657deb 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -3,6 +3,7 @@ mir::{Body, Mutability}, with, DefId, Error, Symbol, }; +use crate::crate_def::CrateDef; use crate::mir::alloc::AllocId; use crate::{Filename, Opaque}; use std::fmt::{self, Debug, Display, Formatter}; @@ -295,11 +296,15 @@ pub enum Movability { Movable, } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct ForeignDef(pub DefId); +crate_def! { + /// Hold information about a ForeignItem in a crate. + pub ForeignDef; +} -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct FnDef(pub DefId); +crate_def! { + /// Hold information about a function definition in a crate. + pub FnDef; +} impl FnDef { pub fn body(&self) -> Body { @@ -307,20 +312,25 @@ pub fn body(&self) -> Body { } } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct ClosureDef(pub DefId); +crate_def! { + pub ClosureDef; +} -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct CoroutineDef(pub DefId); +crate_def! { + pub CoroutineDef; +} -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct ParamDef(pub DefId); +crate_def! { + pub ParamDef; +} -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct BrNamedDef(pub DefId); +crate_def! { + pub BrNamedDef; +} -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct AdtDef(pub DefId); +crate_def! { + pub AdtDef; +} #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub enum AdtKind { @@ -363,26 +373,33 @@ pub fn is_union(&self) -> bool { } } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct AliasDef(pub DefId); +crate_def! { + pub AliasDef; +} -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct TraitDef(pub DefId); +crate_def! { + pub TraitDef; +} -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct GenericDef(pub DefId); +crate_def! { + pub GenericDef; +} -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct ConstDef(pub DefId); +crate_def! { + pub ConstDef; +} -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct ImplDef(pub DefId); +crate_def! { + pub ImplDef; +} -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct RegionDef(pub DefId); +crate_def! { + pub RegionDef; +} -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct CoroutineWitnessDef(pub DefId); +crate_def! { + pub CoroutineWitnessDef; +} /// A list of generic arguments. #[derive(Clone, Debug, Eq, PartialEq)] diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index e5fb7311c0b..170b1fd73b1 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -24,6 +24,7 @@ use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::{CrateItem, CrateItems, ItemKind}; +use stable_mir::crate_def::CrateDef; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::StaticDef; use std::ascii::Char; diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs new file mode 100644 index 00000000000..bbb49596288 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -0,0 +1,106 @@ +// run-pass +//! Test that users are able to use stable mir APIs to retrieve information about crate definitions. + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +// edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use mir::{mono::Instance, TerminatorKind::*}; +use rustc_middle::ty::TyCtxt; +use rustc_smir::rustc_internal; +use stable_mir::ty::{RigidTy, TyKind}; +use stable_mir::*; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { + let entry = stable_mir::entry_fn().unwrap(); + let main_fn = Instance::try_from(entry).unwrap(); + assert_eq!(main_fn.name(), "main"); + assert_eq!(main_fn.trimmed_name(), "main"); + + let instances = get_instances(main_fn.body().unwrap()); + assert_eq!(instances.len(), 2); + test_fn(instances[0], "from_u32", "std::char::from_u32", "core"); + test_fn(instances[1], "Vec::::new", "std::vec::Vec::::new", "alloc"); + ControlFlow::Continue(()) +} + +fn test_fn(instance: Instance, expected_trimmed: &str, expected_qualified: &str, krate: &str) { + let trimmed = instance.trimmed_name(); + let qualified = instance.name(); + assert_eq!(&trimmed, expected_trimmed); + assert_eq!(&qualified, expected_qualified); + + let item = CrateItem::try_from(instance).unwrap(); + let trimmed = item.trimmed_name(); + let qualified = item.name(); + assert_eq!(trimmed, expected_trimmed.replace("u8", "T")); + assert_eq!(qualified, expected_qualified.replace("u8", "T")); + assert_eq!(&item.krate().name, krate); +} + +/// Inspect the instance body +fn get_instances(body: mir::Body) -> Vec { + body.blocks.iter().filter_map(|bb| { + match &bb.terminator.kind { + Call { func, .. } => { + let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else { unreachable! + () }; + let RigidTy::FnDef(def, args) = ty else { unreachable!() }; + Instance::resolve(def, &args).ok() + } + _ => { + None + } + } + }).collect::>() +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "defs_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "-Cpanic=abort".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, tcx, test_stable_mir(tcx)).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + + fn main() {{ + let _c = core::char::from_u32(99); + let _v = Vec::::new(); + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 4164f041022..c2035430a33 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -23,6 +23,7 @@ use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ItemKind; +use stable_mir::crate_def::CrateDef; use stable_mir::mir::mono::Instance; use stable_mir::ty::{RigidTy, TyKind}; use std::assert_matches::assert_matches; diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index 29930763591..8c3fda7b6bb 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -21,6 +21,7 @@ use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; +use stable_mir::crate_def::CrateDef; use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind}; use stable_mir::ty::{RigidTy, TyKind, UintTy}; use stable_mir::ItemKind;