1 #![feature(rustc_private)]
6 extern crate rustc_driver;
7 extern crate env_logger;
8 extern crate log_settings;
10 #[macro_use] extern crate log;
12 use miri::{eval_main, run_mir_passes};
13 use rustc::session::Session;
14 use rustc::mir::mir_map::MirMap;
15 use rustc_driver::{driver, CompilerCalls, Compilation};
16 use syntax::ast::MetaItemKind;
18 struct MiriCompilerCalls;
20 impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
25 ) -> driver::CompileController<'a> {
26 let mut control = driver::CompileController::basic();
27 control.after_hir_lowering.callback = Box::new(|state| {
28 state.session.plugin_attributes.borrow_mut().push(("miri".to_owned(), syntax::feature_gate::AttributeType::Whitelisted));
30 control.after_analysis.stop = Compilation::Stop;
31 control.after_analysis.callback = Box::new(|state| {
32 state.session.abort_if_errors();
34 let tcx = state.tcx.unwrap();
35 let mir_map = state.mir_map.unwrap();
36 let (entry_node_id, _) = state.session.entry_fn.borrow()
37 .expect("no main or start function found");
38 let entry_def_id = tcx.map.local_def_id(entry_node_id);
40 let krate = state.hir_crate.as_ref().unwrap();
41 let mut memory_size = 100*1024*1024; // 100MB
42 let mut step_limit = 1000_000;
43 let mut stack_limit = 100;
44 fn extract_str(lit: &syntax::ast::Lit) -> syntax::parse::token::InternedString {
46 syntax::ast::LitKind::Str(ref s, _) => s.clone(),
47 _ => panic!("attribute values need to be strings"),
50 for attr in krate.attrs.iter() {
51 match attr.node.value.node {
52 MetaItemKind::List(ref name, _) if name != "miri" => {}
53 MetaItemKind::List(_, ref items) => for item in items {
55 MetaItemKind::NameValue(ref name, ref value) => {
57 "memory_size" => memory_size = extract_str(value).parse().expect("not a number"),
58 "step_limit" => step_limit = extract_str(value).parse().expect("not a number"),
59 "stack_limit" => stack_limit = extract_str(value).parse().expect("not a number"),
60 _ => state.session.span_err(item.span, "unknown miri attribute"),
63 _ => state.session.span_err(item.span, "miri attributes need to be of key = value kind"),
70 let mut mir_map_copy = MirMap::new(tcx.dep_graph.clone());
71 for def_id in mir_map.map.keys() {
72 mir_map_copy.map.insert(def_id, mir_map.map.get(&def_id).unwrap().clone());
74 run_mir_passes(tcx, &mut mir_map_copy);
75 eval_main(tcx, &mir_map_copy, entry_def_id, memory_size, step_limit, stack_limit);
77 state.session.abort_if_errors();
85 const MAX_INDENT: usize = 40;
87 let format = |record: &log::LogRecord| {
88 if record.level() == log::LogLevel::Trace {
89 // prepend spaces to indent the final string
90 let indentation = log_settings::settings().indentation;
91 format!("{lvl}:{module}{depth:2}{indent:<indentation$} {text}",
93 module = record.location().module_path(),
94 depth = indentation / MAX_INDENT,
95 indentation = indentation % MAX_INDENT,
99 format!("{lvl}:{module}: {text}",
100 lvl = record.level(),
101 module = record.location().module_path(),
102 text = record.args())
106 let mut builder = env_logger::LogBuilder::new();
107 builder.format(format).filter(None, log::LogLevelFilter::Info);
109 if std::env::var("MIRI_LOG").is_ok() {
110 builder.parse(&std::env::var("MIRI_LOG").unwrap());
113 builder.init().unwrap();
116 fn find_sysroot() -> String {
117 // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
118 let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
119 let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
120 match (home, toolchain) {
121 (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
122 _ => option_env!("RUST_SYSROOT")
123 .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
130 let mut args: Vec<String> = std::env::args().collect();
132 let sysroot_flag = String::from("--sysroot");
133 if !args.contains(&sysroot_flag) {
134 args.push(sysroot_flag);
135 args.push(find_sysroot());
138 rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);