From 6daa6d5ffe04475c8e54498dc1ebcdb4a884928c Mon Sep 17 00:00:00 2001 From: mi_sawa Date: Sat, 12 Feb 2022 02:24:32 +0900 Subject: [PATCH] Optimize redundant_clone by using a static data structure to track transitive relations. --- clippy_lints/src/redundant_clone.rs | 61 +++++++++++++++++------------ 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 3e0e32857f1d..60cc8fddcb49 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -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::{fn_has_unsatisfiable_preds, match_def_path, paths}; 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_hir::intravisit::FnKind; 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` /// possible borrowers of `a`. struct PossibleBorrowerVisitor<'a, 'tcx> { - possible_borrower: TransitiveRelation, + possible_borrower: TransitiveRelation, body: &'a mir::Body<'tcx>, cx: &'a LateContext<'tcx>, possible_origin: FxHashMap>, @@ -543,18 +543,10 @@ impl<'a, 'tcx> PossibleBorrowerVisitor<'a, 'tcx> { 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() { - let mut bs = HybridBitSet::new_empty(self.body.local_decls.len()); - for &c in borrowers { - if c != mir::Local::from_usize(0) { - bs.insert(c); - } - } - - if !bs.is_empty() { - map.insert(row, bs); - } + map.insert(row, borrowers); } } @@ -644,7 +636,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { /// For exampel, `_1 = &mut _2` generate _1: {_2,...} /// Known Problems: not sure all borrowed are tracked struct PossibleOriginVisitor<'a, 'tcx> { - possible_origin: TransitiveRelation, + possible_origin: TransitiveRelation, body: &'a mir::Body<'tcx>, } @@ -663,18 +655,10 @@ impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> { 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() { - let mut bs = HybridBitSet::new_empty(self.body.local_decls.len()); - for &c in borrowers { - if c != mir::Local::from_usize(0) { - bs.insert(c); - } - } - - if !bs.is_empty() { - map.insert(row, bs); - } + map.insert(row, borrowers); } } map @@ -766,3 +750,30 @@ impl PossibleBorrowerMap<'_, '_> { self.maybe_live.contains(local) } } + +#[derive(Default)] +struct TransitiveRelation { + relations: FxHashMap>, +} +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 { + 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 + } +}