Rework the driver docs (#2162)
This commit is contained in:
parent
4e746875ed
commit
e70f551db6
|
|
@ -1,92 +1,92 @@
|
|||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_ast_pretty;
|
||||
extern crate rustc_data_structures;
|
||||
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_middle;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
|
||||
use std::{path, process, str, sync::Arc};
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use rustc_errors::registry;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustc_session::config;
|
||||
use rustc_ast_pretty::pprust::item_to_string;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
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() {
|
||||
let out = process::Command::new("rustc")
|
||||
.arg("--print=sysroot")
|
||||
.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}");
|
||||
let message = "Hello, World!";
|
||||
println!("{message}");
|
||||
}
|
||||
"#
|
||||
.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,
|
||||
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| {
|
||||
compiler.enter(|queries| {
|
||||
// Parse the program and print the syntax tree.
|
||||
let parse = queries.parse().unwrap().get_mut().clone();
|
||||
println!("{parse:?}");
|
||||
// Analyze the program and inspect the types of definitions.
|
||||
queries.global_ctxt().unwrap().enter(|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:?}")
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
.to_string())
|
||||
} else {
|
||||
Err(io::Error::other("oops"))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_binary_file(&self, _path: &Path) -> io::Result<Lrc<[u8]>> {
|
||||
Err(io::Error::other("oops"))
|
||||
}
|
||||
}
|
||||
|
||||
struct MyCallbacks;
|
||||
|
||||
impl rustc_driver::Callbacks for MyCallbacks {
|
||||
fn after_crate_root_parsing(
|
||||
&mut self,
|
||||
_compiler: &Compiler,
|
||||
krate: &rustc_ast::Crate,
|
||||
) -> Compilation {
|
||||
for item in &krate.items {
|
||||
println!("{}", item_to_string(&item));
|
||||
}
|
||||
|
||||
Compilation::Continue
|
||||
}
|
||||
|
||||
fn after_analysis(&mut self, _compiler: &Compiler, tcx: TyCtxt<'_>) -> Compilation {
|
||||
// Analyze the program and inspect the types of definitions.
|
||||
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:?}")
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,90 +1,99 @@
|
|||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_ast_pretty;
|
||||
extern crate rustc_data_structures;
|
||||
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_middle;
|
||||
extern crate rustc_session;
|
||||
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_errors::registry;
|
||||
use rustc_session::config;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_driver::{Compilation, RunCompiler};
|
||||
use rustc_interface::interface::Compiler;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
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 config = rustc_interface::Config {
|
||||
opts: config::Options {
|
||||
maybe_sysroot: Some(path::PathBuf::from(sysroot)),
|
||||
..config::Options::default()
|
||||
},
|
||||
input: config::Input::Str {
|
||||
name: rustc_span::FileName::Custom("main.rs".to_string()),
|
||||
input: r#"
|
||||
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() {
|
||||
let message = "Hello, World!";
|
||||
println!("{message}");
|
||||
}
|
||||
"#
|
||||
.to_string(),
|
||||
},
|
||||
crate_cfg: Vec::new(),
|
||||
crate_check_cfg: Vec::new(),
|
||||
output_dir: None,
|
||||
output_file: None,
|
||||
file_loader: None,
|
||||
locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES,
|
||||
lint_caps: rustc_hash::FxHashMap::default(),
|
||||
psess_created: None,
|
||||
register_lints: None,
|
||||
override_queries: None,
|
||||
make_codegen_backend: None,
|
||||
registry: registry::Registry::new(rustc_errors::codes::DIAGNOSTICS),
|
||||
expanded_args: Vec::new(),
|
||||
ice_file: None,
|
||||
hash_untracked_state: None,
|
||||
using_internal_features: Arc::default(),
|
||||
};
|
||||
rustc_interface::run_compiler(config, |compiler| {
|
||||
compiler.enter(|queries| {
|
||||
// TODO: add this to -Z unpretty
|
||||
let ast_krate = queries.parse().unwrap().get_mut().clone();
|
||||
for item in ast_krate.items {
|
||||
println!("{}", item_to_string(&item));
|
||||
}
|
||||
// Analyze the crate and inspect the types under the cursor.
|
||||
queries.global_ctxt().unwrap().enter(|tcx| {
|
||||
// Every compilation contains a single crate.
|
||||
let hir_krate = tcx.hir();
|
||||
// Iterate over the top-level items in the crate, looking for the main function.
|
||||
for id in hir_krate.items() {
|
||||
let item = hir_krate.item(id);
|
||||
// Use pattern-matching to find a specific node inside the main function.
|
||||
if let rustc_hir::ItemKind::Fn(_, _, body_id) = item.kind {
|
||||
let expr = &tcx.hir().body(body_id).value;
|
||||
if let rustc_hir::ExprKind::Block(block, _) = expr.kind {
|
||||
if let rustc_hir::StmtKind::Let(let_stmt) = block.stmts[0].kind {
|
||||
if let Some(expr) = let_stmt.init {
|
||||
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 ty = tcx.typeck(def_id).node_type(hir_id);
|
||||
println!("{expr:#?}: {ty:?}");
|
||||
}
|
||||
}
|
||||
.to_string())
|
||||
} else {
|
||||
Err(io::Error::other("oops"))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_binary_file(&self, _path: &Path) -> io::Result<Lrc<[u8]>> {
|
||||
Err(io::Error::other("oops"))
|
||||
}
|
||||
}
|
||||
|
||||
struct MyCallbacks;
|
||||
|
||||
impl rustc_driver::Callbacks for MyCallbacks {
|
||||
fn after_crate_root_parsing(
|
||||
&mut self,
|
||||
_compiler: &Compiler,
|
||||
krate: &rustc_ast::Crate,
|
||||
) -> Compilation {
|
||||
for item in &krate.items {
|
||||
println!("{}", item_to_string(&item));
|
||||
}
|
||||
|
||||
Compilation::Continue
|
||||
}
|
||||
|
||||
fn after_analysis(&mut self, _compiler: &Compiler, tcx: TyCtxt<'_>) -> Compilation {
|
||||
// Every compilation contains a single crate.
|
||||
let hir_krate = tcx.hir();
|
||||
// Iterate over the top-level items in the crate, looking for the main function.
|
||||
for id in hir_krate.items() {
|
||||
let item = hir_krate.item(id);
|
||||
// Use pattern-matching to find a specific node inside the main function.
|
||||
if let rustc_hir::ItemKind::Fn(_, _, body_id) = item.kind {
|
||||
let expr = &tcx.hir().body(body_id).value;
|
||||
if let rustc_hir::ExprKind::Block(block, _) = expr.kind {
|
||||
if let rustc_hir::StmtKind::Let(let_stmt) = block.stmts[0].kind {
|
||||
if let Some(expr) = let_stmt.init {
|
||||
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 ty = tcx.typeck(def_id).node_type(hir_id);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:?}")
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_error_codes;
|
||||
extern crate rustc_errors;
|
||||
|
|
@ -9,16 +10,14 @@ extern crate rustc_interface;
|
|||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
|
||||
use rustc_errors::{
|
||||
emitter::Emitter, registry, translation::Translate, DiagCtxt, DiagInner, FluentBundle,
|
||||
};
|
||||
use rustc_errors::emitter::Emitter;
|
||||
use rustc_errors::registry::{self, Registry};
|
||||
use rustc_errors::translation::Translate;
|
||||
use rustc_errors::{DiagCtxt, DiagInner, FluentBundle};
|
||||
use rustc_session::config;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
|
||||
use std::{
|
||||
path, process, str,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
struct DebugEmitter {
|
||||
source_map: Arc<SourceMap>,
|
||||
|
|
@ -26,7 +25,7 @@ struct DebugEmitter {
|
|||
}
|
||||
|
||||
impl Translate for DebugEmitter {
|
||||
fn fluent_bundle(&self) -> Option<&Arc<FluentBundle>> {
|
||||
fn fluent_bundle(&self) -> Option<&FluentBundle> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
@ -36,29 +35,20 @@ impl Translate 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);
|
||||
}
|
||||
|
||||
fn source_map(&self) -> Option<&Arc<SourceMap>> {
|
||||
fn source_map(&self) -> Option<&SourceMap> {
|
||||
Some(&self.source_map)
|
||||
}
|
||||
}
|
||||
|
||||
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 diagnostics = buffer.clone();
|
||||
let config = rustc_interface::Config {
|
||||
opts: config::Options {
|
||||
maybe_sysroot: Some(path::PathBuf::from(sysroot)),
|
||||
..config::Options::default()
|
||||
},
|
||||
opts: config::Options::default(),
|
||||
// This program contains a type error.
|
||||
input: config::Input::Str {
|
||||
name: rustc_span::FileName::Custom("main.rs".into()),
|
||||
|
|
@ -74,7 +64,7 @@ fn main() {
|
|||
output_dir: None,
|
||||
output_file: 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(),
|
||||
psess_created: Some(Box::new(|parse_sess| {
|
||||
parse_sess.set_dcx(DiagCtxt::new(Box::new(DebugEmitter {
|
||||
|
|
@ -92,11 +82,10 @@ fn main() {
|
|||
using_internal_features: Arc::default(),
|
||||
};
|
||||
rustc_interface::run_compiler(config, |compiler| {
|
||||
compiler.enter(|queries| {
|
||||
queries.global_ctxt().unwrap().enter(|tcx| {
|
||||
// Run the analysis phase on the local crate to trigger the type error.
|
||||
let _ = tcx.analysis(());
|
||||
});
|
||||
let krate = rustc_interface::passes::parse(&compiler.sess);
|
||||
rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| {
|
||||
// Run the analysis phase on the local crate to trigger the type error.
|
||||
let _ = tcx.analysis(());
|
||||
});
|
||||
// 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
|
||||
|
|
@ -11,7 +11,7 @@ and run [`TyCtxt.analysis`].
|
|||
The following was tested with <!-- date-check: september 2024 --> `nightly-2024-09-16`:
|
||||
|
||||
```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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
To get the type of an expression, use the [`global_ctxt`] query to [get] a [`TyCtxt`].
|
||||
The following was tested with <!-- date-check: may 2024 --> `nightly-2024-05-09`:
|
||||
To get the type of an expression, use the [`after_analysis`] callback to get a [`TyCtxt`].
|
||||
The following was tested with <!-- date-check: december 2024 --> `nightly-2024-12-15`:
|
||||
|
||||
```rust
|
||||
{{#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
|
||||
[`global_ctxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/queries/struct.Queries.html#method.global_ctxt
|
||||
[`rustc_interface`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface
|
||||
[`after_analysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html#method.after_analysis
|
||||
[`rustc_driver`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver
|
||||
[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
|
||||
|
|
|
|||
|
|
@ -1,35 +1,30 @@
|
|||
# `rustc_driver` and `rustc_interface`
|
||||
|
||||
## `rustc_driver`
|
||||
|
||||
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,
|
||||
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
|
||||
for running code at particular times during 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 (i.e. `rustdoc`
|
||||
compiling code and serving output).
|
||||
The main entry point of [`rustc_driver`] is [`rustc_driver::RunCompiler`][rd_rc].
|
||||
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.
|
||||
[`Callbacks`][cb] is a `trait` that allows for custom compiler configuration,
|
||||
as well as allowing custom code to run after different phases of the compilation.
|
||||
|
||||
More specifically the [`rustc_interface::run_compiler`][i_rc] function is the
|
||||
main entrypoint for using [`nightly-rustc`] as a library.
|
||||
Initially [`run_compiler`][i_rc] takes a configuration variable for the compiler
|
||||
## `rustc_interface`
|
||||
|
||||
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`].
|
||||
Operationally [`run_compiler`][i_rc] creates a `Compiler` from the configuration and passes
|
||||
it to the `closure`. Inside the `closure` you can use the `Compiler` to drive
|
||||
queries to compile a crate and get the results.
|
||||
Providing results about the internal state of the compiler what the [`rustc_driver`] does too.
|
||||
[`run_compiler`][i_rc] creates a `Compiler` from the configuration and passes it to the `closure`.
|
||||
Inside the `closure` you can use the `Compiler` to call various functions to compile a crate and get the results.
|
||||
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 queries by looking at the `rustc_driver` implementation,
|
||||
specifically [`rustc_driver::run_compiler`][rd_rc]
|
||||
You can see an example of how to use the various functions using [`rustc_interface`] needs by looking at the `rustc_driver` implementation,
|
||||
specifically [`rustc_driver_impl::run_compiler`][rdi_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
|
||||
> 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
|
||||
[Appendix A]: appendix/stupid-stats.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
|
||||
[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
|
||||
[`nightly-rustc`]: https://doc.rust-lang.org/nightly/nightly-rustc/
|
||||
|
|
|
|||
Loading…
Reference in New Issue