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;
19 use rustc::session::Session;
20 use rustc_driver::{driver, CompilerCalls};
21 use rustc::ty::{TyCtxt, subst};
22 use rustc::hir::def_id::DefId;
24 struct MiriCompilerCalls;
26 impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
31 ) -> driver::CompileController<'a> {
32 let mut control = driver::CompileController::basic();
34 control.after_analysis.callback = Box::new(|state| {
35 state.session.abort_if_errors();
37 let tcx = state.tcx.unwrap();
38 let mir_map = state.mir_map.unwrap();
40 let (node_id, span) = state.session.entry_fn.borrow().expect("no main or start function found");
41 debug!("found `main` function at: {:?}", span);
43 let mir = mir_map.map.get(&node_id).expect("no mir for main function");
44 let def_id = tcx.map.local_def_id(node_id);
45 let mut ecx = EvalContext::new(tcx, mir_map);
46 let substs = tcx.mk_substs(subst::Substs::empty());
47 let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs).expect("main function should not be diverging");
49 ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr));
51 if mir.arg_decls.len() == 2 {
53 let ptr_size = ecx.memory().pointer_size;
54 let nargs = ecx.memory_mut().allocate(ptr_size);
55 ecx.memory_mut().write_usize(nargs, 0).unwrap();
56 let args = ecx.memory_mut().allocate(ptr_size);
57 ecx.memory_mut().write_usize(args, 0).unwrap();
58 ecx.frame_mut().locals[0] = nargs;
59 ecx.frame_mut().locals[1] = args;
63 match step(&mut ecx) {
66 // FIXME: diverging functions can end up here in some future miri
79 fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
80 let frame = ecx.stack().last().expect("stackframe was empty");
81 let block = &frame.mir.basic_blocks()[frame.next_block];
82 let span = if frame.stmt < block.statements.len() {
83 block.statements[frame.stmt].source_info.span
85 block.terminator().source_info.span
87 let mut err = tcx.sess.struct_span_err(span, &e.to_string());
88 for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() {
89 // FIXME(solson): Find a way to do this without this Display impl hack.
90 use rustc::util::ppaux;
92 struct Instance<'tcx>(DefId, &'tcx subst::Substs<'tcx>);
93 impl<'tcx> fmt::Display for Instance<'tcx> {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[],
96 |tcx| Some(tcx.lookup_item_type(self.0).generics))
99 err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
106 let args: Vec<String> = std::env::args().collect();
107 rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
111 const NSPACES: usize = 40;
112 let format = |record: &log::LogRecord| {
113 // prepend spaces to indent the final string
114 let indentation = log_settings::settings().indentation;
115 format!("{lvl}:{module}{depth:2}{indent:<indentation$} {text}",
116 lvl = record.level(),
117 module = record.location().module_path(),
118 depth = indentation / NSPACES,
119 indentation = indentation % NSPACES,
121 text = record.args())
124 let mut builder = env_logger::LogBuilder::new();
125 builder.format(format).filter(None, log::LogLevelFilter::Info);
127 if std::env::var("MIRI_LOG").is_ok() {
128 builder.parse(&std::env::var("MIRI_LOG").unwrap());
131 builder.init().unwrap();