Skip to content

Commit e8880c1

Browse files
committed
Implement PossibleBorrowerMap using the borrowck crate
1 parent 71926a2 commit e8880c1

File tree

10 files changed

+357
-354
lines changed

10 files changed

+357
-354
lines changed

clippy_lints/src/dereference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,7 @@ fn referent_used_exactly_once<'tcx>(
12791279
.last()
12801280
.map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id)
12811281
{
1282-
possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
1282+
possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, body_owner_local_def_id)));
12831283
}
12841284
let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
12851285
// If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The

clippy_lints/src/redundant_clone.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
8282

8383
let mir = cx.tcx.optimized_mir(def_id.to_def_id());
8484

85-
let mut possible_borrower = PossibleBorrowerMap::new(cx, mir);
85+
let mut possible_borrower = PossibleBorrowerMap::new(cx, def_id);
8686

8787
for (bb, bbdata) in mir.basic_blocks.iter_enumerated() {
8888
let terminator = bbdata.terminator();

clippy_utils/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
extern crate rustc_ast;
2222
extern crate rustc_ast_pretty;
2323
extern crate rustc_attr;
24+
extern crate rustc_borrowck;
2425
extern crate rustc_data_structures;
2526
// The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate.
2627
#[allow(unused_extern_crates)]
@@ -33,7 +34,9 @@ extern crate rustc_infer;
3334
extern crate rustc_lexer;
3435
extern crate rustc_lint;
3536
extern crate rustc_middle;
37+
extern crate rustc_mir_build;
3638
extern crate rustc_mir_dataflow;
39+
extern crate rustc_mir_transform;
3740
extern crate rustc_parse_format;
3841
extern crate rustc_session;
3942
extern crate rustc_span;

clippy_utils/src/mir/mod.rs

Lines changed: 193 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
use rustc_hir::{Expr, HirId};
2-
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
2+
use rustc_middle::mir::visit::{
3+
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, TyContext, Visitor,
4+
};
35
use rustc_middle::mir::{
4-
traversal, Body, InlineAsmOperand, Local, Location, Place, StatementKind, TerminatorKind, START_BLOCK,
6+
traversal, Body, InlineAsmOperand, Local, LocalDecl, Location, Place, Statement, StatementKind, Terminator,
7+
TerminatorKind, START_BLOCK,
58
};
6-
use rustc_middle::ty::TyCtxt;
9+
use rustc_middle::ty::{Region, Ty, TyCtxt};
710

811
mod possible_borrower;
912
pub use possible_borrower::PossibleBorrowerMap;
1013

11-
mod possible_origin;
12-
13-
mod transitive_relation;
14-
1514
#[derive(Clone, Debug, Default)]
1615
pub struct LocalUsage {
1716
/// The locations where the local is used, if any.
@@ -119,6 +118,193 @@ pub fn expr_local(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> Option<Local> {
119118
})
120119
}
121120

121+
/// Tries to find the local in `to_mir` corresponding to `local` in `from_mir`.
122+
pub fn translate_local<'tcx>(
123+
tcx: TyCtxt<'tcx>,
124+
from_mir: &Body<'tcx>,
125+
to_mir: &Body<'tcx>,
126+
local: Local,
127+
) -> Option<Local> {
128+
let equiv_decl = |lhs: &LocalDecl<'tcx>, rhs: &LocalDecl<'tcx>| {
129+
lhs.mutability == rhs.mutability
130+
&& tcx.erase_regions_ty(lhs.ty) == tcx.erase_regions_ty(rhs.ty)
131+
&& lhs.source_info.span == rhs.source_info.span
132+
};
133+
134+
let from_decl = &from_mir.local_decls[local];
135+
136+
// Fast path
137+
if to_mir
138+
.local_decls
139+
.get(local)
140+
.map_or(false, |to_decl| equiv_decl(from_decl, to_decl))
141+
{
142+
return Some(local);
143+
}
144+
145+
// Slow path
146+
to_mir
147+
.local_decls
148+
.iter()
149+
.position(|to_decl| equiv_decl(from_decl, to_decl))
150+
.map(Into::into)
151+
}
152+
153+
/// Tries to find the location in `to_mir` corresponding to `location` in `from_mir`.
154+
pub fn translate_location<'tcx>(
155+
tcx: TyCtxt<'tcx>,
156+
from_mir: &Body<'tcx>,
157+
to_mir: &Body<'tcx>,
158+
location: Location,
159+
) -> Option<Location> {
160+
let normalized_lhs = from_mir
161+
.stmt_at(location)
162+
.map_left(|statement| normalize_statement(tcx, statement))
163+
.map_right(|terminator| normalize_terminator(tcx, terminator));
164+
165+
for (block, block_data) in to_mir.basic_blocks.iter_enumerated() {
166+
if let Some(location) = normalized_lhs.as_ref().either(
167+
|normalized_lhs| {
168+
(0..block_data.statements.len()).find_map(|statement_index| {
169+
let rhs = &block_data.statements[statement_index];
170+
if normalized_lhs.source_info.span == rhs.source_info.span
171+
&& normalized_lhs.kind == normalize_statement(tcx, rhs).kind
172+
{
173+
Some(Location { block, statement_index })
174+
} else {
175+
None
176+
}
177+
})
178+
},
179+
|normalized_lhs| {
180+
if block_data.terminator.as_ref().map_or(false, |rhs| {
181+
normalized_lhs.source_info.span == rhs.source_info.span
182+
&& normalized_lhs.kind == normalize_terminator(tcx, rhs).kind
183+
}) {
184+
Some(Location {
185+
block,
186+
statement_index: block_data.statements.len(),
187+
})
188+
} else {
189+
None
190+
}
191+
},
192+
) {
193+
return Some(location);
194+
}
195+
}
196+
197+
None
198+
}
199+
200+
fn normalize_statement<'tcx>(tcx: TyCtxt<'tcx>, statement: &Statement<'tcx>) -> Statement<'tcx> {
201+
let mut statement = statement.clone();
202+
Normalizer { tcx }.visit_statement(&mut statement, Location::START);
203+
statement
204+
}
205+
206+
fn normalize_terminator<'tcx>(tcx: TyCtxt<'tcx>, terminator: &Terminator<'tcx>) -> Terminator<'tcx> {
207+
let mut terminator = terminator.clone();
208+
Normalizer { tcx }.visit_terminator(&mut terminator, Location::START);
209+
match terminator.kind {
210+
// No basic blocks
211+
TerminatorKind::Abort
212+
| TerminatorKind::GeneratorDrop
213+
| TerminatorKind::Resume
214+
| TerminatorKind::Return
215+
| TerminatorKind::Unreachable => {},
216+
217+
// One basic block
218+
TerminatorKind::Goto { ref mut target } => {
219+
*target = Location::START.block;
220+
},
221+
222+
// Two basic blocks
223+
TerminatorKind::FalseEdge {
224+
ref mut real_target,
225+
ref mut imaginary_target,
226+
} => {
227+
*real_target = Location::START.block;
228+
*imaginary_target = Location::START.block;
229+
},
230+
231+
// One optional and one non-optional basic block
232+
TerminatorKind::Assert {
233+
ref mut target,
234+
cleanup: ref mut unwind,
235+
..
236+
}
237+
| TerminatorKind::Drop {
238+
ref mut target,
239+
ref mut unwind,
240+
..
241+
}
242+
| TerminatorKind::DropAndReplace {
243+
ref mut target,
244+
ref mut unwind,
245+
..
246+
}
247+
| TerminatorKind::FalseUnwind {
248+
real_target: ref mut target,
249+
ref mut unwind,
250+
..
251+
}
252+
| TerminatorKind::Yield {
253+
resume: ref mut target,
254+
drop: ref mut unwind,
255+
..
256+
} => {
257+
*target = Location::START.block;
258+
*unwind = None;
259+
},
260+
261+
// Two optional basic blocks
262+
TerminatorKind::Call {
263+
ref mut target,
264+
ref mut cleanup,
265+
..
266+
}
267+
| TerminatorKind::InlineAsm {
268+
destination: ref mut target,
269+
ref mut cleanup,
270+
..
271+
} => {
272+
*target = None;
273+
*cleanup = None;
274+
},
275+
276+
// Arbitrarily many basic blocks
277+
TerminatorKind::SwitchInt { ref mut targets, .. } => {
278+
for (_, ref mut target) in targets.iter() {
279+
*target = Location::START.block;
280+
}
281+
},
282+
}
283+
terminator
284+
}
285+
286+
struct Normalizer<'tcx> {
287+
tcx: TyCtxt<'tcx>,
288+
}
289+
290+
impl<'tcx> MutVisitor<'tcx> for Normalizer<'tcx> {
291+
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
292+
self.tcx
293+
}
294+
295+
fn visit_local(&mut self, local: &mut Local, _context: PlaceContext, _location: Location) {
296+
*local = Local::from_u32(0);
297+
}
298+
299+
fn visit_region(&mut self, region: &mut Region<'tcx>, _: Location) {
300+
*region = self.tcx.lifetimes.re_erased;
301+
}
302+
303+
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
304+
*ty = self.tcx.erase_regions_ty(*ty);
305+
}
306+
}
307+
122308
/// Returns a vector of `mir::Location` where `local` is assigned.
123309
pub fn local_assignments(mir: &Body<'_>, local: Local) -> Vec<Location> {
124310
let mut locations = Vec::new();

0 commit comments

Comments
 (0)