From c6ac3b02dbd74a4116f7198c442f419fee3cacc5 Mon Sep 17 00:00:00 2001 From: Justin Karneges Date: Thu, 28 Mar 2024 09:55:07 -0700 Subject: [PATCH 1/4] Add `Context::ext` --- library/core/src/task/wake.rs | 55 +++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 1b43c46bda515..227276aa34943 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -2,6 +2,7 @@ use crate::mem::transmute; +use crate::any::Any; use crate::fmt; use crate::marker::PhantomData; use crate::ptr; @@ -220,6 +221,12 @@ impl RawWakerVTable { } } +#[derive(Debug)] +enum ExtData<'a> { + Some(&'a mut dyn Any), + None(()), +} + /// The context of an asynchronous task. /// /// Currently, `Context` only serves to provide access to a [`&Waker`](Waker) @@ -229,6 +236,7 @@ impl RawWakerVTable { pub struct Context<'a> { waker: &'a Waker, local_waker: &'a LocalWaker, + ext: ExtData<'a>, // Ensure we future-proof against variance changes by forcing // the lifetime to be invariant (argument-position lifetimes // are contravariant while return-position lifetimes are @@ -257,6 +265,7 @@ impl<'a> Context<'a> { pub const fn waker(&self) -> &'a Waker { &self.waker } + /// Returns a reference to the [`LocalWaker`] for the current task. #[inline] #[unstable(feature = "local_waker", issue = "118959")] @@ -264,6 +273,17 @@ impl<'a> Context<'a> { pub const fn local_waker(&self) -> &'a LocalWaker { &self.local_waker } + + /// Returns a reference to the extension data for the current task. + #[inline] + #[unstable(feature = "context_ext", issue = "none")] + #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + pub const fn ext(&mut self) -> &mut dyn Any { + match &mut self.ext { + ExtData::Some(data) => *data, + ExtData::None(unit) => unit, + } + } } #[stable(feature = "futures_api", since = "1.36.0")] @@ -300,6 +320,7 @@ impl fmt::Debug for Context<'_> { pub struct ContextBuilder<'a> { waker: &'a Waker, local_waker: &'a LocalWaker, + ext: ExtData<'a>, // Ensure we future-proof against variance changes by forcing // the lifetime to be invariant (argument-position lifetimes // are contravariant while return-position lifetimes are @@ -318,7 +339,27 @@ impl<'a> ContextBuilder<'a> { pub const fn from_waker(waker: &'a Waker) -> Self { // SAFETY: LocalWaker is just Waker without thread safety let local_waker = unsafe { transmute(waker) }; - Self { waker: waker, local_waker, _marker: PhantomData, _marker2: PhantomData } + Self { waker: waker, local_waker, ext: ExtData::None(()), _marker: PhantomData, _marker2: PhantomData } + } + + /// Create a ContextBuilder from an existing Context. + #[inline] + #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[unstable(feature = "context_ext", issue = "none")] + pub const fn from(cx: &'a mut Context<'_>) -> Self { + let ext = match &mut cx.ext { + ExtData::Some(ext) => ExtData::Some(*ext), + ExtData::None(()) => ExtData::None(()), + }; + Self { waker: cx.waker, local_waker: cx.local_waker, ext, _marker: PhantomData, _marker2: PhantomData } + } + + /// This method is used to set the value for the waker on `Context`. + #[inline] + #[unstable(feature = "context_ext", issue = "none")] + #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + pub const fn waker(self, waker: &'a Waker) -> Self { + Self { waker, ..self } } /// This method is used to set the value for the local waker on `Context`. @@ -329,13 +370,21 @@ impl<'a> ContextBuilder<'a> { Self { local_waker, ..self } } + /// This method is used to set the value for the extension data on `Context`. + #[inline] + #[unstable(feature = "context_ext", issue = "none")] + #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + pub const fn ext(self, data: &'a mut dyn Any) -> Self { + Self { ext: ExtData::Some(data), ..self } + } + /// Builds the `Context`. #[inline] #[unstable(feature = "local_waker", issue = "118959")] #[rustc_const_unstable(feature = "const_waker", issue = "102012")] pub const fn build(self) -> Context<'a> { - let ContextBuilder { waker, local_waker, _marker, _marker2 } = self; - Context { waker, local_waker, _marker, _marker2 } + let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self; + Context { waker, local_waker, ext, _marker, _marker2 } } } From 13838a53fd736526626993b842562322eec24c4e Mon Sep 17 00:00:00 2001 From: Justin Karneges Date: Fri, 29 Mar 2024 12:16:09 -0700 Subject: [PATCH 2/4] rustfmt --- library/core/src/task/wake.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 227276aa34943..98e2c2912ef6f 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -339,7 +339,13 @@ impl<'a> ContextBuilder<'a> { pub const fn from_waker(waker: &'a Waker) -> Self { // SAFETY: LocalWaker is just Waker without thread safety let local_waker = unsafe { transmute(waker) }; - Self { waker: waker, local_waker, ext: ExtData::None(()), _marker: PhantomData, _marker2: PhantomData } + Self { + waker: waker, + local_waker, + ext: ExtData::None(()), + _marker: PhantomData, + _marker2: PhantomData, + } } /// Create a ContextBuilder from an existing Context. @@ -351,7 +357,13 @@ impl<'a> ContextBuilder<'a> { ExtData::Some(ext) => ExtData::Some(*ext), ExtData::None(()) => ExtData::None(()), }; - Self { waker: cx.waker, local_waker: cx.local_waker, ext, _marker: PhantomData, _marker2: PhantomData } + Self { + waker: cx.waker, + local_waker: cx.local_waker, + ext, + _marker: PhantomData, + _marker2: PhantomData, + } } /// This method is used to set the value for the waker on `Context`. From 4f82731bba9bebf452e3ffae383ab5d57522562d Mon Sep 17 00:00:00 2001 From: Justin Karneges Date: Fri, 29 Mar 2024 14:27:13 -0700 Subject: [PATCH 3/4] update tests --- tests/ui/async-await/async-is-unwindsafe.rs | 1 + .../ui/async-await/async-is-unwindsafe.stderr | 43 ++++++++++++++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/tests/ui/async-await/async-is-unwindsafe.rs b/tests/ui/async-await/async-is-unwindsafe.rs index 53009b6e7410f..d0202f72f0086 100644 --- a/tests/ui/async-await/async-is-unwindsafe.rs +++ b/tests/ui/async-await/async-is-unwindsafe.rs @@ -11,6 +11,7 @@ fn main() { is_unwindsafe(async { //~^ ERROR the type `&mut Context<'_>` may not be safely transferred across an unwind boundary + //~| ERROR the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary use std::ptr::null; use std::task::{Context, RawWaker, RawWakerVTable, Waker}; let waker = unsafe { diff --git a/tests/ui/async-await/async-is-unwindsafe.stderr b/tests/ui/async-await/async-is-unwindsafe.stderr index 5d87fc747682a..6bb06df9f39e9 100644 --- a/tests/ui/async-await/async-is-unwindsafe.stderr +++ b/tests/ui/async-await/async-is-unwindsafe.stderr @@ -6,19 +6,18 @@ LL | is_unwindsafe(async { | |_____| | || LL | || +LL | || LL | || use std::ptr::null; -LL | || use std::task::{Context, RawWaker, RawWakerVTable, Waker}; ... || LL | || drop(cx_ref); LL | || }); | ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary | |_____| - | within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}` + | within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}` | - = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}: UnwindSafe` - = note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>` + = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}: UnwindSafe` note: future does not implement `UnwindSafe` as this value is used across an await - --> $DIR/async-is-unwindsafe.rs:25:18 + --> $DIR/async-is-unwindsafe.rs:26:18 | LL | let cx_ref = &mut cx; | ------ has type `&mut Context<'_>` which does not implement `UnwindSafe` @@ -31,6 +30,38 @@ note: required by a bound in `is_unwindsafe` LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {} | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe` -error: aborting due to 1 previous error +error[E0277]: the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary + --> $DIR/async-is-unwindsafe.rs:12:5 + | +LL | is_unwindsafe(async { + | _____^_____________- + | |_____| + | || +LL | || +LL | || +LL | || use std::ptr::null; +... || +LL | || drop(cx_ref); +LL | || }); + | ||_____-^ `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary + | |_____| + | within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}` + | + = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`, the trait `UnwindSafe` is not implemented for `&mut (dyn Any + 'static)`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}: UnwindSafe` +note: future does not implement `UnwindSafe` as this value is used across an await + --> $DIR/async-is-unwindsafe.rs:26:18 + | +LL | let mut cx = Context::from_waker(&waker); + | ------ has type `Context<'_>` which does not implement `UnwindSafe` +... +LL | async {}.await; // this needs an inner await point + | ^^^^^ await occurs here, with `mut cx` maybe used later +note: required by a bound in `is_unwindsafe` + --> $DIR/async-is-unwindsafe.rs:3:26 + | +LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {} + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. From 036085dfec3f58cf63f8014f6c94adddace3b527 Mon Sep 17 00:00:00 2001 From: Justin Karneges Date: Tue, 2 Apr 2024 15:45:53 -0700 Subject: [PATCH 4/4] set tracking issue --- library/core/src/task/wake.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 98e2c2912ef6f..fe39f6c0b5691 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -276,7 +276,7 @@ impl<'a> Context<'a> { /// Returns a reference to the extension data for the current task. #[inline] - #[unstable(feature = "context_ext", issue = "none")] + #[unstable(feature = "context_ext", issue = "123392")] #[rustc_const_unstable(feature = "const_waker", issue = "102012")] pub const fn ext(&mut self) -> &mut dyn Any { match &mut self.ext { @@ -351,7 +351,7 @@ impl<'a> ContextBuilder<'a> { /// Create a ContextBuilder from an existing Context. #[inline] #[rustc_const_unstable(feature = "const_waker", issue = "102012")] - #[unstable(feature = "context_ext", issue = "none")] + #[unstable(feature = "context_ext", issue = "123392")] pub const fn from(cx: &'a mut Context<'_>) -> Self { let ext = match &mut cx.ext { ExtData::Some(ext) => ExtData::Some(*ext), @@ -368,7 +368,7 @@ impl<'a> ContextBuilder<'a> { /// This method is used to set the value for the waker on `Context`. #[inline] - #[unstable(feature = "context_ext", issue = "none")] + #[unstable(feature = "context_ext", issue = "123392")] #[rustc_const_unstable(feature = "const_waker", issue = "102012")] pub const fn waker(self, waker: &'a Waker) -> Self { Self { waker, ..self } @@ -384,7 +384,7 @@ impl<'a> ContextBuilder<'a> { /// This method is used to set the value for the extension data on `Context`. #[inline] - #[unstable(feature = "context_ext", issue = "none")] + #[unstable(feature = "context_ext", issue = "123392")] #[rustc_const_unstable(feature = "const_waker", issue = "102012")] pub const fn ext(self, data: &'a mut dyn Any) -> Self { Self { ext: ExtData::Some(data), ..self }