@@ -3,7 +3,8 @@ use std::fmt;
3
3
4
4
use log:: trace;
5
5
6
- use rustc_span:: DUMMY_SP ;
6
+ use rustc_middle:: ty:: { self , TyCtxt } ;
7
+ use rustc_span:: { source_map:: DUMMY_SP , Span } ;
7
8
8
9
use crate :: * ;
9
10
@@ -116,7 +117,17 @@ pub fn report_error<'tcx, 'mir>(
116
117
117
118
e. print_backtrace ( ) ;
118
119
let msg = e. to_string ( ) ;
119
- report_msg ( ecx, & format ! ( "{}: {}" , title, msg) , msg, helps, true ) ;
120
+ report_msg ( * ecx. tcx , /*error*/ true , & format ! ( "{}: {}" , title, msg) , msg, helps, & ecx. generate_stacktrace ( ) ) ;
121
+
122
+ // Debug-dump all locals.
123
+ for ( i, frame) in ecx. active_thread_stack ( ) . iter ( ) . enumerate ( ) {
124
+ trace ! ( "-------------------" ) ;
125
+ trace ! ( "Frame {}" , i) ;
126
+ trace ! ( " return: {:?}" , frame. return_place. map( |p| * p) ) ;
127
+ for ( i, local) in frame. locals . iter ( ) . enumerate ( ) {
128
+ trace ! ( " local {}: {:?}" , i, local. value) ;
129
+ }
130
+ }
120
131
121
132
// Extra output to help debug specific issues.
122
133
match e. kind {
@@ -135,24 +146,21 @@ pub fn report_error<'tcx, 'mir>(
135
146
None
136
147
}
137
148
138
- /// Report an error or note (depending on the `error` argument) at the current frame's current statement .
149
+ /// Report an error or note (depending on the `error` argument) with the given stacktrace .
139
150
/// Also emits a full stacktrace of the interpreter stack.
140
- fn report_msg < ' tcx , ' mir > (
141
- ecx : & InterpCx < ' mir , ' tcx , Evaluator < ' mir , ' tcx > > ,
151
+ fn report_msg < ' tcx > (
152
+ tcx : TyCtxt < ' tcx > ,
153
+ error : bool ,
142
154
title : & str ,
143
155
span_msg : String ,
144
156
mut helps : Vec < String > ,
145
- error : bool ,
157
+ stacktrace : & [ FrameInfo < ' tcx > ] ,
146
158
) {
147
- let span = if let Some ( frame) = ecx. active_thread_stack ( ) . last ( ) {
148
- frame. current_source_info ( ) . unwrap ( ) . span
149
- } else {
150
- DUMMY_SP
151
- } ;
159
+ let span = stacktrace. first ( ) . map_or ( DUMMY_SP , |fi| fi. span ) ;
152
160
let mut err = if error {
153
- ecx . tcx . sess . struct_span_err ( span, title)
161
+ tcx. sess . struct_span_err ( span, title)
154
162
} else {
155
- ecx . tcx . sess . diagnostic ( ) . span_note_diag ( span, title)
163
+ tcx. sess . diagnostic ( ) . span_note_diag ( span, title)
156
164
} ;
157
165
err. span_label ( span, span_msg) ;
158
166
if !helps. is_empty ( ) {
@@ -163,8 +171,7 @@ fn report_msg<'tcx, 'mir>(
163
171
}
164
172
}
165
173
// Add backtrace
166
- let frames = ecx. generate_stacktrace ( ) ;
167
- for ( idx, frame_info) in frames. iter ( ) . enumerate ( ) {
174
+ for ( idx, frame_info) in stacktrace. iter ( ) . enumerate ( ) {
168
175
let is_local = frame_info. instance . def_id ( ) . is_local ( ) ;
169
176
// No span for non-local frames and the first frame (which is the error site).
170
177
if is_local && idx > 0 {
@@ -175,15 +182,6 @@ fn report_msg<'tcx, 'mir>(
175
182
}
176
183
177
184
err. emit ( ) ;
178
-
179
- for ( i, frame) in ecx. active_thread_stack ( ) . iter ( ) . enumerate ( ) {
180
- trace ! ( "-------------------" ) ;
181
- trace ! ( "Frame {}" , i) ;
182
- trace ! ( " return: {:?}" , frame. return_place. map( |p| * p) ) ;
183
- for ( i, local) in frame. locals . iter ( ) . enumerate ( ) {
184
- trace ! ( " local {}: {:?}" , i, local. value) ;
185
- }
186
- }
187
185
}
188
186
189
187
thread_local ! {
@@ -196,13 +194,62 @@ pub fn register_diagnostic(e: NonHaltingDiagnostic) {
196
194
DIAGNOSTICS . with ( |diagnostics| diagnostics. borrow_mut ( ) . push ( e) ) ;
197
195
}
198
196
197
+ /// Remember enough about the topmost frame so that we can restore the stack
198
+ /// after a step was taken.
199
+ pub struct TopFrameInfo < ' tcx > {
200
+ stack_size : usize ,
201
+ instance : ty:: Instance < ' tcx > ,
202
+ span : Span ,
203
+ }
204
+
199
205
impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
200
206
pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
207
+ fn preprocess_diagnostics ( & self ) -> TopFrameInfo < ' tcx > {
208
+ // Ensure we have no lingering diagnostics.
209
+ DIAGNOSTICS . with ( |diagnostics| assert ! ( diagnostics. borrow( ) . is_empty( ) ) ) ;
210
+
211
+ let this = self . eval_context_ref ( ) ;
212
+ let frame = this. frame ( ) ;
213
+
214
+ TopFrameInfo {
215
+ stack_size : this. active_thread_stack ( ) . len ( ) ,
216
+ instance : frame. instance ,
217
+ span : frame. current_source_info ( ) . map_or ( DUMMY_SP , |si| si. span ) ,
218
+ }
219
+ }
220
+
201
221
/// Emit all diagnostics that were registed with `register_diagnostics`
202
- fn process_diagnostics ( & self ) {
222
+ fn process_diagnostics ( & self , info : TopFrameInfo < ' tcx > ) {
203
223
let this = self . eval_context_ref ( ) ;
204
224
DIAGNOSTICS . with ( |diagnostics| {
205
- for e in diagnostics. borrow_mut ( ) . drain ( ..) {
225
+ let mut diagnostics = diagnostics. borrow_mut ( ) ;
226
+ if diagnostics. is_empty ( ) {
227
+ return ;
228
+ }
229
+ // We need to fix up the stack trace, because the machine has already
230
+ // stepped to the next statement.
231
+ let mut stacktrace = this. generate_stacktrace ( ) ;
232
+ // Remove newly pushed frames.
233
+ while stacktrace. len ( ) > info. stack_size {
234
+ stacktrace. remove ( 0 ) ;
235
+ }
236
+ // Add popped frame back.
237
+ if stacktrace. len ( ) < info. stack_size {
238
+ assert ! ( stacktrace. len( ) == info. stack_size-1 , "we should never pop more than one frame at once" ) ;
239
+ let frame_info = FrameInfo {
240
+ instance : info. instance ,
241
+ span : info. span ,
242
+ lint_root : None ,
243
+ } ;
244
+ stacktrace. insert ( 0 , frame_info) ;
245
+ } else {
246
+ // Adjust topmost frame.
247
+ stacktrace[ 0 ] . span = info. span ;
248
+ assert_eq ! ( stacktrace[ 0 ] . instance, info. instance, "we should not pop and push a frame in one step" ) ;
249
+ }
250
+
251
+ // Show diagnostics.
252
+ for e in diagnostics. drain ( ..) {
206
253
use NonHaltingDiagnostic :: * ;
207
254
let msg = match e {
208
255
PoppedPointerTag ( item) =>
@@ -214,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
214
261
FreedAlloc ( AllocId ( id) ) =>
215
262
format ! ( "freed allocation with id {}" , id) ,
216
263
} ;
217
- report_msg ( this, "tracking was triggered" , msg, vec ! [ ] , false ) ;
264
+ report_msg ( * this. tcx , /*error*/ false , "tracking was triggered" , msg, vec ! [ ] , & stacktrace ) ;
218
265
}
219
266
} ) ;
220
267
}
0 commit comments