]> git.lizzy.rs Git - rust.git/blob - src/diagnostics.rs
504863b13427c97d9a1831b65f91d982c140857b
[rust.git] / src / diagnostics.rs
1 use rustc_mir::interpret::InterpErrorInfo;
2
3 use crate::*;
4
5 pub fn report_err<'tcx, 'mir>(
6     ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
7     mut e: InterpErrorInfo<'tcx>,
8 ) -> Option<i64> {
9     // Special treatment for some error kinds
10     let msg = match e.kind {
11         InterpError::MachineStop(ref info) => {
12             let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
13             match info {
14                 TerminationInfo::Exit(code) => return Some(*code),
15                 TerminationInfo::PoppedTrackedPointerTag(item) =>
16                     format!("popped tracked tag for item {:?}", item),
17                 TerminationInfo::Abort => format!("the evaluated program aborted execution"),
18             }
19         }
20         err_unsup!(NoMirFor(..)) => format!(
21             "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.",
22             e
23         ),
24         InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e),
25         _ => e.to_string(),
26     };
27     e.print_backtrace();
28     if let Some(frame) = ecx.stack().last() {
29         let span = frame.current_source_info().unwrap().span;
30
31         let msg = format!("Miri evaluation error: {}", msg);
32         let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str());
33         let frames = ecx.generate_stacktrace(None);
34         err.span_label(span, msg);
35         // We iterate with indices because we need to look at the next frame (the caller).
36         for idx in 0..frames.len() {
37             let frame_info = &frames[idx];
38             let call_site_is_local = frames
39                 .get(idx + 1)
40                 .map_or(false, |caller_info| caller_info.instance.def_id().is_local());
41             if call_site_is_local {
42                 err.span_note(frame_info.call_site, &frame_info.to_string());
43             } else {
44                 err.note(&frame_info.to_string());
45             }
46         }
47         err.emit();
48     } else {
49         ecx.tcx.sess.err(&msg);
50     }
51
52     for (i, frame) in ecx.stack().iter().enumerate() {
53         trace!("-------------------");
54         trace!("Frame {}", i);
55         trace!("    return: {:?}", frame.return_place.map(|p| *p));
56         for (i, local) in frame.locals.iter().enumerate() {
57             trace!("    local {}: {:?}", i, local.value);
58         }
59     }
60     // Let the reported error determine the return code.
61     return None;
62 }
63
64 use std::cell::RefCell;
65 thread_local! {
66     static ECX: RefCell<Vec<InterpErrorInfo<'static>>> = RefCell::new(Vec::new());
67 }
68
69 pub fn register_err(e: InterpErrorInfo<'static>) {
70     ECX.with(|ecx| ecx.borrow_mut().push(e));
71 }
72
73 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
74 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
75     fn process_errors(&self) {
76         let this = self.eval_context_ref();
77         ECX.with(|ecx| {
78             for e in ecx.borrow_mut().drain(..) {
79                 report_err(this, e);
80             }
81         });
82     }
83 }