Skip to content

Commit

Permalink
Auto merge of rust-lang#111590 - dtolnay:panictemporaries, r=bjorn3
Browse files Browse the repository at this point in the history
Shorten even more panic temporary lifetimes

Followup to rust-lang#104134. As pointed out by `@bjorn3` in rust-lang#104134 (review), there are other cases in the panic macros which would also benefit from dropping their non-Send temporaries as soon as possible, avoiding pointlessly holding them across an await point.

For the tests added in this PR, here are the failures you get today on master without the macro changes in this PR:

<details>
<summary>tests/ui/macros/panic-temporaries-2018.rs</summary>

```console
error: future cannot be sent between threads safely
  --> tests/ui/macros/panic-temporaries-2018.rs:52:18
   |
LL |     require_send(panic_display());
   |                  ^^^^^^^^^^^^^^^ future returned by `panic_display` is not `Send`
   |
   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `*const u8`
note: future is not `Send` as this value is used across an await
  --> tests/ui/macros/panic-temporaries-2018.rs:35:31
   |
LL |     f(panic!("{}", NOT_SEND)).await;
   |                    --------   ^^^^^- `NOT_SEND` is later dropped here
   |                    |          |
   |                    |          await occurs here, with `NOT_SEND` maybe used later
   |                    has type `NotSend` which is not `Send`
note: required by a bound in `require_send`
  --> tests/ui/macros/panic-temporaries-2018.rs:48:25
   |
LL | fn require_send(_: impl Send) {}
   |                         ^^^^ required by this bound in `require_send`

error: future cannot be sent between threads safely
  --> tests/ui/macros/panic-temporaries-2018.rs:52:18
   |
LL |     require_send(panic_display());
   |                  ^^^^^^^^^^^^^^^ future returned by `panic_display` is not `Send`
   |
   = help: within `NotSend`, the trait `Sync` is not implemented for `*const u8`
note: future is not `Send` as this value is used across an await
  --> tests/ui/macros/panic-temporaries-2018.rs:35:31
   |
LL |     f(panic!("{}", NOT_SEND)).await;
   |       ----------------------  ^^^^^- the value is later dropped here
   |       |                       |
   |       |                       await occurs here, with the value maybe used later
   |       has type `&NotSend` which is not `Send`
note: required by a bound in `require_send`
  --> tests/ui/macros/panic-temporaries-2018.rs:48:25
   |
LL | fn require_send(_: impl Send) {}
   |                         ^^^^ required by this bound in `require_send`

error: future cannot be sent between threads safely
  --> tests/ui/macros/panic-temporaries-2018.rs:53:18
   |
LL |     require_send(panic_str());
   |                  ^^^^^^^^^^^ future returned by `panic_str` is not `Send`
   |
   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `*const u8`
note: future is not `Send` as this value is used across an await
  --> tests/ui/macros/panic-temporaries-2018.rs:40:36
   |
LL |     f(panic!((NOT_SEND, "...").1)).await;
   |               --------             ^^^^^- `NOT_SEND` is later dropped here
   |               |                    |
   |               |                    await occurs here, with `NOT_SEND` maybe used later
   |               has type `NotSend` which is not `Send`
note: required by a bound in `require_send`
  --> tests/ui/macros/panic-temporaries-2018.rs:48:25
   |
LL | fn require_send(_: impl Send) {}
   |                         ^^^^ required by this bound in `require_send`

error: future cannot be sent between threads safely
  --> tests/ui/macros/panic-temporaries-2018.rs:54:18
   |
LL |     require_send(unreachable_display());
   |                  ^^^^^^^^^^^^^^^^^^^^^ future returned by `unreachable_display` is not `Send`
   |
   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `*const u8`
note: future is not `Send` as this value is used across an await
  --> tests/ui/macros/panic-temporaries-2018.rs:45:31
   |
LL |     f(unreachable!(NOT_SEND)).await;
   |                    --------   ^^^^^- `NOT_SEND` is later dropped here
   |                    |          |
   |                    |          await occurs here, with `NOT_SEND` maybe used later
   |                    has type `NotSend` which is not `Send`
note: required by a bound in `require_send`
  --> tests/ui/macros/panic-temporaries-2018.rs:48:25
   |
LL | fn require_send(_: impl Send) {}
   |                         ^^^^ required by this bound in `require_send`

error: future cannot be sent between threads safely
  --> tests/ui/macros/panic-temporaries-2018.rs:54:18
   |
LL |     require_send(unreachable_display());
   |                  ^^^^^^^^^^^^^^^^^^^^^ future returned by `unreachable_display` is not `Send`
   |
   = help: within `NotSend`, the trait `Sync` is not implemented for `*const u8`
note: future is not `Send` as this value is used across an await
  --> tests/ui/macros/panic-temporaries-2018.rs:45:31
   |
LL |     f(unreachable!(NOT_SEND)).await;
   |       ----------------------  ^^^^^- the value is later dropped here
   |       |                       |
   |       |                       await occurs here, with the value maybe used later
   |       has type `&NotSend` which is not `Send`
note: required by a bound in `require_send`
  --> tests/ui/macros/panic-temporaries-2018.rs:48:25
   |
LL | fn require_send(_: impl Send) {}
   |                         ^^^^ required by this bound in `require_send`

error: aborting due to 5 previous errors
```
</details>

<details>
<summary>tests/ui/macros/panic-temporaries.rs</summary>

```console
error: future cannot be sent between threads safely
  --> tests/ui/macros/panic-temporaries.rs:42:18
   |
LL |     require_send(panic_display());
   |                  ^^^^^^^^^^^^^^^ future returned by `panic_display` is not `Send`
   |
   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `*const u8`
note: future is not `Send` as this value is used across an await
  --> tests/ui/macros/panic-temporaries.rs:35:31
   |
LL |     f(panic!("{}", NOT_SEND)).await;
   |                    --------   ^^^^^- `NOT_SEND` is later dropped here
   |                    |          |
   |                    |          await occurs here, with `NOT_SEND` maybe used later
   |                    has type `NotSend` which is not `Send`
note: required by a bound in `require_send`
  --> tests/ui/macros/panic-temporaries.rs:38:25
   |
LL | fn require_send(_: impl Send) {}
   |                         ^^^^ required by this bound in `require_send`

error: future cannot be sent between threads safely
  --> tests/ui/macros/panic-temporaries.rs:42:18
   |
LL |     require_send(panic_display());
   |                  ^^^^^^^^^^^^^^^ future returned by `panic_display` is not `Send`
   |
   = help: within `NotSend`, the trait `Sync` is not implemented for `*const u8`
note: future is not `Send` as this value is used across an await
  --> tests/ui/macros/panic-temporaries.rs:35:31
   |
LL |     f(panic!("{}", NOT_SEND)).await;
   |       ----------------------  ^^^^^- the value is later dropped here
   |       |                       |
   |       |                       await occurs here, with the value maybe used later
   |       has type `&NotSend` which is not `Send`
note: required by a bound in `require_send`
  --> tests/ui/macros/panic-temporaries.rs:38:25
   |
LL | fn require_send(_: impl Send) {}
   |                         ^^^^ required by this bound in `require_send`

error: aborting due to 2 previous errors
```
</details>

r? bjorn3
  • Loading branch information
bors committed May 19, 2023
2 parents 19ca569 + 2f5d993 commit 2d17294
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 18 deletions.
24 changes: 12 additions & 12 deletions library/core/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ pub macro panic_2015 {
$crate::panicking::panic($msg)
),
// Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint.
($msg:expr $(,)?) => (
$crate::panicking::panic_str($msg)
),
($msg:expr $(,)?) => ({
$crate::panicking::panic_str($msg);
}),
// Special-case the single-argument case for const_panic.
("{}", $arg:expr $(,)?) => (
$crate::panicking::panic_display(&$arg)
),
("{}", $arg:expr $(,)?) => ({
$crate::panicking::panic_display(&$arg);
}),
($fmt:expr, $($arg:tt)+) => ({
// Semicolon to prevent temporaries inside the formatting machinery from
// being considered alive in the caller after the panic_fmt call.
Expand All @@ -52,9 +52,9 @@ pub macro panic_2021 {
$crate::panicking::panic("explicit panic")
),
// Special-case the single-argument case for const_panic.
("{}", $arg:expr $(,)?) => (
$crate::panicking::panic_display(&$arg)
),
("{}", $arg:expr $(,)?) => ({
$crate::panicking::panic_display(&$arg);
}),
($($t:tt)+) => ({
// Semicolon to prevent temporaries inside the formatting machinery from
// being considered alive in the caller after the panic_fmt call.
Expand All @@ -73,9 +73,9 @@ pub macro unreachable_2015 {
),
// Use of `unreachable_display` for non_fmt_panic lint.
// NOTE: the message ("internal error ...") is embedded directly in unreachable_display
($msg:expr $(,)?) => (
$crate::panicking::unreachable_display(&$msg)
),
($msg:expr $(,)?) => ({
$crate::panicking::unreachable_display(&$msg);
}),
($fmt:expr, $($arg:tt)*) => (
$crate::panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
),
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ pub macro panic_2015 {
$crate::rt::begin_panic("explicit panic")
}),
($msg:expr $(,)?) => ({
$crate::rt::begin_panic($msg)
$crate::rt::begin_panic($msg);
}),
// Special-case the single-argument case for const_panic.
("{}", $arg:expr $(,)?) => ({
$crate::rt::panic_display(&$arg)
$crate::rt::panic_display(&$arg);
}),
($fmt:expr, $($arg:tt)+) => ({
// Semicolon to prevent temporaries inside the formatting machinery from
Expand Down
55 changes: 55 additions & 0 deletions tests/ui/macros/panic-temporaries-2018.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// check-pass
// edition:2018

#![allow(non_fmt_panics, unreachable_code)]

use std::fmt::{self, Display};
use std::marker::PhantomData;

struct NotSend {
marker: PhantomData<*const u8>,
}

const NOT_SEND: NotSend = NotSend { marker: PhantomData };

impl Display for NotSend {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("this value does not implement Send")
}
}

async fn f(_: u8) {}

// Exercises this matcher in panic_2015:
// ($fmt:expr, $($arg:tt)+) => $crate::panicking::panic_fmt(...)
async fn panic_fmt() {
// Panic returns `!`, so the await is never reached, and in particular the
// temporaries inside the formatting machinery are not still alive at the
// await point.
let todo = "...";
f(panic!("not yet implemented: {}", todo)).await;
}

// Exercises ("{}", $arg:expr) => $crate::panicking::panic_display(&$arg)
async fn panic_display() {
f(panic!("{}", NOT_SEND)).await;
}

// Exercises ($msg:expr) => $crate::panicking::panic_str($msg)
async fn panic_str() {
f(panic!((NOT_SEND, "...").1)).await;
}

// Exercises ($msg:expr) => $crate::panicking::unreachable_display(&$msg)
async fn unreachable_display() {
f(unreachable!(NOT_SEND)).await;
}

fn require_send(_: impl Send) {}

fn main() {
require_send(panic_fmt());
require_send(panic_display());
require_send(panic_str());
require_send(unreachable_display());
}
32 changes: 28 additions & 4 deletions tests/ui/macros/panic-temporaries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,41 @@

#![allow(unreachable_code)]

use std::fmt::{self, Display};
use std::marker::PhantomData;

struct NotSend {
marker: PhantomData<*const u8>,
}

const NOT_SEND: NotSend = NotSend { marker: PhantomData };

impl Display for NotSend {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("this value does not implement Send")
}
}

async fn f(_: u8) {}

async fn g() {
// Todo returns `!`, so the await is never reached, and in particular the
// Exercises this matcher in panic_2021:
// ($($t:tt)+) => $crate::panicking::panic_fmt(...)
async fn panic_fmt() {
// Panic returns `!`, so the await is never reached, and in particular the
// temporaries inside the formatting machinery are not still alive at the
// await point.
f(todo!("...")).await;
let todo = "...";
f(panic!("not yet implemented: {}", todo)).await;
}

// Exercises ("{}", $arg:expr) => $crate::panicking::panic_display(&$arg)
async fn panic_display() {
f(panic!("{}", NOT_SEND)).await;
}

fn require_send(_: impl Send) {}

fn main() {
require_send(g());
require_send(panic_fmt());
require_send(panic_display());
}

0 comments on commit 2d17294

Please sign in to comment.