@@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
121121 } ;
122122 }
123123 } ,
124- )
124+ ) ;
125125 }
126126 }
127127 }
@@ -145,6 +145,8 @@ impl<'tcx> NonSendField<'tcx> {
145145 }
146146}
147147
148+ /// Given a type, collect all of its generic parameters.
149+ /// Example: MyStruct<P, Box<Q, R>> => vec![P, Q, R]
148150fn collect_generic_params < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> Vec < Ty < ' tcx > > {
149151 ty. walk ( cx. tcx )
150152 . filter_map ( |inner| match inner. unpack ( ) {
@@ -155,14 +157,47 @@ fn collect_generic_params<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Vec<Ty<
155157 . collect ( )
156158}
157159
158- fn ty_allowed_in_send < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , send_trait : DefId ) -> bool {
159- raw_pointer_in_ty_def ( cx, ty) || implements_trait ( cx, ty, send_trait, & [ ] ) || is_copy ( cx, ty)
160+ /// Determine if the given type is allowed in an ADT that implements `Send`
161+ fn ty_allowed_in_send ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , send_trait : DefId ) -> bool {
162+ // TODO: check configuration and call `ty_implements_send_or_copy()` or
163+ // `ty_allowed_with_raw_pointer_heuristic()`
164+ ty_allowed_with_raw_pointer_heuristic ( cx, ty, send_trait)
160165}
161166
162- /// Returns `true` if the type itself is a raw pointer or has a raw pointer as a
163- /// generic parameter, e.g., `Vec<*const u8>`.
164- /// Note that it does not look into enum variants or struct fields.
165- fn raw_pointer_in_ty_def < ' tcx > ( cx : & LateContext < ' tcx > , target_ty : Ty < ' tcx > ) -> bool {
167+ /// Determine if the given type is `Send` or `Copy`
168+ fn ty_implements_send_or_copy ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , send_trait : DefId ) -> bool {
169+ implements_trait ( cx, ty, send_trait, & [ ] ) || is_copy ( cx, ty)
170+ }
171+
172+ /// Heuristic to allow cases like `Vec<*const u8>`
173+ fn ty_allowed_with_raw_pointer_heuristic < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , send_trait : DefId ) -> bool {
174+ if ty_implements_send_or_copy ( cx, ty, send_trait) {
175+ true
176+ } else {
177+ // The type is known to be `!Send` and `!Copy`
178+ match ty. kind ( ) {
179+ ty:: Tuple ( _) => ty
180+ . tuple_fields ( )
181+ . all ( |ty| ty_allowed_with_raw_pointer_heuristic ( cx, ty, send_trait) ) ,
182+ ty:: Array ( ty, _) | ty:: Slice ( ty) => ty_allowed_with_raw_pointer_heuristic ( cx, ty, send_trait) ,
183+ ty:: Adt ( _, substs) => {
184+ if contains_raw_pointer ( cx, ty) {
185+ // descends only if ADT contains any raw pointers
186+ substs. iter ( ) . all ( |generic_arg| match generic_arg. unpack ( ) {
187+ GenericArgKind :: Type ( ty) => ty_allowed_with_raw_pointer_heuristic ( cx, ty, send_trait) ,
188+ GenericArgKind :: Lifetime ( _) | GenericArgKind :: Const ( _) => true ,
189+ } )
190+ } else {
191+ false
192+ }
193+ } ,
194+ ty:: RawPtr ( _) => true ,
195+ _ => false ,
196+ }
197+ }
198+ }
199+
200+ fn contains_raw_pointer < ' tcx > ( cx : & LateContext < ' tcx > , target_ty : Ty < ' tcx > ) -> bool {
166201 for ty_node in target_ty. walk ( cx. tcx ) {
167202 if_chain ! {
168203 if let GenericArgKind :: Type ( inner_ty) = ty_node. unpack( ) ;
0 commit comments