Skip to content

Commit cd1337d

Browse files
committed
Do not use DerefMut on non-Copy union fields
Union fields not implementing `Copy` cannot implicitely use the `DerefMut` trait.
1 parent 820a6c5 commit cd1337d

File tree

4 files changed

+85
-1
lines changed

4 files changed

+85
-1
lines changed

clippy_lints/src/reference.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::source::{SpanRangeExt, snippet_with_applicability};
3+
use clippy_utils::ty::is_copy;
34
use rustc_errors::Applicability;
45
use rustc_hir::{Expr, ExprKind, Mutability, UnOp};
56
use rustc_lint::{LateContext, LateLintPass};
@@ -44,6 +45,7 @@ impl LateLintPass<'_> for DerefAddrOf {
4445
// NOTE(tesuji): `*&` forces rustc to const-promote the array to `.rodata` section.
4546
// See #12854 for details.
4647
&& !matches!(addrof_target.kind, ExprKind::Array(_))
48+
&& !is_non_copy_union_field(cx, addrof_target)
4749
&& deref_target.span.eq_ctxt(e.span)
4850
&& !addrof_target.span.from_expansion()
4951
{
@@ -102,3 +104,11 @@ impl LateLintPass<'_> for DerefAddrOf {
102104
}
103105
}
104106
}
107+
108+
fn is_non_copy_union_field(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
109+
if let ExprKind::Field(parent, _) = expr.kind {
110+
cx.typeck_results().expr_ty_adjusted(parent).is_union() && !is_copy(cx, cx.typeck_results().expr_ty(expr))
111+
} else {
112+
false
113+
}
114+
}

tests/ui/deref_addrof.fixed

+31
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,34 @@ impl S {
7272
//~^ deref_addrof
7373
}
7474
}
75+
76+
fn issue14386() {
77+
use std::mem::ManuallyDrop;
78+
79+
struct Data {
80+
num: u64,
81+
}
82+
83+
union DataWithPadding {
84+
data: ManuallyDrop<Data>,
85+
x: ManuallyDrop<u64>,
86+
with_padding: [u8; size_of::<Data>()],
87+
}
88+
89+
let mut a = DataWithPadding {
90+
with_padding: [0; size_of::<DataWithPadding>()],
91+
};
92+
unsafe {
93+
// Do not lint as `DerefMut` will not work on non-`Copy` union
94+
// fields.
95+
(*(&raw mut a.data)).num = 42;
96+
97+
// Lint, as `Copy` fields in unions are ok.
98+
a.with_padding = [1; size_of::<DataWithPadding>()];
99+
//~^ deref_addrof
100+
101+
// Ensure that the trigger conditions is determined by `Copy`, not by `ManuallyDrop`.
102+
*a.x = 0;
103+
//~^ deref_addrof
104+
}
105+
}

tests/ui/deref_addrof.rs

+31
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,34 @@ impl S {
7272
//~^ deref_addrof
7373
}
7474
}
75+
76+
fn issue14386() {
77+
use std::mem::ManuallyDrop;
78+
79+
struct Data {
80+
num: u64,
81+
}
82+
83+
union DataWithPadding {
84+
data: ManuallyDrop<Data>,
85+
x: ManuallyDrop<u64>,
86+
with_padding: [u8; size_of::<Data>()],
87+
}
88+
89+
let mut a = DataWithPadding {
90+
with_padding: [0; size_of::<DataWithPadding>()],
91+
};
92+
unsafe {
93+
// Do not lint as `DerefMut` will not work on non-`Copy` union
94+
// fields.
95+
(*(&raw mut a.data)).num = 42;
96+
97+
// Lint, as `Copy` fields in unions are ok.
98+
(*(&raw mut a.with_padding)) = [1; size_of::<DataWithPadding>()];
99+
//~^ deref_addrof
100+
101+
// Ensure that the trigger conditions is determined by `Copy`, not by `ManuallyDrop`.
102+
*(*(&raw mut a.x)) = 0;
103+
//~^ deref_addrof
104+
}
105+
}

tests/ui/deref_addrof.stderr

+13-1
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,17 @@ LL | inline!(*&mut $(@expr self))
7171
|
7272
= note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
7373

74-
error: aborting due to 11 previous errors
74+
error: immediately dereferencing a reference
75+
--> tests/ui/deref_addrof.rs:98:9
76+
|
77+
LL | (*(&raw mut a.with_padding)) = [1; size_of::<DataWithPadding>()];
78+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.with_padding`
79+
80+
error: immediately dereferencing a reference
81+
--> tests/ui/deref_addrof.rs:102:10
82+
|
83+
LL | *(*(&raw mut a.x)) = 0;
84+
| ^^^^^^^^^^^^^^^^^ help: try: `a.x`
85+
86+
error: aborting due to 13 previous errors
7587

0 commit comments

Comments
 (0)