Skip to content

Commit a68cd88

Browse files
committed
Lint needless_borrow on most union field accesses
1 parent 34b7d15 commit a68cd88

File tree

4 files changed

+116
-33
lines changed

4 files changed

+116
-33
lines changed

clippy_lints/src/dereference.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
55
use clippy_utils::{
66
expr_use_ctxt, get_parent_expr, get_parent_node, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
77
};
8+
use core::mem;
89
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
910
use rustc_data_structures::fx::FxIndexMap;
1011
use rustc_errors::Applicability;
@@ -342,8 +343,24 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
342343
TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return())
343344
});
344345
let can_auto_borrow = match use_cx.node {
345-
ExprUseNode::Callee => true,
346-
ExprUseNode::FieldAccess(_) => adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union()),
346+
ExprUseNode::FieldAccess(_)
347+
if !use_cx.moved_before_use && matches!(sub_expr.kind, ExprKind::Field(..)) =>
348+
{
349+
// `ManuallyDrop` fields of a union will not automatically call
350+
// `deref_mut` when accessing a field.
351+
// Note: if the `ManuallyDrop` value is not directly a field of a
352+
// union then `DerefMut` will work as normal.
353+
//
354+
// This means we need to not modify an expression such as `(&mut x.y).z`
355+
// if accessing `z` would require `DerefMut`.
356+
let mut ty = expr_ty;
357+
!use_cx.adjustments.iter().any(|a| {
358+
let ty = mem::replace(&mut ty, a.target);
359+
matches!(a.kind, Adjust::Deref(Some(ref op)) if op.mutbl == Mutability::Mut)
360+
&& ty.ty_adt_def().map_or(false, |def| def.is_manually_drop())
361+
})
362+
},
363+
ExprUseNode::Callee | ExprUseNode::FieldAccess(_) => true,
347364
ExprUseNode::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => {
348365
// Check for calls to trait methods where the trait is implemented
349366
// on a reference.

tests/ui/needless_borrow.fixed

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -190,27 +190,48 @@ fn issue9383() {
190190
// Should not lint because unions need explicit deref when accessing field
191191
use std::mem::ManuallyDrop;
192192

193-
union Coral {
194-
crab: ManuallyDrop<Vec<i32>>,
193+
#[derive(Clone, Copy)]
194+
struct Wrap<T>(T);
195+
impl<T> core::ops::Deref for Wrap<T> {
196+
type Target = T;
197+
fn deref(&self) -> &T {
198+
&self.0
199+
}
200+
}
201+
impl<T> core::ops::DerefMut for Wrap<T> {
202+
fn deref_mut(&mut self) -> &mut T {
203+
&mut self.0
204+
}
195205
}
196206

197-
union Ocean {
198-
coral: ManuallyDrop<Coral>,
207+
union U<T: Copy> {
208+
u: T,
199209
}
200210

201-
let mut ocean = Ocean {
202-
coral: ManuallyDrop::new(Coral {
203-
crab: ManuallyDrop::new(vec![1, 2, 3]),
204-
}),
205-
};
211+
#[derive(Clone, Copy)]
212+
struct Foo {
213+
x: u32,
214+
}
206215

207216
unsafe {
208-
ManuallyDrop::drop(&mut (&mut ocean.coral).crab);
209-
210-
(*ocean.coral).crab = ManuallyDrop::new(vec![4, 5, 6]);
211-
ManuallyDrop::drop(&mut (*ocean.coral).crab);
212-
213-
ManuallyDrop::drop(&mut ocean.coral);
217+
let mut x = U {
218+
u: ManuallyDrop::new(Foo { x: 0 }),
219+
};
220+
let _ = &mut (&mut x.u).x;
221+
let _ = &mut { x.u }.x;
222+
let _ = &mut ({ &mut x.u }).x;
223+
224+
let mut x = U {
225+
u: Wrap(ManuallyDrop::new(Foo { x: 0 })),
226+
};
227+
let _ = &mut (&mut x.u).x;
228+
let _ = &mut { x.u }.x;
229+
let _ = &mut ({ &mut x.u }).x;
230+
231+
let mut x = U { u: Wrap(Foo { x: 0 }) };
232+
let _ = &mut x.u.x;
233+
let _ = &mut { x.u }.x;
234+
let _ = &mut ({ &mut x.u }).x;
214235
}
215236
}
216237

tests/ui/needless_borrow.rs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -190,27 +190,48 @@ fn issue9383() {
190190
// Should not lint because unions need explicit deref when accessing field
191191
use std::mem::ManuallyDrop;
192192

193-
union Coral {
194-
crab: ManuallyDrop<Vec<i32>>,
193+
#[derive(Clone, Copy)]
194+
struct Wrap<T>(T);
195+
impl<T> core::ops::Deref for Wrap<T> {
196+
type Target = T;
197+
fn deref(&self) -> &T {
198+
&self.0
199+
}
200+
}
201+
impl<T> core::ops::DerefMut for Wrap<T> {
202+
fn deref_mut(&mut self) -> &mut T {
203+
&mut self.0
204+
}
195205
}
196206

197-
union Ocean {
198-
coral: ManuallyDrop<Coral>,
207+
union U<T: Copy> {
208+
u: T,
199209
}
200210

201-
let mut ocean = Ocean {
202-
coral: ManuallyDrop::new(Coral {
203-
crab: ManuallyDrop::new(vec![1, 2, 3]),
204-
}),
205-
};
211+
#[derive(Clone, Copy)]
212+
struct Foo {
213+
x: u32,
214+
}
206215

207216
unsafe {
208-
ManuallyDrop::drop(&mut (&mut ocean.coral).crab);
209-
210-
(*ocean.coral).crab = ManuallyDrop::new(vec![4, 5, 6]);
211-
ManuallyDrop::drop(&mut (*ocean.coral).crab);
212-
213-
ManuallyDrop::drop(&mut ocean.coral);
217+
let mut x = U {
218+
u: ManuallyDrop::new(Foo { x: 0 }),
219+
};
220+
let _ = &mut (&mut x.u).x;
221+
let _ = &mut (&mut { x.u }).x;
222+
let _ = &mut ({ &mut x.u }).x;
223+
224+
let mut x = U {
225+
u: Wrap(ManuallyDrop::new(Foo { x: 0 })),
226+
};
227+
let _ = &mut (&mut x.u).x;
228+
let _ = &mut (&mut { x.u }).x;
229+
let _ = &mut ({ &mut x.u }).x;
230+
231+
let mut x = U { u: Wrap(Foo { x: 0 }) };
232+
let _ = &mut (&mut x.u).x;
233+
let _ = &mut (&mut { x.u }).x;
234+
let _ = &mut ({ &mut x.u }).x;
214235
}
215236
}
216237

tests/ui/needless_borrow.stderr

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,5 +133,29 @@ error: this expression borrows a value the compiler would automatically borrow
133133
LL | (&mut self.f)()
134134
| ^^^^^^^^^^^^^ help: change this to: `(self.f)`
135135

136-
error: aborting due to 22 previous errors
136+
error: this expression borrows a value the compiler would automatically borrow
137+
--> $DIR/needless_borrow.rs:221:22
138+
|
139+
LL | let _ = &mut (&mut { x.u }).x;
140+
| ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
141+
142+
error: this expression borrows a value the compiler would automatically borrow
143+
--> $DIR/needless_borrow.rs:228:22
144+
|
145+
LL | let _ = &mut (&mut { x.u }).x;
146+
| ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
147+
148+
error: this expression borrows a value the compiler would automatically borrow
149+
--> $DIR/needless_borrow.rs:232:22
150+
|
151+
LL | let _ = &mut (&mut x.u).x;
152+
| ^^^^^^^^^^ help: change this to: `x.u`
153+
154+
error: this expression borrows a value the compiler would automatically borrow
155+
--> $DIR/needless_borrow.rs:233:22
156+
|
157+
LL | let _ = &mut (&mut { x.u }).x;
158+
| ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
159+
160+
error: aborting due to 26 previous errors
137161

0 commit comments

Comments
 (0)