From 06e4ff4d61f44d7e239e02256829ecf1e5598657 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Fri, 27 Sep 2019 17:15:17 -0400 Subject: [PATCH 1/3] Scope format! temporaries 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/rust#64477 for details. --- src/liballoc/macros.rs | 5 ++++- src/test/ui/fmt/issue-64477.rs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/fmt/issue-64477.rs diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs index 2f2cdc39c633d..422d3486f92b2 100644 --- a/src/liballoc/macros.rs +++ b/src/liballoc/macros.rs @@ -98,5 +98,8 @@ macro_rules! vec { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! format { - ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) + ($($arg:tt)*) => {{ + let res = $crate::fmt::format($crate::__export::format_args!($($arg)*)); + res + }} } diff --git a/src/test/ui/fmt/issue-64477.rs b/src/test/ui/fmt/issue-64477.rs new file mode 100644 index 0000000000000..b7c8cf17c3148 --- /dev/null +++ b/src/test/ui/fmt/issue-64477.rs @@ -0,0 +1,16 @@ +// In the past, the code generated by `format!` produced temporaries in the surrounding scope that +// borrowed the arguments through `&dyn Trait`. These temporaries do not implement `Send`, which +// meant that when `format!` was used in an async block, the resulting generator was not `Send`. +// See https://github.com/rust-lang/rust/issues/64477#issuecomment-534669068 for details +// and https://github.com/rust-lang/rust/issues/64477#issuecomment-531882958 for an example. +async fn foo(_: String) {} + +fn bar() -> impl Send { + async move { + foo(format!("{}:{}", 1, 2)).await; + } +} + +fn main() { + let _ = bar(); +} From 4d34ce2c2515a429bea325b93aea332ac8d6a7b9 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Fri, 27 Sep 2019 23:19:37 -0400 Subject: [PATCH 2/3] Place test with async-await and use 2018 edition --- .../issue-64477.rs => async-await/issues/issue-64477-2.rs} | 6 ++++++ 1 file changed, 6 insertions(+) rename src/test/ui/{fmt/issue-64477.rs => async-await/issues/issue-64477-2.rs} (89%) diff --git a/src/test/ui/fmt/issue-64477.rs b/src/test/ui/async-await/issues/issue-64477-2.rs similarity index 89% rename from src/test/ui/fmt/issue-64477.rs rename to src/test/ui/async-await/issues/issue-64477-2.rs index b7c8cf17c3148..2360b57cc4544 100644 --- a/src/test/ui/fmt/issue-64477.rs +++ b/src/test/ui/async-await/issues/issue-64477-2.rs @@ -1,8 +1,14 @@ +// Another regression test for #64477. +// // In the past, the code generated by `format!` produced temporaries in the surrounding scope that // borrowed the arguments through `&dyn Trait`. These temporaries do not implement `Send`, which // meant that when `format!` was used in an async block, the resulting generator was not `Send`. // See https://github.com/rust-lang/rust/issues/64477#issuecomment-534669068 for details // and https://github.com/rust-lang/rust/issues/64477#issuecomment-531882958 for an example. +// +// check-pass +// edition:2018 + async fn foo(_: String) {} fn bar() -> impl Send { From 8990f7d627525db934831cc29d5805172d80e156 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Sat, 28 Sep 2019 09:55:22 -0400 Subject: [PATCH 3/3] Update pretty-print test with new format! impl --- src/test/pretty/issue-4264.pp | 56 +++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 4cf2e90e635fd..0f71dbe486b97 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -29,33 +29,37 @@ - ((::alloc::fmt::format as - for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::core::fmt::Arguments>::new_v1 - as - fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments::<'_>::new_v1})((&([("test" - as - &'static str)] - as - [&str; 1]) - as - &[&str; 1]), - (&(match (() + ({ + let res = + ((::alloc::fmt::format as + for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::core::fmt::Arguments>::new_v1 + as + fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments::<'_>::new_v1})((&([("test" + as + &'static str)] + as + [&str; 1]) as - ()) - { - () - => - ([] - as - [std::fmt::ArgumentV1<'_>; 0]), - } - as - [std::fmt::ArgumentV1<'_>; 0]) - as - &[std::fmt::ArgumentV1<'_>; 0])) - as - std::fmt::Arguments<'_>)) - as std::string::String); + &[&str; 1]), + (&(match (() + as + ()) + { + () + => + ([] + as + [std::fmt::ArgumentV1<'_>; 0]), + } + as + [std::fmt::ArgumentV1<'_>; 0]) + as + &[std::fmt::ArgumentV1<'_>; 0])) + as + std::fmt::Arguments<'_>)) + as std::string::String); + (res as std::string::String) + } as std::string::String); } as ()) pub type Foo = [i32; (3 as usize)]; pub struct Bar {