Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement #[must_not_suspend] #88865

Merged
merged 9 commits into from Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/active.rs
Expand Up @@ -679,6 +679,10 @@ declare_features! (
/// Allows `let...else` statements.
(active, let_else, "1.56.0", Some(87335), None),

/// Allows the `#[must_not_suspend]` attribute.
(active, must_not_suspend, "1.57.0", Some(83310), None),


// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Expand Up @@ -202,6 +202,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
ungated!(must_use, Normal, template!(Word, NameValueStr: "reason")),
gated!(
must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), must_not_suspend,
experimental!(must_not_suspend)
),
// FIXME(#14407)
ungated!(
deprecated, Normal,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/lib.rs
Expand Up @@ -298,6 +298,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
UNUSED_LABELS,
UNUSED_PARENS,
UNUSED_BRACES,
MUST_NOT_SUSPEND,
REDUNDANT_SEMICOLONS
);

Expand Down
39 changes: 39 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Expand Up @@ -314,6 +314,44 @@ declare_lint! {
"imports that are never used"
}

declare_lint! {
/// The `must_not_suspend` lint guards against values that shouldn't be held across suspend points
/// (`.await`)
///
/// ### Example
///
/// ```rust
/// #![feature(must_not_suspend)]
///
/// #[must_not_suspend]
/// struct SyncThing {}
///
/// async fn yield_now() {}
///
/// pub async fn uhoh() {
/// let guard = SyncThing {};
/// yield_now().await;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The `must_not_suspend` lint detects values that are marked with the `#[must_not_suspend]`
/// attribute being held across suspend points. A "suspend" point is usually a `.await` in an async
/// function.
///
/// This attribute can be used to mark values that are semantically incorrect across suspends
/// (like certain types of timers), values that have async alternatives, and values that
/// regularly cause problems with the `Send`-ness of async fn's returned futures (like
/// `MutexGuard`'s)
///
pub MUST_NOT_SUSPEND,
Warn,
"use of a `#[must_not_suspend]` value across a yield point",
}

declare_lint! {
/// The `unused_extern_crates` lint guards against `extern crate` items
/// that are never used.
Expand Down Expand Up @@ -2993,6 +3031,7 @@ declare_lint_pass! {
CENUM_IMPL_DROP_CAST,
CONST_EVALUATABLE_UNCHECKED,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
MUST_NOT_SUSPEND,
UNINHABITED_STATIC,
FUNCTION_ITEM_REFERENCES,
USELESS_DEPRECATED,
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_passes/src/check_attr.rs
Expand Up @@ -104,6 +104,7 @@ impl CheckAttrVisitor<'tcx> {
sym::default_method_body_is_const => {
self.check_default_method_body_is_const(attr, span, target)
}
sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
sym::rustc_const_unstable
| sym::rustc_const_stable
| sym::unstable
Expand Down Expand Up @@ -1014,6 +1015,21 @@ impl CheckAttrVisitor<'tcx> {
is_valid
}

/// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid.
fn check_must_not_suspend(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Struct | Target::Enum | Target::Union | Target::Trait => true,
_ => {
self.tcx
.sess
.struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait")
.span_label(*span, "is not a struct, enum, or trait")
.emit();
false
}
}
}

/// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid.
fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Expand Up @@ -836,6 +836,7 @@ symbols! {
mul,
mul_assign,
mul_with_overflow,
must_not_suspend,
must_use,
mut_ptr,
mut_slice_ptr,
Expand Down