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 atomic 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