Skip to content

Commit 469eced

Browse files
committed
Remove unconditional-send-future config
1 parent 8e6b75d commit 469eced

File tree

13 files changed

+71
-376
lines changed

13 files changed

+71
-376
lines changed

CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6220,7 +6220,6 @@ Released 2018-09-13
62206220
[`too-many-lines-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-lines-threshold
62216221
[`trivial-copy-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trivial-copy-size-limit
62226222
[`type-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#type-complexity-threshold
6223-
[`unconditional-send-futures`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unconditional-send-futures
62246223
[`unnecessary-box-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unnecessary-box-size
62256224
[`unreadable-literal-lint-fractions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unreadable-literal-lint-fractions
62266225
[`upper-case-acronyms-aggressive`]: https://doc.rust-lang.org/clippy/lint_configuration.html#upper-case-acronyms-aggressive

book/src/lint_configuration.md

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -883,33 +883,6 @@ The maximum complexity a type can have
883883
* [`type_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity)
884884

885885

886-
## `unconditional-send-futures`
887-
Whether `future_not_send` should require futures to implement `Send` unconditionally.
888-
Enabling this makes the lint more strict and requires generic functions have `Send` bounds
889-
on type parameters.
890-
891-
### Example
892-
```
893-
async fn foo<R>(r: R) {
894-
std::future::ready(()).await;
895-
r;
896-
}
897-
```
898-
The returned future by this async function may or may not be `Send` - it depends on the particular type
899-
that `R` is instantiated with at call site, so it is **not** unconditionally `Send`.
900-
Adding an `R: Send` bound to the function definition satisfies it, but is more restrictive for callers.
901-
902-
For library crate authors that want to make sure that their async functions are compatible
903-
with both single-threaded and multi-threaded executors, the default behavior of allowing `!Send` futures
904-
if type parameters are `!Send` makes sense.
905-
906-
**Default Value:** `false`
907-
908-
---
909-
**Affected lints:**
910-
* [`future_not_send`](https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send)
911-
912-
913886
## `unnecessary-box-size`
914887
The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
915888

clippy_config/src/conf.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -645,26 +645,6 @@ define_Conf! {
645645
/// The maximum complexity a type can have
646646
#[lints(type_complexity)]
647647
type_complexity_threshold: u64 = 250,
648-
/// Whether `future_not_send` should require futures to implement `Send` unconditionally.
649-
/// Enabling this makes the lint more strict and requires generic functions have `Send` bounds
650-
/// on type parameters.
651-
///
652-
/// ### Example
653-
/// ```
654-
/// async fn foo<R>(r: R) {
655-
/// std::future::ready(()).await;
656-
/// r;
657-
/// }
658-
/// ```
659-
/// The returned future by this async function may or may not be `Send` - it depends on the particular type
660-
/// that `R` is instantiated with at call site, so it is **not** unconditionally `Send`.
661-
/// Adding an `R: Send` bound to the function definition satisfies it, but is more restrictive for callers.
662-
///
663-
/// For library crate authors that want to make sure that their async functions are compatible
664-
/// with both single-threaded and multi-threaded executors, the default behavior of allowing `!Send` futures
665-
/// if type parameters are `!Send` makes sense.
666-
#[lints(future_not_send)]
667-
unconditional_send_futures: bool = false,
668648
/// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
669649
#[lints(unnecessary_box_returns)]
670650
unnecessary_box_size: u64 = 128,

clippy_lints/src/future_not_send.rs

Lines changed: 40 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::ops::ControlFlow;
22

3-
use clippy_config::Conf;
43
use clippy_utils::diagnostics::span_lint_and_then;
54
use clippy_utils::return_ty;
65
use rustc_hir::intravisit::FnKind;
@@ -11,7 +10,7 @@ use rustc_middle::ty::print::PrintTraitRefExt;
1110
use 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;
1514
use rustc_span::def_id::LocalDefId;
1615
use rustc_span::{Span, sym};
1716
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -20,23 +19,17 @@ use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
2019
declare_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

8364
impl<'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+
}

clippy_lints/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
777777
store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
778778
store.register_late_pass(|_| Box::<dereference::Dereferencing<'_>>::default());
779779
store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
780-
store.register_late_pass(move |_| Box::new(future_not_send::FutureNotSend::new(conf)));
780+
store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
781781
store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(conf)));
782782
store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
783783
store.register_late_pass(|_| Box::new(if_not_else::IfNotElse));

tests/ui-toml/future_not_send/default/clippy.toml

Whitespace-only changes.

0 commit comments

Comments
 (0)