@@ -223,6 +223,13 @@ impl AbstractConst<'tcx> {
223223 }
224224}
225225
226+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
227+ struct WorkNode < ' tcx > {
228+ node : Node < ' tcx > ,
229+ span : Span ,
230+ used : bool ,
231+ }
232+
226233struct AbstractConstBuilder < ' a , ' tcx > {
227234 tcx : TyCtxt < ' tcx > ,
228235 body : & ' a mir:: Body < ' tcx > ,
@@ -232,7 +239,7 @@ struct AbstractConstBuilder<'a, 'tcx> {
232239 /// so we store this here. Note that we also consider nodes as used
233240 /// if they are mentioned in an assert, so some used nodes are never
234241 /// actually reachable by walking the [`AbstractConst`].
235- nodes : IndexVec < NodeId , ( Node < ' tcx > , bool ) > ,
242+ nodes : IndexVec < NodeId , WorkNode < ' tcx > > ,
236243 locals : IndexVec < mir:: Local , NodeId > ,
237244 /// We only allow field accesses if they access
238245 /// the result of a checked operation.
@@ -279,25 +286,25 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
279286 Ok ( Some ( builder) )
280287 }
281288
282- fn add_node ( & mut self , n : Node < ' tcx > ) -> NodeId {
289+ fn add_node ( & mut self , node : Node < ' tcx > , span : Span ) -> NodeId {
283290 // Mark used nodes.
284- match n {
291+ match node {
285292 Node :: Leaf ( _) => ( ) ,
286293 Node :: Binop ( _, lhs, rhs) => {
287- self . nodes [ lhs] . 1 = true ;
288- self . nodes [ rhs] . 1 = true ;
294+ self . nodes [ lhs] . used = true ;
295+ self . nodes [ rhs] . used = true ;
289296 }
290297 Node :: UnaryOp ( _, input) => {
291- self . nodes [ input] . 1 = true ;
298+ self . nodes [ input] . used = true ;
292299 }
293300 Node :: FunctionCall ( func, nodes) => {
294- self . nodes [ func] . 1 = true ;
295- nodes. iter ( ) . for_each ( |& n| self . nodes [ n] . 1 = true ) ;
301+ self . nodes [ func] . used = true ;
302+ nodes. iter ( ) . for_each ( |& n| self . nodes [ n] . used = true ) ;
296303 }
297304 }
298305
299306 // Nodes start as unused.
300- self . nodes . push ( ( n , false ) )
307+ self . nodes . push ( WorkNode { node , span , used : false } )
301308 }
302309
303310 fn place_to_local (
@@ -337,7 +344,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
337344 let local = self . place_to_local ( span, p) ?;
338345 Ok ( self . locals [ local] )
339346 }
340- mir:: Operand :: Constant ( ct) => Ok ( self . add_node ( Node :: Leaf ( ct. literal ) ) ) ,
347+ mir:: Operand :: Constant ( ct) => Ok ( self . add_node ( Node :: Leaf ( ct. literal ) , span ) ) ,
341348 }
342349 }
343350
@@ -362,38 +369,38 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
362369
363370 fn build_statement ( & mut self , stmt : & mir:: Statement < ' tcx > ) -> Result < ( ) , ErrorReported > {
364371 debug ! ( "AbstractConstBuilder: stmt={:?}" , stmt) ;
372+ let span = stmt. source_info . span ;
365373 match stmt. kind {
366374 StatementKind :: Assign ( box ( ref place, ref rvalue) ) => {
367- let local = self . place_to_local ( stmt . source_info . span , place) ?;
375+ let local = self . place_to_local ( span, place) ?;
368376 match * rvalue {
369377 Rvalue :: Use ( ref operand) => {
370- self . locals [ local] =
371- self . operand_to_node ( stmt. source_info . span , operand) ?;
378+ self . locals [ local] = self . operand_to_node ( span, operand) ?;
372379 Ok ( ( ) )
373380 }
374381 Rvalue :: BinaryOp ( op, ref lhs, ref rhs) if Self :: check_binop ( op) => {
375- let lhs = self . operand_to_node ( stmt . source_info . span , lhs) ?;
376- let rhs = self . operand_to_node ( stmt . source_info . span , rhs) ?;
377- self . locals [ local] = self . add_node ( Node :: Binop ( op, lhs, rhs) ) ;
382+ let lhs = self . operand_to_node ( span, lhs) ?;
383+ let rhs = self . operand_to_node ( span, rhs) ?;
384+ self . locals [ local] = self . add_node ( Node :: Binop ( op, lhs, rhs) , span ) ;
378385 if op. is_checkable ( ) {
379386 bug ! ( "unexpected unchecked checkable binary operation" ) ;
380387 } else {
381388 Ok ( ( ) )
382389 }
383390 }
384391 Rvalue :: CheckedBinaryOp ( op, ref lhs, ref rhs) if Self :: check_binop ( op) => {
385- let lhs = self . operand_to_node ( stmt . source_info . span , lhs) ?;
386- let rhs = self . operand_to_node ( stmt . source_info . span , rhs) ?;
387- self . locals [ local] = self . add_node ( Node :: Binop ( op, lhs, rhs) ) ;
392+ let lhs = self . operand_to_node ( span, lhs) ?;
393+ let rhs = self . operand_to_node ( span, rhs) ?;
394+ self . locals [ local] = self . add_node ( Node :: Binop ( op, lhs, rhs) , span ) ;
388395 self . checked_op_locals . insert ( local) ;
389396 Ok ( ( ) )
390397 }
391398 Rvalue :: UnaryOp ( op, ref operand) if Self :: check_unop ( op) => {
392- let operand = self . operand_to_node ( stmt . source_info . span , operand) ?;
393- self . locals [ local] = self . add_node ( Node :: UnaryOp ( op, operand) ) ;
399+ let operand = self . operand_to_node ( span, operand) ?;
400+ self . locals [ local] = self . add_node ( Node :: UnaryOp ( op, operand) , span ) ;
394401 Ok ( ( ) )
395402 }
396- _ => self . error ( Some ( stmt . source_info . span ) , "unsupported rvalue" ) ?,
403+ _ => self . error ( Some ( span) , "unsupported rvalue" ) ?,
397404 }
398405 }
399406 // These are not actually relevant for us here, so we can ignore them.
@@ -441,7 +448,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
441448 . map ( |arg| self . operand_to_node ( terminator. source_info . span , arg) )
442449 . collect :: < Result < Vec < NodeId > , _ > > ( ) ?,
443450 ) ;
444- self . locals [ local] = self . add_node ( Node :: FunctionCall ( func, args) ) ;
451+ self . locals [ local] = self . add_node ( Node :: FunctionCall ( func, args) , fn_span ) ;
445452 Ok ( Some ( target) )
446453 }
447454 TerminatorKind :: Assert { ref cond, expected : false , target, .. } => {
@@ -458,7 +465,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
458465 //
459466 // This is needed because division does not use `CheckedBinop` but instead
460467 // adds an explicit assert for `divisor != 0`.
461- self . nodes [ self . locals [ p] ] . 1 = true ;
468+ self . nodes [ self . locals [ p] ] . used = true ;
462469 return Ok ( Some ( target) ) ;
463470 } else if let & [ mir:: ProjectionElem :: Field ( ONE_FIELD , _) ] = p. projection . as_ref ( ) {
464471 // Only allow asserts checking the result of a checked operation.
@@ -487,16 +494,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
487494 if let Some ( next) = self . build_terminator ( block. terminator ( ) ) ? {
488495 block = & self . body . basic_blocks ( ) [ next] ;
489496 } else {
490- assert_eq ! ( self . locals[ mir:: Local :: from_usize ( 0 ) ] , self . nodes. last( ) . unwrap( ) ) ;
491- self . nodes [ self . locals [ mir:: Local :: from_usize ( 0 ) ] ] . 1 = true ;
492- if ! self . nodes . iter ( ) . all ( |n| n . 1 ) {
493- self . error ( None , "unused node " ) ?;
497+ assert_eq ! ( self . locals[ mir:: RETURN_PLACE ] , self . nodes. last( ) . unwrap( ) ) ;
498+ self . nodes [ self . locals [ mir:: RETURN_PLACE ] ] . used = true ;
499+ if let Some ( & unused ) = self . nodes . iter ( ) . find ( |n| !n . used ) {
500+ self . error ( Some ( unused . span ) , "dead code " ) ?;
494501 }
495502
496- return Ok ( self
497- . tcx
498- . arena
499- . alloc_from_iter ( self . nodes . into_iter ( ) . map ( |( n, _used) | n) ) ) ;
503+ return Ok ( self . tcx . arena . alloc_from_iter ( self . nodes . into_iter ( ) . map ( |n| n. node ) ) ) ;
500504 }
501505 }
502506 }
0 commit comments