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 00000000000..339ccbc33ac --- /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 00000000000..03ecc4b4418 --- /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 ddd4c9754bf..59323828bc3 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 */