diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 629d9f8adab3..f047556671f2 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -468,9 +468,7 @@ // The standard macros that are not built-in to the compiler. #[macro_use] -#[doc(hidden)] -#[unstable(feature = "std_internals", issue = "none")] -pub mod macros; +mod macros; // The runtime entry point and a few unstable public functions used by the // compiler diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 0bb14552432d..25e2b7ea1370 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -347,70 +347,35 @@ macro_rules! eprintln { /// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html /// [`log`]: https://crates.io/crates/log #[macro_export] -#[allow_internal_unstable(std_internals)] #[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")] #[stable(feature = "dbg_macro", since = "1.32.0")] macro_rules! dbg { + // NOTE: We cannot use `concat!` to make a static string as a format argument + // of `eprintln!` because `file!` could contain a `{` or + // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!` + // will be malformed. () => { $crate::eprintln!("[{}:{}:{}]", $crate::file!(), $crate::line!(), $crate::column!()) }; - ($($val:expr),+ $(,)?) => { - $crate::macros::dbg_internal!(() () ($($val),+)) - }; -} - -/// Internal macro that processes a list of expressions and produces a chain of -/// nested `match`es, one for each expression, before finally calling `eprint!` -/// with the collected information and returning all the evaluated expressions -/// in a tuple. -/// -/// E.g. `dbg_internal!(() () (1, 2))` expands into -/// ```rust, ignore -/// match 1 { -/// tmp_1 => match 2 { -/// tmp_2 => { -/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */); -/// (tmp_1, tmp_2) -/// } -/// } -/// } -/// ``` -/// -/// This is necessary so that `dbg!` outputs don't get torn, see #136703. -#[doc(hidden)] -#[rustc_macro_transparency = "semiopaque"] -pub macro dbg_internal { - (($($piece:literal),+) ($($processed:expr => $bound:expr),+) ()) => {{ - $crate::eprint!( - $crate::concat!($($piece),+), - $( - $crate::stringify!($processed), - // The `&T: Debug` check happens here (not in the format literal desugaring) - // to avoid format literal related messages and suggestions. - &&$bound as &dyn $crate::fmt::Debug - ),+, - // The location returned here is that of the macro invocation, so - // it will be the same for all expressions. Thus, label these - // arguments so that they can be reused in every piece of the - // formatting template. - file=$crate::file!(), - line=$crate::line!(), - column=$crate::column!() - ); - // Comma separate the variables only when necessary so that this will - // not yield a tuple for a single expression, but rather just parenthesize - // the expression. - ($($bound),+) - }}, - (($($piece:literal),*) ($($processed:expr => $bound:expr),*) ($val:expr $(,$rest:expr)*)) => { + ($val:expr $(,)?) => { // Use of `match` here is intentional because it affects the lifetimes // of temporaries - https://stackoverflow.com/a/48732525/1063961 match $val { - tmp => $crate::macros::dbg_internal!( - ($($piece,)* "[{file}:{line}:{column}] {} = {:#?}\n") - ($($processed => $bound,)* $val => tmp) - ($($rest),*) - ), + tmp => { + $crate::eprintln!("[{}:{}:{}] {} = {:#?}", + $crate::file!(), + $crate::line!(), + $crate::column!(), + $crate::stringify!($val), + // The `&T: Debug` check happens here (not in the format literal desugaring) + // to avoid format literal related messages and suggestions. + &&tmp as &dyn $crate::fmt::Debug, + ); + tmp + } } - }, + }; + ($($val:expr),+ $(,)?) => { + ($($crate::dbg!($val)),+,) + }; } diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index f47d0d4835a9..8d86a9f34631 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -5,7 +5,7 @@ use clippy_utils::source::snippet_with_applicability; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{Arm, Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind}; +use rustc_hir::{Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::{Span, SyntaxContext}; @@ -92,27 +92,33 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { (macro_call.span, String::from("()")) } }, - ExprKind::Match(first, arms, _) => { - let vals = collect_vals(first, arms); - let suggestion = match *vals.as_slice() { - // dbg!(1) => 1 - [val] => { - snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability) - .to_string() + // dbg!(1) + ExprKind::Match(val, ..) => ( + macro_call.span, + snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability) + .to_string(), + ), + // dbg!(2, 3) + ExprKind::Tup( + [ + Expr { + kind: ExprKind::Match(first, ..), + .. }, - // dbg!(2, 3) => (2, 3) - [first, .., last] => { - let snippet = snippet_with_applicability( - cx, - first.span.source_callsite().to(last.span.source_callsite()), - "..", - &mut applicability, - ); - format!("({snippet})") + .., + Expr { + kind: ExprKind::Match(last, ..), + .. }, - _ => unreachable!(), - }; - (macro_call.span, suggestion) + ], + ) => { + let snippet = snippet_with_applicability( + cx, + first.span.source_callsite().to(last.span.source_callsite()), + "..", + &mut applicability, + ); + (macro_call.span, format!("({snippet})")) }, _ => unreachable!(), }; @@ -165,39 +171,3 @@ fn is_async_move_desugar<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option { macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id)) } - -/// Extracts all value expressions from the `match`-tree generated by `dbg!`. -/// -/// E.g. from -/// ```rust, ignore -/// match 1 { -/// tmp_1 => match 2 { -/// tmp_2 => { -/// /* printing */ -/// (tmp_1, tmp_2) -/// } -/// } -/// } -/// ``` -/// this extracts `1` and `2`. -fn collect_vals<'hir>(first: &'hir Expr<'hir>, mut arms: &'hir [Arm<'hir>]) -> Vec<&'hir Expr<'hir>> { - let mut vals = vec![first]; - loop { - let [arm] = arms else { - unreachable!("dbg! macro expansion only has single-arm matches") - }; - - match is_async_move_desugar(arm.body) - .unwrap_or(arm.body) - .peel_drop_temps() - .kind - { - ExprKind::Block(..) => return vals, - ExprKind::Match(val, a, _) => { - vals.push(val); - arms = a; - }, - _ => unreachable!("dbg! macro expansion only results in block or match expressions"), - } - } -}