1
1
use clippy_utils:: diagnostics:: span_lint;
2
2
use clippy_utils:: sym;
3
+ use clippy_utils:: ty:: is_type_diagnostic_item;
3
4
use rustc_hir:: { Expr , ExprKind } ;
4
5
use rustc_lint:: { LateContext , LateLintPass } ;
5
- use rustc_middle:: ty:: { self , Ty } ;
6
+ use rustc_middle:: ty:: { self , Ty , TypeVisitableExt } ;
6
7
use rustc_session:: declare_lint_pass;
7
8
8
9
declare_clippy_lint ! {
@@ -50,60 +51,36 @@ declare_clippy_lint! {
50
51
/// }
51
52
/// }
52
53
/// ```
53
- #[ clippy:: version = "1.91 .0" ]
54
+ #[ clippy:: version = "1.92 .0" ]
54
55
pub VOLATILE_COMPOSITES ,
55
56
nursery,
56
57
"warn about volatile read/write applied to composite types"
57
58
}
58
59
declare_lint_pass ! ( VolatileComposites => [ VOLATILE_COMPOSITES ] ) ;
59
60
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.
74
64
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 ( ) )
82
68
}
83
69
84
- // Make sure the raw pointer has no metadata
70
+ /// Make sure the raw pointer has no metadata.
85
71
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 ) )
91
73
}
92
74
93
- // Enum with some fixed representation and no data-carrying variants
75
+ /// Enum with some fixed representation and no data-carrying variants.
94
76
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
+ } )
103
80
}
104
81
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.
107
84
fn is_struct_repr_transparent < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
108
85
if let ty:: Adt ( adt_def, args) = ty. kind ( )
109
86
&& adt_def. is_struct ( )
@@ -123,8 +100,8 @@ fn is_struct_repr_transparent<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> boo
123
100
}
124
101
}
125
102
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.
128
105
fn is_simd_repr < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
129
106
if let ty:: Adt ( adt_def, _args) = ty. kind ( )
130
107
&& adt_def. is_struct ( )
@@ -137,21 +114,19 @@ fn is_simd_repr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
137
114
}
138
115
}
139
116
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.
145
118
fn is_volatile_safe_ty < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
146
119
ty. is_primitive ( )
147
120
|| is_narrow_raw_ptr ( cx, ty)
148
121
|| is_zero_sized_ty ( cx, ty)
149
122
|| is_enum_repr_c ( cx, ty)
150
123
|| is_simd_repr ( cx, ty)
151
124
|| 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 ( )
153
127
}
154
128
129
+ /// Print diagnostic for volatile read/write on non-volatile-safe types.
155
130
fn report_volatile_safe < ' tcx > ( cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > , ty : Ty < ' tcx > ) {
156
131
if !is_volatile_safe_ty ( cx, ty) {
157
132
span_lint (
@@ -177,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for VolatileComposites {
177
152
// Raw pointers
178
153
ty:: RawPtr ( innerty, _) => report_volatile_safe ( cx, expr, * innerty) ,
179
154
// 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 ) => {
181
156
report_volatile_safe ( cx, expr, args. type_at ( 0 ) ) ;
182
157
} ,
183
158
_ => ( ) ,
@@ -192,7 +167,7 @@ impl<'tcx> LateLintPass<'tcx> for VolatileComposites {
192
167
cx. tcx. get_diagnostic_name( def_id) ,
193
168
Some ( sym:: ptr_read_volatile | sym:: ptr_write_volatile)
194
169
)
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 ( )
196
171
{
197
172
report_volatile_safe ( cx, expr, * ptrty) ;
198
173
}
0 commit comments