Fix cycle detection in `needless_borrow`
This commit is contained in:
parent
6734e96ba4
commit
fed036a57c
|
@ -12,7 +12,6 @@ use hir::def::DefKind;
|
|||
use hir::MatchSource;
|
||||
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
|
@ -1172,8 +1171,6 @@ fn referent_used_exactly_once<'tcx>(
|
|||
&& let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
|
||||
&& let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
|
||||
&& !place.is_indirect_first_projection()
|
||||
// Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710)
|
||||
&& TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none()
|
||||
{
|
||||
let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
|
||||
if possible_borrowers
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use rustc_hir::{Expr, HirId};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{
|
||||
traversal, Body, InlineAsmOperand, Local, Location, Place, StatementKind, TerminatorKind, START_BLOCK,
|
||||
traversal, BasicBlock, Body, InlineAsmOperand, Local, Location, Place, StatementKind, TerminatorKind, START_BLOCK,
|
||||
};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
|
@ -79,8 +80,32 @@ impl<'a, 'tcx> Visitor<'tcx> for V<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if the block is part of a cycle
|
||||
pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool {
|
||||
let mut seen = BitSet::new_empty(body.basic_blocks.len());
|
||||
let mut to_visit = Vec::with_capacity(body.basic_blocks.len() / 2);
|
||||
|
||||
seen.insert(block);
|
||||
let mut next = block;
|
||||
loop {
|
||||
for succ in body.basic_blocks[next].terminator().successors() {
|
||||
if seen.insert(succ) {
|
||||
to_visit.push(succ);
|
||||
} else if succ == block {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(x) = to_visit.pop() {
|
||||
next = x;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience wrapper around `visit_local_usage`.
|
||||
pub fn used_exactly_once(mir: &rustc_middle::mir::Body<'_>, local: rustc_middle::mir::Local) -> Option<bool> {
|
||||
pub fn used_exactly_once(mir: &Body<'_>, local: rustc_middle::mir::Local) -> Option<bool> {
|
||||
visit_local_usage(
|
||||
&[local],
|
||||
mir,
|
||||
|
@ -91,11 +116,14 @@ pub fn used_exactly_once(mir: &rustc_middle::mir::Body<'_>, local: rustc_middle:
|
|||
)
|
||||
.map(|mut vec| {
|
||||
let LocalUsage { local_use_locs, .. } = vec.remove(0);
|
||||
local_use_locs
|
||||
let mut locations = local_use_locs
|
||||
.into_iter()
|
||||
.filter(|location| !is_local_assignment(mir, local, *location))
|
||||
.count()
|
||||
== 1
|
||||
.filter(|&location| !is_local_assignment(mir, local, location));
|
||||
if let Some(location) = locations.next() {
|
||||
locations.next().is_none() && !block_in_cycle(mir, location.block)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue