Optimize redundant_clone
by using a static data structure to track transitive relations.
This commit is contained in:
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_opt;
|
|||||||
use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth};
|
use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth};
|
||||||
use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
|
use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_data_structures::{fx::FxHashMap, transitive_relation::TransitiveRelation};
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::intravisit::FnKind;
|
use rustc_hir::intravisit::FnKind;
|
||||||
use rustc_hir::{def_id, Body, FnDecl, HirId};
|
use rustc_hir::{def_id, Body, FnDecl, HirId};
|
||||||
@@ -512,7 +512,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
|
|||||||
/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
|
/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
|
||||||
/// possible borrowers of `a`.
|
/// possible borrowers of `a`.
|
||||||
struct PossibleBorrowerVisitor<'a, 'tcx> {
|
struct PossibleBorrowerVisitor<'a, 'tcx> {
|
||||||
possible_borrower: TransitiveRelation<mir::Local>,
|
possible_borrower: TransitiveRelation,
|
||||||
body: &'a mir::Body<'tcx>,
|
body: &'a mir::Body<'tcx>,
|
||||||
cx: &'a LateContext<'tcx>,
|
cx: &'a LateContext<'tcx>,
|
||||||
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
|
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
|
||||||
@@ -543,18 +543,10 @@ impl<'a, 'tcx> PossibleBorrowerVisitor<'a, 'tcx> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let borrowers = self.possible_borrower.reachable_from(&row);
|
let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
|
||||||
|
borrowers.remove(mir::Local::from_usize(0));
|
||||||
if !borrowers.is_empty() {
|
if !borrowers.is_empty() {
|
||||||
let mut bs = HybridBitSet::new_empty(self.body.local_decls.len());
|
map.insert(row, borrowers);
|
||||||
for &c in borrowers {
|
|
||||||
if c != mir::Local::from_usize(0) {
|
|
||||||
bs.insert(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bs.is_empty() {
|
|
||||||
map.insert(row, bs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,7 +636,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
|
|||||||
/// For exampel, `_1 = &mut _2` generate _1: {_2,...}
|
/// For exampel, `_1 = &mut _2` generate _1: {_2,...}
|
||||||
/// Known Problems: not sure all borrowed are tracked
|
/// Known Problems: not sure all borrowed are tracked
|
||||||
struct PossibleOriginVisitor<'a, 'tcx> {
|
struct PossibleOriginVisitor<'a, 'tcx> {
|
||||||
possible_origin: TransitiveRelation<mir::Local>,
|
possible_origin: TransitiveRelation,
|
||||||
body: &'a mir::Body<'tcx>,
|
body: &'a mir::Body<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -663,18 +655,10 @@ impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let borrowers = self.possible_origin.reachable_from(&row);
|
let mut borrowers = self.possible_origin.reachable_from(row, self.body.local_decls.len());
|
||||||
|
borrowers.remove(mir::Local::from_usize(0));
|
||||||
if !borrowers.is_empty() {
|
if !borrowers.is_empty() {
|
||||||
let mut bs = HybridBitSet::new_empty(self.body.local_decls.len());
|
map.insert(row, borrowers);
|
||||||
for &c in borrowers {
|
|
||||||
if c != mir::Local::from_usize(0) {
|
|
||||||
bs.insert(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bs.is_empty() {
|
|
||||||
map.insert(row, bs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
map
|
map
|
||||||
@@ -766,3 +750,30 @@ impl PossibleBorrowerMap<'_, '_> {
|
|||||||
self.maybe_live.contains(local)
|
self.maybe_live.contains(local)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct TransitiveRelation {
|
||||||
|
relations: FxHashMap<mir::Local, Vec<mir::Local>>,
|
||||||
|
}
|
||||||
|
impl TransitiveRelation {
|
||||||
|
fn add(&mut self, a: mir::Local, b: mir::Local) {
|
||||||
|
self.relations.entry(a).or_default().push(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reachable_from(&self, a: mir::Local, domain_size: usize) -> HybridBitSet<mir::Local> {
|
||||||
|
let mut seen = HybridBitSet::new_empty(domain_size);
|
||||||
|
seen.insert(a);
|
||||||
|
let mut stack = vec![a];
|
||||||
|
while let Some(u) = stack.pop() {
|
||||||
|
if let Some(edges) = self.relations.get(&u) {
|
||||||
|
for &v in edges {
|
||||||
|
if seen.insert(v) {
|
||||||
|
stack.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seen.remove(a);
|
||||||
|
seen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user