11use clippy_utils:: diagnostics:: span_lint;
22use clippy_utils:: sym;
3+ use clippy_utils:: ty:: is_type_diagnostic_item;
34use rustc_hir:: { Expr , ExprKind } ;
45use rustc_lint:: { LateContext , LateLintPass } ;
5- use rustc_middle:: ty:: { self , Ty } ;
6+ use rustc_middle:: ty:: layout:: LayoutOf ;
7+ use rustc_middle:: ty:: { self , Ty , TypeVisitableExt } ;
68use rustc_session:: declare_lint_pass;
79
810declare_clippy_lint ! {
@@ -50,60 +52,37 @@ declare_clippy_lint! {
5052 /// }
5153 /// }
5254 /// ```
53- #[ clippy:: version = "1.91 .0" ]
55+ #[ clippy:: version = "1.92 .0" ]
5456 pub VOLATILE_COMPOSITES ,
5557 nursery,
5658 "warn about volatile read/write applied to composite types"
5759}
5860declare_lint_pass ! ( VolatileComposites => [ VOLATILE_COMPOSITES ] ) ;
5961
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.
62+ /// Zero-sized types are intrinsically safe to use volatile on since they won't
63+ /// actually generate *any* loads or stores. But this is also used to skip zero-sized
64+ /// fields of `#[repr(transparent)]` structures.
7465fn 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- }
66+ cx. layout_of ( ty) . is_ok_and ( |layout| layout. is_zst ( ) )
8267}
8368
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
69+ /// A thin raw pointer or reference.
70+ fn is_narrow_ptr < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
71+ match ty. kind ( ) {
72+ ty:: RawPtr ( inner, _) | ty:: Ref ( _, inner, _) => inner. has_trivial_sizedness ( cx. tcx , ty:: SizedTraitKind :: Sized ) ,
73+ _ => false ,
9074 }
9175}
9276
93- // Enum with some fixed representation and no data-carrying variants
77+ /// Enum with some fixed representation and no data-carrying variants.
9478fn 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- }
79+ ty. ty_adt_def ( ) . is_some_and ( |adt_def| {
80+ adt_def. is_enum ( ) && adt_def. repr ( ) . inhibit_struct_field_reordering ( ) && adt_def. is_payloadfree ( )
81+ } )
10382}
10483
105- // #[repr(transparent)] structures are also OK if the only non-zero
106- // sized field contains a volatile-safe type
84+ /// ` #[repr(transparent)]` structures are also OK if the only non-zero
85+ /// sized field contains a volatile-safe type.
10786fn is_struct_repr_transparent < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
10887 if let ty:: Adt ( adt_def, args) = ty. kind ( )
10988 && adt_def. is_struct ( )
@@ -123,8 +102,8 @@ fn is_struct_repr_transparent<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> boo
123102 }
124103}
125104
126- // SIMD can be useful to get larger atomic loads/stores, though this is still
127- // pretty machine-dependent.
105+ /// SIMD can be useful to get larger single loads/stores, though this is still
106+ /// pretty machine-dependent.
128107fn is_simd_repr < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
129108 if let ty:: Adt ( adt_def, _args) = ty. kind ( )
130109 && adt_def. is_struct ( )
@@ -137,21 +116,19 @@ fn is_simd_repr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
137116 }
138117}
139118
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-
119+ /// Top-level predicate for whether a type is volatile-safe or not.
145120fn is_volatile_safe_ty < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
146121 ty. is_primitive ( )
147- || is_narrow_raw_ptr ( cx, ty)
122+ || is_narrow_ptr ( cx, ty)
148123 || is_zero_sized_ty ( cx, ty)
149124 || is_enum_repr_c ( cx, ty)
150125 || is_simd_repr ( cx, ty)
151126 || is_struct_repr_transparent ( cx, ty)
152- || is_generic ( cx, ty)
127+ // We can't know about a generic type, so just let it pass to avoid noise
128+ || ty. has_non_region_param ( )
153129}
154130
131+ /// Print diagnostic for volatile read/write on non-volatile-safe types.
155132fn report_volatile_safe < ' tcx > ( cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > , ty : Ty < ' tcx > ) {
156133 if !is_volatile_safe_ty ( cx, ty) {
157134 span_lint (
@@ -177,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for VolatileComposites {
177154 // Raw pointers
178155 ty:: RawPtr ( innerty, _) => report_volatile_safe ( cx, expr, * innerty) ,
179156 // std::ptr::NonNull
180- ty:: Adt ( adt_def , args) if cx . tcx . is_diagnostic_item ( sym:: NonNull , adt_def . did ( ) ) => {
157+ ty:: Adt ( _ , args) if is_type_diagnostic_item ( cx , self_ty , sym:: NonNull ) => {
181158 report_volatile_safe ( cx, expr, args. type_at ( 0 ) ) ;
182159 } ,
183160 _ => ( ) ,
@@ -192,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for VolatileComposites {
192169 cx. tcx. get_diagnostic_name( def_id) ,
193170 Some ( sym:: ptr_read_volatile | sym:: ptr_write_volatile)
194171 )
195- && let ty:: RawPtr ( ptrty, _) = cx. typeck_results ( ) . expr_ty ( arg_ptr) . kind ( )
172+ && let ty:: RawPtr ( ptrty, _) = cx. typeck_results ( ) . expr_ty_adjusted ( arg_ptr) . kind ( )
196173 {
197174 report_volatile_safe ( cx, expr, * ptrty) ;
198175 }
0 commit comments