@@ -1377,33 +1377,43 @@ pub fn option_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
13771377 }
13781378}
13791379
1380- /// Check if `ty` is an `Iterator` and has side effects when iterated over. Currently, this only
1381- /// checks if the `ty` contains mutable captures, and thus may be imcomplete .
1380+ /// Check if a Ty<'_> of `Iterator` has side effects when iterated over by checking if it
1381+ /// captures any mutable references or equivalents .
13821382pub fn is_iter_with_side_effects < ' tcx > ( cx : & LateContext < ' tcx > , iter_ty : Ty < ' tcx > ) -> bool {
1383- let Some ( iter_trait) = cx. tcx . lang_items ( ) . iterator_trait ( ) else {
1384- return false ;
1385- } ;
1386-
1387- is_iter_with_side_effects_impl ( cx, iter_ty, iter_trait)
1383+ let mut phantoms = FxHashSet :: default ( ) ;
1384+ has_non_owning_mutable_access ( cx, & mut phantoms, iter_ty)
13881385}
13891386
1390- fn is_iter_with_side_effects_impl < ' tcx > ( cx : & LateContext < ' tcx > , iter_ty : Ty < ' tcx > , iter_trait : DefId ) -> bool {
1391- if implements_trait ( cx, iter_ty, iter_trait, & [ ] )
1392- && let ty:: Adt ( _, args) = iter_ty. kind ( )
1393- {
1394- return args. types ( ) . any ( |arg_ty| {
1395- if let ty:: Closure ( _, closure_args) = arg_ty. kind ( )
1396- && let Some ( captures) = closure_args. types ( ) . next_back ( )
1397- {
1398- captures
1399- . tuple_fields ( )
1400- . iter ( )
1401- . any ( |capture_ty| matches ! ( capture_ty. ref_mutability( ) , Some ( Mutability :: Mut ) ) )
1402- } else {
1403- is_iter_with_side_effects_impl ( cx, arg_ty, iter_trait)
1404- }
1405- } ) ;
1406- }
1387+ /// Check if `ty` contains mutable references or equivalent, which includes:
1388+ /// - A mutable reference/pointer.
1389+ /// - A reference/pointer to a non-`Freeze` type.
1390+ /// - A `PhantomData` type containing any of the previous.
1391+ fn has_non_owning_mutable_access < ' tcx > (
1392+ cx : & LateContext < ' tcx > ,
1393+ phantoms : & mut FxHashSet < Ty < ' tcx > > ,
1394+ ty : Ty < ' tcx > ,
1395+ ) -> bool {
1396+ match ty. kind ( ) {
1397+ ty:: Adt ( adt_def, args) if adt_def. is_phantom_data ( ) => {
1398+ phantoms. insert ( ty)
1399+ && args
1400+ . types ( )
1401+ . any ( |arg_ty| has_non_owning_mutable_access ( cx, phantoms, arg_ty) )
1402+ } ,
1403+ ty:: Adt ( adt_def, args) => adt_def
1404+ . all_fields ( )
1405+ . any ( |field| has_non_owning_mutable_access ( cx, phantoms, field. ty ( cx. tcx , args) ) ) ,
1406+ ty:: Array ( elem_ty, _) | ty:: Slice ( elem_ty) => has_non_owning_mutable_access ( cx, phantoms, * elem_ty) ,
14071407
1408- false
1408+ ty:: RawPtr ( pointee_ty, mutability) | ty:: Ref ( _, pointee_ty, mutability) => {
1409+ mutability. is_mut ( ) || !pointee_ty. is_freeze ( cx. tcx , cx. typing_env ( ) )
1410+ } ,
1411+ ty:: Closure ( _, closure_args) => {
1412+ matches ! ( closure_args. types( ) . next_back( ) , Some ( captures) if has_non_owning_mutable_access( cx, phantoms, captures) )
1413+ } ,
1414+ ty:: Tuple ( tuple_args) => tuple_args
1415+ . iter ( )
1416+ . any ( |arg_ty| has_non_owning_mutable_access ( cx, phantoms, arg_ty) ) ,
1417+ _ => false ,
1418+ }
14091419}
0 commit comments