|
| 1 | +// ignore-tidy-dbg |
| 2 | + |
| 3 | +use core::fmt::Debug; |
| 4 | + |
| 5 | +/// Test for <https://github.com/rust-lang/rust/issues/153850>: |
| 6 | +/// `dbg!` shouldn't drop arguments' temporaries. |
| 7 | +#[test] |
| 8 | +fn no_dropping_temps() { |
| 9 | + fn temp() {} |
| 10 | + |
| 11 | + *dbg!(&temp()); |
| 12 | + *dbg!(&temp(), 1).0; |
| 13 | + *dbg!(0, &temp()).1; |
| 14 | + *dbg!(0, &temp(), 2).1; |
| 15 | +} |
| 16 | + |
| 17 | +/// Test for <https://github.com/rust-lang/rust/issues/154988>: |
| 18 | +/// `dbg!` shouldn't create a temporary that lives past its invocation. |
| 19 | +#[test] |
| 20 | +fn no_leaking_internal_temps_from_dbg() { |
| 21 | + #[derive(Debug)] |
| 22 | + struct Foo; |
| 23 | + |
| 24 | + #[derive(Debug)] |
| 25 | + struct Bar<'a>(#[allow(unused)] &'a Foo); |
| 26 | + impl Drop for Bar<'_> { |
| 27 | + fn drop(&mut self) {} |
| 28 | + } |
| 29 | + |
| 30 | + let foo = Foo; |
| 31 | + let bar = Bar(&foo); |
| 32 | + // If `dbg!` creates a `(Bar<'_>,)` temporary that lasts past its expansion, this will fail |
| 33 | + // to compile, because it will be dropped after `foo`, which it borrows from. The tuple |
| 34 | + // mimics the drop order of block tail expressions before Rust 2024: first the result of `dbg!` |
| 35 | + // is dropped, then `foo`, then any temporaries left over from `dbg!` are dropped, if present. |
| 36 | + (drop(dbg!(bar)), drop(foo)); |
| 37 | +} |
| 38 | + |
| 39 | +/// Test for <https://github.com/rust-lang/rust/issues/155902>: |
| 40 | +/// `dbg!` shouldn't create a temporary that borrowck thinks can live past its invocation on a false |
| 41 | +/// unwind path. |
| 42 | +#[test] |
| 43 | +fn no_leaking_internal_temps_from_dbg_even_on_false_unwind() { |
| 44 | + #[derive(Debug)] |
| 45 | + struct Foo; |
| 46 | + impl Drop for Foo { |
| 47 | + fn drop(&mut self) {} |
| 48 | + } |
| 49 | + |
| 50 | + #[derive(Debug)] |
| 51 | + struct Bar<'a>(#[allow(unused)] &'a Foo); |
| 52 | + impl Drop for Bar<'_> { |
| 53 | + fn drop(&mut self) {} |
| 54 | + } |
| 55 | + |
| 56 | + { |
| 57 | + let foo = Foo; |
| 58 | + let bar = Bar(&foo); |
| 59 | + // The temporaries of this `super let`'s scrutinee will outlive `bar` and `foo`, emulating |
| 60 | + // the drop order of block tail expressions before Rust 2024. If borrowck thinks that a |
| 61 | + // panic from moving `bar` is possible and that a `Bar<'_>`-containing temporary lives past |
| 62 | + // the end of the block because of that, this will fail to compile. Because `Foo` implements |
| 63 | + // `Drop`, it's an error for `foo` to be dropped before such a temporary when unwinding; |
| 64 | + // otherwise, `foo` would just live to the end of the stack frame when unwinding. |
| 65 | + super let _ = drop(dbg!(bar)); |
| 66 | + } |
| 67 | +} |
0 commit comments