Uh oh!
There was an error while loading. Please reload this page.
Scope format! temporaries - #64856
Conversation
rust-highfive
commented
Sep 27, 2019
r? @sfackler (rust_highfive has picked a reviewer for you, use r? to override) |
jonhoo
commented
Sep 27, 2019
See in particular @nikomatsakis' description of the problem in #64477 (comment) and @Nemo157's proposed solution in #64477 (comment) (which this PR implements). |
Uh oh!
There was an error while loading. Please reload this page.
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
06e4ff4CompareCentril
commented
Sep 27, 2019
This is a breaking change (that may only be noticed in the dynamic semantics rather than the static semantics). By inserting the |
jonhoo
commented
Sep 27, 2019
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.
jonhoo
commented
Sep 28, 2019
@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.
Centril
commented
Sep 28, 2019
@craterbot run mode=build-and-test (Changes dynamic semantics possibly.) |
craterbot
commented
Sep 28, 2019
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
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.
brunoczim
commented
Dec 23, 2019
Do this mean we can use format! inside multi-threaded futures? |
sfackler
commented
Dec 23, 2019
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};pubtraitAsyncWriteFmt{fnwrite_fmt<'this,'args,'async_trait>(&'thismutself,args: fmt::Arguments<'args>,) -> Pin<Box<dynFuture<Output = io::Result<()>> + Send + 'async_trait>>where'this:'async_trait,Self:Sync + 'async_trait;}implAsyncWriteFmtfor io::Stdout{fnwrite_fmt<'this,'args,'async_trait>(&'thismutself,args: fmt::Arguments<'args>,) -> Pin<Box<dynFuture<Output = io::Result<()>> + Send + 'async_trait>>where'this:'async_trait,Self:Sync + 'async_trait,{let string = format!("{}", args);drop(args);Box::pin(asyncmove{self.write_all(string.as_bytes()).await})}}asyncfnwrite_hello(){write!(io::stdout(),"Hello, World!\n").await.unwrap()}fnmain(){
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. |
sfackler
commented
Dec 23, 2019
That error is coming from |
brunoczim
commented
Dec 23, 2019
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};pubtraitAsyncWriteFmt{fnwrite_fmt<'this,'args,'async_trait>(&'thismutself,args: fmt::Arguments<'args>,) -> Pin<Box<dynFuture<Output = io::Result<()>> + Send + 'async_trait>>where'this:'async_trait,Self:Sync + 'async_trait;}implAsyncWriteFmtfor io::Stdout{fnwrite_fmt<'this,'args,'async_trait>(&'thismutself,args: fmt::Arguments<'args>,) -> Pin<Box<dynFuture<Output = io::Result<()>> + Send + 'async_trait>>where'this:'async_trait,Self:Sync + 'async_trait,{let string = format!("{}", args);drop(args);Box::pin(asyncmove{self.write_all(string.as_bytes()).await})}}asyncfnwrite_hello(){letmut stdout = io::stdout();let future = write!(stdout,"Hello, World!\n");
future.await.unwrap()}fnmain(){
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 Traitnot beingSync).See #64477 for details.