Rollup merge of #125392 - workingjubilee:unwind-a-problem-in-context, r=Amanieu
Wrap Context.ext in AssertUnwindSafe Fixes https://github.com/rust-lang/rust/issues/125193 Alternative to https://github.com/rust-lang/rust/pull/125377 Relevant to https://github.com/rust-lang/rust/issues/123392 I believe this approach is justifiable due to the fact that this function is unstable API and we have been considering trying to dispose of the notion of "unwind safety". Making a more long-term decision should be considered carefully as part of stabilizing `fn ext`, if ever. r? `@Amanieu`
This commit is contained in:
commit
5126d4b87b
4 changed files with 27 additions and 42 deletions
|
@ -5,6 +5,7 @@ use crate::mem::transmute;
|
||||||
use crate::any::Any;
|
use crate::any::Any;
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::marker::PhantomData;
|
use crate::marker::PhantomData;
|
||||||
|
use crate::panic::AssertUnwindSafe;
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
|
|
||||||
/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
|
/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
|
||||||
|
@ -236,7 +237,7 @@ enum ExtData<'a> {
|
||||||
pub struct Context<'a> {
|
pub struct Context<'a> {
|
||||||
waker: &'a Waker,
|
waker: &'a Waker,
|
||||||
local_waker: &'a LocalWaker,
|
local_waker: &'a LocalWaker,
|
||||||
ext: ExtData<'a>,
|
ext: AssertUnwindSafe<ExtData<'a>>,
|
||||||
// Ensure we future-proof against variance changes by forcing
|
// Ensure we future-proof against variance changes by forcing
|
||||||
// the lifetime to be invariant (argument-position lifetimes
|
// the lifetime to be invariant (argument-position lifetimes
|
||||||
// are contravariant while return-position lifetimes are
|
// are contravariant while return-position lifetimes are
|
||||||
|
@ -279,7 +280,9 @@ impl<'a> Context<'a> {
|
||||||
#[unstable(feature = "context_ext", issue = "123392")]
|
#[unstable(feature = "context_ext", issue = "123392")]
|
||||||
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
pub const fn ext(&mut self) -> &mut dyn Any {
|
pub const fn ext(&mut self) -> &mut dyn Any {
|
||||||
match &mut self.ext {
|
// FIXME: this field makes Context extra-weird about unwind safety
|
||||||
|
// can we justify AssertUnwindSafe if we stabilize this? do we care?
|
||||||
|
match &mut *self.ext {
|
||||||
ExtData::Some(data) => *data,
|
ExtData::Some(data) => *data,
|
||||||
ExtData::None(unit) => unit,
|
ExtData::None(unit) => unit,
|
||||||
}
|
}
|
||||||
|
@ -353,7 +356,7 @@ impl<'a> ContextBuilder<'a> {
|
||||||
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
#[unstable(feature = "context_ext", issue = "123392")]
|
#[unstable(feature = "context_ext", issue = "123392")]
|
||||||
pub const fn from(cx: &'a mut Context<'_>) -> Self {
|
pub const fn from(cx: &'a mut Context<'_>) -> Self {
|
||||||
let ext = match &mut cx.ext {
|
let ext = match &mut *cx.ext {
|
||||||
ExtData::Some(ext) => ExtData::Some(*ext),
|
ExtData::Some(ext) => ExtData::Some(*ext),
|
||||||
ExtData::None(()) => ExtData::None(()),
|
ExtData::None(()) => ExtData::None(()),
|
||||||
};
|
};
|
||||||
|
@ -396,7 +399,7 @@ impl<'a> ContextBuilder<'a> {
|
||||||
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
pub const fn build(self) -> Context<'a> {
|
pub const fn build(self) -> Context<'a> {
|
||||||
let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
|
let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
|
||||||
Context { waker, local_waker, ext, _marker, _marker2 }
|
Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ fn main() {
|
||||||
|
|
||||||
is_unwindsafe(async {
|
is_unwindsafe(async {
|
||||||
//~^ ERROR the type `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
//~^ 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::ptr::null;
|
||||||
use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
||||||
let waker = unsafe {
|
let waker = unsafe {
|
||||||
|
|
|
@ -6,18 +6,19 @@ LL | is_unwindsafe(async {
|
||||||
| |_____|
|
| |_____|
|
||||||
| ||
|
| ||
|
||||||
LL | ||
|
LL | ||
|
||||||
LL | ||
|
|
||||||
LL | || use std::ptr::null;
|
LL | || use std::ptr::null;
|
||||||
|
LL | || use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
||||||
... ||
|
... ||
|
||||||
LL | || drop(cx_ref);
|
LL | || drop(cx_ref);
|
||||||
LL | || });
|
LL | || });
|
||||||
| ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
| ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
||||||
| |_____|
|
| |_____|
|
||||||
| within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`
|
| within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`
|
||||||
|
|
|
|
||||||
= 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`
|
= 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<'_>`
|
||||||
note: future does not implement `UnwindSafe` as this value is used across an await
|
note: future does not implement `UnwindSafe` as this value is used across an await
|
||||||
--> $DIR/async-is-unwindsafe.rs:26:18
|
--> $DIR/async-is-unwindsafe.rs:25:18
|
||||||
|
|
|
|
||||||
LL | let cx_ref = &mut cx;
|
LL | let cx_ref = &mut cx;
|
||||||
| ------ has type `&mut Context<'_>` which does not implement `UnwindSafe`
|
| ------ has type `&mut Context<'_>` which does not implement `UnwindSafe`
|
||||||
|
@ -30,38 +31,6 @@ note: required by a bound in `is_unwindsafe`
|
||||||
LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
|
LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
|
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
|
||||||
|
|
||||||
error[E0277]: the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
|
error: aborting due to 1 previous error
|
||||||
--> $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`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
14
tests/ui/async-await/context-is-sorta-unwindsafe.rs
Normal file
14
tests/ui/async-await/context-is-sorta-unwindsafe.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
//@ run-pass
|
||||||
|
// Tests against a regression surfaced by crater in https://github.com/rust-lang/rust/issues/125193
|
||||||
|
// Unwind Safety is not a very coherent concept, but we'd prefer no regressions until we kibosh it
|
||||||
|
// and this is an unstable feature anyways sooo...
|
||||||
|
|
||||||
|
use std::panic::UnwindSafe;
|
||||||
|
use std::task::Context;
|
||||||
|
|
||||||
|
fn unwind_safe<T: UnwindSafe>() {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unwind_safe::<Context<'_>>(); // test UnwindSafe
|
||||||
|
unwind_safe::<&Context<'_>>(); // test RefUnwindSafe
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue