Use the new rustc interface
This commit is contained in:
parent
e66d6ec58b
commit
7d142ecf75
3 changed files with 105 additions and 219 deletions
|
|
@ -2,18 +2,39 @@ extern crate getopts;
|
|||
extern crate miri;
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_interface;
|
||||
extern crate test;
|
||||
|
||||
use rustc_driver::{driver, Compilation};
|
||||
use self::miri::eval_main;
|
||||
use rustc::hir::def_id::LOCAL_CRATE;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use miri::{MiriConfig, eval_main};
|
||||
|
||||
use rustc_interface::interface;
|
||||
use crate::test::Bencher;
|
||||
|
||||
pub struct MiriCompilerCalls<'a>(Rc<RefCell<&'a mut Bencher>>);
|
||||
struct MiriCompilerCalls<'a> {
|
||||
bencher: &'a mut Bencher,
|
||||
}
|
||||
|
||||
impl rustc_driver::Callbacks for MiriCompilerCalls<'_> {
|
||||
fn after_analysis(&mut self, compiler: &interface::Compiler<'_>) -> bool {
|
||||
compiler.session().abort_if_errors();
|
||||
|
||||
compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
|
||||
let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect(
|
||||
"no main or start function found",
|
||||
);
|
||||
|
||||
self.bencher.iter(|| {
|
||||
let config = MiriConfig { validate: true, args: vec![] };
|
||||
eval_main(tcx, entry_def_id, config);
|
||||
});
|
||||
});
|
||||
|
||||
compiler.session().abort_if_errors();
|
||||
|
||||
// Don't continue execution
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn find_sysroot() -> String {
|
||||
// Taken from https://github.com/Manishearth/rust-clippy/pull/911.
|
||||
|
|
@ -38,26 +59,5 @@ pub fn run(filename: &str, bencher: &mut Bencher) {
|
|||
"--sysroot".to_string(),
|
||||
find_sysroot(),
|
||||
];
|
||||
let bencher = RefCell::new(bencher);
|
||||
|
||||
let mut control = driver::CompileController::basic();
|
||||
|
||||
control.after_analysis.stop = Compilation::Stop;
|
||||
control.after_analysis.callback = Box::new(move |state| {
|
||||
state.session.abort_if_errors();
|
||||
|
||||
let tcx = state.tcx.unwrap();
|
||||
let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect(
|
||||
"no main or start function found",
|
||||
);
|
||||
|
||||
bencher.borrow_mut().iter(|| {
|
||||
let config = MiriConfig { validate: true, args: vec![] };
|
||||
eval_main(tcx, entry_def_id, config);
|
||||
});
|
||||
|
||||
state.session.abort_if_errors();
|
||||
});
|
||||
|
||||
rustc_driver::run_compiler(args, Box::new(control), None, None);
|
||||
rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ extern crate rustc_metadata;
|
|||
extern crate rustc_driver;
|
||||
extern crate rustc_errors;
|
||||
extern crate rustc_codegen_utils;
|
||||
extern crate rustc_interface;
|
||||
extern crate syntax;
|
||||
|
||||
use std::path::{PathBuf, Path};
|
||||
|
|
@ -15,12 +16,10 @@ use std::io;
|
|||
|
||||
|
||||
use rustc::session::Session;
|
||||
use rustc_interface::interface;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
|
||||
use rustc_driver::driver::{CompileState, CompileController};
|
||||
use rustc::session::config::{self, Input, ErrorOutputType};
|
||||
use rustc::hir::{self, itemlikevisit};
|
||||
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||
use rustc::ty::TyCtxt;
|
||||
use syntax::ast;
|
||||
use rustc::hir::def_id::LOCAL_CRATE;
|
||||
|
|
@ -28,93 +27,55 @@ use rustc::hir::def_id::LOCAL_CRATE;
|
|||
use miri::MiriConfig;
|
||||
|
||||
struct MiriCompilerCalls {
|
||||
default: Box<RustcDefaultCalls>,
|
||||
/// whether we are building for the host
|
||||
host_target: bool,
|
||||
}
|
||||
|
||||
impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
|
||||
fn early_callback(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
descriptions: &rustc_errors::registry::Registry,
|
||||
output: ErrorOutputType
|
||||
) -> Compilation {
|
||||
self.default.early_callback(matches, sopts, cfg, descriptions, output)
|
||||
}
|
||||
fn no_input(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
descriptions: &rustc_errors::registry::Registry
|
||||
) -> Option<(Input, Option<PathBuf>)> {
|
||||
self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions)
|
||||
}
|
||||
fn late_callback(
|
||||
&mut self,
|
||||
trans: &CodegenBackend,
|
||||
matches: &getopts::Matches,
|
||||
sess: &Session,
|
||||
cstore: &CStore,
|
||||
input: &Input,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
) -> Compilation {
|
||||
self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile)
|
||||
}
|
||||
fn build_controller(self: Box<Self>, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> {
|
||||
let this = *self;
|
||||
let mut control = this.default.build_controller(sess, matches);
|
||||
control.after_hir_lowering.callback = Box::new(after_hir_lowering);
|
||||
control.after_analysis.callback = Box::new(after_analysis);
|
||||
if !this.host_target {
|
||||
// only fully compile targets on the host
|
||||
control.after_analysis.stop = Compilation::Stop;
|
||||
}
|
||||
control
|
||||
}
|
||||
}
|
||||
impl rustc_driver::Callbacks for MiriCompilerCalls {
|
||||
fn after_parsing(&mut self, compiler: &interface::Compiler<'_>) -> bool {
|
||||
let attr = (
|
||||
String::from("miri"),
|
||||
syntax::feature_gate::AttributeType::Whitelisted,
|
||||
);
|
||||
compiler.session().plugin_attributes.borrow_mut().push(attr);
|
||||
|
||||
fn after_hir_lowering(state: &mut CompileState) {
|
||||
let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted);
|
||||
state.session.plugin_attributes.borrow_mut().push(attr);
|
||||
}
|
||||
// Continue execution
|
||||
true
|
||||
}
|
||||
|
||||
fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
|
||||
state.session.abort_if_errors();
|
||||
|
||||
let tcx = state.tcx.unwrap();
|
||||
|
||||
if std::env::args().any(|arg| arg == "--test") {
|
||||
struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>);
|
||||
impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
|
||||
fn visit_item(&mut self, i: &'hir hir::Item) {
|
||||
if let hir::ItemKind::Fn(.., body_id) = i.node {
|
||||
if i.attrs.iter().any(|attr| attr.name() == "test") {
|
||||
let config = MiriConfig { validate: true, args: vec![] };
|
||||
let did = self.0.hir().body_owner_def_id(body_id);
|
||||
println!("running test: {}", self.0.def_path_debug_str(did));
|
||||
miri::eval_main(self.0, did, config);
|
||||
self.1.session.abort_if_errors();
|
||||
fn after_analysis(&mut self, compiler: &interface::Compiler<'_>) -> bool {
|
||||
compiler.session().abort_if_errors();
|
||||
compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
|
||||
if std::env::args().any(|arg| arg == "--test") {
|
||||
struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>);
|
||||
impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
|
||||
fn visit_item(&mut self, i: &'hir hir::Item) {
|
||||
if let hir::ItemKind::Fn(.., body_id) = i.node {
|
||||
if i.attrs.iter().any(|attr| attr.name() == "test") {
|
||||
let config = MiriConfig { validate: true, args: vec![] };
|
||||
let did = self.0.hir().body_owner_def_id(body_id);
|
||||
println!("running test: {}", self.0.def_path_debug_str(did));
|
||||
miri::eval_main(self.0, did, config);
|
||||
self.0.sess.abort_if_errors();
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
|
||||
fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
|
||||
}
|
||||
}
|
||||
fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
|
||||
fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
|
||||
}
|
||||
state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state));
|
||||
} else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
|
||||
let config = MiriConfig { validate: true, args: vec![] };
|
||||
miri::eval_main(tcx, entry_def_id, config);
|
||||
tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx));
|
||||
} else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
|
||||
let config = MiriConfig { validate: true, args: vec![] };
|
||||
miri::eval_main(tcx, entry_def_id, config);
|
||||
|
||||
state.session.abort_if_errors();
|
||||
} else {
|
||||
println!("no main function found, assuming auxiliary build");
|
||||
compiler.session().abort_if_errors();
|
||||
} else {
|
||||
println!("no main function found, assuming auxiliary build");
|
||||
}
|
||||
});
|
||||
|
||||
// Continue execution on host target
|
||||
self.host_target
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -185,10 +146,7 @@ fn main() {
|
|||
let buf = BufWriter::default();
|
||||
let output = buf.clone();
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls {
|
||||
default: Box::new(RustcDefaultCalls),
|
||||
host_target,
|
||||
}), None, Some(Box::new(buf)));
|
||||
rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf)));
|
||||
});
|
||||
|
||||
match result {
|
||||
|
|
|
|||
138
src/bin/miri.rs
138
src/bin/miri.rs
|
|
@ -11,115 +11,46 @@ extern crate rustc_metadata;
|
|||
extern crate rustc_driver;
|
||||
extern crate rustc_errors;
|
||||
extern crate rustc_codegen_utils;
|
||||
extern crate rustc_interface;
|
||||
extern crate syntax;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::env;
|
||||
|
||||
use miri::MiriConfig;
|
||||
use rustc::session::Session;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
|
||||
use rustc_driver::driver::{CompileState, CompileController};
|
||||
use rustc::session::config::{self, Input, ErrorOutputType};
|
||||
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||
use rustc_interface::interface;
|
||||
use rustc::hir::def_id::LOCAL_CRATE;
|
||||
use syntax::ast;
|
||||
|
||||
struct MiriCompilerCalls {
|
||||
default: Box<RustcDefaultCalls>,
|
||||
miri_config: MiriConfig,
|
||||
miri_config: miri::MiriConfig,
|
||||
}
|
||||
|
||||
impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
|
||||
fn early_callback(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
descriptions: &rustc_errors::registry::Registry,
|
||||
output: ErrorOutputType,
|
||||
) -> Compilation {
|
||||
self.default.early_callback(
|
||||
matches,
|
||||
sopts,
|
||||
cfg,
|
||||
descriptions,
|
||||
output,
|
||||
)
|
||||
impl rustc_driver::Callbacks for MiriCompilerCalls {
|
||||
fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool {
|
||||
let attr = (
|
||||
String::from("miri"),
|
||||
syntax::feature_gate::AttributeType::Whitelisted,
|
||||
);
|
||||
compiler.session().plugin_attributes.borrow_mut().push(attr);
|
||||
|
||||
// Continue execution
|
||||
true
|
||||
}
|
||||
fn no_input(
|
||||
&mut self,
|
||||
matches: &getopts::Matches,
|
||||
sopts: &config::Options,
|
||||
cfg: &ast::CrateConfig,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
descriptions: &rustc_errors::registry::Registry,
|
||||
) -> Option<(Input, Option<PathBuf>)> {
|
||||
self.default.no_input(
|
||||
matches,
|
||||
sopts,
|
||||
cfg,
|
||||
odir,
|
||||
ofile,
|
||||
descriptions,
|
||||
)
|
||||
|
||||
fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool {
|
||||
init_late_loggers();
|
||||
compiler.session().abort_if_errors();
|
||||
|
||||
compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
|
||||
let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
|
||||
|
||||
miri::eval_main(tcx, entry_def_id, self.miri_config.clone());
|
||||
});
|
||||
|
||||
compiler.session().abort_if_errors();
|
||||
|
||||
// Don't continue execution
|
||||
false
|
||||
}
|
||||
fn late_callback(
|
||||
&mut self,
|
||||
codegen_backend: &CodegenBackend,
|
||||
matches: &getopts::Matches,
|
||||
sess: &Session,
|
||||
cstore: &CStore,
|
||||
input: &Input,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
) -> Compilation {
|
||||
// Called *before* `build_controller`. Add filename to `miri` arguments.
|
||||
self.miri_config.args.insert(0, input.filestem().to_string());
|
||||
self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile)
|
||||
}
|
||||
fn build_controller(
|
||||
self: Box<Self>,
|
||||
sess: &Session,
|
||||
matches: &getopts::Matches,
|
||||
) -> CompileController<'a> {
|
||||
let this = *self;
|
||||
let mut control = this.default.build_controller(sess, matches);
|
||||
control.after_hir_lowering.callback = Box::new(after_hir_lowering);
|
||||
let miri_config = this.miri_config;
|
||||
control.after_analysis.callback =
|
||||
Box::new(move |state| after_analysis(state, miri_config.clone()));
|
||||
control.after_analysis.stop = Compilation::Stop;
|
||||
control
|
||||
}
|
||||
}
|
||||
|
||||
fn after_hir_lowering(state: &mut CompileState) {
|
||||
let attr = (
|
||||
String::from("miri"),
|
||||
syntax::feature_gate::AttributeType::Whitelisted,
|
||||
);
|
||||
state.session.plugin_attributes.borrow_mut().push(attr);
|
||||
}
|
||||
|
||||
fn after_analysis<'a, 'tcx>(
|
||||
state: &mut CompileState<'a, 'tcx>,
|
||||
miri_config: MiriConfig,
|
||||
) {
|
||||
init_late_loggers();
|
||||
state.session.abort_if_errors();
|
||||
|
||||
let tcx = state.tcx.unwrap();
|
||||
|
||||
|
||||
let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
|
||||
|
||||
miri::eval_main(tcx, entry_def_id, miri_config);
|
||||
|
||||
state.session.abort_if_errors();
|
||||
}
|
||||
|
||||
fn init_early_loggers() {
|
||||
|
|
@ -228,12 +159,9 @@ fn main() {
|
|||
|
||||
debug!("rustc arguments: {:?}", rustc_args);
|
||||
debug!("miri arguments: {:?}", miri_args);
|
||||
let miri_config = MiriConfig { validate, args: miri_args };
|
||||
let result = rustc_driver::run(move || {
|
||||
rustc_driver::run_compiler(&rustc_args, Box::new(MiriCompilerCalls {
|
||||
default: Box::new(RustcDefaultCalls),
|
||||
miri_config,
|
||||
}), None, None)
|
||||
});
|
||||
std::process::exit(result as i32);
|
||||
let miri_config = miri::MiriConfig { validate, args: miri_args };
|
||||
let result = rustc_driver::report_ices_to_stderr_if_any(move || {
|
||||
rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
|
||||
}).and_then(|result| result);
|
||||
std::process::exit(result.is_err() as i32);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue