Skip to content

Commit 63fad69

Browse files
committed
lowering: extend temporary lifetimes around await
This commit changes the HIR lowering around `await` so that temporary lifetimes are extended. Previously, await was lowered as: ```rust { let mut pinned = future; loop { match ::std::future::poll_with_tls_context(unsafe { <::std::pin::Pin>::new_unchecked(&mut pinned) }) { ::std::task::Poll::Ready(result) => break result, ::std::task::Poll::Pending => {} } yield (); } } ``` With this commit, await is lowered as: ```rust match future { mut pinned => loop { match ::std::future::poll_with_tls_context(unsafe { <::std::pin::Pin>::new_unchecked(&mut pinned) }) { ::std::task::Poll::Ready(result) => break result, ::std::task::Poll::Pending => {} } yield (); } } ``` However, this change has the following side-effects: - All temporaries in future will be considered to live across a yield for the purpose of auto-traits. - Borrowed temporaries in future are likely to be considered to be live across the yield for the purpose of the generator transform. Signed-off-by: David Wood <[email protected]>
1 parent 43a5ff4 commit 63fad69

File tree

4 files changed

+58
-32
lines changed

4 files changed

+58
-32
lines changed

src/librustc/hir/lowering/expr.rs

+15-20
Original file line numberDiff line numberDiff line change
@@ -507,14 +507,13 @@ impl LoweringContext<'_> {
507507

508508
/// Desugar `<expr>.await` into:
509509
/// ```rust
510-
/// {
511-
/// let mut pinned = <expr>;
512-
/// loop {
510+
/// match <expr> {
511+
/// mut pinned => loop {
513512
/// match ::std::future::poll_with_tls_context(unsafe {
514-
/// ::std::pin::Pin::new_unchecked(&mut pinned)
513+
/// <::std::pin::Pin>::new_unchecked(&mut pinned)
515514
/// }) {
516515
/// ::std::task::Poll::Ready(result) => break result,
517-
/// ::std::task::Poll::Pending => {},
516+
/// ::std::task::Poll::Pending => {}
518517
/// }
519518
/// yield ();
520519
/// }
@@ -549,21 +548,12 @@ impl LoweringContext<'_> {
549548
self.allow_gen_future.clone(),
550549
);
551550

552-
// let mut pinned = <expr>;
553-
let expr = P(self.lower_expr(expr));
554551
let pinned_ident = Ident::with_dummy_span(sym::pinned);
555552
let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
556553
span,
557554
pinned_ident,
558555
hir::BindingAnnotation::Mutable,
559556
);
560-
let pinned_let = self.stmt_let_pat(
561-
ThinVec::new(),
562-
span,
563-
Some(expr),
564-
pinned_pat,
565-
hir::LocalSource::AwaitDesugar,
566-
);
567557

568558
// ::std::future::poll_with_tls_context(unsafe {
569559
// ::std::pin::Pin::new_unchecked(&mut pinned)
@@ -621,7 +611,7 @@ impl LoweringContext<'_> {
621611
self.arm(hir_vec![pending_pat], empty_block)
622612
};
623613

624-
let match_stmt = {
614+
let inner_match_stmt = {
625615
let match_expr = self.expr_match(
626616
span,
627617
poll_expr,
@@ -643,10 +633,11 @@ impl LoweringContext<'_> {
643633

644634
let loop_block = P(self.block_all(
645635
span,
646-
hir_vec![match_stmt, yield_stmt],
636+
hir_vec![inner_match_stmt, yield_stmt],
647637
None,
648638
));
649639

640+
// loop { .. }
650641
let loop_expr = P(hir::Expr {
651642
hir_id: loop_hir_id,
652643
node: hir::ExprKind::Loop(
@@ -658,10 +649,14 @@ impl LoweringContext<'_> {
658649
attrs: ThinVec::new(),
659650
});
660651

661-
hir::ExprKind::Block(
662-
P(self.block_all(span, hir_vec![pinned_let], Some(loop_expr))),
663-
None,
664-
)
652+
// mut pinned => loop { ... }
653+
let pinned_arm = self.arm(hir_vec![pinned_pat], loop_expr);
654+
655+
// match <expr> {
656+
// mut pinned => loop { .. }
657+
// }
658+
let expr = P(self.lower_expr(expr));
659+
hir::ExprKind::Match(expr, hir_vec![pinned_arm], hir::MatchSource::AwaitDesugar)
665660
}
666661

667662
fn lower_expr_closure(

src/test/ui/async-await/async-fn-nonsend.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ LL | assert_send(local_dropped_before_await());
99
|
1010
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
1111
= note: required because it appears within the type `impl std::fmt::Debug`
12-
= note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, ()}`
13-
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, ()}]`
14-
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, ()}]>`
12+
= note: required because it appears within the type `{impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
13+
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
14+
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
1515
= note: required because it appears within the type `impl std::future::Future`
1616
= note: required because it appears within the type `impl std::future::Future`
1717

@@ -26,9 +26,9 @@ LL | assert_send(non_send_temporary_in_match());
2626
|
2727
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
2828
= note: required because it appears within the type `impl std::fmt::Debug`
29-
= note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}`
30-
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}]`
31-
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}]>`
29+
= note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
30+
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
31+
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
3232
= note: required because it appears within the type `impl std::future::Future`
3333
= note: required because it appears within the type `impl std::future::Future`
3434

@@ -45,9 +45,9 @@ LL | assert_send(non_sync_with_method_call());
4545
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write`
4646
= note: required because it appears within the type `std::fmt::Formatter<'_>`
4747
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
48-
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}`
49-
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]`
50-
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>`
48+
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
49+
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
50+
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
5151
= note: required because it appears within the type `impl std::future::Future`
5252
= note: required because it appears within the type `impl std::future::Future`
5353

@@ -68,9 +68,9 @@ LL | assert_send(non_sync_with_method_call());
6868
= note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>`
6969
= note: required because it appears within the type `std::fmt::Formatter<'_>`
7070
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
71-
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}`
72-
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]`
73-
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>`
71+
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
72+
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
73+
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
7474
= note: required because it appears within the type `impl std::future::Future`
7575
= note: required because it appears within the type `impl std::future::Future`
7676

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// check-pass
2+
// edition:2018
3+
4+
struct Test(String);
5+
6+
impl Test {
7+
async fn borrow_async(&self) {}
8+
9+
fn with(&mut self, s: &str) -> &mut Self {
10+
self.0 = s.into();
11+
self
12+
}
13+
}
14+
15+
async fn test() {
16+
Test("".to_string()).with("123").borrow_async().await;
17+
}
18+
19+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// check-pass
2+
// edition:2018
3+
4+
async fn foo(x: &[Vec<u32>]) -> u32 {
5+
0
6+
}
7+
8+
async fn bar() {
9+
foo(&[vec![123]]).await;
10+
}
11+
12+
fn main() { }

0 commit comments

Comments
 (0)