11use  std:: ops:: ControlFlow ; 
22
3- use  clippy_config:: Conf ; 
43use  clippy_utils:: diagnostics:: span_lint_and_then; 
54use  clippy_utils:: return_ty; 
65use  rustc_hir:: intravisit:: FnKind ; 
@@ -11,7 +10,7 @@ use rustc_middle::ty::print::PrintTraitRefExt;
1110use  rustc_middle:: ty:: { 
1211    self ,  AliasTy ,  Binder ,  ClauseKind ,  PredicateKind ,  Ty ,  TyCtxt ,  TypeVisitable ,  TypeVisitableExt ,  TypeVisitor , 
1312} ; 
14- use  rustc_session:: impl_lint_pass ; 
13+ use  rustc_session:: declare_lint_pass ; 
1514use  rustc_span:: def_id:: LocalDefId ; 
1615use  rustc_span:: { Span ,  sym} ; 
1716use  rustc_trait_selection:: error_reporting:: InferCtxtErrorExt ; 
@@ -20,23 +19,17 @@ use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
2019declare_clippy_lint !  { 
2120    /// ### What it does 
2221     /// This lint requires Future implementations returned from 
23-      /// functions and methods to implement the `Send` marker trait. 
22+      /// functions and methods to implement the `Send` marker trait, 
23+      /// ignoring type parameters. 
24+      /// 
25+      /// If a function is generic and its Future conditionally implements `Send` 
26+      /// based on a generic parameter then it is considered `Send` and no warning is emitted. 
2427     /// 
25-      /// The default configuration of this lint only emits warnings for futures 
26-      /// that are unconditionally `!Send`, ignoring generic parameters. 
2728     /// This can be used by library authors (public and internal) to ensure 
28-      /// their functions are compatible with multi-threaded runtimes that require `Send` futures, 
29+      /// their functions are compatible with both  multi-threaded runtimes that require `Send` futures, 
2930     /// as well as single-threaded runtimes where callers may choose `!Send` types 
3031     /// for generic parameters. 
3132     /// 
32-      /// A more strict version can be enabled through the `unconditional_send_futures` configuration, 
33-      /// which requires that futures must always unconditionally implement `Send`, 
34-      /// even if whether the future is `Send` or not is determined at call site for generic functions. 
35-      /// This can be useful for binary crates that always use a multi-threaded runtime to find `!Send` futures 
36-      /// as early as possible and keep errors contained in the most relevant place, 
37-      /// instead of propagating `!Send` and be left with a hard-to-debug error in an 
38-      /// unrelated place (e.g. the final future passed to `tokio::spawn()`). 
39-      /// 
4033     /// ### Why is this bad? 
4134     /// A Future implementation captures some state that it 
4235     /// needs to eventually produce its final value. When targeting a multithreaded 
@@ -66,19 +59,7 @@ declare_clippy_lint! {
6659    "public Futures must be Send" 
6760} 
6861
69- pub  struct  FutureNotSend  { 
70-     unconditionally_not_send :  bool , 
71- } 
72- 
73- impl  FutureNotSend  { 
74-     pub  fn  new ( conf :  & ' static  Conf )  -> Self  { 
75-         Self  { 
76-             unconditionally_not_send :  conf. unconditional_send_futures , 
77-         } 
78-     } 
79- } 
80- 
81- impl_lint_pass ! ( FutureNotSend  => [ FUTURE_NOT_SEND ] ) ; 
62+ declare_lint_pass ! ( FutureNotSend  => [ FUTURE_NOT_SEND ] ) ; 
8263
8364impl < ' tcx >  LateLintPass < ' tcx >  for  FutureNotSend  { 
8465    fn  check_fn ( 
@@ -111,43 +92,27 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
11192                ocx. register_bound ( cause,  cx. param_env ,  ret_ty,  send_trait) ; 
11293                let  send_errors = ocx. select_all_or_error ( ) ; 
11394
114-                 let  is_send = if  self . unconditionally_not_send  { 
115-                     send_errors. is_empty ( ) 
116-                 }  else  { 
117-                     // Allow errors that try to prove `Send` for types that "mention" a generic parameter at the "top 
118-                     // level". 
119-                     // For example, allow errors that `T: Send` can't be proven, but reject `Rc<T>: Send` errors, 
120-                     // which is always unconditionally `!Send` for any possible type `T`. 
121-                     // 
122-                     // We also allow associated type projections if the self type is either itself a projection or a 
123-                     // type parameter. 
124-                     // This is to prevent emitting warnings for e.g. holding a `<Fut as Future>::Output` across await 
125-                     // points, where `Fut` is a type parameter. 
126- 
127-                     struct  TypeWalker ; 
128-                     impl < ' tcx >  TypeVisitor < TyCtxt < ' tcx > >  for  TypeWalker  { 
129-                         type  Result  = ControlFlow < bool > ; 
130-                         fn  visit_ty ( & mut  self ,  ty :  Ty < ' tcx > )  -> Self :: Result  { 
131-                             match  ty. kind ( )  { 
132-                                 ty:: Param ( _)  => ControlFlow :: Break ( true ) , 
133-                                 ty:: Alias ( ty:: AliasTyKind :: Projection ,  ty)  => ty. visit_with ( self ) , 
134-                                 _ => ControlFlow :: Break ( false ) , 
135-                             } 
136-                         } 
137-                     } 
95+                 // Allow errors that try to prove `Send` for types that "mention" a generic parameter at the "top 
96+                 // level". 
97+                 // For example, allow errors that `T: Send` can't be proven, but reject `Rc<T>: Send` errors, 
98+                 // which is always unconditionally `!Send` for any possible type `T`. 
99+                 // 
100+                 // We also allow associated type projections if the self type is either itself a projection or a 
101+                 // type parameter. 
102+                 // This is to prevent emitting warnings for e.g. holding a `<Fut as Future>::Output` across await 
103+                 // points, where `Fut` is a type parameter. 
138104
139-                     send_errors. iter ( ) . all ( |err| { 
140-                         err. obligation 
141-                             . predicate 
142-                             . as_trait_clause ( ) 
143-                             . map ( Binder :: skip_binder) 
144-                             . is_some_and ( |pred| { 
145-                                 pred. def_id ( )  == send_trait
146-                                     && pred. self_ty ( ) . has_param ( ) 
147-                                     && TypeWalker . visit_ty ( pred. self_ty ( ) )  == ControlFlow :: Break ( true ) 
148-                             } ) 
149-                     } ) 
150-                 } ; 
105+                 let  is_send = send_errors. iter ( ) . all ( |err| { 
106+                     err. obligation 
107+                         . predicate 
108+                         . as_trait_clause ( ) 
109+                         . map ( Binder :: skip_binder) 
110+                         . is_some_and ( |pred| { 
111+                             pred. def_id ( )  == send_trait
112+                                 && pred. self_ty ( ) . has_param ( ) 
113+                                 && TyParamAtTopLevelVisitor . visit_ty ( pred. self_ty ( ) )  == ControlFlow :: Break ( true ) 
114+                         } ) 
115+                 } ) ; 
151116
152117                if  !is_send { 
153118                    span_lint_and_then ( 
@@ -177,3 +142,15 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
177142        } 
178143    } 
179144} 
145+ 
146+ struct  TyParamAtTopLevelVisitor ; 
147+ impl < ' tcx >  TypeVisitor < TyCtxt < ' tcx > >  for  TyParamAtTopLevelVisitor  { 
148+     type  Result  = ControlFlow < bool > ; 
149+     fn  visit_ty ( & mut  self ,  ty :  Ty < ' tcx > )  -> Self :: Result  { 
150+         match  ty. kind ( )  { 
151+             ty:: Param ( _)  => ControlFlow :: Break ( true ) , 
152+             ty:: Alias ( ty:: AliasTyKind :: Projection ,  ty)  => ty. visit_with ( self ) , 
153+             _ => ControlFlow :: Break ( false ) , 
154+         } 
155+     } 
156+ } 
0 commit comments