Skip to content

avoid tearing dbg! prints, implemented using super let#157576

Open
dianne wants to merge 2 commits into
rust-lang:mainfrom
dianne:dbg-via-super-let-2
Open

avoid tearing dbg! prints, implemented using super let#157576
dianne wants to merge 2 commits into
rust-lang:mainfrom
dianne:dbg-via-super-let-2

Conversation

@dianne

@dianne dianne commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #136703.

This is a revival of #149869 using the approach from #155915. super let statements aren't the cleanest for this in their current state (it required a bit of trickery), but I'll be working on making temporary scoping in macros nicer soon.

r? libs

dianne added 2 commits June 7, 2026 03:03
Two things:

Since `dbg!` is changing, this removes parts of the file that assumed it
expands a certain way. The removed tests will no longer get the
"consider borrowing" messages going forward, but I think that's fine;
it's unlikely that someone would have hand-written them and the
suggestion could easily be wrong in the general case. If we want a more
general help message to suggest borrowing in those cases, I think it
should be designed as such from the ground up, not targeting `dbg!`.

From what I can tell, this test file was intended to be for the
"consider borrowing" help messages on diagnostics for `dbg!`. To make it
harder to accidentally mess with those messages, I've added checks for
them and some comments to clarify intent.
@rustbot

rustbot commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

The Clippy subtree was changed

cc @rust-lang/clippy

The Miri subtree was changed

cc @rust-lang/miri

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 7, 2026
@dianne

dianne commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

honestly I'm a bit ambivalent about this at this point, but I figure since the work's done, I may as well open a PR so we can go ahead with it if we want (provided crater's clean).

assuming we'd like to stop dbg! outputs from tearing, using temporary scoping constructs is the lightest-weight approach I've seen, and hopefully soon it'll be the most idiomatic too (unfortunately it's not quite there yet). of course, it's also unstable.

@theemathas

Copy link
Copy Markdown
Contributor

Preparing for crater:

@bors try

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jun 7, 2026
avoid tearing `dbg!` prints, implemented using `super let`
@rust-bors

rust-bors Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: fceb2de (fceb2de603f0807f9049222f3f612ed51ed8f9dc, parent: 43a4909ee98ed4d006d9d773f5d94dc58e34f846)

@theemathas

Copy link
Copy Markdown
Contributor

Unsure if we need to also run tests in crater, but let's go with

@craterbot check

@craterbot

Copy link
Copy Markdown
Collaborator

👌 Experiment pr-157576 created and queued.
🤖 Automatically detected try build fceb2de
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 7, 2026
Comment thread library/std/src/macros.rs
pub macro dbg_internal {
(($($piece:literal),+) ($($processed:expr => $bound:ident),+) ()) => {{
$(let $bound);+;
$(super let _ = ($bound = $processed));+;

@clarfonthey clarfonthey Jun 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this syntax is very confusing and should probably be explained a bit better. To me, I see this as the unit return value of the compound expression ($bound = $processed) being given higher scope, not $bound, which doesn't make any sense. I assume that some heavier lifting is being done but there should be some comments explaining why this works, so people will understand if we later change the semantics of super let before stabilisation and it breaks.

View changes since the review

Comment thread library/std/src/macros.rs
#[unstable(feature = "std_internals", issue = "none")]
pub macro dbg_internal {
(($($piece:literal),+) ($($processed:expr => $bound:ident),+) ()) => {{
$(let $bound);+;

@clarfonthey clarfonthey Jun 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit, but I personally would prefer calling this just var or ident or really anything other than bound, since the term "bound" makes my mind immediately go toward trait bounds and that's not what this is. It's technically clear by itself, but that would make the macro code a bit easier to read.

View changes since the review

Comment thread library/std/src/macros.rs
$(let $bound);+;
$(super let _ = ($bound = $processed));+;
$crate::eprint!(
$crate::concat!($($piece),+),

@clarfonthey clarfonthey Jun 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, I think piece should be reworded as maybe fmt_piece or something that clarifies that this is for the formatting string being used, since otherwise it immediately begs "piece of what?"

Again, this is clear from the implementation alone, but it would be nice to have a grasp on what is being done before reading the full implementation.

View changes since the review

Comment thread library/std/src/macros.rs
/// Internal macro that processes a list of expressions, binds their results, calls `eprint!` with
/// the collected information, and returns all the evaluated expressions in a tuple.
///
/// E.g. `dbg_internal!(() () (1, 2))` expands into

@clarfonthey clarfonthey Jun 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would clarify this further to the sequence:

  • dbg_internal!(() () (1, 2))
  • dbg_internal!(("...") (1 => tmp_1) (2))
  • dbg_internal!(("...", "...") (1 => tmp_1, 2 => tmp_2) ()

Followed by the code generated.

I would also note that the _1 and _2 suffixes are not actually used, and that we rely on macro hygiene to make multiple tmp idents distinct. Again, technically something you should be able to figure out from the implementation, but it speeds up reading it a bit more.

View changes since the review

Comment thread library/std/src/macros.rs
/// let tmp_2;
/// super let _ = (tmp_1 = 1);
/// super let _ = (tmp_2 = 2);
/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */);

@clarfonthey clarfonthey Jun 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would replace "..." with concat!("...", "...") to clarify that we do genuinely just concatenate all the strings together, so it's clear that the \n on each string is load-bearing.

View changes since the review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-crater Status: Waiting on a crater run to be completed. T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dbg! prints can tear in multi-threading code

5 participants