@@ -223,6 +223,13 @@ impl AbstractConst<'tcx> {
223
223
}
224
224
}
225
225
226
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
227
+ struct WorkNode < ' tcx > {
228
+ node : Node < ' tcx > ,
229
+ span : Span ,
230
+ used : bool ,
231
+ }
232
+
226
233
struct AbstractConstBuilder < ' a , ' tcx > {
227
234
tcx : TyCtxt < ' tcx > ,
228
235
body : & ' a mir:: Body < ' tcx > ,
@@ -232,7 +239,7 @@ struct AbstractConstBuilder<'a, 'tcx> {
232
239
/// so we store this here. Note that we also consider nodes as used
233
240
/// if they are mentioned in an assert, so some used nodes are never
234
241
/// actually reachable by walking the [`AbstractConst`].
235
- nodes : IndexVec < NodeId , ( Node < ' tcx > , bool ) > ,
242
+ nodes : IndexVec < NodeId , WorkNode < ' tcx > > ,
236
243
locals : IndexVec < mir:: Local , NodeId > ,
237
244
/// We only allow field accesses if they access
238
245
/// the result of a checked operation.
@@ -279,25 +286,25 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
279
286
Ok ( Some ( builder) )
280
287
}
281
288
282
- fn add_node ( & mut self , n : Node < ' tcx > ) -> NodeId {
289
+ fn add_node ( & mut self , node : Node < ' tcx > , span : Span ) -> NodeId {
283
290
// Mark used nodes.
284
- match n {
291
+ match node {
285
292
Node :: Leaf ( _) => ( ) ,
286
293
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 ;
289
296
}
290
297
Node :: UnaryOp ( _, input) => {
291
- self . nodes [ input] . 1 = true ;
298
+ self . nodes [ input] . used = true ;
292
299
}
293
300
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 ) ;
296
303
}
297
304
}
298
305
299
306
// Nodes start as unused.
300
- self . nodes . push ( ( n , false ) )
307
+ self . nodes . push ( WorkNode { node , span , used : false } )
301
308
}
302
309
303
310
fn place_to_local (
@@ -337,7 +344,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
337
344
let local = self . place_to_local ( span, p) ?;
338
345
Ok ( self . locals [ local] )
339
346
}
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 ) ) ,
341
348
}
342
349
}
343
350
@@ -362,38 +369,38 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
362
369
363
370
fn build_statement ( & mut self , stmt : & mir:: Statement < ' tcx > ) -> Result < ( ) , ErrorReported > {
364
371
debug ! ( "AbstractConstBuilder: stmt={:?}" , stmt) ;
372
+ let span = stmt. source_info . span ;
365
373
match stmt. kind {
366
374
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) ?;
368
376
match * rvalue {
369
377
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) ?;
372
379
Ok ( ( ) )
373
380
}
374
381
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 ) ;
378
385
if op. is_checkable ( ) {
379
386
bug ! ( "unexpected unchecked checkable binary operation" ) ;
380
387
} else {
381
388
Ok ( ( ) )
382
389
}
383
390
}
384
391
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 ) ;
388
395
self . checked_op_locals . insert ( local) ;
389
396
Ok ( ( ) )
390
397
}
391
398
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 ) ;
394
401
Ok ( ( ) )
395
402
}
396
- _ => self . error ( Some ( stmt . source_info . span ) , "unsupported rvalue" ) ?,
403
+ _ => self . error ( Some ( span) , "unsupported rvalue" ) ?,
397
404
}
398
405
}
399
406
// These are not actually relevant for us here, so we can ignore them.
@@ -441,7 +448,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
441
448
. map ( |arg| self . operand_to_node ( terminator. source_info . span , arg) )
442
449
. collect :: < Result < Vec < NodeId > , _ > > ( ) ?,
443
450
) ;
444
- self . locals [ local] = self . add_node ( Node :: FunctionCall ( func, args) ) ;
451
+ self . locals [ local] = self . add_node ( Node :: FunctionCall ( func, args) , fn_span ) ;
445
452
Ok ( Some ( target) )
446
453
}
447
454
TerminatorKind :: Assert { ref cond, expected : false , target, .. } => {
@@ -458,7 +465,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
458
465
//
459
466
// This is needed because division does not use `CheckedBinop` but instead
460
467
// adds an explicit assert for `divisor != 0`.
461
- self . nodes [ self . locals [ p] ] . 1 = true ;
468
+ self . nodes [ self . locals [ p] ] . used = true ;
462
469
return Ok ( Some ( target) ) ;
463
470
} else if let & [ mir:: ProjectionElem :: Field ( ONE_FIELD , _) ] = p. projection . as_ref ( ) {
464
471
// Only allow asserts checking the result of a checked operation.
@@ -487,16 +494,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
487
494
if let Some ( next) = self . build_terminator ( block. terminator ( ) ) ? {
488
495
block = & self . body . basic_blocks ( ) [ next] ;
489
496
} 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 " ) ?;
494
501
}
495
502
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 ) ) ) ;
500
504
}
501
505
}
502
506
}
0 commit comments