1
1
use rustc_hir:: { Expr , HirId } ;
2
+ use rustc_index:: bit_set:: BitSet ;
2
3
use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
3
4
use rustc_middle:: mir:: {
4
- traversal, Body , InlineAsmOperand , Local , Location , Place , StatementKind , TerminatorKind , START_BLOCK ,
5
+ traversal, BasicBlock , Body , InlineAsmOperand , Local , Location , Place , StatementKind , TerminatorKind , START_BLOCK ,
5
6
} ;
6
7
use rustc_middle:: ty:: TyCtxt ;
7
8
@@ -79,8 +80,32 @@ impl<'a, 'tcx> Visitor<'tcx> for V<'a> {
79
80
}
80
81
}
81
82
83
+ /// Checks if the block is part of a cycle
84
+ pub fn block_in_cycle ( body : & Body < ' _ > , block : BasicBlock ) -> bool {
85
+ let mut seen = BitSet :: new_empty ( body. basic_blocks . len ( ) ) ;
86
+ let mut to_visit = Vec :: with_capacity ( body. basic_blocks . len ( ) / 2 ) ;
87
+
88
+ seen. insert ( block) ;
89
+ let mut next = block;
90
+ loop {
91
+ for succ in body. basic_blocks [ next] . terminator ( ) . successors ( ) {
92
+ if seen. insert ( succ) {
93
+ to_visit. push ( succ) ;
94
+ } else if succ == block {
95
+ return true ;
96
+ }
97
+ }
98
+
99
+ if let Some ( x) = to_visit. pop ( ) {
100
+ next = x;
101
+ } else {
102
+ return false ;
103
+ }
104
+ }
105
+ }
106
+
82
107
/// Convenience wrapper around `visit_local_usage`.
83
- pub fn used_exactly_once ( mir : & rustc_middle :: mir :: Body < ' _ > , local : rustc_middle:: mir:: Local ) -> Option < bool > {
108
+ pub fn used_exactly_once ( mir : & Body < ' _ > , local : rustc_middle:: mir:: Local ) -> Option < bool > {
84
109
visit_local_usage (
85
110
& [ local] ,
86
111
mir,
@@ -91,11 +116,14 @@ pub fn used_exactly_once(mir: &rustc_middle::mir::Body<'_>, local: rustc_middle:
91
116
)
92
117
. map ( |mut vec| {
93
118
let LocalUsage { local_use_locs, .. } = vec. remove ( 0 ) ;
94
- local_use_locs
119
+ let mut locations = local_use_locs
95
120
. into_iter ( )
96
- . filter ( |location| !is_local_assignment ( mir, local, * location) )
97
- . count ( )
98
- == 1
121
+ . filter ( |& location| !is_local_assignment ( mir, local, location) ) ;
122
+ if let Some ( location) = locations. next ( ) {
123
+ locations. next ( ) . is_none ( ) && !block_in_cycle ( mir, location. block )
124
+ } else {
125
+ false
126
+ }
99
127
} )
100
128
}
101
129
0 commit comments