diff --git a/compiler/rustc_public/README.md b/compiler/rustc_public/README.md index e0bf562d00614..9272e2202cdad 100644 --- a/compiler/rustc_public/README.md +++ b/compiler/rustc_public/README.md @@ -1,45 +1,42 @@ This crate is currently developed in-tree together with the compiler. -Our goal is to start publishing `stable_mir` into crates.io. +Our goal is to start publishing `rustc_public` into crates.io. Until then, users will use this as any other rustc crate, by installing -the rustup component `rustc-dev`, and declaring `stable-mir` as an external crate. +the rustup component `rustc-dev`, and declaring `rustc-public` as an external crate. -See the StableMIR ["Getting Started"](https://rust-lang.github.io/rustc_public/getting-started.html) +See the rustc_public ["Getting Started"](https://rust-lang.github.io/rustc_public/getting-started.html) guide for more information. -## Stable MIR Design +## Design -The stable-mir will follow a similar approach to proc-macro2. Its +The `rustc_public` crate will follow a similar approach to [`proc-macro2`](https://crates.io/crates/proc-macro2). Its implementation is split between two main crates: -- `stable_mir`: Public crate, to be published on crates.io, which will contain -the stable data structure as well as calls to `rustc_smir` APIs. The -translation between stable and internal constructs will also be done in this crate, -however, this is currently implemented in the `rustc_smir` crate.[^translation]. -- `rustc_smir`: This crate implements the public APIs to the compiler. +- `rustc_public`: Public crate, to be published on crates.io, which will contain +the "stable" data structure as well as calls to `rustc_public_bridge` APIs. The +translation between public and internal constructs is also done in this crate. +- `rustc_public_bridge`: This crate implements the public APIs to the compiler. It is responsible for gathering all the information requested, and providing -the data in its unstable form. - -[^translation]: This is currently implemented in the `rustc_smir` crate, -but we are working to change that. +the data in its unstable internal form. I.e., -tools will depend on `stable_mir` crate, -which will invoke the compiler using APIs defined in `rustc_smir`. +tools will depend on `rustc_public` crate, +which will invoke the compiler using APIs defined in `rustc_public_bridge`. I.e.: ``` - ┌──────────────────────────────────┐ ┌──────────────────────────────────┐ - │ External Tool ┌──────────┐ │ │ ┌──────────┐ Rust Compiler │ - │ │ │ │ │ │ │ │ - │ │stable_mir| │ │ │rustc_smir│ │ - │ │ │ ├──────────►| │ │ │ - │ │ │ │◄──────────┤ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ │ │ │ │ - │ └──────────┘ │ │ └──────────┘ │ - └──────────────────────────────────┘ └──────────────────────────────────┘ + ┌────────────────────────────┐ ┌───────────────────────────┐ + │ External Tool │ │ Rust Compiler │ + │ ┌────────────┐ │ │ ┌────────┐ │ + │ │ │ │ │ │ │ │ + │ │rustc_public│ │ │ │rustc │ │ + │ │ │ ├──────────►| │public │ │ + │ │ │ │◄──────────┤ │bridge │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ + │ └────────────┘ │ │ └────────┘ │ + └────────────────────────────┘ └───────────────────────────┘ ``` More details can be found here: diff --git a/compiler/rustc_public/src/lib.rs b/compiler/rustc_public/src/lib.rs index 5b7e1580532a8..4adc0e139a68e 100644 --- a/compiler/rustc_public/src/lib.rs +++ b/compiler/rustc_public/src/lib.rs @@ -1,20 +1,50 @@ -//! The WIP public interface to rustc internals. +//! # `rustc_public` — A Public Interface to `rustc` //! -//! For more information see +//! 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. //! -//! # Note +//! The goal is to publish this crate on [crates.io](https://crates.io) with semver +//! guarantees. For more details on the proposed plan, see +//! . //! -//! This API is still completely unstable and subject to change. +//! ## 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 . #![allow(rustc::usage_of_ty_tykind)] #![doc(test(attr(allow(unused_variables), deny(warnings), allow(internal_features))))] #![feature(sized_hierarchy)] -//! -//! This crate shall contain all type definitions and APIs that we expect third-party tools to invoke to -//! interact with the compiler. -//! -//! The goal is to eventually be published on -//! [crates.io](https://crates.io). use std::fmt::Debug; use std::marker::PhantomData; @@ -23,11 +53,14 @@ use std::{fmt, io}; pub(crate) use rustc_public_bridge::IndexedVal; use rustc_public_bridge::Tables; use rustc_public_bridge::context::CompilerCtxt; -/// Export the rustc_internal APIs. Note that this module has no stability -/// guarantees and it is not taken into account for semver. +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 serde::Serialize; use crate::compiler_interface::with; pub use crate::crate_def::{CrateDef, CrateDefType, DefId}; @@ -55,10 +88,11 @@ mod tests; pub mod ty; pub mod visitor; -/// Use String for now but we should replace it. +// 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; -/// The number that identifies a crate. +/// 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); @@ -69,117 +103,165 @@ impl Debug for DefId { } } -/// A list of crate items. +/// A collection of items defined in a crate. pub type CrateItems = Vec; -/// A list of trait decls. +/// A collection of trait declarations. pub type TraitDecls = Vec; -/// A list of impl trait decls. +/// A collection of trait implementation blocks. pub type ImplTraitDecls = Vec; -/// A list of associated items. +/// A collection of associated items (methods, constants, or types within a trait or impl). pub type AssocItems = Vec; -/// Holds information about a crate. +/// 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 { - /// The list of foreign modules in this crate. + /// Return all foreign modules (e.g., `extern "C" { ... }` blocks) in this crate. pub fn foreign_modules(&self) -> Vec { with(|cx| cx.foreign_modules(self.id)) } - /// The list of traits declared in this crate. + /// 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)) } - /// The list of trait implementations in this crate. + /// Return all trait implementation blocks in this crate. pub fn trait_impls(&self) -> ImplTraitDecls { with(|cx| cx.trait_impls(self.id)) } - /// Return a list of function definitions from this crate independent on their visibility. + /// 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 { with(|cx| cx.crate_functions(self.id)) } - /// Return a list of static items defined in this crate independent on their visibility. + /// 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 { with(|cx| cx.crate_statics(self.id)) } - /// Return a list of ADTs defined in this crate independent on their visibility. + /// 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 { 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! { - /// Holds information about an item in a crate. + /// 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 { - /// This will return the body of an item or panic if it's not available. + /// 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 body of an item if available. + /// 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 { with(|cx| cx.has_body(self.0).then(|| cx.mir_body(self.0))) } - /// Check if a body is available for this item. + /// 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)) } - /// Emit MIR for this item body. + /// Write the MIR textual representation of this item's body to `w`. pub fn emit_mir(&self, w: &mut W) -> io::Result<()> { self.body() .ok_or_else(|| io::Error::other(format!("No body found for `{}`", self.name())))? @@ -187,42 +269,57 @@ impl CrateItem { } } -/// Return the function where execution starts if the current -/// crate defines that. This is usually `main`, but could be -/// `start` if the crate is a no-std crate. +/// 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 { with(|cx| cx.entry_fn()) } -/// Access to the local crate. +/// Return the local crate (the crate currently being compiled). pub fn local_crate() -> Crate { with(|cx| cx.local_crate()) } -/// Try to find a crate or crates if multiple crates exist from given name. +/// 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 { with(|cx| cx.find_crates(name)) } -/// Try to find a crate with the given name. +/// Return all external (non-local) crates in the compilation. pub fn external_crates() -> Vec { with(|cx| cx.external_crates()) } -/// Retrieve all items in the local crate that have a MIR associated with them. +/// 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()) } -/// A type that provides internal information but that can still be used for debug purpose. +/// 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); @@ -238,6 +335,7 @@ impl std::fmt::Debug for Opaque { } } +/// Create an [`Opaque`] value from any debuggable type. pub fn opaque(value: &T) -> Opaque { Opaque(format!("{value:?}")) }