Skip to content

Commit 16829a3

Browse files
Don't emit needless_pass_by_ref_mut if the variable is used in an unsafe block or function
1 parent 9554e47 commit 16829a3

File tree

1 file changed

+39
-2
lines changed

1 file changed

+39
-2
lines changed

clippy_lints/src/needless_pass_by_ref_mut.rs

+39-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
77
use rustc_errors::Applicability;
88
use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
99
use rustc_hir::{
10-
Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath,
10+
BlockCheckMode, Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node,
11+
PatKind, QPath,
1112
};
1213
use rustc_hir_typeck::expr_use_visitor as euv;
1314
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -139,13 +140,23 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
139140
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
140141
let is_async = match kind {
141142
FnKind::ItemFn(.., header) => {
143+
if header.is_unsafe() {
144+
// We don't check unsafe functions.
145+
return;
146+
}
142147
let attrs = cx.tcx.hir().attrs(hir_id);
143148
if header.abi != Abi::Rust || requires_exact_signature(attrs) {
144149
return;
145150
}
146151
header.is_async()
147152
},
148-
FnKind::Method(.., sig) => sig.header.is_async(),
153+
FnKind::Method(.., sig) => {
154+
if sig.header.is_unsafe() {
155+
// We don't check unsafe functions.
156+
return;
157+
}
158+
sig.header.is_async()
159+
},
149160
FnKind::Closure => return,
150161
};
151162

@@ -304,9 +315,26 @@ impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
304315
}
305316
self.aliases.insert(alias, target);
306317
}
318+
319+
// The goal here is to find if the current scope is unsafe or not. It stops when it finds
320+
// a function or an unsafe block.
321+
fn is_in_unsafe_block(&self, item: HirId) -> bool {
322+
let hir = self.tcx.hir();
323+
for (parent, node) in hir.parent_iter(item) {
324+
if let Some(fn_sig) = hir.fn_sig_by_hir_id(parent) {
325+
return fn_sig.header.is_unsafe();
326+
} else if let Node::Block(block) = node {
327+
if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) {
328+
return true;
329+
}
330+
}
331+
}
332+
false
333+
}
307334
}
308335

309336
impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
337+
#[allow(clippy::if_same_then_else)]
310338
fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
311339
if let euv::Place {
312340
base:
@@ -327,12 +355,17 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
327355
&& matches!(base_ty.ref_mutability(), Some(Mutability::Mut))
328356
{
329357
self.add_mutably_used_var(*vid);
358+
} else if self.is_in_unsafe_block(*vid) {
359+
// If we are in an unsafe block, any operation on this variable must not be warned
360+
// upon!
361+
self.add_mutably_used_var(*vid);
330362
}
331363
self.prev_bind = None;
332364
self.prev_move_to_closure.remove(vid);
333365
}
334366
}
335367

368+
#[allow(clippy::if_same_then_else)]
336369
fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId, borrow: ty::BorrowKind) {
337370
self.prev_bind = None;
338371
if let euv::Place {
@@ -355,6 +388,10 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
355388
|| (borrow == ty::BorrowKind::UniqueImmBorrow && base_ty.ref_mutability() == Some(Mutability::Mut))
356389
{
357390
self.add_mutably_used_var(*vid);
391+
} else if self.is_in_unsafe_block(*vid) {
392+
// If we are in an unsafe block, any operation on this variable must not be warned
393+
// upon!
394+
self.add_mutably_used_var(*vid);
358395
}
359396
} else if borrow == ty::ImmBorrow {
360397
// If there is an `async block`, it'll contain a call to a closure which we need to

0 commit comments

Comments
 (0)