Rework the driver docs (#2162)

This commit is contained in:
bjorn3 2024-12-27 13:40:32 +01:00 committed by GitHub
parent 1fe9814d06
commit f756d616dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 273 additions and 199 deletions

View File

@ -1,92 +1,92 @@
#![feature(rustc_private)] #![feature(rustc_private)]
extern crate rustc_ast;
extern crate rustc_ast_pretty;
extern crate rustc_data_structures;
extern crate rustc_driver; extern crate rustc_driver;
extern crate rustc_error_codes; extern crate rustc_error_codes;
extern crate rustc_errors; extern crate rustc_errors;
extern crate rustc_hash; extern crate rustc_hash;
extern crate rustc_hir; extern crate rustc_hir;
extern crate rustc_interface; extern crate rustc_interface;
extern crate rustc_middle;
extern crate rustc_session; extern crate rustc_session;
extern crate rustc_span; extern crate rustc_span;
use std::{path, process, str, sync::Arc}; use std::io;
use std::path::Path;
use rustc_errors::registry; use rustc_ast_pretty::pprust::item_to_string;
use rustc_hash::FxHashMap; use rustc_data_structures::sync::Lrc;
use rustc_session::config; use rustc_driver::{Compilation, RunCompiler};
use rustc_interface::interface::Compiler;
use rustc_middle::ty::TyCtxt;
struct MyFileLoader;
impl rustc_span::source_map::FileLoader for MyFileLoader {
fn file_exists(&self, path: &Path) -> bool {
path == Path::new("main.rs")
}
fn read_file(&self, path: &Path) -> io::Result<String> {
if path == Path::new("main.rs") {
Ok(r#"
fn main() { fn main() {
let out = process::Command::new("rustc") let message = "Hello, World!";
.arg("--print=sysroot") println!("{message}");
.current_dir(".")
.output()
.unwrap();
let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
let config = rustc_interface::Config {
// Command line options
opts: config::Options {
maybe_sysroot: Some(path::PathBuf::from(sysroot)),
..config::Options::default()
},
// cfg! configuration in addition to the default ones
crate_cfg: Vec::new(), // FxHashSet<(String, Option<String>)>
crate_check_cfg: Vec::new(), // CheckCfg
input: config::Input::Str {
name: rustc_span::FileName::Custom("main.rs".into()),
input: r#"
static HELLO: &str = "Hello, world!";
fn main() {
println!("{HELLO}");
} }
"# "#
.into(), .to_string())
}, } else {
output_dir: None, // Option<PathBuf> Err(io::Error::other("oops"))
output_file: None, // Option<PathBuf> }
file_loader: None, // Option<Box<dyn FileLoader + Send + Sync>> }
locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES,
lint_caps: FxHashMap::default(), // FxHashMap<lint::LintId, lint::Level> fn read_binary_file(&self, _path: &Path) -> io::Result<Lrc<[u8]>> {
// This is a callback from the driver that is called when [`ParseSess`] is created. Err(io::Error::other("oops"))
psess_created: None, //Option<Box<dyn FnOnce(&mut ParseSess) + Send>> }
// This is a callback from the driver that is called when we're registering lints; }
// it is called during plugin registration when we have the LintStore in a non-shared state.
// struct MyCallbacks;
// Note that if you find a Some here you probably want to call that function in the new
// function being registered. impl rustc_driver::Callbacks for MyCallbacks {
register_lints: None, // Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> fn after_crate_root_parsing(
// This is a callback from the driver that is called just after we have populated &mut self,
// the list of queries. _compiler: &Compiler,
// krate: &rustc_ast::Crate,
// The second parameter is local providers and the third parameter is external providers. ) -> Compilation {
override_queries: None, // Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)> for item in &krate.items {
// Registry of diagnostics codes. println!("{}", item_to_string(&item));
registry: registry::Registry::new(rustc_errors::codes::DIAGNOSTICS), }
make_codegen_backend: None,
expanded_args: Vec::new(), Compilation::Continue
ice_file: None, }
hash_untracked_state: None,
using_internal_features: Arc::default(), fn after_analysis(&mut self, _compiler: &Compiler, tcx: TyCtxt<'_>) -> Compilation {
}; // Analyze the program and inspect the types of definitions.
rustc_interface::run_compiler(config, |compiler| { for id in tcx.hir().items() {
compiler.enter(|queries| { let hir = tcx.hir();
// Parse the program and print the syntax tree. let item = hir.item(id);
let parse = queries.parse().unwrap().get_mut().clone(); match item.kind {
println!("{parse:?}"); rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn(_, _, _) => {
// Analyze the program and inspect the types of definitions. let name = item.ident;
queries.global_ctxt().unwrap().enter(|tcx| { let ty = tcx.type_of(item.hir_id().owner.def_id);
for id in tcx.hir().items() { println!("{name:?}:\t{ty:?}")
let hir = tcx.hir(); }
let item = hir.item(id); _ => (),
match item.kind { }
rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn(_, _, _) => { }
let name = item.ident;
let ty = tcx.type_of(item.hir_id().owner.def_id); Compilation::Stop
println!("{name:?}:\t{ty:?}") }
} }
_ => (),
} fn main() {
} match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) {
}) mut compiler => {
}); compiler.set_file_loader(Some(Box::new(MyFileLoader)));
}); compiler.run();
}
}
} }

View File

@ -1,90 +1,99 @@
#![feature(rustc_private)] #![feature(rustc_private)]
extern crate rustc_ast;
extern crate rustc_ast_pretty; extern crate rustc_ast_pretty;
extern crate rustc_data_structures;
extern crate rustc_driver; extern crate rustc_driver;
extern crate rustc_error_codes; extern crate rustc_error_codes;
extern crate rustc_errors; extern crate rustc_errors;
extern crate rustc_hash; extern crate rustc_hash;
extern crate rustc_hir; extern crate rustc_hir;
extern crate rustc_interface; extern crate rustc_interface;
extern crate rustc_middle;
extern crate rustc_session; extern crate rustc_session;
extern crate rustc_span; extern crate rustc_span;
use std::{path, process, str, sync::Arc}; use std::io;
use std::path::Path;
use rustc_ast_pretty::pprust::item_to_string; use rustc_ast_pretty::pprust::item_to_string;
use rustc_errors::registry; use rustc_data_structures::sync::Lrc;
use rustc_session::config; use rustc_driver::{Compilation, RunCompiler};
use rustc_interface::interface::Compiler;
use rustc_middle::ty::TyCtxt;
fn main() { struct MyFileLoader;
let out = process::Command::new("rustc")
.arg("--print=sysroot") impl rustc_span::source_map::FileLoader for MyFileLoader {
.current_dir(".") fn file_exists(&self, path: &Path) -> bool {
.output() path == Path::new("main.rs")
.unwrap(); }
let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
let config = rustc_interface::Config { fn read_file(&self, path: &Path) -> io::Result<String> {
opts: config::Options { if path == Path::new("main.rs") {
maybe_sysroot: Some(path::PathBuf::from(sysroot)), Ok(r#"
..config::Options::default()
},
input: config::Input::Str {
name: rustc_span::FileName::Custom("main.rs".to_string()),
input: r#"
fn main() { fn main() {
let message = "Hello, World!"; let message = "Hello, World!";
println!("{message}"); println!("{message}");
} }
"# "#
.to_string(), .to_string())
}, } else {
crate_cfg: Vec::new(), Err(io::Error::other("oops"))
crate_check_cfg: Vec::new(), }
output_dir: None, }
output_file: None,
file_loader: None, fn read_binary_file(&self, _path: &Path) -> io::Result<Lrc<[u8]>> {
locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES, Err(io::Error::other("oops"))
lint_caps: rustc_hash::FxHashMap::default(), }
psess_created: None, }
register_lints: None,
override_queries: None, struct MyCallbacks;
make_codegen_backend: None,
registry: registry::Registry::new(rustc_errors::codes::DIAGNOSTICS), impl rustc_driver::Callbacks for MyCallbacks {
expanded_args: Vec::new(), fn after_crate_root_parsing(
ice_file: None, &mut self,
hash_untracked_state: None, _compiler: &Compiler,
using_internal_features: Arc::default(), krate: &rustc_ast::Crate,
}; ) -> Compilation {
rustc_interface::run_compiler(config, |compiler| { for item in &krate.items {
compiler.enter(|queries| { println!("{}", item_to_string(&item));
// TODO: add this to -Z unpretty }
let ast_krate = queries.parse().unwrap().get_mut().clone();
for item in ast_krate.items { Compilation::Continue
println!("{}", item_to_string(&item)); }
}
// Analyze the crate and inspect the types under the cursor. fn after_analysis(&mut self, _compiler: &Compiler, tcx: TyCtxt<'_>) -> Compilation {
queries.global_ctxt().unwrap().enter(|tcx| { // Every compilation contains a single crate.
// Every compilation contains a single crate. let hir_krate = tcx.hir();
let hir_krate = tcx.hir(); // Iterate over the top-level items in the crate, looking for the main function.
// Iterate over the top-level items in the crate, looking for the main function. for id in hir_krate.items() {
for id in hir_krate.items() { let item = hir_krate.item(id);
let item = hir_krate.item(id); // Use pattern-matching to find a specific node inside the main function.
// Use pattern-matching to find a specific node inside the main function. if let rustc_hir::ItemKind::Fn(_, _, body_id) = item.kind {
if let rustc_hir::ItemKind::Fn(_, _, body_id) = item.kind { let expr = &tcx.hir().body(body_id).value;
let expr = &tcx.hir().body(body_id).value; if let rustc_hir::ExprKind::Block(block, _) = expr.kind {
if let rustc_hir::ExprKind::Block(block, _) = expr.kind { if let rustc_hir::StmtKind::Let(let_stmt) = block.stmts[0].kind {
if let rustc_hir::StmtKind::Let(let_stmt) = block.stmts[0].kind { if let Some(expr) = let_stmt.init {
if let Some(expr) = let_stmt.init { let hir_id = expr.hir_id; // hir_id identifies the string "Hello, world!"
let hir_id = expr.hir_id; // hir_id identifies the string "Hello, world!" let def_id = item.hir_id().owner.def_id; // def_id identifies the main function
let def_id = item.hir_id().owner.def_id; // def_id identifies the main function let ty = tcx.typeck(def_id).node_type(hir_id);
let ty = tcx.typeck(def_id).node_type(hir_id); println!("{expr:#?}: {ty:?}");
println!("{expr:#?}: {ty:?}");
}
}
} }
} }
} }
}) }
}); }
});
Compilation::Stop
}
}
fn main() {
match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) {
mut compiler => {
compiler.set_file_loader(Some(Box::new(MyFileLoader)));
compiler.run();
}
}
} }

View File

@ -0,0 +1,81 @@
#![feature(rustc_private)]
extern crate rustc_driver;
extern crate rustc_error_codes;
extern crate rustc_errors;
extern crate rustc_hash;
extern crate rustc_hir;
extern crate rustc_interface;
extern crate rustc_session;
extern crate rustc_span;
use std::sync::Arc;
use rustc_errors::registry;
use rustc_hash::FxHashMap;
use rustc_session::config;
fn main() {
let config = rustc_interface::Config {
// Command line options
opts: config::Options::default(),
// cfg! configuration in addition to the default ones
crate_cfg: Vec::new(), // FxHashSet<(String, Option<String>)>
crate_check_cfg: Vec::new(), // CheckCfg
input: config::Input::Str {
name: rustc_span::FileName::Custom("main.rs".into()),
input: r#"
static HELLO: &str = "Hello, world!";
fn main() {
println!("{HELLO}");
}
"#
.into(),
},
output_dir: None, // Option<PathBuf>
output_file: None, // Option<PathBuf>
file_loader: None, // Option<Box<dyn FileLoader + Send + Sync>>
locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES.to_owned(),
lint_caps: FxHashMap::default(), // FxHashMap<lint::LintId, lint::Level>
// This is a callback from the driver that is called when [`ParseSess`] is created.
psess_created: None, //Option<Box<dyn FnOnce(&mut ParseSess) + Send>>
// This is a callback from the driver that is called when we're registering lints;
// it is called during plugin registration when we have the LintStore in a non-shared state.
//
// Note that if you find a Some here you probably want to call that function in the new
// function being registered.
register_lints: None, // Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>
// This is a callback from the driver that is called just after we have populated
// the list of queries.
//
// The second parameter is local providers and the third parameter is external providers.
override_queries: None, // Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)>
// Registry of diagnostics codes.
registry: registry::Registry::new(rustc_errors::codes::DIAGNOSTICS),
make_codegen_backend: None,
expanded_args: Vec::new(),
ice_file: None,
hash_untracked_state: None,
using_internal_features: Arc::default(),
};
rustc_interface::run_compiler(config, |compiler| {
// Parse the program and print the syntax tree.
let krate = rustc_interface::passes::parse(&compiler.sess);
println!("{krate:?}");
// Analyze the program and inspect the types of definitions.
rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| {
for id in tcx.hir().items() {
let hir = tcx.hir();
let item = hir.item(id);
match item.kind {
rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn(_, _, _) => {
let name = item.ident;
let ty = tcx.type_of(item.hir_id().owner.def_id);
println!("{name:?}:\t{ty:?}")
}
_ => (),
}
}
});
});
}

View File

@ -1,5 +1,6 @@
#![feature(rustc_private)] #![feature(rustc_private)]
extern crate rustc_data_structures;
extern crate rustc_driver; extern crate rustc_driver;
extern crate rustc_error_codes; extern crate rustc_error_codes;
extern crate rustc_errors; extern crate rustc_errors;
@ -9,16 +10,14 @@ extern crate rustc_interface;
extern crate rustc_session; extern crate rustc_session;
extern crate rustc_span; extern crate rustc_span;
use rustc_errors::{ use rustc_errors::emitter::Emitter;
emitter::Emitter, registry, translation::Translate, DiagCtxt, DiagInner, FluentBundle, use rustc_errors::registry::{self, Registry};
}; use rustc_errors::translation::Translate;
use rustc_errors::{DiagCtxt, DiagInner, FluentBundle};
use rustc_session::config; use rustc_session::config;
use rustc_span::source_map::SourceMap; use rustc_span::source_map::SourceMap;
use std::{ use std::sync::{Arc, Mutex};
path, process, str,
sync::{Arc, Mutex},
};
struct DebugEmitter { struct DebugEmitter {
source_map: Arc<SourceMap>, source_map: Arc<SourceMap>,
@ -26,7 +25,7 @@ struct DebugEmitter {
} }
impl Translate for DebugEmitter { impl Translate for DebugEmitter {
fn fluent_bundle(&self) -> Option<&Arc<FluentBundle>> { fn fluent_bundle(&self) -> Option<&FluentBundle> {
None None
} }
@ -36,29 +35,20 @@ impl Translate for DebugEmitter {
} }
impl Emitter for DebugEmitter { impl Emitter for DebugEmitter {
fn emit_diagnostic(&mut self, diag: DiagInner) { fn emit_diagnostic(&mut self, diag: DiagInner, _: &Registry) {
self.diagnostics.lock().unwrap().push(diag); self.diagnostics.lock().unwrap().push(diag);
} }
fn source_map(&self) -> Option<&Arc<SourceMap>> { fn source_map(&self) -> Option<&SourceMap> {
Some(&self.source_map) Some(&self.source_map)
} }
} }
fn main() { fn main() {
let out = process::Command::new("rustc")
.arg("--print=sysroot")
.current_dir(".")
.output()
.unwrap();
let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
let buffer: Arc<Mutex<Vec<DiagInner>>> = Arc::default(); let buffer: Arc<Mutex<Vec<DiagInner>>> = Arc::default();
let diagnostics = buffer.clone(); let diagnostics = buffer.clone();
let config = rustc_interface::Config { let config = rustc_interface::Config {
opts: config::Options { opts: config::Options::default(),
maybe_sysroot: Some(path::PathBuf::from(sysroot)),
..config::Options::default()
},
// This program contains a type error. // This program contains a type error.
input: config::Input::Str { input: config::Input::Str {
name: rustc_span::FileName::Custom("main.rs".into()), name: rustc_span::FileName::Custom("main.rs".into()),
@ -74,7 +64,7 @@ fn main() {
output_dir: None, output_dir: None,
output_file: None, output_file: None,
file_loader: None, file_loader: None,
locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES, locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES.to_owned(),
lint_caps: rustc_hash::FxHashMap::default(), lint_caps: rustc_hash::FxHashMap::default(),
psess_created: Some(Box::new(|parse_sess| { psess_created: Some(Box::new(|parse_sess| {
parse_sess.set_dcx(DiagCtxt::new(Box::new(DebugEmitter { parse_sess.set_dcx(DiagCtxt::new(Box::new(DebugEmitter {
@ -92,11 +82,10 @@ fn main() {
using_internal_features: Arc::default(), using_internal_features: Arc::default(),
}; };
rustc_interface::run_compiler(config, |compiler| { rustc_interface::run_compiler(config, |compiler| {
compiler.enter(|queries| { let krate = rustc_interface::passes::parse(&compiler.sess);
queries.global_ctxt().unwrap().enter(|tcx| { rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| {
// Run the analysis phase on the local crate to trigger the type error. // Run the analysis phase on the local crate to trigger the type error.
let _ = tcx.analysis(()); let _ = tcx.analysis(());
});
}); });
// If the compiler has encountered errors when this closure returns, it will abort (!) the program. // If the compiler has encountered errors when this closure returns, it will abort (!) the program.
// We avoid this by resetting the error count before returning // We avoid this by resetting the error count before returning

View File

@ -11,7 +11,7 @@ and run [`TyCtxt.analysis`].
The following was tested with <!-- date-check: september 2024 --> `nightly-2024-09-16`: The following was tested with <!-- date-check: september 2024 --> `nightly-2024-09-16`:
```rust ```rust
{{#include ../../examples/rustc-driver-getting-diagnostics.rs}} {{#include ../../examples/rustc-interface-getting-diagnostics.rs}}
``` ```
[`rustc_interface`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/index.html [`rustc_interface`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/index.html

View File

@ -1,16 +1,15 @@
# Example: Type checking through `rustc_interface` # Example: Type checking through `rustc_driver`
The [`rustc_interface`] allows you to interact with Rust code at various stages of compilation. [`rustc_driver`] allows you to interact with Rust code at various stages of compilation.
## Getting the type of an expression ## Getting the type of an expression
To get the type of an expression, use the [`global_ctxt`] query to [get] a [`TyCtxt`]. To get the type of an expression, use the [`after_analysis`] callback to get a [`TyCtxt`].
The following was tested with <!-- date-check: may 2024 --> `nightly-2024-05-09`: The following was tested with <!-- date-check: december 2024 --> `nightly-2024-12-15`:
```rust ```rust
{{#include ../../examples/rustc-driver-interacting-with-the-ast.rs}} {{#include ../../examples/rustc-driver-interacting-with-the-ast.rs}}
``` ```
[get]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.GlobalCtxt.html#method.enter [`after_analysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html#method.after_analysis
[`global_ctxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/queries/struct.Queries.html#method.global_ctxt [`rustc_driver`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver
[`rustc_interface`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface
[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html [`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html

View File

@ -1,35 +1,30 @@
# `rustc_driver` and `rustc_interface` # `rustc_driver` and `rustc_interface`
## `rustc_driver`
The [`rustc_driver`] is essentially `rustc`'s `main` function. The [`rustc_driver`] is essentially `rustc`'s `main` function.
It acts as the glue for running the various phases of the compiler in the correct order, It acts as the glue for running the various phases of the compiler in the correct order,
using the interface defined in the [`rustc_interface`] crate. using the interface defined in the [`rustc_interface`] crate. Where possible, using [`rustc_driver`] rather than [`rustc_interface`] is recommended.
Generally the [`rustc_interface`] crate provides external users with an (unstable) API The main entry point of [`rustc_driver`] is [`rustc_driver::RunCompiler`][rd_rc].
for running code at particular times during the compilation process, allowing This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`][cb] and a couple of other optional options.
third parties to effectively use `rustc`'s internals as a library for [`Callbacks`][cb] is a `trait` that allows for custom compiler configuration,
analyzing a crate or for ad hoc emulating of the compiler (i.e. `rustdoc` as well as allowing custom code to run after different phases of the compilation.
compiling code and serving output).
More specifically the [`rustc_interface::run_compiler`][i_rc] function is the ## `rustc_interface`
main entrypoint for using [`nightly-rustc`] as a library.
Initially [`run_compiler`][i_rc] takes a configuration variable for the compiler The [`rustc_interface`] crate provides a low level API to external users for manually driving the compilation process,
allowing third parties to effectively use `rustc`'s internals as a library for analyzing a crate or for ad hoc emulating of the compiler for cases where [`rustc_driver`] is not flexible enough (i.e. `rustdoc` compiling code and serving output).
The main entry point of [`rustc_interface`] ([`rustc_interface::run_compiler`][i_rc]) takes a configuration variable for the compiler
and a `closure` taking a yet unresolved [`Compiler`]. and a `closure` taking a yet unresolved [`Compiler`].
Operationally [`run_compiler`][i_rc] creates a `Compiler` from the configuration and passes [`run_compiler`][i_rc] creates a `Compiler` from the configuration and passes it to the `closure`.
it to the `closure`. Inside the `closure` you can use the `Compiler` to drive Inside the `closure` you can use the `Compiler` to call various functions to compile a crate and get the results.
queries to compile a crate and get the results.
Providing results about the internal state of the compiler what the [`rustc_driver`] does too.
You can see a minimal example of how to use [`rustc_interface`] [here][example]. You can see a minimal example of how to use [`rustc_interface`] [here][example].
You can see what queries are currently available in the [`Compiler`] rustdocs. You can see an example of how to use the various functions using [`rustc_interface`] needs by looking at the `rustc_driver` implementation,
You can see an example of how to use the queries by looking at the `rustc_driver` implementation, specifically [`rustc_driver_impl::run_compiler`][rdi_rc]
specifically [`rustc_driver::run_compiler`][rd_rc]
(not to be confused with [`rustc_interface::run_compiler`][i_rc]). (not to be confused with [`rustc_interface::run_compiler`][i_rc]).
Generally [`rustc_driver::run_compiler`][i_rc] takes a bunch of command-line args
and some other configurations and drives the compilation to completion.
Finally [`rustc_driver::run_compiler`][rd_rc] also takes a [`Callbacks`][cb],
which is a `trait` that allows for custom compiler configuration,
as well as allowing custom code to run after different phases of the compilation.
> **Warning:** By its very nature, the internal compiler APIs are always going > **Warning:** By its very nature, the internal compiler APIs are always going
> to be unstable. That said, we do try not to break things unnecessarily. > to be unstable. That said, we do try not to break things unnecessarily.
@ -43,8 +38,9 @@ as well as allowing custom code to run after different phases of the compilation
[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html [`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html
[Appendix A]: appendix/stupid-stats.html [Appendix A]: appendix/stupid-stats.html
[cb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html [cb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html
[example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-driver-example.rs [example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-interface-example.rs
[i_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/fn.run_compiler.html [i_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/fn.run_compiler.html
[rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver_impl/fn.run_compiler.html [rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/struct.RunCompiler.html
[rdi_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver_impl/fn.run_compiler.html
[stupid-stats]: https://github.com/nrc/stupid-stats [stupid-stats]: https://github.com/nrc/stupid-stats
[`nightly-rustc`]: https://doc.rust-lang.org/nightly/nightly-rustc/ [`nightly-rustc`]: https://doc.rust-lang.org/nightly/nightly-rustc/