-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Scope format! temporaries #64856
Scope format! temporaries #64856
Conversation
r? @sfackler (rust_highfive has picked a reviewer for you, use r? to override) |
See in particular @nikomatsakis' description of the problem in #64477 (comment) and @Nemo157's proposed solution in #64477 (comment) (which this PR implements). |
This places the temporaries that `format!` generates to refer to its arguments (through `&dyn Trait`) in a short-lived scope surrounding just the invocation of `format!`. This enables `format!` to be used in generators without the temporaries preventing the generator from being `Send` (due to `dyn Trait` not being `Sync`). See rust-lang#64477 for details.
6ab3f04
to
06e4ff4
Compare
This is a breaking change (that may only be noticed in the dynamic semantics rather than the static semantics). By inserting the |
That is true — I hadn't considered that. I wonder if there's an easy way for us to just cause the created |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@Centril thinking some more about this, I don't think there's a way to get out of changing the drop order except by making macro_rules! format {
($($arg:tt)*) => ((|| {$crate::fmt::format($crate::__export::format_args!($($arg)*))})())
} But the closure tries to move arguments passed to In #64477 (comment), @nikomatsakis said:
I'm not sure how we could go about doing that without adding additional bounds on types passed to Ultimately, my guess at the moment is that we will either have to change drop order, have |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@craterbot run mode=build-and-test (Changes dynamic semantics possibly.) |
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
Rustup Rustups: - rust-lang/rust#66671 (Ast address-of) - rust-lang/rust#64856 (Scope format! temporaries) changelog: none
Rustup to rustc 1.41.0-nightly (e87a205 2019-11-27) Rustups: - rust-lang/rust#66671 (Ast address-of) - rust-lang/rust#64856 (Scope format! temporaries) - http://github.com/rust-lang/rust/pull/66719 changelog: none
Rustup to rustc 1.41.0-nightly (e87a205 2019-11-27) Rustups: - rust-lang/rust#66671 (Ast address-of) - rust-lang/rust#64856 (Scope format! temporaries) - http://github.com/rust-lang/rust/pull/66719 changelog: none
Raise the nightly version to one that accepts '...(format!(...)).await'. This additionally reverts commit bdbf80f.
Raise the nightly version to one that accepts '...(format!(...)).await'. This additionally reverts commit bdbf80f.
Do this mean we can use format! inside multi-threaded futures? |
You can already use format in multi-threaded features. You just can't put it in an expression with an |
It is just that... this does not seem to work. /*
[dependencies]
tokio = { version = "0.2.6", features = ["io-util", "io-std", "macros"] }
*/
use std::{fmt, future::Future, pin::Pin};
use tokio::io::{self, AsyncWriteExt};
pub trait AsyncWriteFmt {
fn write_fmt<'this, 'args, 'async_trait>(
&'this mut self,
args: fmt::Arguments<'args>,
) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'async_trait>>
where
'this: 'async_trait,
Self: Sync + 'async_trait;
}
impl AsyncWriteFmt for io::Stdout {
fn write_fmt<'this, 'args, 'async_trait>(
&'this mut self,
args: fmt::Arguments<'args>,
) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'async_trait>>
where
'this: 'async_trait,
Self: Sync + 'async_trait,
{
let string = format!("{}", args);
drop(args);
Box::pin(async move { self.write_all(string.as_bytes()).await })
}
}
async fn write_hello() {
write!(io::stdout(), "Hello, World!\n").await.unwrap()
}
fn main() {
tokio::spawn(write_hello());
}
error: future cannot be sent between threads safely
--> src/main.rs:48:5
|
48 | tokio::spawn(write_hello());
| ^^^^^^^^^^^^ future returned by `write_hello` is not `Send`
|
::: /home/bruno/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.6/src/task/spawn.rs:123:21
|
123 | T: Future + Send + 'static,
| ---- required by this bound in `tokio::task::spawn::spawn`
|
= help: within `core::fmt::Void`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`
note: future is not `Send` as this value is used across an await
--> src/main.rs:44:5
|
44 | write!(io::stdout(), "Hello, World!\n").await.unwrap()
| ---------------------------------------^^^^^^
| |
| await occurs here, with `$ crate :: format_args ! ($ ($ arg) *)` maybe used later
| has type `[std::fmt::ArgumentV1<'_>; 0]`
45 | }
| - `$ crate :: format_args ! ($ ($ arg) *)` is later dropped here
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) EDIT: this will deliberately panic, but the code is just to show compile time issues. |
That error is coming from |
Well, this seems to work, weirdly. /*
[dependencies]
tokio = { version = "0.2.6", features = ["io-util", "io-std", "macros"] }
async-trait = "0.1.21"
*/
use async_trait::async_trait;
use std::{fmt, future::Future, pin::Pin};
use tokio::io::{self, AsyncWriteExt};
pub trait AsyncWriteFmt {
fn write_fmt<'this, 'args, 'async_trait>(
&'this mut self,
args: fmt::Arguments<'args>,
) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'async_trait>>
where
'this: 'async_trait,
Self: Sync + 'async_trait;
}
impl AsyncWriteFmt for io::Stdout {
fn write_fmt<'this, 'args, 'async_trait>(
&'this mut self,
args: fmt::Arguments<'args>,
) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'async_trait>>
where
'this: 'async_trait,
Self: Sync + 'async_trait,
{
let string = format!("{}", args);
drop(args);
Box::pin(async move { self.write_all(string.as_bytes()).await })
}
}
async fn write_hello() {
let mut stdout = io::stdout();
let future = write!(stdout, "Hello, World!\n");
future.await.unwrap()
}
fn main() {
tokio::spawn(write_hello());
} |
Raise the nightly version to one that accepts '...(format!(...)).await'. This additionally reverts commit bdbf80f.
Raise the nightly version to one that accepts '...(format!(...)).await'. This additionally reverts commit bdbf80f.
Raise the nightly version to one that accepts '...(format!(...)).await'. This additionally reverts commit bdbf80f.
Raise the nightly version to one that accepts '...(format!(...)).await'. This additionally reverts commit bdbf80f.
Raise the nightly version to one that accepts '...(format!(...)).await'. This additionally reverts commit bdbf80f.
Raise the nightly version to one that accepts '...(format!(...)).await'. This additionally reverts commit bdbf80f.
This version includes a critical fix for `format!()` calls in async fn: rust-lang/rust#64856
This version includes a critical fix for `format!()` calls in async fn: rust-lang/rust#64856
This version includes a critical fix for `format!()` calls in async fn: rust-lang/rust#64856
This version includes a critical fix for `format!()` calls in async fn: rust-lang/rust#64856
This version includes a critical fix for `format!()` calls in async fn: rust-lang/rust#64856
This places the temporaries that
format!
generates to refer to its arguments (through&dyn Trait
) in a short-lived scope surrounding just the invocation offormat!
. This enablesformat!
to be used in generators without the temporaries preventing the generator from beingSend
(due todyn Trait
not beingSync
).See #64477 for details.