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,39 @@ 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.
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.
126104
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- }
105+ struct TypeWalker ;
106+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for TypeWalker {
107+ type Result = ControlFlow < bool > ;
108+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> Self :: Result {
109+ match ty. kind ( ) {
110+ ty:: Param ( _) => ControlFlow :: Break ( true ) ,
111+ ty:: Alias ( ty:: AliasTyKind :: Projection , ty) => ty. visit_with ( self ) ,
112+ _ => ControlFlow :: Break ( false ) ,
136113 }
137114 }
115+ }
138116
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- } ;
117+ let is_send = send_errors. iter ( ) . all ( |err| {
118+ err. obligation
119+ . predicate
120+ . as_trait_clause ( )
121+ . map ( Binder :: skip_binder)
122+ . is_some_and ( |pred| {
123+ pred. def_id ( ) == send_trait
124+ && pred. self_ty ( ) . has_param ( )
125+ && TypeWalker . visit_ty ( pred. self_ty ( ) ) == ControlFlow :: Break ( true )
126+ } )
127+ } ) ;
151128
152129 if !is_send {
153130 span_lint_and_then (
0 commit comments