Auto merge of #9490 - kraktus:needless_borrow, r=Jarcho

fix [`needless_borrow`], [`explicit_auto_deref`] FPs on unions

fix https://github.com/rust-lang/rust-clippy/issues/9383

changelog: fix [`needless_borrow`] false positive on unions
changelog: fix [`explicit_auto_deref`] false positive on unions

Left a couple debug derived impls on purpose I needed to debug as I don't think it's noise
This commit is contained in:
bors 2022-09-28 14:58:07 +00:00
commit 8845f82142
3 changed files with 87 additions and 8 deletions

View File

@ -184,6 +184,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
}
}
#[derive(Debug)]
struct StateData {
/// Span of the top level expression
span: Span,
@ -191,12 +192,14 @@ struct StateData {
position: Position,
}
#[derive(Debug)]
struct DerefedBorrow {
count: usize,
msg: &'static str,
snip_expr: Option<HirId>,
}
#[derive(Debug)]
enum State {
// Any number of deref method calls.
DerefMethod {
@ -276,10 +279,12 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
(None, kind) => {
let expr_ty = typeck.expr_ty(expr);
let (position, adjustments) = walk_parents(cx, expr, self.msrv);
match kind {
RefOp::Deref => {
if let Position::FieldAccess(name) = position
if let Position::FieldAccess {
name,
of_union: false,
} = position
&& !ty_contains_field(typeck.expr_ty(sub_expr), name)
{
self.state = Some((
@ -451,7 +456,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
(Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
let position = data.position;
report(cx, expr, State::DerefedBorrow(state), data);
if let Position::FieldAccess(name) = position
if let Position::FieldAccess{name, ..} = position
&& !ty_contains_field(typeck.expr_ty(sub_expr), name)
{
self.state = Some((
@ -616,14 +621,17 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
}
/// The position of an expression relative to it's parent.
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
enum Position {
MethodReceiver,
/// The method is defined on a reference type. e.g. `impl Foo for &T`
MethodReceiverRefImpl,
Callee,
ImplArg(HirId),
FieldAccess(Symbol),
FieldAccess {
name: Symbol,
of_union: bool,
}, // union fields cannot be auto borrowed
Postfix,
Deref,
/// Any other location which will trigger auto-deref to a specific time.
@ -645,7 +653,10 @@ fn is_reborrow_stable(self) -> bool {
}
fn can_auto_borrow(self) -> bool {
matches!(self, Self::MethodReceiver | Self::FieldAccess(_) | Self::Callee)
matches!(
self,
Self::MethodReceiver | Self::FieldAccess { of_union: false, .. } | Self::Callee
)
}
fn lint_explicit_deref(self) -> bool {
@ -657,7 +668,7 @@ fn precedence(self) -> i8 {
Self::MethodReceiver
| Self::MethodReceiverRefImpl
| Self::Callee
| Self::FieldAccess(_)
| Self::FieldAccess { .. }
| Self::Postfix => PREC_POSTFIX,
Self::ImplArg(_) | Self::Deref => PREC_PREFIX,
Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
@ -844,7 +855,10 @@ fn walk_parents<'tcx>(
}
})
},
ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess {
name: name.name,
of_union: is_union(cx.typeck_results(), child),
}),
ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
| ExprKind::Index(child, _)
@ -865,6 +879,13 @@ fn walk_parents<'tcx>(
(position, adjustments)
}
fn is_union<'tcx>(typeck: &'tcx TypeckResults<'_>, path_expr: &'tcx Expr<'_>) -> bool {
typeck
.expr_ty_adjusted(path_expr)
.ty_adt_def()
.map_or(false, rustc_middle::ty::AdtDef::is_union)
}
fn closure_result_position<'tcx>(
cx: &LateContext<'tcx>,
closure: &'tcx Closure<'_>,

View File

@ -298,3 +298,32 @@ mod meets_msrv {
let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap();
}
}
#[allow(unused)]
fn issue9383() {
// Should not lint because unions need explicit deref when accessing field
use std::mem::ManuallyDrop;
union Coral {
crab: ManuallyDrop<Vec<i32>>,
}
union Ocean {
coral: ManuallyDrop<Coral>,
}
let mut ocean = Ocean {
coral: ManuallyDrop::new(Coral {
crab: ManuallyDrop::new(vec![1, 2, 3]),
}),
};
unsafe {
ManuallyDrop::drop(&mut (&mut ocean.coral).crab);
(*ocean.coral).crab = ManuallyDrop::new(vec![4, 5, 6]);
ManuallyDrop::drop(&mut (*ocean.coral).crab);
ManuallyDrop::drop(&mut ocean.coral);
}
}

View File

@ -298,3 +298,32 @@ fn foo() {
let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
}
}
#[allow(unused)]
fn issue9383() {
// Should not lint because unions need explicit deref when accessing field
use std::mem::ManuallyDrop;
union Coral {
crab: ManuallyDrop<Vec<i32>>,
}
union Ocean {
coral: ManuallyDrop<Coral>,
}
let mut ocean = Ocean {
coral: ManuallyDrop::new(Coral {
crab: ManuallyDrop::new(vec![1, 2, 3]),
}),
};
unsafe {
ManuallyDrop::drop(&mut (&mut ocean.coral).crab);
(*ocean.coral).crab = ManuallyDrop::new(vec![4, 5, 6]);
ManuallyDrop::drop(&mut (*ocean.coral).crab);
ManuallyDrop::drop(&mut ocean.coral);
}
}