From cb0ed1bdaed082205c7da4375b78a112a0872ddf Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jul 2022 11:06:54 -0700 Subject: [PATCH 1/4] Add regression test minimized from async-std write --- .../macros/format-args-temporaries-async.rs | 40 +++++++++++++++++++ .../format-args-temporaries-async.stderr | 27 +++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/test/ui/macros/format-args-temporaries-async.rs create mode 100644 src/test/ui/macros/format-args-temporaries-async.stderr diff --git a/src/test/ui/macros/format-args-temporaries-async.rs b/src/test/ui/macros/format-args-temporaries-async.rs new file mode 100644 index 0000000000000..fc2e5e2190f33 --- /dev/null +++ b/src/test/ui/macros/format-args-temporaries-async.rs @@ -0,0 +1,40 @@ +// FIXME: check-pass +// check-fail +// edition:2021 + +use std::fmt::{self, Display}; +use std::future::Future; +use std::io; +use std::pin::Pin; +use std::task::{Context, Poll}; + +struct AsyncStdout; + +impl AsyncStdout { + fn write_fmt<'a>(&'a mut self, _args: fmt::Arguments) -> WriteFmtFuture<'a, Self> + where + Self: Unpin, + { + WriteFmtFuture(self) + } +} + +struct WriteFmtFuture<'a, T>(&'a mut T); + +impl<'a, T> Future for WriteFmtFuture<'a, T> { + type Output = io::Result<()>; + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + unimplemented!() + } +} + +async fn async_main() { + let _write = write!(&mut AsyncStdout, "...").await; + //~^ ERROR temporary value dropped while borrowed + let _writeln = writeln!(&mut AsyncStdout, "...").await; + //~^ ERROR temporary value dropped while borrowed +} + +fn main() { + let _ = async_main; +} diff --git a/src/test/ui/macros/format-args-temporaries-async.stderr b/src/test/ui/macros/format-args-temporaries-async.stderr new file mode 100644 index 0000000000000..73019d7eb6e49 --- /dev/null +++ b/src/test/ui/macros/format-args-temporaries-async.stderr @@ -0,0 +1,27 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/format-args-temporaries-async.rs:32:30 + | +LL | let _write = write!(&mut AsyncStdout, "...").await; + | ------------^^^^^^^^^^^-------- + | | | + | | creates a temporary which is freed while still in use + | temporary value is freed at the end of this statement + | borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error[E0716]: temporary value dropped while borrowed + --> $DIR/format-args-temporaries-async.rs:34:34 + | +LL | let _writeln = writeln!(&mut AsyncStdout, "...").await; + | --------------^^^^^^^^^^^-------- + | | | + | | creates a temporary which is freed while still in use + | temporary value is freed at the end of this statement + | borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. From f1ca69d2453710587804b830182f3de76d9a9e70 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jul 2022 10:44:00 -0700 Subject: [PATCH 2/4] Revert write! and writeln! to late drop temporaries --- library/core/src/macros/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index bd62bc5c3056c..3a115a8b8b6c6 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -496,10 +496,9 @@ macro_rules! r#try { #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "write_macro")] macro_rules! write { - ($dst:expr, $($arg:tt)*) => {{ - let result = $dst.write_fmt($crate::format_args!($($arg)*)); - result - }}; + ($dst:expr, $($arg:tt)*) => { + $dst.write_fmt($crate::format_args!($($arg)*)) + }; } /// Write formatted data into a buffer, with a newline appended. @@ -554,10 +553,9 @@ macro_rules! writeln { ($dst:expr $(,)?) => { $crate::write!($dst, "\n") }; - ($dst:expr, $($arg:tt)*) => {{ - let result = $dst.write_fmt($crate::format_args_nl!($($arg)*)); - result - }}; + ($dst:expr, $($arg:tt)*) => { + $dst.write_fmt($crate::format_args_nl!($($arg)*)) + }; } /// Indicates unreachable code. From 4d65048d4105da9b841c4d79aecdddf11bfc925e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jul 2022 11:16:00 -0700 Subject: [PATCH 3/4] Regression in issue 99684 fixed --- .../macros/format-args-temporaries-async.rs | 5 +--- .../format-args-temporaries-async.stderr | 27 ------------------- 2 files changed, 1 insertion(+), 31 deletions(-) delete mode 100644 src/test/ui/macros/format-args-temporaries-async.stderr diff --git a/src/test/ui/macros/format-args-temporaries-async.rs b/src/test/ui/macros/format-args-temporaries-async.rs index fc2e5e2190f33..d959329b9fce2 100644 --- a/src/test/ui/macros/format-args-temporaries-async.rs +++ b/src/test/ui/macros/format-args-temporaries-async.rs @@ -1,5 +1,4 @@ -// FIXME: check-pass -// check-fail +// check-pass // edition:2021 use std::fmt::{self, Display}; @@ -30,9 +29,7 @@ impl<'a, T> Future for WriteFmtFuture<'a, T> { async fn async_main() { let _write = write!(&mut AsyncStdout, "...").await; - //~^ ERROR temporary value dropped while borrowed let _writeln = writeln!(&mut AsyncStdout, "...").await; - //~^ ERROR temporary value dropped while borrowed } fn main() { diff --git a/src/test/ui/macros/format-args-temporaries-async.stderr b/src/test/ui/macros/format-args-temporaries-async.stderr deleted file mode 100644 index 73019d7eb6e49..0000000000000 --- a/src/test/ui/macros/format-args-temporaries-async.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/format-args-temporaries-async.rs:32:30 - | -LL | let _write = write!(&mut AsyncStdout, "...").await; - | ------------^^^^^^^^^^^-------- - | | | - | | creates a temporary which is freed while still in use - | temporary value is freed at the end of this statement - | borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error[E0716]: temporary value dropped while borrowed - --> $DIR/format-args-temporaries-async.rs:34:34 - | -LL | let _writeln = writeln!(&mut AsyncStdout, "...").await; - | --------------^^^^^^^^^^^-------- - | | | - | | creates a temporary which is freed while still in use - | temporary value is freed at the end of this statement - | borrow later used here - | - = note: consider using a `let` binding to create a longer lived value - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0716`. From ffab6bf10ffcb4b76042c96e339513fdba4c6009 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jul 2022 11:01:01 -0700 Subject: [PATCH 4/4] Move write! and writeln! temporaries test to check-fail --- .../format-args-temporaries-in-write.rs | 50 +++++++++++++++++++ .../format-args-temporaries-in-write.stderr | 43 ++++++++++++++++ src/test/ui/macros/format-args-temporaries.rs | 16 ------ 3 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/macros/format-args-temporaries-in-write.rs create mode 100644 src/test/ui/macros/format-args-temporaries-in-write.stderr diff --git a/src/test/ui/macros/format-args-temporaries-in-write.rs b/src/test/ui/macros/format-args-temporaries-in-write.rs new file mode 100644 index 0000000000000..339ccbc33ac98 --- /dev/null +++ b/src/test/ui/macros/format-args-temporaries-in-write.rs @@ -0,0 +1,50 @@ +// check-fail + +use std::fmt::{self, Display}; + +struct Mutex; + +impl Mutex { + fn lock(&self) -> MutexGuard { + MutexGuard(self) + } +} + +struct MutexGuard<'a>(&'a Mutex); + +impl<'a> Drop for MutexGuard<'a> { + fn drop(&mut self) { + // Empty but this is a necessary part of the repro. Otherwise borrow + // checker is fine with 'a dangling at the time that MutexGuard goes out + // of scope. + } +} + +struct Out; + +impl Out { + fn write_fmt(&self, _args: fmt::Arguments) {} +} + +impl<'a> Display for MutexGuard<'a> { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +fn main() { + // FIXME(dtolnay): We actually want both of these to work. I think it's + // sadly unimplementable today though. + + let _write = { + let mutex = Mutex; + write!(Out, "{}", mutex.lock()) /* no semicolon */ + //~^ ERROR `mutex` does not live long enough + }; + + let _writeln = { + let mutex = Mutex; + writeln!(Out, "{}", mutex.lock()) /* no semicolon */ + //~^ ERROR `mutex` does not live long enough + }; +} diff --git a/src/test/ui/macros/format-args-temporaries-in-write.stderr b/src/test/ui/macros/format-args-temporaries-in-write.stderr new file mode 100644 index 0000000000000..03ecc4b4418c6 --- /dev/null +++ b/src/test/ui/macros/format-args-temporaries-in-write.stderr @@ -0,0 +1,43 @@ +error[E0597]: `mutex` does not live long enough + --> $DIR/format-args-temporaries-in-write.rs:41:27 + | +LL | write!(Out, "{}", mutex.lock()) /* no semicolon */ + | ^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +LL | +LL | }; + | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` + | | + | `mutex` dropped here while still borrowed + | +help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | +LL | $dst.write_fmt($crate::format_args!($($arg)*)); + | + + +error[E0597]: `mutex` does not live long enough + --> $DIR/format-args-temporaries-in-write.rs:47:29 + | +LL | writeln!(Out, "{}", mutex.lock()) /* no semicolon */ + | ^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +LL | +LL | }; + | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` + | | + | `mutex` dropped here while still borrowed + | +help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | +LL | $dst.write_fmt($crate::format_args_nl!($($arg)*)); + | + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/macros/format-args-temporaries.rs b/src/test/ui/macros/format-args-temporaries.rs index ddd4c9754bfa4..59323828bc37f 100644 --- a/src/test/ui/macros/format-args-temporaries.rs +++ b/src/test/ui/macros/format-args-temporaries.rs @@ -20,10 +20,6 @@ impl<'a> Drop for MutexGuard<'a> { } } -impl<'a> MutexGuard<'a> { - fn write_fmt(&self, _args: fmt::Arguments) {} -} - impl<'a> Display for MutexGuard<'a> { fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { Ok(()) @@ -31,18 +27,6 @@ impl<'a> Display for MutexGuard<'a> { } fn main() { - let _write = { - let out = Mutex; - let mutex = Mutex; - write!(out.lock(), "{}", mutex.lock()) /* no semicolon */ - }; - - let _writeln = { - let out = Mutex; - let mutex = Mutex; - writeln!(out.lock(), "{}", mutex.lock()) /* no semicolon */ - }; - let _print = { let mutex = Mutex; print!("{}", mutex.lock()) /* no semicolon */