@@ -13,6 +13,8 @@ use crate::dataflow::{self, do_dataflow, DebugFormatted};
13
13
use crate :: dataflow:: MoveDataParamEnv ;
14
14
use crate :: dataflow:: BitDenotation ;
15
15
use crate :: dataflow:: DataflowResults ;
16
+ use crate :: dataflow:: HaveBeenBorrowedLocals ;
17
+ use crate :: dataflow:: { ReachingDefinitions , UseDefChain } ;
16
18
use crate :: dataflow:: {
17
19
DefinitelyInitializedPlaces , MaybeInitializedPlaces , MaybeUninitializedPlaces
18
20
} ;
@@ -51,6 +53,17 @@ impl MirPass for SanityCheck {
51
53
DefinitelyInitializedPlaces :: new ( tcx, body, & mdpe) ,
52
54
|bd, i| DebugFormatted :: new ( & bd. move_data ( ) . move_paths [ i] ) ) ;
53
55
56
+ let flow_borrowed_locals =
57
+ do_dataflow ( tcx, body, def_id, & attributes, & dead_unwinds,
58
+ HaveBeenBorrowedLocals :: new ( body) ,
59
+ |_bd, i| DebugFormatted :: new ( & i) ) ;
60
+ let flow_reaching_defs =
61
+ do_dataflow ( tcx, body, def_id, & attributes, & dead_unwinds,
62
+ ReachingDefinitions :: new ( body) ,
63
+ |bd, i| DebugFormatted :: new ( & bd. get ( i) . location ) ) ;
64
+ let flow_use_def_chain =
65
+ UseDefChain :: new ( body, & flow_reaching_defs, & flow_borrowed_locals) ;
66
+
54
67
if has_rustc_mir_with ( & attributes, sym:: rustc_peek_maybe_init) . is_some ( ) {
55
68
sanity_check_via_rustc_peek ( tcx, body, def_id, & attributes, & flow_inits) ;
56
69
}
@@ -60,6 +73,9 @@ impl MirPass for SanityCheck {
60
73
if has_rustc_mir_with ( & attributes, sym:: rustc_peek_definite_init) . is_some ( ) {
61
74
sanity_check_via_rustc_peek ( tcx, body, def_id, & attributes, & flow_def_inits) ;
62
75
}
76
+ if has_rustc_mir_with ( & attributes, sym:: rustc_peek_use_def_chain) . is_some ( ) {
77
+ sanity_check_via_rustc_peek ( tcx, body, def_id, & attributes, & flow_use_def_chain) ;
78
+ }
63
79
if has_rustc_mir_with ( & attributes, sym:: stop_after_dataflow) . is_some ( ) {
64
80
tcx. sess . fatal ( "stop_after_dataflow ended compilation" ) ;
65
81
}
@@ -87,7 +103,7 @@ pub fn sanity_check_via_rustc_peek<'tcx, O>(
87
103
body : & Body < ' tcx > ,
88
104
def_id : DefId ,
89
105
_attributes : & [ ast:: Attribute ] ,
90
- results : & DataflowResults < ' tcx , O > ,
106
+ results : & O ,
91
107
) where O : RustcPeekAt < ' tcx > {
92
108
debug ! ( "sanity_check_via_rustc_peek def_id: {:?}" , def_id) ;
93
109
@@ -214,27 +230,32 @@ impl PeekCall {
214
230
}
215
231
}
216
232
217
- pub trait RustcPeekAt < ' tcx > : BitDenotation < ' tcx > {
233
+ pub trait RustcPeekAt < ' tcx > {
218
234
fn peek_at (
219
235
& self ,
220
236
tcx : TyCtxt < ' tcx > ,
237
+ body : & mir:: Body < ' tcx > ,
221
238
place : & mir:: Place < ' tcx > ,
222
- flow_state : & BitSet < Self :: Idx > ,
239
+ location : Location ,
223
240
call : PeekCall ,
224
241
) ;
225
242
}
226
243
227
- impl < ' tcx , O > RustcPeekAt < ' tcx > for O
244
+ impl < ' tcx , O > RustcPeekAt < ' tcx > for DataflowResults < ' tcx , O >
228
245
where O : BitDenotation < ' tcx , Idx = MovePathIndex > + HasMoveData < ' tcx > ,
229
246
{
230
247
fn peek_at (
231
248
& self ,
232
249
tcx : TyCtxt < ' tcx > ,
250
+ body : & mir:: Body < ' tcx > ,
233
251
place : & mir:: Place < ' tcx > ,
234
- flow_state : & BitSet < Self :: Idx > ,
252
+ location : Location ,
235
253
call : PeekCall ,
236
254
) {
237
- match self . move_data ( ) . rev_lookup . find ( place) {
255
+ let operator = self . operator ( ) ;
256
+ let flow_state = dataflow:: state_for_location ( location, operator, self , body) ;
257
+
258
+ match operator. move_data ( ) . rev_lookup . find ( place) {
238
259
LookupResult :: Exact ( peek_mpi) => {
239
260
let bit_state = flow_state. contains ( peek_mpi) ;
240
261
debug ! ( "rustc_peek({:?} = &{:?}) bit_state: {}" ,
@@ -249,3 +270,57 @@ impl<'tcx, O> RustcPeekAt<'tcx> for O
249
270
}
250
271
}
251
272
}
273
+
274
+ impl < ' tcx > RustcPeekAt < ' tcx > for UseDefChain < ' _ , ' tcx > {
275
+ fn peek_at (
276
+ & self ,
277
+ tcx : TyCtxt < ' tcx > ,
278
+ body : & mir:: Body < ' tcx > ,
279
+ place : & mir:: Place < ' tcx > ,
280
+ location : Location ,
281
+ call : PeekCall ,
282
+ ) {
283
+
284
+ let base_local = place
285
+ . base_direct ( )
286
+ . expect ( "Deref in argument to `rustc_peek`" )
287
+ . local ( )
288
+ . expect ( "Argument to `rustc_peek` must be a local variable" ) ;
289
+
290
+ let mut defs: Vec < _ > = self
291
+ . defs_for_use ( base_local, location)
292
+ . map ( |def| {
293
+ let span = def
294
+ . location
295
+ . map ( |loc| {
296
+ let block = & body. basic_blocks ( ) [ loc. block ] ;
297
+ block. statements
298
+ . get ( loc. statement_index )
299
+ . map ( |stmt| stmt. source_info )
300
+ . unwrap_or ( block. terminator ( ) . source_info )
301
+ . span
302
+ } )
303
+ . unwrap_or_else ( || {
304
+ // `def` represents the value of a parameter on function entry.
305
+ let local = def. kind . direct ( ) . unwrap ( ) ;
306
+ body. local_decls [ local] . source_info . span
307
+ } ) ;
308
+
309
+ let src = tcx. sess . source_map ( ) ;
310
+ let snippet = src. span_to_snippet ( span) . unwrap ( ) ;
311
+ let line_index = src. span_to_lines ( span) . unwrap ( ) . lines [ 0 ] . line_index ;
312
+ let line_no = line_index + 1 ;
313
+
314
+ ( line_no, snippet)
315
+ } )
316
+ . collect ( ) ;
317
+
318
+ defs. sort_by_key ( |( line_no, _) | * line_no) ;
319
+ let defs: Vec < _ > = defs. into_iter ( )
320
+ . map ( |( line_no, snippet) | format ! ( "{}: \" {}\" " , line_no, snippet) )
321
+ . collect ( ) ;
322
+
323
+ let msg = format ! ( "rustc_peek: [{}]" , defs. join( ", " ) ) ;
324
+ tcx. sess . span_err ( call. span , & msg) ;
325
+ }
326
+ }
0 commit comments