Skip to content

Commit dfcfa17

Browse files
Make async/await lowering use resume arguments
1 parent 18adc45 commit dfcfa17

File tree

5 files changed

+86
-23
lines changed

5 files changed

+86
-23
lines changed

src/librustc_ast_lowering/expr.rs

Lines changed: 76 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_hir as hir;
1010
use rustc_hir::def::Res;
1111
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
1212
use rustc_span::symbol::{sym, Symbol};
13+
use rustc_span::DUMMY_SP;
1314

1415
impl<'hir> LoweringContext<'_, 'hir> {
1516
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
@@ -483,14 +484,44 @@ impl<'hir> LoweringContext<'_, 'hir> {
483484
Some(ty) => FnRetTy::Ty(ty),
484485
None => FnRetTy::Default(span),
485486
};
486-
let ast_decl = FnDecl { inputs: vec![], output };
487+
488+
let task_context_id = self.resolver.next_node_id();
489+
let task_context_hid = self.lower_node_id(task_context_id);
490+
let ast_decl = FnDecl {
491+
inputs: vec![Param {
492+
attrs: AttrVec::new(),
493+
ty: AstP(Ty {
494+
id: self.resolver.next_node_id(),
495+
kind: TyKind::Infer,
496+
span: DUMMY_SP,
497+
}),
498+
pat: AstP(Pat {
499+
id: task_context_id,
500+
kind: PatKind::Ident(
501+
BindingMode::ByValue(Mutability::Mut),
502+
Ident::with_dummy_span(sym::_task_context),
503+
None,
504+
),
505+
span: DUMMY_SP,
506+
}),
507+
id: self.resolver.next_node_id(),
508+
span: DUMMY_SP,
509+
is_placeholder: false,
510+
}],
511+
output,
512+
};
487513
let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
488514
let body_id = self.lower_fn_body(&ast_decl, |this| {
489515
this.generator_kind = Some(hir::GeneratorKind::Async(async_gen_kind));
490-
body(this)
516+
517+
let old_ctx = this.task_context;
518+
this.task_context = Some(task_context_hid);
519+
let res = body(this);
520+
this.task_context = old_ctx;
521+
res
491522
});
492523

493-
// `static || -> <ret_ty> { body }`:
524+
// `static |task_context| -> <ret_ty> { body }`:
494525
let generator_kind = hir::ExprKind::Closure(
495526
capture_clause,
496527
decl,
@@ -523,9 +554,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
523554
/// ```rust
524555
/// match <expr> {
525556
/// mut pinned => loop {
526-
/// match ::std::future::poll_with_tls_context(unsafe {
527-
/// <::std::pin::Pin>::new_unchecked(&mut pinned)
528-
/// }) {
557+
/// match unsafe { ::std::future::poll_with_context(
558+
/// <::std::pin::Pin>::new_unchecked(&mut pinned),
559+
/// task_context,
560+
/// ) } {
529561
/// ::std::task::Poll::Ready(result) => break result,
530562
/// ::std::task::Poll::Pending => {}
531563
/// }
@@ -561,12 +593,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
561593
let (pinned_pat, pinned_pat_hid) =
562594
self.pat_ident_binding_mode(span, pinned_ident, hir::BindingAnnotation::Mutable);
563595

564-
// ::std::future::poll_with_tls_context(unsafe {
565-
// ::std::pin::Pin::new_unchecked(&mut pinned)
566-
// })`
596+
let task_context_ident = Ident::with_dummy_span(sym::_task_context);
597+
598+
// unsafe {
599+
// ::std::future::poll_with_context(
600+
// ::std::pin::Pin::new_unchecked(&mut pinned),
601+
// task_context,
602+
// )
603+
// }
567604
let poll_expr = {
568605
let pinned = self.expr_ident(span, pinned_ident, pinned_pat_hid);
569606
let ref_mut_pinned = self.expr_mut_addr_of(span, pinned);
607+
let task_context = if let Some(task_context_hid) = self.task_context {
608+
self.expr_ident_mut(span, task_context_ident, task_context_hid)
609+
} else {
610+
// Use of `await` outside of an async context, we cannot use `task_context` here.
611+
self.expr_err(span)
612+
};
570613
let pin_ty_id = self.next_id();
571614
let new_unchecked_expr_kind = self.expr_call_std_assoc_fn(
572615
pin_ty_id,
@@ -575,14 +618,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
575618
"new_unchecked",
576619
arena_vec![self; ref_mut_pinned],
577620
);
578-
let new_unchecked =
579-
self.arena.alloc(self.expr(span, new_unchecked_expr_kind, ThinVec::new()));
580-
let unsafe_expr = self.expr_unsafe(new_unchecked);
581-
self.expr_call_std_path(
621+
let new_unchecked = self.expr(span, new_unchecked_expr_kind, ThinVec::new());
622+
let call = self.expr_call_std_path(
582623
gen_future_span,
583-
&[sym::future, sym::poll_with_tls_context],
584-
arena_vec![self; unsafe_expr],
585-
)
624+
&[sym::future, sym::poll_with_context],
625+
arena_vec![self; new_unchecked, task_context],
626+
);
627+
self.arena.alloc(self.expr_unsafe(call))
586628
};
587629

588630
// `::std::task::Poll::Ready(result) => break result`
@@ -629,12 +671,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
629671
hir::ExprKind::Yield(unit, hir::YieldSource::Await),
630672
ThinVec::new(),
631673
);
632-
self.stmt_expr(span, yield_expr)
674+
let yield_expr = self.arena.alloc(yield_expr);
675+
676+
if let Some(task_context_hid) = self.task_context {
677+
let lhs = self.expr_ident(span, task_context_ident, task_context_hid);
678+
let assign = self.expr(
679+
span,
680+
hir::ExprKind::Assign(lhs, yield_expr, span),
681+
AttrVec::new(),
682+
);
683+
self.stmt_expr(span, assign)
684+
} else {
685+
// Use of `await` outside of an async context. Return `yield_expr` so that we can
686+
// proceed with type checking.
687+
self.stmt(span, hir::StmtKind::Semi(yield_expr))
688+
}
633689
};
634690

635-
let loop_block = self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None);
691+
let loop_block =
692+
self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None);
636693

637-
// loop { .. }
694+
// loop { ...; task_context = yield (); }
638695
let loop_expr = self.arena.alloc(hir::Expr {
639696
hir_id: loop_hir_id,
640697
kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop),

src/librustc_ast_lowering/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
809809
}
810810

811811
/// Construct `ExprKind::Err` for the given `span`.
812-
fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> {
812+
crate fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> {
813813
self.expr(span, hir::ExprKind::Err, AttrVec::new())
814814
}
815815

src/librustc_ast_lowering/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ struct LoweringContext<'a, 'hir: 'a> {
117117

118118
generator_kind: Option<hir::GeneratorKind>,
119119

120+
/// When inside an `async` context, this is the `HirId` of the
121+
/// `task_context` local bound to the resume argument of the generator.
122+
task_context: Option<hir::HirId>,
123+
120124
/// Used to get the current `fn`'s def span to point to when using `await`
121125
/// outside of an `async fn`.
122126
current_item: Option<Span>,
@@ -295,6 +299,7 @@ pub fn lower_crate<'a, 'hir>(
295299
item_local_id_counters: Default::default(),
296300
node_id_to_hir_id: IndexVec::new(),
297301
generator_kind: None,
302+
task_context: None,
298303
current_item: None,
299304
lifetimes_to_define: Vec::new(),
300305
is_collecting_in_band_lifetimes: false,

src/librustc_span/symbol.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ symbols! {
544544
plugin_registrar,
545545
plugins,
546546
Poll,
547-
poll_with_tls_context,
547+
poll_with_context,
548548
powerpc_target_feature,
549549
precise_pointer_size_matching,
550550
pref_align_of,
@@ -720,6 +720,7 @@ symbols! {
720720
target_has_atomic_load_store,
721721
target_thread_local,
722722
task,
723+
_task_context,
723724
tbm_target_feature,
724725
termination_trait,
725726
termination_trait_test,

src/test/ui/async-await/issues/issue-62009-1.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:16:5: 16:15]: std:
3333
LL | (|_| 2333).await;
3434
| ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:16:5: 16:15]`
3535
|
36-
::: $SRC_DIR/libstd/future.rs:LL:COL
36+
::: $SRC_DIR/libcore/future/mod.rs:LL:COL
3737
|
3838
LL | F: Future,
39-
| ------ required by this bound in `std::future::poll_with_tls_context`
39+
| ------ required by this bound in `std::future::poll_with_context`
4040

4141
error: aborting due to 4 previous errors
4242

0 commit comments

Comments
 (0)