Skip to content

Commit cf031a3

Browse files
committed
Replace usage of ResumeTy in async lowering with Context
Replaces using `ResumeTy` / `get_context` in favor of using `&'static mut Context<'_>`. Usage of the `'static` lifetime here is technically "cheating", and replaces the raw pointer in `ResumeTy` and the `get_context` fn that pulls the correct lifetimes out of thin air.
1 parent ed61c13 commit cf031a3

14 files changed

+70
-43
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+36-21
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_hir::def::Res;
1616
use rustc_hir::definitions::DefPathData;
1717
use rustc_session::errors::report_lit_error;
1818
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
19-
use rustc_span::symbol::{sym, Ident};
19+
use rustc_span::symbol::{kw, sym, Ident};
2020
use rustc_span::DUMMY_SP;
2121
use thin_vec::thin_vec;
2222

@@ -594,14 +594,38 @@ impl<'hir> LoweringContext<'_, 'hir> {
594594
) -> hir::ExprKind<'hir> {
595595
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
596596

597-
// Resume argument type: `ResumeTy`
598-
let unstable_span =
599-
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
600-
let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span, None);
597+
// Resume argument type, which should be `&mut Context<'_>`.
598+
// NOTE: Using the `'static` lifetime here is technically cheating.
599+
// The `Future::poll` argument really is `&'a mut Context<'b>`, but we cannot
600+
// express the fact that we are not storing it across yield-points yet,
601+
// and we would thus run into lifetime errors.
602+
// See <https://github.com/rust-lang/rust/issues/68923>.
603+
// Our lowering makes sure we are not mis-using the `_task_context` input type
604+
// in the sense that we are indeed not using it across yield points. We
605+
// get a fresh `&mut Context` for each resume / call of `Future::poll`.
606+
// This "cheating" was previously done with a `ResumeTy` that contained a raw
607+
// pointer, and a `get_context` accessor that pulled the `Context` lifetimes
608+
// out of thin air.
609+
let context_lifetime_ident = Ident::with_dummy_span(kw::StaticLifetime);
610+
let context_lifetime = self.arena.alloc(hir::Lifetime {
611+
hir_id: self.next_id(),
612+
ident: context_lifetime_ident,
613+
res: hir::LifetimeName::Static,
614+
});
615+
let context_path =
616+
hir::QPath::LangItem(hir::LangItem::Context, self.lower_span(span), None);
617+
let context_ty = hir::MutTy {
618+
ty: self.arena.alloc(hir::Ty {
619+
hir_id: self.next_id(),
620+
kind: hir::TyKind::Path(context_path),
621+
span: self.lower_span(span),
622+
}),
623+
mutbl: hir::Mutability::Mut,
624+
};
601625
let input_ty = hir::Ty {
602626
hir_id: self.next_id(),
603-
kind: hir::TyKind::Path(resume_ty),
604-
span: unstable_span,
627+
kind: hir::TyKind::Rptr(context_lifetime, context_ty),
628+
span: self.lower_span(span),
605629
};
606630

607631
// The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
@@ -659,12 +683,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
659683
.map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)));
660684

661685
let hir_id = self.lower_node_id(closure_node_id);
686+
let unstable_span =
687+
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
662688
if track_caller {
663-
let unstable_span = self.mark_span_with_reason(
664-
DesugaringKind::Async,
665-
span,
666-
self.allow_gen_future.clone(),
667-
);
668689
self.lower_attrs(
669690
hir_id,
670691
&[Attribute {
@@ -711,7 +732,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
711732
/// mut __awaitee => loop {
712733
/// match unsafe { ::std::future::Future::poll(
713734
/// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
714-
/// ::std::future::get_context(task_context),
735+
/// task_context,
715736
/// ) } {
716737
/// ::std::task::Poll::Ready(result) => break result,
717738
/// ::std::task::Poll::Pending => {}
@@ -752,7 +773,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
752773
// unsafe {
753774
// ::std::future::Future::poll(
754775
// ::std::pin::Pin::new_unchecked(&mut __awaitee),
755-
// ::std::future::get_context(task_context),
776+
// task_context,
756777
// )
757778
// }
758779
let poll_expr = {
@@ -770,16 +791,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
770791
arena_vec![self; ref_mut_awaitee],
771792
Some(expr_hir_id),
772793
);
773-
let get_context = self.expr_call_lang_item_fn_mut(
774-
gen_future_span,
775-
hir::LangItem::GetContext,
776-
arena_vec![self; task_context],
777-
Some(expr_hir_id),
778-
);
779794
let call = self.expr_call_lang_item_fn(
780795
span,
781796
hir::LangItem::FuturePoll,
782-
arena_vec![self; new_unchecked, get_context],
797+
arena_vec![self; new_unchecked, task_context],
783798
Some(expr_hir_id),
784799
);
785800
self.arena.alloc(self.expr_unsafe(call))

compiler/rustc_hir/src/lang_items.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,9 @@ language_item_table! {
286286

287287
// FIXME(swatinem): the following lang items are used for async lowering and
288288
// should become obsolete eventually.
289-
ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None;
290289
IdentityFuture, sym::identity_future, identity_future_fn, Target::Fn, GenericRequirement::None;
291-
GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;
292290

291+
Context, sym::Context, context, Target::Struct, GenericRequirement::None;
293292
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
294293

295294
FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;

compiler/rustc_span/src/symbol.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ symbols! {
165165
Capture,
166166
Center,
167167
Clone,
168+
Context,
168169
Continue,
169170
Copy,
170171
Count,
@@ -264,7 +265,6 @@ symbols! {
264265
Relaxed,
265266
Release,
266267
Result,
267-
ResumeTy,
268268
Return,
269269
Right,
270270
Rust,
@@ -754,7 +754,6 @@ symbols! {
754754
generic_associated_types_extended,
755755
generic_const_exprs,
756756
generic_param_attrs,
757-
get_context,
758757
global_allocator,
759758
global_asm,
760759
globs,

library/core/src/future/mod.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub use poll_fn::{poll_fn, PollFn};
4444
/// non-Send/Sync as well, and we don't want that.
4545
///
4646
/// It also simplifies the HIR lowering of `.await`.
47-
#[cfg_attr(not(bootstrap), lang = "ResumeTy")]
47+
// FIXME(swatinem): This type can be removed when bumping the bootstrap compiler
4848
#[doc(hidden)]
4949
#[unstable(feature = "gen_future", issue = "50547")]
5050
#[derive(Debug, Copy, Clone)]
@@ -61,6 +61,7 @@ unsafe impl Sync for ResumeTy {}
6161
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
6262
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
6363
// This is `const` to avoid extra errors after we recover from `const async fn`
64+
// FIXME(swatinem): This fn can be removed when bumping the bootstrap compiler
6465
#[cfg_attr(bootstrap, lang = "from_generator")]
6566
#[doc(hidden)]
6667
#[unstable(feature = "gen_future", issue = "50547")]
@@ -102,7 +103,8 @@ where
102103
GenFuture(gen)
103104
}
104105

105-
#[lang = "get_context"]
106+
// FIXME(swatinem): This fn can be removed when bumping the bootstrap compiler
107+
#[cfg_attr(bootstrap, lang = "get_context")]
106108
#[doc(hidden)]
107109
#[unstable(feature = "gen_future", issue = "50547")]
108110
#[must_use]
@@ -113,6 +115,10 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
113115
unsafe { &mut *cx.0.as_ptr().cast() }
114116
}
115117

118+
// FIXME(swatinem): This fn is currently needed to work around shortcomings
119+
// in type and lifetime inference.
120+
// See the comment at the bottom of `LoweringContext::make_async_expr` and
121+
// <https://github.com/rust-lang/rust/issues/104826>.
116122
#[cfg_attr(not(bootstrap), lang = "identity_future")]
117123
#[doc(hidden)]
118124
#[unstable(feature = "gen_future", issue = "50547")]

library/core/src/task/wake.rs

+1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ impl RawWakerVTable {
174174
/// Currently, `Context` only serves to provide access to a [`&Waker`](Waker)
175175
/// which can be used to wake the current task.
176176
#[stable(feature = "futures_api", since = "1.36.0")]
177+
#[cfg_attr(not(bootstrap), lang = "Context")]
177178
pub struct Context<'a> {
178179
waker: &'a Waker,
179180
// Ensure we future-proof against variance changes by forcing

src/test/ui/async-await/async-await-let-else.drop-tracking.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ LL | async fn bar2<T>(_: T) -> ! {
4040
LL | | panic!()
4141
LL | | }
4242
| |_^
43-
= note: required because it captures the following types: `ResumeTy`, `Option<bool>`, `impl Future<Output = !>`, `()`
43+
= note: required because it captures the following types: `&mut Context<'_>`, `Option<bool>`, `impl Future<Output = !>`, `()`
4444
note: required because it's used within this `async fn` body
4545
--> $DIR/async-await-let-else.rs:21:32
4646
|

src/test/ui/async-await/issue-68112.drop_tracking.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ note: required because it appears within the type `impl Future<Output = Arc<RefC
5757
|
5858
LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> {
5959
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
60-
= note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `Ready<i32>`
60+
= note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `Ready<i32>`
6161
note: required because it's used within this `async` block
6262
--> $DIR/issue-68112.rs:60:20
6363
|

src/test/ui/async-await/issue-68112.no_drop_tracking.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ note: required because it appears within the type `impl Future<Output = Arc<RefC
5757
|
5858
LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> {
5959
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
60-
= note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>`
60+
= note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>`
6161
note: required because it's used within this `async` block
6262
--> $DIR/issue-68112.rs:60:20
6363
|

src/test/ui/async-await/issue-69446-fnmut-capture.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ LL | | });
1414
|
1515
= note: `FnMut` closures only have access to their captured variables while they are executing...
1616
= note: ...therefore, they cannot allow references to captured variables to escape
17+
= note: requirement occurs because of a mutable reference to `Context<'_>`
18+
= note: mutable references are invariant over their type parameter
19+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
1720

1821
error: aborting due to previous error
1922

src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
1818
| ___________________________________________________________________^
1919
LL | | }
2020
| |_^
21-
= note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()`
21+
= note: required because it captures the following types: `&mut Context<'_>`, `impl Future<Output = ()>`, `()`
2222
note: required because it's used within this `async` block
2323
--> $DIR/issue-70935-complex-spans.rs:16:5
2424
|

src/test/ui/async-await/partial-drop-partial-reinit.drop_tracking.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ LL | async fn foo() {
1111
|
1212
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
1313
= note: required because it appears within the type `(NotSend,)`
14-
= note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `()`, `impl Future<Output = ()>`
14+
= note: required because it captures the following types: `&mut Context<'_>`, `(NotSend,)`, `()`, `impl Future<Output = ()>`
1515
note: required because it's used within this `async fn` body
1616
--> $DIR/partial-drop-partial-reinit.rs:31:16
1717
|

src/test/ui/async-await/partial-drop-partial-reinit.no_drop_tracking.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ LL | async fn foo() {
1111
|
1212
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
1313
= note: required because it appears within the type `(NotSend,)`
14-
= note: required because it captures the following types: `ResumeTy`, `(NotSend,)`, `impl Future<Output = ()>`, `()`
14+
= note: required because it captures the following types: `&mut Context<'_>`, `(NotSend,)`, `impl Future<Output = ()>`, `()`
1515
note: required because it's used within this `async fn` body
1616
--> $DIR/partial-drop-partial-reinit.rs:31:16
1717
|

src/test/ui/regions/closure-in-projection-issue-97405.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ fn good_generic_fn<T>() {
2222
// This should fail because `T` ends up in the upvars of the closure.
2323
fn bad_generic_fn<T: Copy>(t: T) {
2424
assert_static(opaque(async move { t; }).next());
25-
//~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough
25+
//~^ ERROR the parameter type `T` may not live long enough
2626
assert_static(opaque(move || { t; }).next());
2727
//~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough
2828
assert_static(opaque(opaque(async move { t; }).next()).next());
29-
//~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough
29+
//~^ ERROR the parameter type `T` may not live long enough
3030
}
3131

3232
fn main() {}

src/test/ui/regions/closure-in-projection-issue-97405.stderr

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
1+
error[E0310]: the parameter type `T` may not live long enough
22
--> $DIR/closure-in-projection-issue-97405.rs:24:5
33
|
44
LL | assert_static(opaque(async move { t; }).next());
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
66
|
7-
= help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
8-
= note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
7+
help: consider adding an explicit lifetime bound...
8+
|
9+
LL | fn bad_generic_fn<T: Copy + 'static>(t: T) {
10+
| +++++++++
911

1012
error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
1113
--> $DIR/closure-in-projection-issue-97405.rs:26:5
@@ -16,14 +18,16 @@ LL | assert_static(opaque(move || { t; }).next());
1618
= help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
1719
= note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
1820

19-
error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough
21+
error[E0310]: the parameter type `T` may not live long enough
2022
--> $DIR/closure-in-projection-issue-97405.rs:28:5
2123
|
2224
LL | assert_static(opaque(opaque(async move { t; }).next()).next());
23-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
2426
|
25-
= help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`...
26-
= note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds
27+
help: consider adding an explicit lifetime bound...
28+
|
29+
LL | fn bad_generic_fn<T: Copy + 'static>(t: T) {
30+
| +++++++++
2731

2832
error: aborting due to 3 previous errors
2933

0 commit comments

Comments
 (0)