Skip to content

Commit fed036a

Browse files
committed
Fix cycle detection in needless_borrow
1 parent 6734e96 commit fed036a

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

clippy_lints/src/dereference.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use hir::def::DefKind;
1212
use hir::MatchSource;
1313
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
1414
use rustc_data_structures::fx::FxIndexMap;
15-
use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
1615
use rustc_errors::Applicability;
1716
use rustc_hir::def::Res;
1817
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -1172,8 +1171,6 @@ fn referent_used_exactly_once<'tcx>(
11721171
&& let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
11731172
&& let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
11741173
&& !place.is_indirect_first_projection()
1175-
// Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710)
1176-
&& TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none()
11771174
{
11781175
let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
11791176
if possible_borrowers

clippy_utils/src/mir/mod.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use rustc_hir::{Expr, HirId};
2+
use rustc_index::bit_set::BitSet;
23
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
34
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,
56
};
67
use rustc_middle::ty::TyCtxt;
78

@@ -79,8 +80,32 @@ impl<'a, 'tcx> Visitor<'tcx> for V<'a> {
7980
}
8081
}
8182

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+
82107
/// 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> {
84109
visit_local_usage(
85110
&[local],
86111
mir,
@@ -91,11 +116,14 @@ pub fn used_exactly_once(mir: &rustc_middle::mir::Body<'_>, local: rustc_middle:
91116
)
92117
.map(|mut vec| {
93118
let LocalUsage { local_use_locs, .. } = vec.remove(0);
94-
local_use_locs
119+
let mut locations = local_use_locs
95120
.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+
}
99127
})
100128
}
101129

0 commit comments

Comments
 (0)