Skip to content

Commit ce45663

Browse files
committed
Auto merge of #88865 - guswynn:must_not_suspend, r=oli-obk
Implement `#[must_not_suspend]` implements #83310 Some notes on the impl: 1. The code that searches for the attribute on the ADT is basically copied from the `must_use` lint. It's not shared, as the logic did diverge 2. The RFC does specify that the attribute can be placed on fn's (and fn-like objects), like `must_use`. I think this is a direct copy from the `must_use` reference definition. This implementation does NOT support this, as I felt that ADT's (+ `impl Trait` + `dyn Trait`) cover the usecase's people actually want on the RFC, and adding an imp for the fn call case would be significantly harder. The `must_use` impl can do a single check at fn call stmt time, but `must_not_suspend` would need to answer the question: "for some value X with type T, find any fn call that COULD have produced this value". That would require significant changes to `generator_interior.rs`, and I would need mentorship on that. `@eholk` and I are discussing it. 3. `@estebank` do you know a way I can make the user-provided `reason` note pop out? right now it seems quite hidden Also, I am not sure if we should run perf on this r? `@nikomatsakis`
2 parents 77f4143 + 08e0266 commit ce45663

27 files changed

+701
-5
lines changed

compiler/rustc_feature/src/active.rs

+4
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,10 @@ declare_features! (
675675
/// Allows `let...else` statements.
676676
(active, let_else, "1.56.0", Some(87335), None),
677677

678+
/// Allows the `#[must_not_suspend]` attribute.
679+
(active, must_not_suspend, "1.57.0", Some(83310), None),
680+
681+
678682
// -------------------------------------------------------------------------
679683
// feature-group-end: actual feature gates
680684
// -------------------------------------------------------------------------

compiler/rustc_feature/src/builtin_attrs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
202202
ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
203203
ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
204204
ungated!(must_use, Normal, template!(Word, NameValueStr: "reason")),
205+
gated!(
206+
must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), must_not_suspend,
207+
experimental!(must_not_suspend)
208+
),
205209
// FIXME(#14407)
206210
ungated!(
207211
deprecated, Normal,

compiler/rustc_lint/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
298298
UNUSED_LABELS,
299299
UNUSED_PARENS,
300300
UNUSED_BRACES,
301+
MUST_NOT_SUSPEND,
301302
REDUNDANT_SEMICOLONS
302303
);
303304

compiler/rustc_lint_defs/src/builtin.rs

+39
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,44 @@ declare_lint! {
314314
"imports that are never used"
315315
}
316316

317+
declare_lint! {
318+
/// The `must_not_suspend` lint guards against values that shouldn't be held across suspend points
319+
/// (`.await`)
320+
///
321+
/// ### Example
322+
///
323+
/// ```rust
324+
/// #![feature(must_not_suspend)]
325+
///
326+
/// #[must_not_suspend]
327+
/// struct SyncThing {}
328+
///
329+
/// async fn yield_now() {}
330+
///
331+
/// pub async fn uhoh() {
332+
/// let guard = SyncThing {};
333+
/// yield_now().await;
334+
/// }
335+
/// ```
336+
///
337+
/// {{produces}}
338+
///
339+
/// ### Explanation
340+
///
341+
/// The `must_not_suspend` lint detects values that are marked with the `#[must_not_suspend]`
342+
/// attribute being held across suspend points. A "suspend" point is usually a `.await` in an async
343+
/// function.
344+
///
345+
/// This attribute can be used to mark values that are semantically incorrect across suspends
346+
/// (like certain types of timers), values that have async alternatives, and values that
347+
/// regularly cause problems with the `Send`-ness of async fn's returned futures (like
348+
/// `MutexGuard`'s)
349+
///
350+
pub MUST_NOT_SUSPEND,
351+
Warn,
352+
"use of a `#[must_not_suspend]` value across a yield point",
353+
}
354+
317355
declare_lint! {
318356
/// The `unused_extern_crates` lint guards against `extern crate` items
319357
/// that are never used.
@@ -2993,6 +3031,7 @@ declare_lint_pass! {
29933031
CENUM_IMPL_DROP_CAST,
29943032
CONST_EVALUATABLE_UNCHECKED,
29953033
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
3034+
MUST_NOT_SUSPEND,
29963035
UNINHABITED_STATIC,
29973036
FUNCTION_ITEM_REFERENCES,
29983037
USELESS_DEPRECATED,

compiler/rustc_passes/src/check_attr.rs

+16
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ impl CheckAttrVisitor<'tcx> {
104104
sym::default_method_body_is_const => {
105105
self.check_default_method_body_is_const(attr, span, target)
106106
}
107+
sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
107108
sym::rustc_const_unstable
108109
| sym::rustc_const_stable
109110
| sym::unstable
@@ -1014,6 +1015,21 @@ impl CheckAttrVisitor<'tcx> {
10141015
is_valid
10151016
}
10161017

1018+
/// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid.
1019+
fn check_must_not_suspend(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
1020+
match target {
1021+
Target::Struct | Target::Enum | Target::Union | Target::Trait => true,
1022+
_ => {
1023+
self.tcx
1024+
.sess
1025+
.struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait")
1026+
.span_label(*span, "is not a struct, enum, or trait")
1027+
.emit();
1028+
false
1029+
}
1030+
}
1031+
}
1032+
10171033
/// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid.
10181034
fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
10191035
match target {

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,7 @@ symbols! {
837837
mul,
838838
mul_assign,
839839
mul_with_overflow,
840+
must_not_suspend,
840841
must_use,
841842
mut_ptr,
842843
mut_slice_ptr,

0 commit comments

Comments
 (0)