Skip to content

Commit 0620b2e

Browse files
Rollup merge of #96455 - dtolnay:writetmp, r=m-ou-se
Make write/print macros eagerly drop temporaries This PR fixes the 2 regressions in #96434 (`println` and `eprintln`) and changes all the other similar macros (`write`, `writeln`, `print`, `eprint`) to match the old pre-#94868 behavior of `println` and `eprintln`. argument position | before #94868 | after #94868 | after this PR --- |:---:|:---:|:---: `write!($tmp, "…", …)` | :rage: | :rage: | :smiley_cat: `write!(…, "…", $tmp)` | :rage: | :rage: | :smiley_cat: `writeln!($tmp, "…", …)` | :rage: | :rage: | :smiley_cat: `writeln!(…, "…", $tmp)` | :rage: | :rage: | :smiley_cat: `print!("…", $tmp)` | :rage: | :rage: | :smiley_cat: `println!("…", $tmp)` | :smiley_cat: | :rage: | :smiley_cat: `eprint!("…", $tmp)` | :rage: | :rage: | :smiley_cat: `eprintln!("…", $tmp)` | :smiley_cat: | :rage: | :smiley_cat: `panic!("…", $tmp)` | :smiley_cat: | :smiley_cat: | :smiley_cat: Example of code that is affected by this change: ```rust use std::sync::Mutex; fn main() { let mutex = Mutex::new(0); print!("{}", mutex.lock().unwrap()) /* no semicolon */ } ``` You can see several real-world examples like this in the Crater links at the top of #96434. This code failed to compile prior to this PR as follows, but works after this PR. ```console error[E0597]: `mutex` does not live long enough --> src/main.rs:5:18 | 5 | print!("{}", mutex.lock().unwrap()) /* no semicolon */ | ^^^^^^^^^^^^--------- | | | borrowed value does not live long enough | a temporary with access to the borrow is created here ... 6 | } | - | | | `mutex` dropped here while still borrowed | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` ```
2 parents b36be12 + a03f15a commit 0620b2e

File tree

3 files changed

+84
-12
lines changed

3 files changed

+84
-12
lines changed

library/core/src/macros/mod.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -496,9 +496,10 @@ macro_rules! r#try {
496496
#[stable(feature = "rust1", since = "1.0.0")]
497497
#[cfg_attr(not(test), rustc_diagnostic_item = "write_macro")]
498498
macro_rules! write {
499-
($dst:expr, $($arg:tt)*) => {
500-
$dst.write_fmt($crate::format_args!($($arg)*))
501-
};
499+
($dst:expr, $($arg:tt)*) => {{
500+
let result = $dst.write_fmt($crate::format_args!($($arg)*));
501+
result
502+
}};
502503
}
503504

504505
/// Write formatted data into a buffer, with a newline appended.
@@ -553,9 +554,10 @@ macro_rules! writeln {
553554
($dst:expr $(,)?) => {
554555
$crate::write!($dst, "\n")
555556
};
556-
($dst:expr, $($arg:tt)*) => {
557-
$dst.write_fmt($crate::format_args_nl!($($arg)*))
558-
};
557+
($dst:expr, $($arg:tt)*) => {{
558+
let result = $dst.write_fmt($crate::format_args_nl!($($arg)*));
559+
result
560+
}};
559561
}
560562

561563
/// Indicates unreachable code.

library/std/src/macros.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ macro_rules! panic {
6262
#[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")]
6363
#[allow_internal_unstable(print_internals)]
6464
macro_rules! print {
65-
($($arg:tt)*) => {
66-
$crate::io::_print($crate::format_args!($($arg)*))
67-
};
65+
($($arg:tt)*) => {{
66+
$crate::io::_print($crate::format_args!($($arg)*));
67+
}};
6868
}
6969

7070
/// Prints to the standard output, with a newline.
@@ -133,9 +133,9 @@ macro_rules! println {
133133
#[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")]
134134
#[allow_internal_unstable(print_internals)]
135135
macro_rules! eprint {
136-
($($arg:tt)*) => {
137-
$crate::io::_eprint($crate::format_args!($($arg)*))
138-
};
136+
($($arg:tt)*) => {{
137+
$crate::io::_eprint($crate::format_args!($($arg)*));
138+
}};
139139
}
140140

141141
/// Prints to the standard error, with a newline.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// check-pass
2+
3+
use std::fmt::{self, Display};
4+
5+
struct Mutex;
6+
7+
impl Mutex {
8+
fn lock(&self) -> MutexGuard {
9+
MutexGuard(self)
10+
}
11+
}
12+
13+
struct MutexGuard<'a>(&'a Mutex);
14+
15+
impl<'a> Drop for MutexGuard<'a> {
16+
fn drop(&mut self) {
17+
// Empty but this is a necessary part of the repro. Otherwise borrow
18+
// checker is fine with 'a dangling at the time that MutexGuard goes out
19+
// of scope.
20+
}
21+
}
22+
23+
impl<'a> MutexGuard<'a> {
24+
fn write_fmt(&self, _args: fmt::Arguments) {}
25+
}
26+
27+
impl<'a> Display for MutexGuard<'a> {
28+
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
29+
Ok(())
30+
}
31+
}
32+
33+
fn main() {
34+
let _write = {
35+
let out = Mutex;
36+
let mutex = Mutex;
37+
write!(out.lock(), "{}", mutex.lock()) /* no semicolon */
38+
};
39+
40+
let _writeln = {
41+
let out = Mutex;
42+
let mutex = Mutex;
43+
writeln!(out.lock(), "{}", mutex.lock()) /* no semicolon */
44+
};
45+
46+
let _print = {
47+
let mutex = Mutex;
48+
print!("{}", mutex.lock()) /* no semicolon */
49+
};
50+
51+
let _println = {
52+
let mutex = Mutex;
53+
println!("{}", mutex.lock()) /* no semicolon */
54+
};
55+
56+
let _eprint = {
57+
let mutex = Mutex;
58+
eprint!("{}", mutex.lock()) /* no semicolon */
59+
};
60+
61+
let _eprintln = {
62+
let mutex = Mutex;
63+
eprintln!("{}", mutex.lock()) /* no semicolon */
64+
};
65+
66+
let _panic = {
67+
let mutex = Mutex;
68+
panic!("{}", mutex.lock()) /* no semicolon */
69+
};
70+
}

0 commit comments

Comments
 (0)