Skip to content

Commit 263a25e

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 263a25e

File tree

4 files changed

+97
-1
lines changed

4 files changed

+97
-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

+34
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,37 @@ 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+
y: (u32, u32),
88+
z: (ManuallyDrop<Data>,),
89+
}
90+
91+
let mut a = DataWithPadding {
92+
with_padding: [0; size_of::<DataWithPadding>()],
93+
};
94+
unsafe {
95+
// Do not lint as `DerefMut` will not work on non-`Copy` union
96+
// fields.
97+
(*(&raw mut a.data)).num = 42;
98+
(*(&raw mut a.z)).0.num = 42;
99+
100+
// Lint, as `Copy` fields in unions are ok.
101+
a.with_padding = [1; size_of::<DataWithPadding>()];
102+
//~^ deref_addrof
103+
*a.x = 0;
104+
//~^ deref_addrof
105+
a.y.0 = 0;
106+
//~^ deref_addrof
107+
}
108+
}

tests/ui/deref_addrof.rs

+34
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,37 @@ 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+
y: (u32, u32),
88+
z: (ManuallyDrop<Data>,),
89+
}
90+
91+
let mut a = DataWithPadding {
92+
with_padding: [0; size_of::<DataWithPadding>()],
93+
};
94+
unsafe {
95+
// Do not lint as `DerefMut` will not work on non-`Copy` union
96+
// fields.
97+
(*(&raw mut a.data)).num = 42;
98+
(*(&raw mut a.z)).0.num = 42;
99+
100+
// Lint, as `Copy` fields in unions are ok.
101+
(*(&raw mut a.with_padding)) = [1; size_of::<DataWithPadding>()];
102+
//~^ deref_addrof
103+
*(*(&raw mut a.x)) = 0;
104+
//~^ deref_addrof
105+
(*(&raw mut a.y)).0 = 0;
106+
//~^ deref_addrof
107+
}
108+
}

tests/ui/deref_addrof.stderr

+19-1
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,23 @@ 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:101: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:103:10
82+
|
83+
LL | *(*(&raw mut a.x)) = 0;
84+
| ^^^^^^^^^^^^^^^^^ help: try: `a.x`
85+
86+
error: immediately dereferencing a reference
87+
--> tests/ui/deref_addrof.rs:105:9
88+
|
89+
LL | (*(&raw mut a.y)).0 = 0;
90+
| ^^^^^^^^^^^^^^^^^ help: try: `a.y`
91+
92+
error: aborting due to 14 previous errors
7593

0 commit comments

Comments
 (0)