Skip to content

Commit 340ae34

Browse files
committed
Address review comments
1 parent fc17293 commit 340ae34

File tree

3 files changed

+38
-51
lines changed

3 files changed

+38
-51
lines changed

clippy_lints/src/volatile_composites.rs

Lines changed: 25 additions & 50 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,36 @@ 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
70+
/// Make sure the raw pointer has no metadata.
8571
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
90-
}
72+
matches!(ty.kind(), ty::RawPtr(inner, _) if inner.has_trivial_sizedness(cx.tcx, ty::SizedTraitKind::Sized))
9173
}
9274

93-
// Enum with some fixed representation and no data-carrying variants
75+
/// Enum with some fixed representation and no data-carrying variants.
9476
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-
}
77+
ty.ty_adt_def().is_some_and(|adt_def| {
78+
adt_def.is_enum() && adt_def.repr().inhibit_struct_field_reordering() && adt_def.is_payloadfree()
79+
})
10380
}
10481

105-
// #[repr(transparent)] structures are also OK if the only non-zero
106-
// sized field contains a volatile-safe type
82+
/// `#[repr(transparent)]` structures are also OK if the only non-zero
83+
/// sized field contains a volatile-safe type.
10784
fn is_struct_repr_transparent<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
10885
if let ty::Adt(adt_def, args) = ty.kind()
10986
&& adt_def.is_struct()
@@ -123,8 +100,8 @@ fn is_struct_repr_transparent<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> boo
123100
}
124101
}
125102

126-
// SIMD can be useful to get larger atomic loads/stores, though this is still
127-
// pretty machine-dependent.
103+
/// SIMD can be useful to get larger atomic loads/stores, though this is still
104+
/// pretty machine-dependent.
128105
fn is_simd_repr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
129106
if let ty::Adt(adt_def, _args) = ty.kind()
130107
&& adt_def.is_struct()
@@ -137,21 +114,19 @@ fn is_simd_repr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
137114
}
138115
}
139116

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-
117+
/// Top-level predicate for whether a type is volatile-safe or not.
145118
fn is_volatile_safe_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
146119
ty.is_primitive()
147120
|| is_narrow_raw_ptr(cx, ty)
148121
|| is_zero_sized_ty(cx, ty)
149122
|| is_enum_repr_c(cx, ty)
150123
|| is_simd_repr(cx, ty)
151124
|| is_struct_repr_transparent(cx, ty)
152-
|| is_generic(cx, ty)
125+
// We can't know about a generic type, so just let it pass to avoid noise
126+
|| ty.has_non_region_param()
153127
}
154128

129+
/// Print diagnostic for volatile read/write on non-volatile-safe types.
155130
fn report_volatile_safe<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty: Ty<'tcx>) {
156131
if !is_volatile_safe_ty(cx, ty) {
157132
span_lint(
@@ -177,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for VolatileComposites {
177152
// Raw pointers
178153
ty::RawPtr(innerty, _) => report_volatile_safe(cx, expr, *innerty),
179154
// std::ptr::NonNull
180-
ty::Adt(adt_def, args) if cx.tcx.is_diagnostic_item(sym::NonNull, adt_def.did()) => {
155+
ty::Adt(_, args) if is_type_diagnostic_item(cx, self_ty, sym::NonNull) => {
181156
report_volatile_safe(cx, expr, args.type_at(0));
182157
},
183158
_ => (),
@@ -192,7 +167,7 @@ impl<'tcx> LateLintPass<'tcx> for VolatileComposites {
192167
cx.tcx.get_diagnostic_name(def_id),
193168
Some(sym::ptr_read_volatile | sym::ptr_write_volatile)
194169
)
195-
&& let ty::RawPtr(ptrty, _) = cx.typeck_results().expr_ty(arg_ptr).kind()
170+
&& let ty::RawPtr(ptrty, _) = cx.typeck_results().expr_ty_adjusted(arg_ptr).kind()
196171
{
197172
report_volatile_safe(cx, expr, *ptrty);
198173
}

tests/ui/volatile_composites.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,12 @@ fn main() {
187187
unsafe {
188188
do_device_write::<MyDevRegisters>(0xdead as *mut _, Default::default()); // OK
189189
}
190+
191+
let mut s = String::from("foo");
192+
unsafe {
193+
std::ptr::write_volatile(&mut s, String::from("bar"));
194+
//~^ volatile_composites
195+
}
190196
}
191197

192198
// Generic OK

tests/ui/volatile_composites.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,11 @@ error: type `main::ReprSumType` is not volatile-compatible
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:193: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)