1 use rustc_mir::interpret::InterpErrorInfo;
2 use std::cell::RefCell;
6 /// Miri specific diagnostics
7 pub enum NonHaltingDiagnostic {
8 PoppedTrackedPointerTag(Item),
11 /// Emit a custom diagnostic without going through the miri-engine machinery
12 pub fn report_diagnostic<'tcx, 'mir>(
13 ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
14 mut e: InterpErrorInfo<'tcx>,
16 // Special treatment for some error kinds
17 let msg = match e.kind {
18 InterpError::MachineStop(ref info) => {
19 let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
21 TerminationInfo::Exit(code) => return Some(*code),
22 TerminationInfo::Abort => format!("the evaluated program aborted execution"),
25 err_unsup!(NoMirFor(..)) => format!(
26 "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.",
29 InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e),
33 report_msg(ecx, msg, true)
36 /// Report an error or note (depending on the `error` argument) at the current frame's current statement.
37 /// Also emits a full stacktrace of the interpreter stack.
38 pub fn report_msg<'tcx, 'mir>(
39 ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
43 if let Some(frame) = ecx.stack().last() {
44 let span = frame.current_source_info().unwrap().span;
46 let mut err = if error {
47 let msg = format!("Miri evaluation error: {}", msg);
48 ecx.tcx.sess.struct_span_err(span, msg.as_str())
50 ecx.tcx.sess.diagnostic().span_note_diag(span, msg.as_str())
52 let frames = ecx.generate_stacktrace(None);
53 err.span_label(span, msg);
54 // We iterate with indices because we need to look at the next frame (the caller).
55 for idx in 0..frames.len() {
56 let frame_info = &frames[idx];
57 let call_site_is_local = frames
59 .map_or(false, |caller_info| caller_info.instance.def_id().is_local());
60 if call_site_is_local {
61 err.span_note(frame_info.call_site, &frame_info.to_string());
63 err.note(&frame_info.to_string());
68 ecx.tcx.sess.err(&msg);
71 for (i, frame) in ecx.stack().iter().enumerate() {
72 trace!("-------------------");
73 trace!("Frame {}", i);
74 trace!(" return: {:?}", frame.return_place.map(|p| *p));
75 for (i, local) in frame.locals.iter().enumerate() {
76 trace!(" local {}: {:?}", i, local.value);
79 // Let the reported error determine the return code.
84 static DIAGNOSTICS: RefCell<Vec<NonHaltingDiagnostic>> = RefCell::new(Vec::new());
87 /// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available.
88 /// The diagnostic will be emitted after the current interpreter step is finished.
89 pub fn register_diagnostic(e: NonHaltingDiagnostic) {
90 DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
93 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
94 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
95 /// Emit all diagnostics that were registed with `register_diagnostics`
96 fn process_diagnostics(&self) {
97 let this = self.eval_context_ref();
98 DIAGNOSTICS.with(|diagnostics| {
99 for e in diagnostics.borrow_mut().drain(..) {
101 NonHaltingDiagnostic::PoppedTrackedPointerTag(item) =>
102 format!("popped tracked tag for item {:?}", item),
104 report_msg(this, msg, false);