From a7df4e8d2f89379fb0b620cb0267f97c05bc1598 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 16 Dec 2021 13:34:39 -0800 Subject: [PATCH] Handle empty loops better --- .../check/generator_interior/drop_ranges/cfg_build.rs | 11 +++++++++-- src/test/ui/async-await/async-fn-nonsend.rs | 8 ++++++++ src/test/ui/async-await/async-fn-nonsend.stderr | 8 ++++---- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs index 4656f56569e..b434e05db80 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs @@ -157,8 +157,15 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> { } ExprKind::Loop(body, ..) => { let loop_begin = self.expr_index + 1; - self.visit_block(body); - self.drop_ranges.add_control_edge(self.expr_index, loop_begin); + if body.stmts.is_empty() && body.expr.is_none() { + // For empty loops we won't have updated self.expr_index after visiting the + // body, meaning we'd get an edge from expr_index to expr_index + 1, but + // instead we want an edge from expr_index + 1 to expr_index + 1. + self.drop_ranges.add_control_edge(loop_begin, loop_begin); + } else { + self.visit_block(body); + self.drop_ranges.add_control_edge(self.expr_index, loop_begin); + } } ExprKind::Break(hir::Destination { target_id: Ok(target), .. }, ..) | ExprKind::Continue(hir::Destination { target_id: Ok(target), .. }, ..) => { diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs index 210d9ff3f2d..55629132e40 100644 --- a/src/test/ui/async-await/async-fn-nonsend.rs +++ b/src/test/ui/async-await/async-fn-nonsend.rs @@ -43,6 +43,13 @@ async fn non_sync_with_method_call() { } } +async fn non_sync_with_infinite_loop() { + let f: &mut std::fmt::Formatter = loop {}; + if non_sync().fmt(f).unwrap() == () { + fut().await; + } +} + fn assert_send(_: impl Send) {} pub fn pass_assert() { @@ -51,4 +58,5 @@ pub fn pass_assert() { //~^ ERROR future cannot be sent between threads safely assert_send(non_sync_with_method_call()); //~^ ERROR future cannot be sent between threads safely + assert_send(non_sync_with_infinite_loop()); } diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index abba5585c62..9c87067a4d3 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -1,5 +1,5 @@ error: future cannot be sent between threads safely - --> $DIR/async-fn-nonsend.rs:50:17 + --> $DIR/async-fn-nonsend.rs:57:17 | LL | assert_send(non_send_temporary_in_match()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` @@ -16,13 +16,13 @@ LL | Some(_) => fut().await, LL | } | - `Some(non_send())` is later dropped here note: required by a bound in `assert_send` - --> $DIR/async-fn-nonsend.rs:46:24 + --> $DIR/async-fn-nonsend.rs:53:24 | LL | fn assert_send(_: impl Send) {} | ^^^^ required by this bound in `assert_send` error: future cannot be sent between threads safely - --> $DIR/async-fn-nonsend.rs:52:17 + --> $DIR/async-fn-nonsend.rs:59:17 | LL | assert_send(non_sync_with_method_call()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` @@ -40,7 +40,7 @@ LL | } LL | } | - `f` is later dropped here note: required by a bound in `assert_send` - --> $DIR/async-fn-nonsend.rs:46:24 + --> $DIR/async-fn-nonsend.rs:53:24 | LL | fn assert_send(_: impl Send) {} | ^^^^ required by this bound in `assert_send`