Lint needless_borrow on most union field accesses

This commit is contained in:
Jason Newcomb 2023-09-14 12:41:16 -04:00
parent 34b7d1559f
commit a68cd88860
4 changed files with 112 additions and 29 deletions

View File

@ -5,6 +5,7 @@
use clippy_utils::{ use clippy_utils::{
expr_use_ctxt, get_parent_expr, get_parent_node, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, get_parent_node, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
}; };
use core::mem;
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -342,8 +343,24 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return()) TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return())
}); });
let can_auto_borrow = match use_cx.node { let can_auto_borrow = match use_cx.node {
ExprUseNode::Callee => true, ExprUseNode::FieldAccess(_)
ExprUseNode::FieldAccess(_) => adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union()), if !use_cx.moved_before_use && matches!(sub_expr.kind, ExprKind::Field(..)) =>
{
// `ManuallyDrop` fields of a union will not automatically call
// `deref_mut` when accessing a field.
// Note: if the `ManuallyDrop` value is not directly a field of a
// union then `DerefMut` will work as normal.
//
// This means we need to not modify an expression such as `(&mut x.y).z`
// if accessing `z` would require `DerefMut`.
let mut ty = expr_ty;
!use_cx.adjustments.iter().any(|a| {
let ty = mem::replace(&mut ty, a.target);
matches!(a.kind, Adjust::Deref(Some(ref op)) if op.mutbl == Mutability::Mut)
&& ty.ty_adt_def().map_or(false, |def| def.is_manually_drop())
})
},
ExprUseNode::Callee | ExprUseNode::FieldAccess(_) => true,
ExprUseNode::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => { ExprUseNode::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => {
// Check for calls to trait methods where the trait is implemented // Check for calls to trait methods where the trait is implemented
// on a reference. // on a reference.

View File

@ -190,27 +190,48 @@ fn issue9383() {
// Should not lint because unions need explicit deref when accessing field // Should not lint because unions need explicit deref when accessing field
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
union Coral { #[derive(Clone, Copy)]
crab: ManuallyDrop<Vec<i32>>, struct Wrap<T>(T);
impl<T> core::ops::Deref for Wrap<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> core::ops::DerefMut for Wrap<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
} }
union Ocean { union U<T: Copy> {
coral: ManuallyDrop<Coral>, u: T,
} }
let mut ocean = Ocean { #[derive(Clone, Copy)]
coral: ManuallyDrop::new(Coral { struct Foo {
crab: ManuallyDrop::new(vec![1, 2, 3]), x: u32,
}), }
};
unsafe { unsafe {
ManuallyDrop::drop(&mut (&mut ocean.coral).crab); let mut x = U {
u: ManuallyDrop::new(Foo { x: 0 }),
};
let _ = &mut (&mut x.u).x;
let _ = &mut { x.u }.x;
let _ = &mut ({ &mut x.u }).x;
(*ocean.coral).crab = ManuallyDrop::new(vec![4, 5, 6]); let mut x = U {
ManuallyDrop::drop(&mut (*ocean.coral).crab); u: Wrap(ManuallyDrop::new(Foo { x: 0 })),
};
let _ = &mut (&mut x.u).x;
let _ = &mut { x.u }.x;
let _ = &mut ({ &mut x.u }).x;
ManuallyDrop::drop(&mut ocean.coral); let mut x = U { u: Wrap(Foo { x: 0 }) };
let _ = &mut x.u.x;
let _ = &mut { x.u }.x;
let _ = &mut ({ &mut x.u }).x;
} }
} }

View File

@ -190,27 +190,48 @@ fn issue9383() {
// Should not lint because unions need explicit deref when accessing field // Should not lint because unions need explicit deref when accessing field
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
union Coral { #[derive(Clone, Copy)]
crab: ManuallyDrop<Vec<i32>>, struct Wrap<T>(T);
impl<T> core::ops::Deref for Wrap<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> core::ops::DerefMut for Wrap<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
} }
union Ocean { union U<T: Copy> {
coral: ManuallyDrop<Coral>, u: T,
} }
let mut ocean = Ocean { #[derive(Clone, Copy)]
coral: ManuallyDrop::new(Coral { struct Foo {
crab: ManuallyDrop::new(vec![1, 2, 3]), x: u32,
}), }
};
unsafe { unsafe {
ManuallyDrop::drop(&mut (&mut ocean.coral).crab); let mut x = U {
u: ManuallyDrop::new(Foo { x: 0 }),
};
let _ = &mut (&mut x.u).x;
let _ = &mut (&mut { x.u }).x;
let _ = &mut ({ &mut x.u }).x;
(*ocean.coral).crab = ManuallyDrop::new(vec![4, 5, 6]); let mut x = U {
ManuallyDrop::drop(&mut (*ocean.coral).crab); u: Wrap(ManuallyDrop::new(Foo { x: 0 })),
};
let _ = &mut (&mut x.u).x;
let _ = &mut (&mut { x.u }).x;
let _ = &mut ({ &mut x.u }).x;
ManuallyDrop::drop(&mut ocean.coral); let mut x = U { u: Wrap(Foo { x: 0 }) };
let _ = &mut (&mut x.u).x;
let _ = &mut (&mut { x.u }).x;
let _ = &mut ({ &mut x.u }).x;
} }
} }

View File

@ -133,5 +133,29 @@ error: this expression borrows a value the compiler would automatically borrow
LL | (&mut self.f)() LL | (&mut self.f)()
| ^^^^^^^^^^^^^ help: change this to: `(self.f)` | ^^^^^^^^^^^^^ help: change this to: `(self.f)`
error: aborting due to 22 previous errors error: this expression borrows a value the compiler would automatically borrow
--> $DIR/needless_borrow.rs:221:22
|
LL | let _ = &mut (&mut { x.u }).x;
| ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
error: this expression borrows a value the compiler would automatically borrow
--> $DIR/needless_borrow.rs:228:22
|
LL | let _ = &mut (&mut { x.u }).x;
| ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
error: this expression borrows a value the compiler would automatically borrow
--> $DIR/needless_borrow.rs:232:22
|
LL | let _ = &mut (&mut x.u).x;
| ^^^^^^^^^^ help: change this to: `x.u`
error: this expression borrows a value the compiler would automatically borrow
--> $DIR/needless_borrow.rs:233:22
|
LL | let _ = &mut (&mut { x.u }).x;
| ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
error: aborting due to 26 previous errors