Skip to content

Commit 0a3ac2d

Browse files
georgewfrasermark-i-m
authored andcommitted
Reference complete examples
1 parent 718047c commit 0a3ac2d

5 files changed

+222
-133
lines changed

examples/rustc-driver-example.rs

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
#![feature(rustc_private)]
22

3+
// NOTE: For the example to compile, you will need to first run the following:
4+
// rustup component add rustc-dev
5+
36
extern crate rustc;
47
extern crate rustc_error_codes;
58
extern crate rustc_errors;
69
extern crate rustc_hash;
710
extern crate rustc_hir;
811
extern crate rustc_interface;
12+
extern crate rustc_session;
913
extern crate rustc_span;
1014

11-
use rustc::session;
12-
use rustc::session::config;
1315
use rustc_errors::registry;
1416
use rustc_hash::{FxHashMap, FxHashSet};
17+
use rustc_session::config;
1518
use rustc_span::source_map;
1619
use std::path;
1720
use std::process;
@@ -24,60 +27,41 @@ fn main() {
2427
.output()
2528
.unwrap();
2629
let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
27-
let filename = "main.rs";
28-
let contents = "static HELLO: &str = \"Hello, world!\"; fn main() { println!(\"{}\", HELLO); }";
29-
let errors = registry::Registry::new(&rustc_error_codes::DIAGNOSTICS);
3030
let config = rustc_interface::Config {
3131
// Command line options
3232
opts: config::Options {
3333
maybe_sysroot: Some(path::PathBuf::from(sysroot)),
3434
..config::Options::default()
3535
},
36-
3736
// cfg! configuration in addition to the default ones
38-
// FxHashSet<(String, Option<String>)>
39-
crate_cfg: FxHashSet::default(),
40-
37+
crate_cfg: FxHashSet::default(), // FxHashSet<(String, Option<String>)>
4138
input: config::Input::Str {
42-
name: source_map::FileName::Custom(String::from(filename)),
43-
input: String::from(contents),
39+
name: source_map::FileName::Custom("main.rs".to_string()),
40+
input: "static HELLO: &str = \"Hello, world!\"; fn main() { println!(\"{}\", HELLO); }"
41+
.to_string(),
4442
},
45-
// Option<PathBuf>
46-
input_path: None,
47-
// Option<PathBuf>
48-
output_dir: None,
49-
// Option<PathBuf>
50-
output_file: None,
51-
// Option<Box<dyn FileLoader + Send + Sync>>
52-
file_loader: None,
53-
diagnostic_output: session::DiagnosticOutput::Default,
54-
43+
input_path: None, // Option<PathBuf>
44+
output_dir: None, // Option<PathBuf>
45+
output_file: None, // Option<PathBuf>
46+
file_loader: None, // Option<Box<dyn FileLoader + Send + Sync>>
47+
diagnostic_output: rustc_session::DiagnosticOutput::Default,
5548
// Set to capture stderr output during compiler execution
56-
// Option<Arc<Mutex<Vec<u8>>>>
57-
stderr: None,
58-
59-
// Option<String>
60-
crate_name: None,
61-
// FxHashMap<lint::LintId, lint::Level>
62-
lint_caps: FxHashMap::default(),
63-
49+
stderr: None, // Option<Arc<Mutex<Vec<u8>>>>
50+
crate_name: None, // Option<String>
51+
lint_caps: FxHashMap::default(), // FxHashMap<lint::LintId, lint::Level>
6452
// This is a callback from the driver that is called when we're registering lints;
6553
// it is called during plugin registration when we have the LintStore in a non-shared state.
6654
//
6755
// Note that if you find a Some here you probably want to call that function in the new
6856
// function being registered.
69-
// Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>
70-
register_lints: None,
71-
57+
register_lints: None, // Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>
7258
// This is a callback from the driver that is called just after we have populated
7359
// the list of queries.
7460
//
7561
// The second parameter is local providers and the third parameter is external providers.
76-
// Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)>
77-
override_queries: None,
78-
62+
override_queries: None, // Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)>
7963
// Registry of diagnostics codes.
80-
registry: errors,
64+
registry: registry::Registry::new(&rustc_error_codes::DIAGNOSTICS),
8165
};
8266
rustc_interface::run_compiler(config, |compiler| {
8367
compiler.enter(|queries| {
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#![feature(rustc_private)]
2+
3+
// NOTE: For the example to compile, you will need to first run the following:
4+
// rustup component add rustc-dev
5+
6+
extern crate rustc;
7+
extern crate rustc_error_codes;
8+
extern crate rustc_errors;
9+
extern crate rustc_hash;
10+
extern crate rustc_hir;
11+
extern crate rustc_interface;
12+
extern crate rustc_session;
13+
extern crate rustc_span;
14+
15+
use rustc_errors::registry;
16+
use rustc_session::config;
17+
use rustc_span::source_map;
18+
use std::io;
19+
use std::path;
20+
use std::process;
21+
use std::str;
22+
use std::sync;
23+
24+
// Buffer diagnostics in a Vec<u8>.
25+
#[derive(Clone)]
26+
pub struct DiagnosticSink(sync::Arc<sync::Mutex<Vec<u8>>>);
27+
28+
impl io::Write for DiagnosticSink {
29+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
30+
self.0.lock().unwrap().write(buf)
31+
}
32+
fn flush(&mut self) -> io::Result<()> {
33+
self.0.lock().unwrap().flush()
34+
}
35+
}
36+
37+
fn main() {
38+
let out = process::Command::new("rustc")
39+
.arg("--print=sysroot")
40+
.current_dir(".")
41+
.output()
42+
.unwrap();
43+
let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
44+
let buffer = sync::Arc::new(sync::Mutex::new(Vec::new()));
45+
let config = rustc_interface::Config {
46+
opts: config::Options {
47+
maybe_sysroot: Some(path::PathBuf::from(sysroot)),
48+
// Configure the compiler to emit diagnostics in compact JSON format.
49+
error_format: config::ErrorOutputType::Json {
50+
pretty: false,
51+
json_rendered: rustc_errors::emitter::HumanReadableErrorType::Default(
52+
rustc_errors::emitter::ColorConfig::Never,
53+
),
54+
},
55+
..config::Options::default()
56+
},
57+
// This program contains a type error.
58+
input: config::Input::Str {
59+
name: source_map::FileName::Custom("main.rs".to_string()),
60+
input: "fn main() { let x: &str = 1; }".to_string(),
61+
},
62+
// Redirect the diagnostic output of the compiler to a buffer.
63+
diagnostic_output: rustc_session::DiagnosticOutput::Raw(Box::from(DiagnosticSink(
64+
buffer.clone(),
65+
))),
66+
crate_cfg: rustc_hash::FxHashSet::default(),
67+
input_path: None,
68+
output_dir: None,
69+
output_file: None,
70+
file_loader: None,
71+
stderr: None,
72+
crate_name: None,
73+
lint_caps: rustc_hash::FxHashMap::default(),
74+
register_lints: None,
75+
override_queries: None,
76+
registry: registry::Registry::new(&rustc_error_codes::DIAGNOSTICS),
77+
};
78+
rustc_interface::run_compiler(config, |compiler| {
79+
compiler.enter(|queries| {
80+
queries.global_ctxt().unwrap().take().enter(|tcx| {
81+
// Run the analysis phase on the local crate to trigger the type error.
82+
tcx.analysis(rustc_hir::def_id::LOCAL_CRATE);
83+
});
84+
});
85+
});
86+
// Read buffered diagnostics.
87+
let diagnostics = String::from_utf8(buffer.lock().unwrap().clone()).unwrap();
88+
println!("{}", diagnostics);
89+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#![feature(rustc_private)]
2+
3+
// NOTE: For the example to compile, you will need to first run the following:
4+
// rustup component add rustc-dev
5+
6+
extern crate rustc;
7+
extern crate rustc_error_codes;
8+
extern crate rustc_errors;
9+
extern crate rustc_hash;
10+
extern crate rustc_hir;
11+
extern crate rustc_interface;
12+
extern crate rustc_session;
13+
extern crate rustc_span;
14+
15+
use rustc_errors::registry;
16+
use rustc_session::config;
17+
use rustc_span::source_map;
18+
use std::path;
19+
use std::process;
20+
use std::str;
21+
22+
fn main() {
23+
let out = process::Command::new("rustc")
24+
.arg("--print=sysroot")
25+
.current_dir(".")
26+
.output()
27+
.unwrap();
28+
let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
29+
let config = rustc_interface::Config {
30+
opts: config::Options {
31+
maybe_sysroot: Some(path::PathBuf::from(sysroot)),
32+
..config::Options::default()
33+
},
34+
input: config::Input::Str {
35+
name: source_map::FileName::Custom("main.rs".to_string()),
36+
input: "fn main() { let message = \"Hello, world!\"; println!(\"{}\", message); }"
37+
.to_string(),
38+
},
39+
diagnostic_output: rustc_session::DiagnosticOutput::Default,
40+
crate_cfg: rustc_hash::FxHashSet::default(),
41+
input_path: None,
42+
output_dir: None,
43+
output_file: None,
44+
file_loader: None,
45+
stderr: None,
46+
crate_name: None,
47+
lint_caps: rustc_hash::FxHashMap::default(),
48+
register_lints: None,
49+
override_queries: None,
50+
registry: registry::Registry::new(&rustc_error_codes::DIAGNOSTICS),
51+
};
52+
rustc_interface::run_compiler(config, |compiler| {
53+
compiler.enter(|queries| {
54+
// Analyze the crate and inspect the types under the cursor.
55+
queries.global_ctxt().unwrap().take().enter(|tcx| {
56+
// Every compilation contains a single crate.
57+
let krate = tcx.hir().krate();
58+
// Iterate over the top-level items in the crate, looking for the main function.
59+
for (_, item) in &krate.items {
60+
// Use pattern-matching to find a specific node inside the main function.
61+
if let rustc_hir::ItemKind::Fn(_, _, body_id) = item.kind {
62+
let expr = &tcx.hir().body(body_id).value;
63+
if let rustc_hir::ExprKind::Block(block, _) = expr.kind {
64+
if let rustc_hir::StmtKind::Local(local) = block.stmts[0].kind {
65+
if let Some(expr) = local.init {
66+
let hir_id = expr.hir_id; // hir_id identifies the string "Hello, world!"
67+
let def_id = tcx.hir().local_def_id(item.hir_id); // def_id identifies the main function
68+
let ty = tcx.typeck_tables_of(def_id).node_type(hir_id);
69+
println!("{:?}: {:?}", expr, ty); // prints expr(HirId { owner: DefIndex(3), local_id: 4 }: "Hello, world!"): &'static str
70+
}
71+
}
72+
}
73+
}
74+
}
75+
})
76+
});
77+
});
78+
}

src/rustc-driver-getting-diagnostics.md

Lines changed: 26 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -4,100 +4,38 @@
44

55
## Getting diagnostics
66

7-
NOTE: For the example to compile, you will need to first run the following:
8-
9-
rustup component add rustc-dev
10-
117
To get diagnostics from the compiler,
128
configure `rustc_interface::Config` to output diagnostic to a buffer,
139
and run `TyCtxt.analysis`:
1410

1511
```rust
16-
#![feature(rustc_private)]
17-
18-
extern crate rustc;
19-
extern crate rustc_error_codes;
20-
extern crate rustc_errors;
21-
extern crate rustc_hash;
22-
extern crate rustc_hir;
23-
extern crate rustc_interface;
24-
extern crate rustc_session;
25-
extern crate rustc_span;
26-
27-
use rustc_errors::registry;
28-
use rustc_session::config;
29-
use rustc_span::source_map;
30-
use std::io;
31-
use std::path;
32-
use std::process;
33-
use std::str;
34-
use std::sync;
35-
36-
// Buffer diagnostics in a Vec<u8>.
37-
#[derive(Clone)]
38-
pub struct DiagnosticSink(sync::Arc<sync::Mutex<Vec<u8>>>);
39-
40-
impl io::Write for DiagnosticSink {
41-
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
42-
self.0.lock().unwrap().write(buf)
43-
}
44-
fn flush(&mut self) -> io::Result<()> {
45-
self.0.lock().unwrap().flush()
46-
}
47-
}
48-
49-
fn main() {
50-
let out = process::Command::new("rustc")
51-
.arg("--print=sysroot")
52-
.current_dir(".")
53-
.output()
54-
.unwrap();
55-
let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
56-
let buffer = sync::Arc::new(sync::Mutex::new(Vec::new()));
57-
let config = rustc_interface::Config {
58-
opts: config::Options {
59-
maybe_sysroot: Some(path::PathBuf::from(sysroot)),
60-
// Configure the compiler to emit diagnostics in compact JSON format.
61-
error_format: config::ErrorOutputType::Json {
62-
pretty: false,
63-
json_rendered: rustc_errors::emitter::HumanReadableErrorType::Default(
64-
rustc_errors::emitter::ColorConfig::Never,
65-
),
66-
},
67-
..config::Options::default()
12+
// See https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-driver-getting-diagnostics.rs for complete program.
13+
let buffer = sync::Arc::new(sync::Mutex::new(Vec::new()));
14+
let config = rustc_interface::Config {
15+
opts: config::Options {
16+
// Configure the compiler to emit diagnostics in compact JSON format.
17+
error_format: config::ErrorOutputType::Json {
18+
pretty: false,
19+
json_rendered: rustc_errors::emitter::HumanReadableErrorType::Default(
20+
rustc_errors::emitter::ColorConfig::Never,
21+
),
6822
},
69-
// This program contains a type error.
70-
input: config::Input::Str {
71-
name: source_map::FileName::Custom("main.rs".to_string()),
72-
input: "fn main() { let x: &str = 1; }".to_string(),
73-
},
74-
// Redirect the diagnostic output of the compiler to a buffer.
75-
diagnostic_output: rustc_session::DiagnosticOutput::Raw(Box::from(DiagnosticSink(
76-
buffer.clone(),
77-
))),
78-
crate_cfg: rustc_hash::FxHashSet::default(),
79-
input_path: None,
80-
output_dir: None,
81-
output_file: None,
82-
file_loader: None,
83-
stderr: None,
84-
crate_name: None,
85-
lint_caps: rustc_hash::FxHashMap::default(),
86-
register_lints: None,
87-
override_queries: None,
88-
registry: registry::Registry::new(&rustc_error_codes::DIAGNOSTICS),
89-
};
90-
rustc_interface::run_compiler(config, |compiler| {
91-
compiler.enter(|queries| {
92-
queries.global_ctxt().unwrap().take().enter(|tcx| {
93-
// Run the analysis phase on the local crate to trigger the type error.
94-
tcx.analysis(rustc_hir::def_id::LOCAL_CRATE);
95-
});
23+
/* other config */
24+
},
25+
// Redirect the diagnostic output of the compiler to a buffer.
26+
diagnostic_output: rustc_session::DiagnosticOutput::Raw(Box::from(DiagnosticSink(
27+
buffer.clone(),
28+
))),
29+
/* other config */
30+
};
31+
rustc_interface::run_compiler(config, |compiler| {
32+
compiler.enter(|queries| {
33+
queries.global_ctxt().unwrap().take().enter(|tcx| {
34+
// Run the analysis phase on the local crate to trigger the type error.
35+
tcx.analysis(rustc_hir::def_id::LOCAL_CRATE);
9636
});
9737
});
98-
// Read and print buffered diagnostics.
99-
let diagnostics = String::from_utf8(buffer.lock().unwrap().clone()).unwrap();
100-
println!("{}", diagnostics);
101-
}
102-
38+
});
39+
// Read buffered diagnostics.
40+
let diagnostics = String::from_utf8(buffer.lock().unwrap().clone()).unwrap();
10341
```

0 commit comments

Comments
 (0)