|
5 | 5 | //! library. |
6 | 6 | // ignore-tidy-dbg |
7 | 7 |
|
| 8 | +#[cfg(test)] |
| 9 | +mod tests; |
| 10 | + |
8 | 11 | #[doc = include_str!("../../core/src/macros/panic.md")] |
9 | 12 | #[macro_export] |
10 | 13 | #[rustc_builtin_macro(std_panic)] |
@@ -347,35 +350,73 @@ macro_rules! eprintln { |
347 | 350 | /// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html |
348 | 351 | /// [`log`]: https://crates.io/crates/log |
349 | 352 | #[macro_export] |
| 353 | +#[allow_internal_unstable(std_internals)] |
350 | 354 | #[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")] |
351 | 355 | #[stable(feature = "dbg_macro", since = "1.32.0")] |
352 | 356 | macro_rules! dbg { |
353 | | - // NOTE: We cannot use `concat!` to make a static string as a format argument |
354 | | - // of `eprintln!` because `file!` could contain a `{` or |
355 | | - // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!` |
356 | | - // will be malformed. |
357 | 357 | () => { |
358 | 358 | $crate::eprintln!("[{}:{}:{}]", $crate::file!(), $crate::line!(), $crate::column!()) |
359 | 359 | }; |
360 | | - ($val:expr $(,)?) => { |
361 | | - // Use of `match` here is intentional because it affects the lifetimes |
362 | | - // of temporaries - https://stackoverflow.com/a/48732525/1063961 |
363 | | - match $val { |
364 | | - tmp => { |
365 | | - $crate::eprintln!("[{}:{}:{}] {} = {:#?}", |
366 | | - $crate::file!(), |
367 | | - $crate::line!(), |
368 | | - $crate::column!(), |
369 | | - $crate::stringify!($val), |
370 | | - // The `&T: Debug` check happens here (not in the format literal desugaring) |
371 | | - // to avoid format literal related messages and suggestions. |
372 | | - &&tmp as &dyn $crate::fmt::Debug, |
373 | | - ); |
374 | | - tmp |
375 | | - } |
376 | | - } |
377 | | - }; |
378 | 360 | ($($val:expr),+ $(,)?) => { |
379 | | - ($($crate::dbg!($val)),+,) |
| 361 | + $crate::macros::dbg_internal!(() () ($($val),+)) |
380 | 362 | }; |
381 | 363 | } |
| 364 | + |
| 365 | +/// Internal macro that processes a list of expressions, binds their results, calls `eprint!` with |
| 366 | +/// the collected information, and returns all the evaluated expressions in a tuple. |
| 367 | +/// |
| 368 | +/// E.g. `dbg_internal!(() () (1, 2))` expands into |
| 369 | +/// ```rust, ignore |
| 370 | +/// { |
| 371 | +/// let tmp_1; |
| 372 | +/// let tmp_2; |
| 373 | +/// super let _ = (tmp_1 = 1); |
| 374 | +/// super let _ = (tmp_2 = 2); |
| 375 | +/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */); |
| 376 | +/// (tmp_1, tmp_2) |
| 377 | +/// } |
| 378 | +/// ``` |
| 379 | +/// |
| 380 | +/// This is necessary so that `dbg!` outputs don't get torn, see #136703. |
| 381 | +/// `super let` is used to avoid creating a temporary scope around `dbg!`'s arguments. Nested |
| 382 | +/// `match` is insufficient because match arms introduce temporary scopes (#153850) and using a |
| 383 | +/// single match on a tuple containing all the arguments is insufficient because the borrow checker |
| 384 | +/// thinks that tuple can outlive the `dbg!` invocation if dropping the temporary places the tuple's |
| 385 | +/// elements were moved out of panics (not actually possible; they've been moved from). See #155902. |
| 386 | +#[doc(hidden)] |
| 387 | +#[allow_internal_unstable(std_internals, super_let)] |
| 388 | +#[rustc_macro_transparency = "semiopaque"] |
| 389 | +#[unstable(feature = "std_internals", issue = "none")] |
| 390 | +pub macro dbg_internal { |
| 391 | + (($($piece:literal),+) ($($processed:expr => $bound:ident),+) ()) => {{ |
| 392 | + $(let $bound);+; |
| 393 | + $(super let _ = ($bound = $processed));+; |
| 394 | + $crate::eprint!( |
| 395 | + $crate::concat!($($piece),+), |
| 396 | + $( |
| 397 | + $crate::stringify!($processed), |
| 398 | + // The `&T: Debug` check happens here (not in the format literal desugaring) |
| 399 | + // to avoid format literal related messages and suggestions. |
| 400 | + &&$bound as &dyn $crate::fmt::Debug |
| 401 | + ),+, |
| 402 | + // The location returned here is that of the macro invocation, so |
| 403 | + // it will be the same for all expressions. Thus, label these |
| 404 | + // arguments so that they can be reused in every piece of the |
| 405 | + // formatting template. |
| 406 | + file=$crate::file!(), |
| 407 | + line=$crate::line!(), |
| 408 | + column=$crate::column!() |
| 409 | + ); |
| 410 | + // Comma separate the variables only when necessary so that this will |
| 411 | + // not yield a tuple for a single expression, but rather just parenthesize |
| 412 | + // the expression. |
| 413 | + ($($bound),+) |
| 414 | + }}, |
| 415 | + (($($piece:literal),*) ($($processed:expr => $bound:ident),*) ($val:expr $(,$rest:expr)*)) => { |
| 416 | + $crate::macros::dbg_internal!( |
| 417 | + ($($piece,)* "[{file}:{line}:{column}] {} = {:#?}\n") |
| 418 | + ($($processed => $bound,)* $val => tmp) |
| 419 | + ($($rest),*) |
| 420 | + ) |
| 421 | + }, |
| 422 | +} |
0 commit comments