@@ -347,35 +347,70 @@ macro_rules! eprintln {
347347/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
348348/// [`log`]: https://crates.io/crates/log
349349#[ macro_export]
350+ #[ allow_internal_unstable( std_internals) ]
350351#[ cfg_attr( not( test) , rustc_diagnostic_item = "dbg_macro" ) ]
351352#[ stable( feature = "dbg_macro" , since = "1.32.0" ) ]
352353macro_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.
357354 ( ) => {
358355 $crate:: eprintln!( "[{}:{}:{}]" , $crate:: file!( ) , $crate:: line!( ) , $crate:: column!( ) )
359356 } ;
360- ( $val: expr $( , ) ?) => {
357+ ( $( $val: expr) ,+ $( , ) ?) => {
358+ $crate:: macros:: dbg_internal!( ( ) ( ) ( $( $val) ,+) )
359+ } ;
360+ }
361+
362+ /// Internal macro that processes a list of expressions and produces a chain of
363+ /// nested `match`es, one for each expression, before finally calling `eprint!`
364+ /// with the collected information and returning all the evaluated expressions
365+ /// in a tuple.
366+ ///
367+ /// E.g. `dbg_internal!(() () (1, 2))` expands into
368+ /// ```rust, ignore
369+ /// match 1 {
370+ /// tmp_1 => match 2 {
371+ /// tmp_2 => {
372+ /// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */);
373+ /// (tmp_1, tmp_2)
374+ /// }
375+ /// }
376+ /// }
377+ /// ```
378+ ///
379+ /// This is necessary so that `dbg!` outputs don't get torn, see #136703.
380+ #[ doc( hidden) ]
381+ #[ rustc_macro_transparency = "semitransparent" ]
382+ pub macro dbg_internal {
383+ ( ( $( $piece: literal) , +) ( $( $processed: expr => $bound: expr) , +) ( ) ) => { {
384+ $crate:: eprint!(
385+ $crate :: concat!( $( $piece) , +) ,
386+ $(
387+ $crate :: stringify!( $processed) ,
388+ // The `&T: Debug` check happens here (not in the format literal desugaring)
389+ // to avoid format literal related messages and suggestions.
390+ &&$bound as & dyn $crate :: fmt:: Debug
391+ ) , +,
392+ // The location returned here is that of the macro invokation, so
393+ // it will be the same for all expressions. Thus, label these
394+ // arguments so that they can be reused in every piece of the
395+ // formatting template.
396+ file=$crate :: file!( ) ,
397+ line=$crate :: line!( ) ,
398+ column=$crate :: column!( )
399+ ) ;
400+ // Comma separate the variables only when necessary so that this will
401+ // not yield a tuple for a single expression, but rather just parenthesize
402+ // the expression.
403+ ( $( $bound) , +)
404+ } } ,
405+ ( ( $( $piece: literal) , * ) ( $( $processed: expr => $bound: expr) , * ) ( $val: expr $( , $rest: expr) * ) ) => { {
361406 // Use of `match` here is intentional because it affects the lifetimes
362407 // of temporaries - https://stackoverflow.com/a/48732525/1063961
363408 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- }
409+ tmp => $crate:: macros:: dbg_internal!(
410+ ( $( $piece, ) * "[{file}:{line}:{column}] {} = {:#?}]\n " )
411+ ( $( $processed => $bound, ) * $val => tmp)
412+ ( $( $rest) , * )
413+ ) ,
376414 }
377- } ;
378- ( $( $val: expr) ,+ $( , ) ?) => {
379- ( $( $crate:: dbg!( $val) ) ,+, )
380- } ;
415+ } } ,
381416}
0 commit comments