@@ -350,6 +350,7 @@ macro_rules! eprintln {
350350/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
351351/// [`log`]: https://crates.io/crates/log
352352#[ macro_export]
353+ #[ allow_internal_unstable( std_internals) ]
353354#[ cfg_attr( not( test) , rustc_diagnostic_item = "dbg_macro" ) ]
354355#[ stable( feature = "dbg_macro" , since = "1.32.0" ) ]
355356macro_rules! dbg {
@@ -360,29 +361,69 @@ macro_rules! dbg {
360361 ( ) => {
361362 $crate:: eprintln!( "[{}:{}:{}]" , $crate:: file!( ) , $crate:: line!( ) , $crate:: column!( ) )
362363 } ;
363- ( $val: expr $( , ) ?) => {
364- // Use of `match` here is intentional because it affects the lifetimes
365- // of temporaries - https://stackoverflow.com/a/48732525/1063961
366- match $val {
367- tmp => {
368- $crate:: eprintln!( "[{}:{}:{}] {} = {:#?}" ,
369- $crate:: file!( ) ,
370- $crate:: line!( ) ,
371- $crate:: column!( ) ,
372- $crate:: stringify!( $val) ,
373- // The `&T: Debug` check happens here (not in the format literal desugaring)
374- // to avoid format literal related messages and suggestions.
375- &&tmp as & dyn $crate:: fmt:: Debug ,
376- ) ;
377- tmp
378- }
379- }
380- } ;
381364 ( $( $val: expr) ,+ $( , ) ?) => {
382- ( $ ( $ crate:: dbg! ( $ val) ) ,+ , )
365+ $ crate:: macros :: dbg_internal! ( ( ) ( ) ( $ ( $ val) ,+ ) )
383366 } ;
384367}
385368
369+ /// Internal macro that processes a list of expressions, binds their results, calls `eprint!` with
370+ /// the collected information, and returns all the evaluated expressions in a tuple.
371+ ///
372+ /// E.g. `dbg_internal!(() () (1, 2))` expands into
373+ /// ```rust, ignore
374+ /// {
375+ /// let tmp_1;
376+ /// let tmp_2;
377+ /// super let _ = (tmp_1 = 1);
378+ /// super let _ = (tmp_2 = 2);
379+ /// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */);
380+ /// (tmp_1, tmp_2)
381+ /// }
382+ /// ```
383+ ///
384+ /// This is necessary so that `dbg!` outputs don't get torn, see #136703.
385+ /// `super let` is used to avoid creating a temporary scope around `dbg!`'s arguments. Nested
386+ /// `match` is insufficient because match arms introduce temporary scopes (#153850) and using a
387+ /// single match on a tuple containing all the arguments is insufficient because of an imprecision
388+ /// in the borrow-checker (see #155902).
389+ #[ doc( hidden) ]
390+ #[ allow_internal_unstable( std_internals, super_let) ]
391+ #[ rustc_macro_transparency = "semiopaque" ]
392+ #[ unstable( feature = "std_internals" , issue = "none" ) ]
393+ pub macro dbg_internal {
394+ ( ( $( $piece: literal) , +) ( $( $processed: expr => $bound: ident) , +) ( ) ) => { {
395+ $( let $bound) ; +;
396+ $( super let _ = ( $bound = $processed) ) ; +;
397+ $crate:: eprint!(
398+ $crate :: concat!( $( $piece) , +) ,
399+ $(
400+ $crate :: stringify!( $processed) ,
401+ // The `&T: Debug` check happens here (not in the format literal desugaring)
402+ // to avoid format literal related messages and suggestions.
403+ &&$bound as & dyn $crate :: fmt:: Debug
404+ ) , +,
405+ // The location returned here is that of the macro invocation, so
406+ // it will be the same for all expressions. Thus, label these
407+ // arguments so that they can be reused in every piece of the
408+ // formatting template.
409+ file=$crate :: file!( ) ,
410+ line=$crate :: line!( ) ,
411+ column=$crate :: column!( )
412+ ) ;
413+ // Comma separate the variables only when necessary so that this will
414+ // not yield a tuple for a single expression, but rather just parenthesize
415+ // the expression.
416+ ( $( $bound) , +)
417+ } } ,
418+ ( ( $( $piece: literal) , * ) ( $( $processed: expr => $bound: ident) , * ) ( $val: expr $( , $rest: expr) * ) ) => {
419+ $crate:: macros:: dbg_internal!(
420+ ( $( $piece, ) * "[{file}:{line}:{column}] {} = {:#?}\n " )
421+ ( $( $processed => $bound, ) * $val => tmp)
422+ ( $( $rest) , * )
423+ )
424+ } ,
425+ }
426+
386427#[ doc ( hidden) ]
387428#[ macro_export]
388429#[ allow_internal_unstable( hash_map_internals) ]
0 commit comments