@@ -13,6 +13,8 @@ use crate::dataflow::{self, do_dataflow, DebugFormatted};
1313use crate :: dataflow:: MoveDataParamEnv ;
1414use crate :: dataflow:: BitDenotation ;
1515use crate :: dataflow:: DataflowResults ;
16+ use crate :: dataflow:: HaveBeenBorrowedLocals ;
17+ use crate :: dataflow:: { ReachingDefinitions , UseDefChain } ;
1618use crate :: dataflow:: {
1719 DefinitelyInitializedPlaces , MaybeInitializedPlaces , MaybeUninitializedPlaces
1820} ;
@@ -51,6 +53,17 @@ impl MirPass for SanityCheck {
5153 DefinitelyInitializedPlaces :: new ( tcx, body, & mdpe) ,
5254 |bd, i| DebugFormatted :: new ( & bd. move_data ( ) . move_paths [ i] ) ) ;
5355
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+
5467 if has_rustc_mir_with ( & attributes, sym:: rustc_peek_maybe_init) . is_some ( ) {
5568 sanity_check_via_rustc_peek ( tcx, body, def_id, & attributes, & flow_inits) ;
5669 }
@@ -60,6 +73,9 @@ impl MirPass for SanityCheck {
6073 if has_rustc_mir_with ( & attributes, sym:: rustc_peek_definite_init) . is_some ( ) {
6174 sanity_check_via_rustc_peek ( tcx, body, def_id, & attributes, & flow_def_inits) ;
6275 }
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+ }
6379 if has_rustc_mir_with ( & attributes, sym:: stop_after_dataflow) . is_some ( ) {
6480 tcx. sess . fatal ( "stop_after_dataflow ended compilation" ) ;
6581 }
@@ -87,7 +103,7 @@ pub fn sanity_check_via_rustc_peek<'tcx, O>(
87103 body : & Body < ' tcx > ,
88104 def_id : DefId ,
89105 _attributes : & [ ast:: Attribute ] ,
90- results : & DataflowResults < ' tcx , O > ,
106+ results : & O ,
91107) where O : RustcPeekAt < ' tcx > {
92108 debug ! ( "sanity_check_via_rustc_peek def_id: {:?}" , def_id) ;
93109
@@ -214,27 +230,32 @@ impl PeekCall {
214230 }
215231}
216232
217- pub trait RustcPeekAt < ' tcx > : BitDenotation < ' tcx > {
233+ pub trait RustcPeekAt < ' tcx > {
218234 fn peek_at (
219235 & self ,
220236 tcx : TyCtxt < ' tcx > ,
237+ body : & mir:: Body < ' tcx > ,
221238 place : & mir:: Place < ' tcx > ,
222- flow_state : & BitSet < Self :: Idx > ,
239+ location : Location ,
223240 call : PeekCall ,
224241 ) ;
225242}
226243
227- impl < ' tcx , O > RustcPeekAt < ' tcx > for O
244+ impl < ' tcx , O > RustcPeekAt < ' tcx > for DataflowResults < ' tcx , O >
228245 where O : BitDenotation < ' tcx , Idx = MovePathIndex > + HasMoveData < ' tcx > ,
229246{
230247 fn peek_at (
231248 & self ,
232249 tcx : TyCtxt < ' tcx > ,
250+ body : & mir:: Body < ' tcx > ,
233251 place : & mir:: Place < ' tcx > ,
234- flow_state : & BitSet < Self :: Idx > ,
252+ location : Location ,
235253 call : PeekCall ,
236254 ) {
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) {
238259 LookupResult :: Exact ( peek_mpi) => {
239260 let bit_state = flow_state. contains ( peek_mpi) ;
240261 debug ! ( "rustc_peek({:?} = &{:?}) bit_state: {}" ,
@@ -249,3 +270,57 @@ impl<'tcx, O> RustcPeekAt<'tcx> for O
249270 }
250271 }
251272}
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