Skip to content

Commit 7f27e2e

Browse files
committed
Auto merge of rust-lang#10192 - Jarcho:revert_9701, r=flip1995
Partially revert rust-lang#9701 This partially reverts rust-lang#9701 due to rust-lang#10134 r? `@flip1995` changelog: None
2 parents 0b8ee70 + 757e944 commit 7f27e2e

9 files changed

+109
-233
lines changed

clippy_lints/src/dereference.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>(
12821282
possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
12831283
}
12841284
let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
1285-
// If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The
1286-
// reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible
1287-
// borrower of itself. See the comment in that method for an explanation as to why.
1288-
possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location)
1285+
// If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
1286+
// that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
1287+
// itself. See the comment in that method for an explanation as to why.
1288+
possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
12891289
&& used_exactly_once(mir, place.local).unwrap_or(false)
12901290
} else {
12911291
false

clippy_lints/src/redundant_clone.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
131131
// `res = clone(arg)` can be turned into `res = move arg;`
132132
// if `arg` is the only borrow of `cloned` at this point.
133133

134-
if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) {
134+
if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) {
135135
continue;
136136
}
137137

@@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
178178
// StorageDead(pred_arg);
179179
// res = to_path_buf(cloned);
180180
// ```
181-
if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) {
181+
if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) {
182182
continue;
183183
}
184184

clippy_utils/src/mir/possible_borrower.rs

+99-171
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,90 @@
1-
use super::possible_origin::PossibleOriginVisitor;
1+
use super::{possible_origin::PossibleOriginVisitor, transitive_relation::TransitiveRelation};
22
use crate::ty::is_copy;
3-
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
3+
use rustc_data_structures::fx::FxHashMap;
44
use rustc_index::bit_set::{BitSet, HybridBitSet};
55
use rustc_lint::LateContext;
6-
use rustc_middle::mir::{
7-
self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator,
8-
};
9-
use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt};
10-
use rustc_mir_dataflow::{
11-
fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain,
12-
CallReturnPlaces, ResultsCursor,
13-
};
6+
use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
7+
use rustc_middle::ty::{self, visit::TypeVisitor};
8+
use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor};
149
use std::borrow::Cow;
1510
use std::ops::ControlFlow;
1611

1712
/// Collects the possible borrowers of each local.
1813
/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
1914
/// possible borrowers of `a`.
2015
#[allow(clippy::module_name_repetitions)]
21-
struct PossibleBorrowerAnalysis<'b, 'tcx> {
22-
tcx: TyCtxt<'tcx>,
16+
struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
17+
possible_borrower: TransitiveRelation,
2318
body: &'b mir::Body<'tcx>,
19+
cx: &'a LateContext<'tcx>,
2420
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
2521
}
2622

27-
#[derive(Clone, Debug, Eq, PartialEq)]
28-
struct PossibleBorrowerState {
29-
map: FxIndexMap<Local, BitSet<Local>>,
30-
domain_size: usize,
31-
}
32-
33-
impl PossibleBorrowerState {
34-
fn new(domain_size: usize) -> Self {
23+
impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
24+
fn new(
25+
cx: &'a LateContext<'tcx>,
26+
body: &'b mir::Body<'tcx>,
27+
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
28+
) -> Self {
3529
Self {
36-
map: FxIndexMap::default(),
37-
domain_size,
30+
possible_borrower: TransitiveRelation::default(),
31+
cx,
32+
body,
33+
possible_origin,
3834
}
3935
}
4036

41-
#[allow(clippy::similar_names)]
42-
fn add(&mut self, borrowed: Local, borrower: Local) {
43-
self.map
44-
.entry(borrowed)
45-
.or_insert(BitSet::new_empty(self.domain_size))
46-
.insert(borrower);
47-
}
48-
}
49-
50-
impl<C> DebugWithContext<C> for PossibleBorrowerState {
51-
fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52-
<_ as std::fmt::Debug>::fmt(self, f)
53-
}
54-
fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55-
unimplemented!()
56-
}
57-
}
37+
fn into_map(
38+
self,
39+
cx: &'a LateContext<'tcx>,
40+
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>,
41+
) -> PossibleBorrowerMap<'b, 'tcx> {
42+
let mut map = FxHashMap::default();
43+
for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
44+
if is_copy(cx, self.body.local_decls[row].ty) {
45+
continue;
46+
}
5847

59-
impl JoinSemiLattice for PossibleBorrowerState {
60-
fn join(&mut self, other: &Self) -> bool {
61-
let mut changed = false;
62-
for (&borrowed, borrowers) in other.map.iter() {
48+
let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
49+
borrowers.remove(mir::Local::from_usize(0));
6350
if !borrowers.is_empty() {
64-
changed |= self
65-
.map
66-
.entry(borrowed)
67-
.or_insert(BitSet::new_empty(self.domain_size))
68-
.union(borrowers);
51+
map.insert(row, borrowers);
6952
}
7053
}
71-
changed
72-
}
73-
}
74-
75-
impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
76-
type Domain = PossibleBorrowerState;
77-
78-
const NAME: &'static str = "possible_borrower";
79-
80-
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
81-
PossibleBorrowerState::new(body.local_decls.len())
82-
}
83-
84-
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {}
85-
}
8654

87-
impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> {
88-
fn new(
89-
tcx: TyCtxt<'tcx>,
90-
body: &'b mir::Body<'tcx>,
91-
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
92-
) -> Self {
93-
Self {
94-
tcx,
95-
body,
96-
possible_origin,
55+
let bs = BitSet::new_empty(self.body.local_decls.len());
56+
PossibleBorrowerMap {
57+
map,
58+
maybe_live,
59+
bitset: (bs.clone(), bs),
9760
}
9861
}
9962
}
10063

101-
impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
102-
fn apply_call_return_effect(
103-
&self,
104-
_state: &mut Self::Domain,
105-
_block: BasicBlock,
106-
_return_places: CallReturnPlaces<'_, 'tcx>,
107-
) {
108-
}
109-
110-
fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) {
111-
if let StatementKind::Assign(box (place, rvalue)) = &statement.kind {
112-
let lhs = place.local;
113-
match rvalue {
114-
mir::Rvalue::Ref(_, _, borrowed) => {
115-
state.add(borrowed.local, lhs);
116-
},
117-
other => {
118-
if ContainsRegion
119-
.visit_ty(place.ty(&self.body.local_decls, self.tcx).ty)
120-
.is_continue()
121-
{
122-
return;
64+
impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
65+
fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
66+
let lhs = place.local;
67+
match rvalue {
68+
mir::Rvalue::Ref(_, _, borrowed) => {
69+
self.possible_borrower.add(borrowed.local, lhs);
70+
},
71+
other => {
72+
if ContainsRegion
73+
.visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
74+
.is_continue()
75+
{
76+
return;
77+
}
78+
rvalue_locals(other, |rhs| {
79+
if lhs != rhs {
80+
self.possible_borrower.add(rhs, lhs);
12381
}
124-
rvalue_locals(other, |rhs| {
125-
if lhs != rhs {
126-
state.add(rhs, lhs);
127-
}
128-
});
129-
},
130-
}
82+
});
83+
},
13184
}
13285
}
13386

134-
fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) {
87+
fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
13588
if let mir::TerminatorKind::Call {
13689
args,
13790
destination: mir::Place { local: dest, .. },
@@ -171,10 +124,10 @@ impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
171124

172125
for y in mutable_variables {
173126
for x in &immutable_borrowers {
174-
state.add(*x, y);
127+
self.possible_borrower.add(*x, y);
175128
}
176129
for x in &mutable_borrowers {
177-
state.add(*x, y);
130+
self.possible_borrower.add(*x, y);
178131
}
179132
}
180133
}
@@ -210,98 +163,73 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
210163
}
211164
}
212165

213-
/// Result of `PossibleBorrowerAnalysis`.
166+
/// Result of `PossibleBorrowerVisitor`.
214167
#[allow(clippy::module_name_repetitions)]
215168
pub struct PossibleBorrowerMap<'b, 'tcx> {
216-
body: &'b mir::Body<'tcx>,
217-
possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>,
218-
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>,
219-
pushed: BitSet<Local>,
220-
stack: Vec<Local>,
169+
/// Mapping `Local -> its possible borrowers`
170+
pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
171+
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>,
172+
// Caches to avoid allocation of `BitSet` on every query
173+
pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
221174
}
222175

223-
impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
224-
pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
176+
impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
177+
pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
225178
let possible_origin = {
226179
let mut vis = PossibleOriginVisitor::new(mir);
227180
vis.visit_body(mir);
228181
vis.into_map(cx)
229182
};
230-
let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin)
183+
let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
231184
.into_engine(cx.tcx, mir)
232-
.pass_name("possible_borrower")
185+
.pass_name("redundant_clone")
233186
.iterate_to_fixpoint()
234187
.into_results_cursor(mir);
235-
let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
236-
.into_engine(cx.tcx, mir)
237-
.pass_name("possible_borrower")
238-
.iterate_to_fixpoint()
239-
.into_results_cursor(mir);
240-
PossibleBorrowerMap {
241-
body: mir,
242-
possible_borrower,
243-
maybe_live,
244-
pushed: BitSet::new_empty(mir.local_decls.len()),
245-
stack: Vec::with_capacity(mir.local_decls.len()),
246-
}
188+
let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
189+
vis.visit_body(mir);
190+
vis.into_map(cx, maybe_storage_live_result)
247191
}
248192

249-
/// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than
250-
/// `borrowers`.
251-
/// Notes:
252-
/// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers`
253-
/// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass`
254-
/// `Dereferencing`, which outlives any `LateContext`.
255-
/// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two
256-
/// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If
257-
/// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be
258-
/// adjusted.
259-
pub fn at_most_borrowers(
193+
/// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
194+
pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
195+
self.bounded_borrowers(borrowers, borrowers, borrowed, at)
196+
}
197+
198+
/// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below`
199+
/// but no more than `above`.
200+
pub fn bounded_borrowers(
260201
&mut self,
261-
cx: &LateContext<'tcx>,
262-
borrowers: &[mir::Local],
202+
below: &[mir::Local],
203+
above: &[mir::Local],
263204
borrowed: mir::Local,
264205
at: mir::Location,
265206
) -> bool {
266-
if is_copy(cx, self.body.local_decls[borrowed].ty) {
267-
return true;
268-
}
269-
270-
self.possible_borrower.seek_before_primary_effect(at);
271-
self.maybe_live.seek_before_primary_effect(at);
272-
273-
let possible_borrower = &self.possible_borrower.get().map;
274-
let maybe_live = &self.maybe_live;
275-
276-
self.pushed.clear();
277-
self.stack.clear();
207+
self.maybe_live.seek_after_primary_effect(at);
278208

279-
if let Some(borrowers) = possible_borrower.get(&borrowed) {
280-
for b in borrowers.iter() {
281-
if self.pushed.insert(b) {
282-
self.stack.push(b);
283-
}
209+
self.bitset.0.clear();
210+
let maybe_live = &mut self.maybe_live;
211+
if let Some(bitset) = self.map.get(&borrowed) {
212+
for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
213+
self.bitset.0.insert(b);
284214
}
285215
} else {
286-
// Nothing borrows `borrowed` at `at`.
287-
return true;
216+
return false;
288217
}
289218

290-
while let Some(borrower) = self.stack.pop() {
291-
if maybe_live.contains(borrower) && !borrowers.contains(&borrower) {
292-
return false;
293-
}
219+
self.bitset.1.clear();
220+
for b in below {
221+
self.bitset.1.insert(*b);
222+
}
294223

295-
if let Some(borrowers) = possible_borrower.get(&borrower) {
296-
for b in borrowers.iter() {
297-
if self.pushed.insert(b) {
298-
self.stack.push(b);
299-
}
300-
}
301-
}
224+
if !self.bitset.0.superset(&self.bitset.1) {
225+
return false;
226+
}
227+
228+
for b in above {
229+
self.bitset.0.remove(*b);
302230
}
303231

304-
true
232+
self.bitset.0.is_empty()
305233
}
306234

307235
pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {

0 commit comments

Comments
 (0)