Skip to content

Commit dde75ef

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

File tree

4 files changed

+136
-4
lines changed

4 files changed

+136
-4
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

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

3-
#![allow(clippy::return_self_not_must_use, clippy::useless_vec)]
3+
#![allow(dangerous_implicit_autorefs, clippy::return_self_not_must_use, clippy::useless_vec)]
44
#![warn(clippy::deref_addrof)]
55

66
extern crate proc_macros;
@@ -72,3 +72,45 @@ impl S {
7272
//~^ deref_addrof
7373
}
7474
}
75+
76+
fn issue14386() {
77+
use std::mem::ManuallyDrop;
78+
79+
#[derive(Copy, Clone)]
80+
struct Data {
81+
num: u64,
82+
}
83+
84+
#[derive(Clone, Copy)]
85+
struct M {
86+
md: ManuallyDrop<[u8; 4]>,
87+
}
88+
89+
union DataWithPadding<'lt> {
90+
data: ManuallyDrop<Data>,
91+
prim: ManuallyDrop<u64>,
92+
padding: [u8; size_of::<Data>()],
93+
tup: (ManuallyDrop<Data>, ()),
94+
indirect: M,
95+
indirect_arr: [M; 2],
96+
indirect_ref: &'lt mut M,
97+
}
98+
99+
let mut a = DataWithPadding {
100+
padding: [0; size_of::<DataWithPadding>()],
101+
};
102+
unsafe {
103+
a.padding = [1; size_of::<DataWithPadding>()];
104+
//~^ deref_addrof
105+
a.tup.1 = ();
106+
//~^ deref_addrof
107+
*a.prim = 0;
108+
//~^ deref_addrof
109+
110+
(*(&raw mut a.data)).num = 42;
111+
(*(&raw mut a.tup)).0.num = 42;
112+
(*&mut a.indirect.md)[3] = 1;
113+
(*&mut a.indirect_arr[1].md)[3] = 1;
114+
(*&mut a.indirect_ref.md)[3] = 1;
115+
}
116+
}

tests/ui/deref_addrof.rs

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

3-
#![allow(clippy::return_self_not_must_use, clippy::useless_vec)]
3+
#![allow(dangerous_implicit_autorefs, clippy::return_self_not_must_use, clippy::useless_vec)]
44
#![warn(clippy::deref_addrof)]
55

66
extern crate proc_macros;
@@ -72,3 +72,45 @@ impl S {
7272
//~^ deref_addrof
7373
}
7474
}
75+
76+
fn issue14386() {
77+
use std::mem::ManuallyDrop;
78+
79+
#[derive(Copy, Clone)]
80+
struct Data {
81+
num: u64,
82+
}
83+
84+
#[derive(Clone, Copy)]
85+
struct M {
86+
md: ManuallyDrop<[u8; 4]>,
87+
}
88+
89+
union DataWithPadding<'lt> {
90+
data: ManuallyDrop<Data>,
91+
prim: ManuallyDrop<u64>,
92+
padding: [u8; size_of::<Data>()],
93+
tup: (ManuallyDrop<Data>, ()),
94+
indirect: M,
95+
indirect_arr: [M; 2],
96+
indirect_ref: &'lt mut M,
97+
}
98+
99+
let mut a = DataWithPadding {
100+
padding: [0; size_of::<DataWithPadding>()],
101+
};
102+
unsafe {
103+
(*(&raw mut a.padding)) = [1; size_of::<DataWithPadding>()];
104+
//~^ deref_addrof
105+
(*(&raw mut a.tup)).1 = ();
106+
//~^ deref_addrof
107+
*(*(&raw mut a.prim)) = 0;
108+
//~^ deref_addrof
109+
110+
(*(&raw mut a.data)).num = 42;
111+
(*(&raw mut a.tup)).0.num = 42;
112+
(*&mut a.indirect.md)[3] = 1;
113+
(*&mut a.indirect_arr[1].md)[3] = 1;
114+
(*&mut a.indirect_ref.md)[3] = 1;
115+
}
116+
}

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:103:9
76+
|
77+
LL | (*(&raw 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:105:9
82+
|
83+
LL | (*(&raw mut a.tup)).1 = ();
84+
| ^^^^^^^^^^^^^^^^^^^ help: try: `a.tup`
85+
86+
error: immediately dereferencing a reference
87+
--> tests/ui/deref_addrof.rs:107:10
88+
|
89+
LL | *(*(&raw mut a.prim)) = 0;
90+
| ^^^^^^^^^^^^^^^^^^^^ help: try: `a.prim`
91+
92+
error: aborting due to 14 previous errors
7593

0 commit comments

Comments
 (0)