2 use rustc_hir
::intravisit
::FnKind
;
3 use rustc_hir
::{Body, FnDecl, HirId}
;
4 use rustc_infer
::infer
::TyCtxtInferExt
;
5 use rustc_lint
::{LateContext, LateLintPass}
;
6 use rustc_middle
::ty
::subst
::Subst
;
7 use rustc_middle
::ty
::{Opaque, PredicateKind::Trait}
;
8 use rustc_session
::{declare_lint_pass, declare_tool_lint}
;
9 use rustc_span
::{sym, Span}
;
10 use rustc_trait_selection
::traits
::error_reporting
::suggestions
::InferCtxtExt
;
11 use rustc_trait_selection
::traits
::{self, FulfillmentError, TraitEngine}
;
13 declare_clippy_lint
! {
14 /// **What it does:** This lint requires Future implementations returned from
15 /// functions and methods to implement the `Send` marker trait. It is mostly
16 /// used by library authors (public and internal) that target an audience where
17 /// multithreaded executors are likely to be used for running these Futures.
19 /// **Why is this bad?** A Future implementation captures some state that it
20 /// needs to eventually produce its final value. When targeting a multithreaded
21 /// executor (which is the norm on non-embedded devices) this means that this
22 /// state may need to be transported to other threads, in other words the
23 /// whole Future needs to implement the `Send` marker trait. If it does not,
24 /// then the resulting Future cannot be submitted to a thread pool in the
25 /// end user’s code.
27 /// Especially for generic functions it can be confusing to leave the
28 /// discovery of this problem to the end user: the reported error location
29 /// will be far from its cause and can in many cases not even be fixed without
30 /// modifying the library where the offending Future implementation is
33 /// **Known problems:** None.
38 /// async fn not_send(bytes: std::rc::Rc<[u8]>) {}
42 /// async fn is_send(bytes: std::sync::Arc<[u8]>) {}
46 "public Futures must be Send"
49 declare_lint_pass
!(FutureNotSend
=> [FUTURE_NOT_SEND
]);
51 impl<'tcx
> LateLintPass
<'tcx
> for FutureNotSend
{
54 cx
: &LateContext
<'tcx
>,
56 decl
: &'tcx FnDecl
<'tcx
>,
61 if let FnKind
::Closure
= kind
{
64 let ret_ty
= utils
::return_ty(cx
, hir_id
);
65 if let Opaque(id
, subst
) = *ret_ty
.kind() {
66 let preds
= cx
.tcx
.explicit_item_bounds(id
);
67 let mut is_future
= false;
68 for &(p
, _span
) in preds
{
69 let p
= p
.subst(cx
.tcx
, subst
);
70 if let Some(trait_ref
) = p
.to_opt_poly_trait_ref() {
71 if Some(trait_ref
.value
.def_id()) == cx
.tcx
.lang_items().future_trait() {
78 let send_trait
= cx
.tcx
.get_diagnostic_item(sym
::send_trait
).unwrap();
79 let span
= decl
.output
.span();
80 let send_result
= cx
.tcx
.infer_ctxt().enter(|infcx
| {
81 let cause
= traits
::ObligationCause
::misc(span
, hir_id
);
82 let mut fulfillment_cx
= traits
::FulfillmentContext
::new();
83 fulfillment_cx
.register_bound(&infcx
, cx
.param_env
, ret_ty
, send_trait
, cause
);
84 fulfillment_cx
.select_all_or_error(&infcx
)
86 if let Err(send_errors
) = send_result
{
87 utils
::span_lint_and_then(
91 "future cannot be sent between threads safely",
93 cx
.tcx
.infer_ctxt().enter(|infcx
| {
94 for FulfillmentError { obligation, .. }
in send_errors
{
95 infcx
.maybe_note_obligation_cause_for_async_await(db
, &obligation
);
96 if let Trait(trait_pred
, _
) = obligation
.predicate
.kind().skip_binder() {
98 "`{}` doesn't implement `{}`",
100 trait_pred
.trait_ref
.print_only_trait_path(),