Skip to content

Commit ca9e429

Browse files
committed
Do not use DerefMut on ManuallyDrop<_> reached through unions
1 parent 1c44c8d commit ca9e429

File tree

4 files changed

+173
-15
lines changed

4 files changed

+173
-15
lines changed

clippy_lints/src/reference.rs

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::source::{SpanRangeExt, snippet_with_applicability};
3+
use clippy_utils::ty::adjust_derefs_manually_drop;
34
use rustc_errors::Applicability;
4-
use rustc_hir::{Expr, ExprKind, Mutability, UnOp};
5+
use rustc_hir::{Expr, ExprKind, Mutability, Node, UnOp};
56
use rustc_lint::{LateContext, LateLintPass};
67
use rustc_session::declare_lint_pass;
78
use rustc_span::{BytePos, Span};
@@ -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_manually_drop_through_union(cx, addrof_target)
4749
&& deref_target.span.eq_ctxt(e.span)
4850
&& !addrof_target.span.from_expansion()
4951
{
@@ -102,3 +104,31 @@ impl LateLintPass<'_> for DerefAddrOf {
102104
}
103105
}
104106
}
107+
108+
/// Check if `expr` is part of an access to a `ManuallyDrop` entity reached through a union
109+
fn is_manually_drop_through_union(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
110+
let typeck = cx.typeck_results();
111+
if is_reached_through_union(cx, expr) {
112+
for (_, node) in cx.tcx.hir_parent_iter(expr.hir_id) {
113+
if let Node::Expr(expr) = node {
114+
if adjust_derefs_manually_drop(typeck.expr_adjustments(expr), typeck.expr_ty(expr)) {
115+
return true;
116+
}
117+
} else {
118+
break;
119+
}
120+
}
121+
}
122+
false
123+
}
124+
125+
/// Checks whether `expr` denotes an object reached through a union
126+
fn is_reached_through_union(cx: &LateContext<'_>, mut expr: &Expr<'_>) -> bool {
127+
while let ExprKind::Field(parent, _) | ExprKind::Index(parent, _, _) = expr.kind {
128+
if cx.typeck_results().expr_ty_adjusted(parent).is_union() {
129+
return true;
130+
}
131+
expr = parent;
132+
}
133+
false
134+
}

tests/ui/deref_addrof.fixed

+53-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
//@aux-build:proc_macros.rs
22

3-
#![allow(clippy::return_self_not_must_use, clippy::useless_vec)]
3+
#![allow(
4+
dangerous_implicit_autorefs,
5+
clippy::explicit_auto_deref,
6+
clippy::return_self_not_must_use,
7+
clippy::useless_vec
8+
)]
49
#![warn(clippy::deref_addrof)]
510

611
extern crate proc_macros;
@@ -72,3 +77,50 @@ impl S {
7277
//~^ deref_addrof
7378
}
7479
}
80+
81+
fn issue14386() {
82+
use std::mem::ManuallyDrop;
83+
84+
#[derive(Copy, Clone)]
85+
struct Data {
86+
num: u64,
87+
}
88+
89+
#[derive(Clone, Copy)]
90+
struct M {
91+
md: ManuallyDrop<[u8; 4]>,
92+
}
93+
94+
union DataWithPadding<'lt> {
95+
data: ManuallyDrop<Data>,
96+
prim: ManuallyDrop<u64>,
97+
padding: [u8; size_of::<Data>()],
98+
tup: (ManuallyDrop<Data>, ()),
99+
indirect: M,
100+
indirect_arr: [M; 2],
101+
indirect_ref: &'lt mut M,
102+
}
103+
104+
let mut a = DataWithPadding {
105+
padding: [0; size_of::<DataWithPadding>()],
106+
};
107+
unsafe {
108+
a.padding = [1; size_of::<DataWithPadding>()];
109+
//~^ deref_addrof
110+
a.tup.1 = ();
111+
//~^ deref_addrof
112+
*a.prim = 0;
113+
//~^ deref_addrof
114+
115+
(*&mut a.data).num = 42;
116+
(*&mut a.tup).0.num = 42;
117+
(*&mut a.indirect.md)[3] = 1;
118+
(*&mut a.indirect_arr[1].md)[3] = 1;
119+
(*&mut a.indirect_ref.md)[3] = 1;
120+
121+
// Check that raw pointers are properly considered as well
122+
*a.prim = 0;
123+
//~^ deref_addrof
124+
(*&raw mut a.data).num = 42;
125+
}
126+
}

tests/ui/deref_addrof.rs

+53-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
//@aux-build:proc_macros.rs
22

3-
#![allow(clippy::return_self_not_must_use, clippy::useless_vec)]
3+
#![allow(
4+
dangerous_implicit_autorefs,
5+
clippy::explicit_auto_deref,
6+
clippy::return_self_not_must_use,
7+
clippy::useless_vec
8+
)]
49
#![warn(clippy::deref_addrof)]
510

611
extern crate proc_macros;
@@ -72,3 +77,50 @@ impl S {
7277
//~^ deref_addrof
7378
}
7479
}
80+
81+
fn issue14386() {
82+
use std::mem::ManuallyDrop;
83+
84+
#[derive(Copy, Clone)]
85+
struct Data {
86+
num: u64,
87+
}
88+
89+
#[derive(Clone, Copy)]
90+
struct M {
91+
md: ManuallyDrop<[u8; 4]>,
92+
}
93+
94+
union DataWithPadding<'lt> {
95+
data: ManuallyDrop<Data>,
96+
prim: ManuallyDrop<u64>,
97+
padding: [u8; size_of::<Data>()],
98+
tup: (ManuallyDrop<Data>, ()),
99+
indirect: M,
100+
indirect_arr: [M; 2],
101+
indirect_ref: &'lt mut M,
102+
}
103+
104+
let mut a = DataWithPadding {
105+
padding: [0; size_of::<DataWithPadding>()],
106+
};
107+
unsafe {
108+
(*&mut a.padding) = [1; size_of::<DataWithPadding>()];
109+
//~^ deref_addrof
110+
(*&mut a.tup).1 = ();
111+
//~^ deref_addrof
112+
**&mut a.prim = 0;
113+
//~^ deref_addrof
114+
115+
(*&mut a.data).num = 42;
116+
(*&mut a.tup).0.num = 42;
117+
(*&mut a.indirect.md)[3] = 1;
118+
(*&mut a.indirect_arr[1].md)[3] = 1;
119+
(*&mut a.indirect_ref.md)[3] = 1;
120+
121+
// Check that raw pointers are properly considered as well
122+
**&raw mut a.prim = 0;
123+
//~^ deref_addrof
124+
(*&raw mut a.data).num = 42;
125+
}
126+
}

tests/ui/deref_addrof.stderr

+36-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: immediately dereferencing a reference
2-
--> tests/ui/deref_addrof.rs:23:13
2+
--> tests/ui/deref_addrof.rs:28:13
33
|
44
LL | let b = *&a;
55
| ^^^ help: try: `a`
@@ -8,68 +8,92 @@ LL | let b = *&a;
88
= help: to override `-D warnings` add `#[allow(clippy::deref_addrof)]`
99

1010
error: immediately dereferencing a reference
11-
--> tests/ui/deref_addrof.rs:26:13
11+
--> tests/ui/deref_addrof.rs:31:13
1212
|
1313
LL | let b = *&get_number();
1414
| ^^^^^^^^^^^^^^ help: try: `get_number()`
1515

1616
error: immediately dereferencing a reference
17-
--> tests/ui/deref_addrof.rs:32:13
17+
--> tests/ui/deref_addrof.rs:37:13
1818
|
1919
LL | let b = *&bytes[1..2][0];
2020
| ^^^^^^^^^^^^^^^^ help: try: `bytes[1..2][0]`
2121

2222
error: immediately dereferencing a reference
23-
--> tests/ui/deref_addrof.rs:37:13
23+
--> tests/ui/deref_addrof.rs:42:13
2424
|
2525
LL | let b = *&(a);
2626
| ^^^^^ help: try: `(a)`
2727

2828
error: immediately dereferencing a reference
29-
--> tests/ui/deref_addrof.rs:40:13
29+
--> tests/ui/deref_addrof.rs:45:13
3030
|
3131
LL | let b = *(&a);
3232
| ^^^^^ help: try: `a`
3333

3434
error: immediately dereferencing a reference
35-
--> tests/ui/deref_addrof.rs:44:13
35+
--> tests/ui/deref_addrof.rs:49:13
3636
|
3737
LL | let b = *((&a));
3838
| ^^^^^^^ help: try: `a`
3939

4040
error: immediately dereferencing a reference
41-
--> tests/ui/deref_addrof.rs:47:13
41+
--> tests/ui/deref_addrof.rs:52:13
4242
|
4343
LL | let b = *&&a;
4444
| ^^^^ help: try: `&a`
4545

4646
error: immediately dereferencing a reference
47-
--> tests/ui/deref_addrof.rs:50:14
47+
--> tests/ui/deref_addrof.rs:55:14
4848
|
4949
LL | let b = **&aref;
5050
| ^^^^^^ help: try: `aref`
5151

5252
error: immediately dereferencing a reference
53-
--> tests/ui/deref_addrof.rs:55:19
53+
--> tests/ui/deref_addrof.rs:60:19
5454
|
5555
LL | let _repeat = *&[0; 64];
5656
| ^^^^^^^^^ help: try: `[0; 64]`
5757

5858
error: immediately dereferencing a reference
59-
--> tests/ui/deref_addrof.rs:66:17
59+
--> tests/ui/deref_addrof.rs:71:17
6060
|
6161
LL | inline!(*& $(@expr self))
6262
| ^^^^^^^^^^^^^^^^ help: try: `$(@expr self)`
6363
|
6464
= note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
6565

6666
error: immediately dereferencing a reference
67-
--> tests/ui/deref_addrof.rs:71:17
67+
--> tests/ui/deref_addrof.rs:76:17
6868
|
6969
LL | inline!(*&mut $(@expr self))
7070
| ^^^^^^^^^^^^^^^^^^^ help: try: `$(@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:108:9
76+
|
77+
LL | (*&mut a.padding) = [1; size_of::<DataWithPadding>()];
78+
| ^^^^^^^^^^^^^^^^^ help: try: `a.padding`
79+
80+
error: immediately dereferencing a reference
81+
--> tests/ui/deref_addrof.rs:110:9
82+
|
83+
LL | (*&mut a.tup).1 = ();
84+
| ^^^^^^^^^^^^^ help: try: `a.tup`
85+
86+
error: immediately dereferencing a reference
87+
--> tests/ui/deref_addrof.rs:112:10
88+
|
89+
LL | **&mut a.prim = 0;
90+
| ^^^^^^^^^^^^ help: try: `a.prim`
91+
92+
error: immediately dereferencing a reference
93+
--> tests/ui/deref_addrof.rs:122:10
94+
|
95+
LL | **&raw mut a.prim = 0;
96+
| ^^^^^^^^^^^^^^^^ help: try: `a.prim`
97+
98+
error: aborting due to 15 previous errors
7599

0 commit comments

Comments
 (0)