| //! # `rustc_public` — A Public Interface to `rustc` | |
| //! | |
| //! This crate provides a public API for querying and analyzing Rust programs through the | |
| //! compiler's internal representations. It is designed for third-party tools such as | |
| //! verification engines, linters, and code generators that need access to type information, | |
| //! MIR bodies, monomorphized instances, and ABI details. | |
| //! | |
| //! The goal is to publish this crate on [crates.io](https://crates.io) with semver | |
| //! guarantees. For more details on the proposed plan, see | |
| //! <https://github.com/rust-lang/compiler-team/issues/949>. | |
| //! | |
| //! ## Usage | |
| //! | |
| //! For now, the entry point is the [`run!`] macro, which sets up the compiler session and provides | |
| //! access to the API within a callback. All queries must be performed inside this callback | |
| //! since the data structures are tied to the compiler's thread-local state. | |
| //! | |
| //! ```rust,ignore (requires compiler session) | |
| //! use rustc_public::*; | |
| //! use std::ops::ControlFlow; | |
| //! | |
| //! let result = run!(args, || -> ControlFlow<()> { | |
| //! // Find all crates with the same name (potential duplicates). | |
| //! for krate in external_crates() { | |
| //! let dupes = find_crates(&krate.name); | |
| //! if dupes.len() > 1 { | |
| //! println!("Warning: multiple versions of `{}`", krate.name); | |
| //! } | |
| //! } | |
| //! ControlFlow::Continue(()) | |
| //! }); | |
| //! ``` | |
| //! | |
| //! ## Crate Discovery | |
| //! | |
| //! Use [`local_crate()`] to access the crate being compiled, [`external_crates()`] to list | |
| //! dependencies, or [`find_crates()`] to search by name. Use [`entry_fn()`] to find the | |
| //! program entry point, and [`all_local_items()`] to retrieve all local definitions. | |
| //! | |
| //! ## Status | |
| //! | |
| //! This API is not yet published and is still subject to breaking changes. | |
| //! For more information, see <https://github.com/rust-lang/rustc_public>. | |
| #![allow(rustc::usage_of_ty_tykind)] | |
| #![doc(test(attr(allow(unused_variables), deny(warnings))))] | |
| #![feature(sized_hierarchy)] | |
| use std::fmt::Debug; | |
| use std::marker::PhantomData; | |
| use std::{fmt, io}; | |
| pub(crate) use rustc_public_bridge::IndexedVal; | |
| use rustc_public_bridge::Tables; | |
| use rustc_public_bridge::context::CompilerCtxt; | |
| use serde::Serialize; | |
| /// Unstable internal APIs for bridging with `rustc` internals. | |
| /// | |
| /// This module has no stability guarantees and is not covered by semver. | |
| /// It is only available when the `rustc_internal` feature is enabled. | |
| #[cfg(feature = "rustc_internal")] | |
| pub mod rustc_internal; | |
| use crate::compiler_interface::with; | |
| pub use crate::crate_def::{CrateDef, CrateDefType, DefId}; | |
| pub use crate::error::*; | |
| use crate::mir::mono::StaticDef; | |
| use crate::mir::{Body, Mutability}; | |
| use crate::ty::{ | |
| AdtDef, AssocItem, FnDef, ForeignModuleDef, ImplDef, ProvenanceMap, Span, TraitDef, Ty, | |
| serialize_index_impl, | |
| }; | |
| use crate::unstable::Stable; | |
| pub mod abi; | |
| mod alloc; | |
| pub(crate) mod unstable; | |
| #[macro_use] | |
| pub mod crate_def; | |
| pub mod compiler_interface; | |
| #[macro_use] | |
| pub mod error; | |
| pub mod mir; | |
| pub mod target; | |
| #[cfg(test)] | |
| mod tests; | |
| pub mod ty; | |
| pub mod visitor; | |
| // FIXME: Consider replacing with an opaque or interned type. | |
| /// A symbol name (e.g., function name, crate name), currently represented as a `String`. | |
| pub type Symbol = String; | |
| /// A unique identifier for a crate within the current compilation session. | |
| #[derive(Clone, Copy, PartialEq, Eq, Debug)] | |
| pub struct CrateNum(pub(crate) usize, ThreadLocalIndex); | |
| serialize_index_impl!(CrateNum); | |
| impl Debug for DefId { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| f.debug_struct("DefId").field("id", &self.0).field("name", &self.name()).finish() | |
| } | |
| } | |
| /// A collection of items defined in a crate. | |
| pub type CrateItems = Vec<CrateItem>; | |
| /// A collection of trait declarations. | |
| pub type TraitDecls = Vec<TraitDef>; | |
| /// A collection of trait implementation blocks. | |
| pub type ImplTraitDecls = Vec<ImplDef>; | |
| /// A collection of associated items (methods, constants, or types within a trait or impl). | |
| pub type AssocItems = Vec<AssocItem>; | |
| /// Metadata about a crate in the current compilation. | |
| /// | |
| /// Use [`local_crate()`] to obtain the crate being compiled, or [`external_crates()`] | |
| /// and [`find_crates()`] to discover dependencies. | |
| #[derive(Clone, PartialEq, Eq, Debug, Serialize)] | |
| pub struct Crate { | |
| /// The crate's unique identifier in this compilation session. | |
| pub id: CrateNum, | |
| /// The crate name as declared in `Cargo.toml` or `--crate-name`. | |
| pub name: Symbol, | |
| /// Whether this is the crate currently being compiled. | |
| pub is_local: bool, | |
| } | |
| impl Crate { | |
| /// Return all foreign modules (e.g., `extern "C" { ... }` blocks) in this crate. | |
| pub fn foreign_modules(&self) -> Vec<ForeignModuleDef> { | |
| with(|cx| cx.foreign_modules(self.id)) | |
| } | |
| /// Return all trait declarations in this crate. | |
| /// | |
| /// For the local crate, this includes private traits. For external crates, | |
| /// it returns all traits available in metadata. | |
| pub fn trait_decls(&self) -> TraitDecls { | |
| with(|cx| cx.trait_decls(self.id)) | |
| } | |
| /// Return all trait implementation blocks in this crate. | |
| pub fn trait_impls(&self) -> ImplTraitDecls { | |
| with(|cx| cx.trait_impls(self.id)) | |
| } | |
| /// Return all function definitions in this crate. | |
| /// | |
| /// For the local crate, this includes private functions. For external crates, | |
| /// it returns all functions available in metadata. | |
| pub fn fn_defs(&self) -> Vec<FnDef> { | |
| with(|cx| cx.crate_functions(self.id)) | |
| } | |
| /// Return all static items in this crate. | |
| /// | |
| /// For the local crate, this includes private statics. For external crates, | |
| /// it returns all statics available in metadata. | |
| pub fn statics(&self) -> Vec<StaticDef> { | |
| with(|cx| cx.crate_statics(self.id)) | |
| } | |
| /// Return all ADT (struct, enum, union) definitions in this crate. | |
| /// | |
| /// For the local crate, this includes private types. For external crates, | |
| /// it returns all ADTs available in metadata. | |
| pub fn adts(&self) -> Vec<AdtDef> { | |
| with(|cx| cx.crate_adts(self.id)) | |
| } | |
| } | |
| /// The kind of a [`CrateItem`]. | |
| #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] | |
| pub enum ItemKind { | |
| /// A function (`fn`) or method. | |
| Fn, | |
| /// A static variable (`static`). | |
| Static, | |
| /// A compile-time constant (`const`). | |
| Const, | |
| /// A data constructor for a struct or enum variant. | |
| Ctor(CtorKind), | |
| } | |
| /// The kind of a data constructor. | |
| #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)] | |
| pub enum CtorKind { | |
| /// A unit or constant constructor (e.g., `None`, `struct Foo;`). | |
| Const, | |
| /// A function-like constructor (e.g., `Some(x)`, `struct Foo(u32)`). | |
| Fn, | |
| } | |
| /// A file path string used for source locations and diagnostics. | |
| pub type Filename = String; | |
| crate_def_with_ty! { | |
| /// A definition in the local crate (function, static, const, or constructor). | |
| /// | |
| /// Obtain instances via [`all_local_items()`] or [`Crate::fn_defs()`]. | |
| /// Use [`CrateItem::body()`] to access the MIR, or convert to an | |
| /// [`Instance`](mir::mono::Instance) for monomorphized analysis. | |
| #[derive(Serialize)] | |
| pub CrateItem; | |
| } | |
| impl CrateItem { | |
| /// Return the MIR body of this item, panicking if unavailable. | |
| /// | |
| /// Prefer [`body()`](Self::body) for a non-panicking alternative. | |
| pub fn expect_body(&self) -> mir::Body { | |
| with(|cx| cx.mir_body(self.0)) | |
| } | |
| /// Return the MIR body of this item, or `None` if unavailable. | |
| /// | |
| /// A body may be unavailable for foreign items or compiler built-ins. | |
| pub fn body(&self) -> Option<mir::Body> { | |
| with(|cx| cx.has_body(self.0).then(|| cx.mir_body(self.0))) | |
| } | |
| /// Check whether this item has a MIR body available. | |
| pub fn has_body(&self) -> bool { | |
| with(|cx| cx.has_body(self.0)) | |
| } | |
| /// Return the source span of this item's definition. | |
| pub fn span(&self) -> Span { | |
| self.0.span() | |
| } | |
| /// Return what kind of item this is (function, static, const, or constructor). | |
| pub fn kind(&self) -> ItemKind { | |
| with(|cx| cx.item_kind(*self)) | |
| } | |
| /// Check whether this item is generic and requires monomorphization. | |
| /// | |
| /// Returns `true` if this item, or any enclosing definition (e.g., the impl | |
| /// block it belongs to), has type or const generic parameters. | |
| pub fn requires_monomorphization(&self) -> bool { | |
| with(|cx| cx.requires_monomorphization(self.0)) | |
| } | |
| /// Return the type of this item. | |
| /// | |
| /// For functions, this returns the function type (e.g., `fn(u32) -> bool`). | |
| pub fn ty(&self) -> Ty { | |
| with(|cx| cx.def_ty(self.0)) | |
| } | |
| /// Check whether this item was declared inside an `extern` block. | |
| /// | |
| /// Foreign items (e.g., `extern "C" { fn foo(); }`) are locally defined | |
| /// declarations of externally-linked symbols. | |
| pub fn is_foreign_item(&self) -> bool { | |
| with(|cx| cx.is_foreign_item(self.0)) | |
| } | |
| /// Write the MIR textual representation of this item's body to `w`. | |
| pub fn emit_mir<W: io::Write>(&self, w: &mut W) -> io::Result<()> { | |
| self.body() | |
| .ok_or_else(|| io::Error::other(format!("No body found for `{}`", self.name())))? | |
| .dump(w, &self.trimmed_name()) | |
| } | |
| } | |
| /// Return the program entry point (usually `main`) if defined in the local crate. | |
| /// | |
| /// Returns `None` for library crates. For `no_std` crates this may resolve to | |
| /// a `#[start]` function. | |
| pub fn entry_fn() -> Option<CrateItem> { | |
| with(|cx| cx.entry_fn()) | |
| } | |
| /// Return the local crate (the crate currently being compiled). | |
| pub fn local_crate() -> Crate { | |
| with(|cx| cx.local_crate()) | |
| } | |
| /// Find all crates matching the given name. | |
| /// | |
| /// Multiple crates with the same name can exist when different versions of the | |
| /// same dependency are linked. | |
| pub fn find_crates(name: &str) -> Vec<Crate> { | |
| with(|cx| cx.find_crates(name)) | |
| } | |
| /// Return all external (non-local) crates in the compilation. | |
| pub fn external_crates() -> Vec<Crate> { | |
| with(|cx| cx.external_crates()) | |
| } | |
| /// Return all items in the local crate that have a MIR body. | |
| /// | |
| /// This includes functions, closures, statics with initializers, and constants. | |
| pub fn all_local_items() -> CrateItems { | |
| with(|cx| cx.all_local_items()) | |
| } | |
| /// Return all trait declarations from the local crate and all its dependencies. | |
| /// | |
| /// This includes private traits. Use [`Crate::trait_decls()`] to query a specific crate. | |
| pub fn all_trait_decls() -> TraitDecls { | |
| with(|cx| cx.all_trait_decls()) | |
| } | |
| /// Return all trait implementations from the local crate and all its dependencies. | |
| /// | |
| /// Use [`Crate::trait_impls()`] to query a specific crate. | |
| pub fn all_trait_impls() -> ImplTraitDecls { | |
| with(|cx| cx.all_trait_impls()) | |
| } | |
| /// An opaque wrapper around internal compiler data. | |
| /// | |
| /// This type is used for compiler details that are exposed for debug printing | |
| /// but whose internal structure is not part of the public API. | |
| #[derive(Clone, PartialEq, Eq, Hash, Serialize)] | |
| pub struct Opaque(String); | |
| impl std::fmt::Display for Opaque { | |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
| write!(f, "{}", self.0) | |
| } | |
| } | |
| impl std::fmt::Debug for Opaque { | |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
| write!(f, "{}", self.0) | |
| } | |
| } | |
| /// Create an [`Opaque`] value from any debuggable type. | |
| pub fn opaque<T: Debug>(value: &T) -> Opaque { | |
| Opaque(format!("{value:?}")) | |
| } | |
| macro_rules! bridge_impl { | |
| ( $( $name:ident, $ty:ty ),* $(,)? ) => { | |
| $( | |
| impl rustc_public_bridge::bridge::$name<compiler_interface::BridgeTys> for $ty { | |
| fn new(def: crate::DefId) -> Self { | |
| Self(def) | |
| } | |
| } | |
| )* | |
| }; | |
| } | |
| #[rustfmt::skip] | |
| bridge_impl!( | |
| CrateItem, crate::CrateItem, | |
| AdtDef, crate::ty::AdtDef, | |
| ForeignModuleDef, crate::ty::ForeignModuleDef, | |
| ForeignDef, crate::ty::ForeignDef, | |
| FnDef, crate::ty::FnDef, | |
| ClosureDef, crate::ty::ClosureDef, | |
| CoroutineDef, crate::ty::CoroutineDef, | |
| CoroutineClosureDef, crate::ty::CoroutineClosureDef, | |
| AliasDef, crate::ty::AliasDef, | |
| ParamDef, crate::ty::ParamDef, | |
| BrNamedDef, crate::ty::BrNamedDef, | |
| TraitDef, crate::ty::TraitDef, | |
| GenericDef, crate::ty::GenericDef, | |
| ConstDef, crate::ty::ConstDef, | |
| ImplDef, crate::ty::ImplDef, | |
| RegionDef, crate::ty::RegionDef, | |
| CoroutineWitnessDef, crate::ty::CoroutineWitnessDef, | |
| AssocDef, crate::ty::AssocDef, | |
| OpaqueDef, crate::ty::OpaqueDef, | |
| StaticDef, crate::mir::mono::StaticDef | |
| ); | |
| impl rustc_public_bridge::bridge::Prov<compiler_interface::BridgeTys> for crate::ty::Prov { | |
| fn new(aid: crate::mir::alloc::AllocId) -> Self { | |
| Self(aid) | |
| } | |
| } | |
| impl rustc_public_bridge::bridge::Allocation<compiler_interface::BridgeTys> | |
| for crate::ty::Allocation | |
| { | |
| fn new<'tcx>( | |
| bytes: Vec<Option<u8>>, | |
| ptrs: Vec<(usize, rustc_middle::mir::interpret::AllocId)>, | |
| align: u64, | |
| mutability: rustc_middle::mir::Mutability, | |
| tables: &mut Tables<'tcx, compiler_interface::BridgeTys>, | |
| cx: &CompilerCtxt<'tcx, compiler_interface::BridgeTys>, | |
| ) -> Self { | |
| Self { | |
| bytes, | |
| provenance: ProvenanceMap { | |
| ptrs: ptrs.iter().map(|(i, aid)| (*i, tables.prov(*aid))).collect(), | |
| }, | |
| align, | |
| mutability: mutability.stable(tables, cx), | |
| } | |
| } | |
| } | |
| #[derive(Clone, Copy, Hash, PartialEq, Eq, Default)] | |
| /// Marker type for indexes into thread local structures. | |
| /// | |
| /// Makes things `!Send`/`!Sync`, so users don't move `rustc_public` types to | |
| /// thread with no (or worse, different) `rustc_public` pointer. | |
| /// | |
| /// Note. This doesn't make it impossible to confuse TLS. You could return a | |
| /// `DefId` from one `run!` invocation, and then use it inside a different | |
| /// `run!` invocation with different tables. | |
| pub(crate) struct ThreadLocalIndex { | |
| _phantom: PhantomData<*const ()>, | |
| } | |
| #[expect(non_upper_case_globals)] | |
| /// Emulating unit struct `struct ThreadLocalIndex`; | |
| pub(crate) const ThreadLocalIndex: ThreadLocalIndex = ThreadLocalIndex { _phantom: PhantomData }; | |
| impl fmt::Debug for ThreadLocalIndex { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| f.debug_tuple("ThreadLocalIndex").finish() | |
| } | |
| } |