/// that they may succeed the said yield point in the post-order.
guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
guard_bindings_set: HirIdSet,
+ linted_values: HirIdSet,
}
impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
// Insert the type into the ordered set.
let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree));
- check_must_not_suspend_ty(
- self.fcx,
- ty,
- hir_id,
- SuspendCheckData {
- expr,
- source_span,
- yield_span: yield_data.span,
- plural_len: 1,
- ..Default::default()
- },
- );
+ if !self.linted_values.contains(&hir_id) {
+ check_must_not_suspend_ty(
+ self.fcx,
+ ty,
+ hir_id,
+ SuspendCheckData {
+ expr,
+ source_span,
+ yield_span: yield_data.span,
+ plural_len: 1,
+ ..Default::default()
+ },
+ );
+ self.linted_values.insert(hir_id);
+ }
self.types.insert(ty::GeneratorInteriorTypeCause {
span: source_span,
prev_unresolved_span: None,
guard_bindings: <_>::default(),
guard_bindings_set: <_>::default(),
+ linted_values: <_>::default(),
};
intravisit::walk_body(&mut visitor, body);
--- /dev/null
+// edition:2018
+#![feature(must_not_suspend)]
+#![deny(must_not_suspend)]
+
+#[must_not_suspend]
+struct No {}
+
+async fn shushspend() {}
+
+async fn wheeee<T>(t: T) {
+ shushspend().await;
+ drop(t);
+}
+
+async fn yes() {
+ wheeee(No {}).await; //~ ERROR `No` held across
+}
+
+fn main() {
+}
--- /dev/null
+error: `No` held across a suspend point, but should not be
+ --> $DIR/dedup.rs:16:12
+ |
+LL | wheeee(No {}).await;
+ | -------^^^^^------- the value is held across this suspend point
+ |
+note: the lint level is defined here
+ --> $DIR/dedup.rs:3:9
+ |
+LL | #![deny(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+ --> $DIR/dedup.rs:16:12
+ |
+LL | wheeee(No {}).await;
+ | ^^^^^
+
+error: aborting due to previous error
+
// edition:2018
+// run-pass
+//
+// this test shows a case where the lint doesn't fire in generic code
#![feature(must_not_suspend)]
#![deny(must_not_suspend)]
drop(t);
}
-async fn yes() {
- wheeee(No {}).await; //~ ERROR `No` held across
- //~^ ERROR `No` held across
-}
-
fn main() {
+ let _fut = wheeee(No {});
}
+++ /dev/null
-error: `No` held across a suspend point, but should not be
- --> $DIR/generic.rs:16:12
- |
-LL | wheeee(No {}).await;
- | -------^^^^^------- the value is held across this suspend point
- |
-note: the lint level is defined here
- --> $DIR/generic.rs:3:9
- |
-LL | #![deny(must_not_suspend)]
- | ^^^^^^^^^^^^^^^^
-help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
- --> $DIR/generic.rs:16:12
- |
-LL | wheeee(No {}).await;
- | ^^^^^
-
-error: `No` held across a suspend point, but should not be
- --> $DIR/generic.rs:16:12
- |
-LL | wheeee(No {}).await;
- | -------^^^^^------- the value is held across this suspend point
- |
-help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
- --> $DIR/generic.rs:16:12
- |
-LL | wheeee(No {}).await;
- | ^^^^^
-
-error: aborting due to 2 previous errors
-
impl Bar {
async fn uhoh(&mut self) {
let guard = &mut self.u; //~ ERROR `Umm` held across
- //~^ ERROR `Umm` held across
other().await;
|
LL | let guard = &mut self.u;
| ^^^^^^
-...
+LL |
LL | other().await;
| ------------- the value is held across this suspend point
|
LL | let guard = &mut self.u;
| ^^^^^^
-error: `Umm` held across a suspend point, but should not be
- --> $DIR/ref.rs:18:26
- |
-LL | let guard = &mut self.u;
- | ^^^^^^
-...
-LL | other().await;
- | ------------- the value is held across this suspend point
- |
-note: You gotta use Umm's, ya know?
- --> $DIR/ref.rs:18:26
- |
-LL | let guard = &mut self.u;
- | ^^^^^^
-help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
- --> $DIR/ref.rs:18:26
- |
-LL | let guard = &mut self.u;
- | ^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error