Skip to content

Commit ec9f7c0

Browse files
committed
Address review comments
1 parent fc17293 commit ec9f7c0

File tree

3 files changed

+53
-55
lines changed

3 files changed

+53
-55
lines changed

clippy_lints/src/volatile_composites.rs

Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use clippy_utils::diagnostics::span_lint;
22
use clippy_utils::sym;
3+
use clippy_utils::ty::is_type_diagnostic_item;
34
use rustc_hir::{Expr, ExprKind};
45
use rustc_lint::{LateContext, LateLintPass};
5-
use rustc_middle::ty::{self, Ty};
6+
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
67
use rustc_session::declare_lint_pass;
78

89
declare_clippy_lint! {
@@ -50,60 +51,39 @@ declare_clippy_lint! {
5051
/// }
5152
/// }
5253
/// ```
53-
#[clippy::version = "1.91.0"]
54+
#[clippy::version = "1.92.0"]
5455
pub VOLATILE_COMPOSITES,
5556
nursery,
5657
"warn about volatile read/write applied to composite types"
5758
}
5859
declare_lint_pass!(VolatileComposites => [VOLATILE_COMPOSITES]);
5960

60-
// functions:
61-
// core::ptr::{read_volatile,write_volatile}
62-
// methods:
63-
// pointer::{read_volatile,write_volatile}
64-
// NonNull::{read_volatile,write_volatile}
65-
66-
// primitive type:
67-
// unit, [iu]{8,16,32,64,128?}, f{32,64}, thin pointer, usize, isize, bool, char
68-
// C enum with primitive repr
69-
// #[repr(transparent)] wrapper of above
70-
71-
// Zero-sized types are intrinsically safe to use volatile on since they won't
72-
// actually generate *any* loads or stores. But this is also used to skip zero
73-
// fields of #[repr(transparent)] structures.
61+
/// Zero-sized types are intrinsically safe to use volatile on since they won't
62+
/// actually generate *any* loads or stores. But this is also used to skip zero-sized
63+
/// fields of `#[repr(transparent)]` structures.
7464
fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
75-
if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty)
76-
&& let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty))
77-
{
78-
layout.layout.size().bytes() == 0
79-
} else {
80-
false
81-
}
65+
cx.tcx
66+
.layout_of(cx.typing_env().as_query_input(ty))
67+
.is_ok_and(|layout| layout.is_zst())
8268
}
8369

84-
// Make sure the raw pointer has no metadata
85-
fn is_narrow_raw_ptr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
86-
if let ty::RawPtr(_inner, _) = ty.kind() {
87-
ty.pointee_metadata_ty_or_projection(cx.tcx).is_unit()
88-
} else {
89-
false
70+
/// A thin raw pointer or reference.
71+
fn is_narrow_ptr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
72+
match ty.kind() {
73+
ty::RawPtr(inner, _) | ty::Ref(_, inner, _) => inner.has_trivial_sizedness(cx.tcx, ty::SizedTraitKind::Sized),
74+
_ => false,
9075
}
9176
}
9277

93-
// Enum with some fixed representation and no data-carrying variants
78+
/// Enum with some fixed representation and no data-carrying variants.
9479
fn is_enum_repr_c<'tcx>(_cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
95-
if let ty::Adt(adt_def, _args) = ty.kind()
96-
&& adt_def.is_enum()
97-
&& adt_def.repr().inhibit_struct_field_reordering()
98-
{
99-
adt_def.is_payloadfree()
100-
} else {
101-
false
102-
}
80+
ty.ty_adt_def().is_some_and(|adt_def| {
81+
adt_def.is_enum() && adt_def.repr().inhibit_struct_field_reordering() && adt_def.is_payloadfree()
82+
})
10383
}
10484

105-
// #[repr(transparent)] structures are also OK if the only non-zero
106-
// sized field contains a volatile-safe type
85+
/// `#[repr(transparent)]` structures are also OK if the only non-zero
86+
/// sized field contains a volatile-safe type.
10787
fn is_struct_repr_transparent<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
10888
if let ty::Adt(adt_def, args) = ty.kind()
10989
&& adt_def.is_struct()
@@ -123,8 +103,8 @@ fn is_struct_repr_transparent<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> boo
123103
}
124104
}
125105

126-
// SIMD can be useful to get larger atomic loads/stores, though this is still
127-
// pretty machine-dependent.
106+
/// SIMD can be useful to get larger atomic loads/stores, though this is still
107+
/// pretty machine-dependent.
128108
fn is_simd_repr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
129109
if let ty::Adt(adt_def, _args) = ty.kind()
130110
&& adt_def.is_struct()
@@ -137,21 +117,19 @@ fn is_simd_repr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
137117
}
138118
}
139119

140-
// We can't know about a generic type, so just let it pass to avoid noise
141-
fn is_generic<'tcx>(_cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
142-
ty.flags().intersects(ty::TypeFlags::HAS_PARAM)
143-
}
144-
120+
/// Top-level predicate for whether a type is volatile-safe or not.
145121
fn is_volatile_safe_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
146122
ty.is_primitive()
147-
|| is_narrow_raw_ptr(cx, ty)
123+
|| is_narrow_ptr(cx, ty)
148124
|| is_zero_sized_ty(cx, ty)
149125
|| is_enum_repr_c(cx, ty)
150126
|| is_simd_repr(cx, ty)
151127
|| is_struct_repr_transparent(cx, ty)
152-
|| is_generic(cx, ty)
128+
// We can't know about a generic type, so just let it pass to avoid noise
129+
|| ty.has_non_region_param()
153130
}
154131

132+
/// Print diagnostic for volatile read/write on non-volatile-safe types.
155133
fn report_volatile_safe<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty: Ty<'tcx>) {
156134
if !is_volatile_safe_ty(cx, ty) {
157135
span_lint(
@@ -177,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for VolatileComposites {
177155
// Raw pointers
178156
ty::RawPtr(innerty, _) => report_volatile_safe(cx, expr, *innerty),
179157
// std::ptr::NonNull
180-
ty::Adt(adt_def, args) if cx.tcx.is_diagnostic_item(sym::NonNull, adt_def.did()) => {
158+
ty::Adt(_, args) if is_type_diagnostic_item(cx, self_ty, sym::NonNull) => {
181159
report_volatile_safe(cx, expr, args.type_at(0));
182160
},
183161
_ => (),
@@ -192,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for VolatileComposites {
192170
cx.tcx.get_diagnostic_name(def_id),
193171
Some(sym::ptr_read_volatile | sym::ptr_write_volatile)
194172
)
195-
&& let ty::RawPtr(ptrty, _) = cx.typeck_results().expr_ty(arg_ptr).kind()
173+
&& let ty::RawPtr(ptrty, _) = cx.typeck_results().expr_ty_adjusted(arg_ptr).kind()
196174
{
197175
report_volatile_safe(cx, expr, *ptrty);
198176
}

tests/ui/volatile_composites.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ fn main() {
127127
//~^ volatile_composites
128128
}
129129

130+
// Plain pointers and pointers with lifetimes are OK
131+
unsafe {
132+
let v: u32 = 123;
133+
let rv: &u32 = &v;
134+
135+
(0xdead as *mut &u32).write_volatile(rv); // OK
136+
}
137+
130138
// C-style enums are OK
131139
unsafe {
132140
// Bad: need some specific repr
@@ -187,6 +195,12 @@ fn main() {
187195
unsafe {
188196
do_device_write::<MyDevRegisters>(0xdead as *mut _, Default::default()); // OK
189197
}
198+
199+
let mut s = String::from("foo");
200+
unsafe {
201+
std::ptr::write_volatile(&mut s, String::from("bar"));
202+
//~^ volatile_composites
203+
}
190204
}
191205

192206
// Generic OK

tests/ui/volatile_composites.stderr

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,28 @@ LL | (0xdead as *mut *const [u32]).write_volatile(wideptr);
6262
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6363

6464
error: type `main::PlainEnum` is not volatile-compatible
65-
--> tests/ui/volatile_composites.rs:139:9
65+
--> tests/ui/volatile_composites.rs:147:9
6666
|
6767
LL | (0xdead as *mut PlainEnum).write_volatile(PlainEnum::A);
6868
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6969

7070
error: type `main::SumType` is not volatile-compatible
71-
--> tests/ui/volatile_composites.rs:167:9
71+
--> tests/ui/volatile_composites.rs:175:9
7272
|
7373
LL | (0xdead as *mut SumType).write_volatile(SumType::C);
7474
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7575

7676
error: type `main::ReprSumType` is not volatile-compatible
77-
--> tests/ui/volatile_composites.rs:177:9
77+
--> tests/ui/volatile_composites.rs:185:9
7878
|
7979
LL | (0xdead as *mut ReprSumType).write_volatile(ReprSumType::C);
8080
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8181

82-
error: aborting due to 13 previous errors
82+
error: type `std::string::String` is not volatile-compatible
83+
--> tests/ui/volatile_composites.rs:201:9
84+
|
85+
LL | std::ptr::write_volatile(&mut s, String::from("bar"));
86+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
87+
88+
error: aborting due to 14 previous errors
8389

0 commit comments

Comments
 (0)