rustbot · GitHub

@rustbot added S-waiting-on-review

Status: Awaiting review from the assignee but also interested parties.

T-libs

Relevant to the library team, which will review and decide on the PR/issue.

labels

Jul 14, 2026

@connortsui20 connortsui20 changed the title make debug builders with closures impl with dyn Implement Debug helpers that take closures with &mut dyn FnMut

Jul 14, 2026

Open

rust-bors Bot pushed a commit that referenced this pull request

Jul 14, 2026
Implement `Debug` helpers that take closures with `&mut dyn FnMut`

camsteffen

hanna-kruppe

@rustbot rustbot added S-waiting-on-author

Status: This is awaiting some action (such as code changes or more information) from the author.

and removed S-waiting-on-review

Status: Awaiting review from the assignee but also interested parties.

labels

Jul 15, 2026
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>

@connortsui20

tgross35

camsteffen

Closed

@rust-bors rust-bors Bot added S-waiting-on-bors

Status: Waiting on bors to run and complete tests. Bors will change the label on completion.

and removed S-waiting-on-review

Status: Awaiting review from the assignee but also interested parties.

labels

Jul 16, 2026

jhpratt added a commit to jhpratt/rust that referenced this pull request

Jul 17, 2026
…hanna-kruppe
Implement `Debug` helpers via `Cell`
Related to rust-lang#149745, but does not fix it (yet).
Following @jmillikin's [suggestion](rust-lang#159302 (comment)), the builder logic now lives in the pre-existing non-generic methods taking `&dyn fmt::Debug` (where it used to exist), and each `*_with` method wraps its closure in a private `DebugOnce` struct that implements `Debug` by calling the closure, so the body is compiled once.
Just for context: A `dyn FnOnce` [can't be called behind a reference](rust-lang#149745 (comment)), hence the `Cell<Option<..>>` stuff in `DebugOnce`.
###### repro.rs
```rust
#![feature(debug_closure_helpers)]
#![crate_type = "lib"]
use core::fmt;
pub struct Point {
    pub x: u32,
    pub y: u32,
}
impl fmt::Debug for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Point")
            .field_with("x", |f| self.x.fmt(f))
            .field_with("y", |f| self.y.fmt(f))
            .finish()
    }
}
```
```bash
rustc +nightly --edition=2024 --emit=llvm-ir -Copt-level=0 -o before.ll repro.rs
rustc +stage1  --edition=2024 --emit=llvm-ir -Copt-level=0 -o after.ll  repro.rs
```
On the repro above, I saw the LLVM IR drop from 739 to 268 lines (an earlier version of this PR using `&mut dyn FnMut` measured 372). Since the stable `&dyn fmt::Debug` methods no longer go through any closure indirection, this should also avoid the potential runtime regression in the `derive(Debug)` microbenchmark.
This was the only remaining [blocker](rust-lang#117729 (comment)) for stabilizing `debug_closure_helpers`, so it should unblock rust-lang#146099.

Closed

rust-bors Bot pushed a commit that referenced this pull request

Jul 17, 2026
Rollup of 10 pull requests
Successful merges:
 - #156977 (interpret: properly check for inhabitedness of nested references)
 - #159365 (fix: point at method call chain when a return-position `impl Trait` assoc type diverges)
 - #159402 (Clarify safety requirements for SIMD shl/shr and masked load/store)
 - #159410 (rustdoc: remove old `--emit` types)
 - #159302 (Implement `Debug` helpers via `Cell`)
 - #159386 (add a fallback for `fmuladdf*`)
 - #159391 (Update tests for LLVM 23)
 - #159400 (Update books)
 - #159401 (Gate `tests/debuginfo/function-call.rs` on min GDB 15.1)
 - #159404 ([aarch64][win] Pass oversized c-variadic args indirectly on Arm64EC)

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request

Jul 17, 2026
…hanna-kruppe
Implement `Debug` helpers via `Cell`
Related to rust-lang#149745, but does not fix it (yet).
Following @jmillikin's [suggestion](rust-lang#159302 (comment)), the builder logic now lives in the pre-existing non-generic methods taking `&dyn fmt::Debug` (where it used to exist), and each `*_with` method wraps its closure in a private `DebugOnce` struct that implements `Debug` by calling the closure, so the body is compiled once.
Just for context: A `dyn FnOnce` [can't be called behind a reference](rust-lang#149745 (comment)), hence the `Cell<Option<..>>` stuff in `DebugOnce`.
###### repro.rs
```rust
#![feature(debug_closure_helpers)]
#![crate_type = "lib"]
use core::fmt;
pub struct Point {
    pub x: u32,
    pub y: u32,
}
impl fmt::Debug for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Point")
            .field_with("x", |f| self.x.fmt(f))
            .field_with("y", |f| self.y.fmt(f))
            .finish()
    }
}
```
```bash
rustc +nightly --edition=2024 --emit=llvm-ir -Copt-level=0 -o before.ll repro.rs
rustc +stage1  --edition=2024 --emit=llvm-ir -Copt-level=0 -o after.ll  repro.rs
```
On the repro above, I saw the LLVM IR drop from 739 to 268 lines (an earlier version of this PR using `&mut dyn FnMut` measured 372). Since the stable `&dyn fmt::Debug` methods no longer go through any closure indirection, this should also avoid the potential runtime regression in the `derive(Debug)` microbenchmark.
This was the only remaining [blocker](rust-lang#117729 (comment)) for stabilizing `debug_closure_helpers`, so it should unblock rust-lang#146099.

Closed

rust-bors Bot pushed a commit that referenced this pull request

Jul 17, 2026
…uwer
Rollup of 10 pull requests
Successful merges:
 - #159365 (fix: point at method call chain when a return-position `impl Trait` assoc type diverges)
 - #159402 (Clarify safety requirements for SIMD shl/shr and masked load/store)
 - #159410 (rustdoc: remove old `--emit` types)
 - #159302 (Implement `Debug` helpers via `Cell`)
 - #159386 (add a fallback for `fmuladdf*`)
 - #159391 (Update tests for LLVM 23)
 - #159400 (Update books)
 - #159401 (Gate `tests/debuginfo/function-call.rs` on min GDB 15.1)
 - #159404 ([aarch64][win] Pass oversized c-variadic args indirectly on Arm64EC)
 - #159405 (Manually implement Clone for GrowableBitSet)

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request

Jul 17, 2026
…hanna-kruppe
Implement `Debug` helpers via `Cell`
Related to rust-lang#149745, but does not fix it (yet).
Following @jmillikin's [suggestion](rust-lang#159302 (comment)), the builder logic now lives in the pre-existing non-generic methods taking `&dyn fmt::Debug` (where it used to exist), and each `*_with` method wraps its closure in a private `DebugOnce` struct that implements `Debug` by calling the closure, so the body is compiled once.
Just for context: A `dyn FnOnce` [can't be called behind a reference](rust-lang#149745 (comment)), hence the `Cell<Option<..>>` stuff in `DebugOnce`.
###### repro.rs
```rust
#![feature(debug_closure_helpers)]
#![crate_type = "lib"]
use core::fmt;
pub struct Point {
    pub x: u32,
    pub y: u32,
}
impl fmt::Debug for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Point")
            .field_with("x", |f| self.x.fmt(f))
            .field_with("y", |f| self.y.fmt(f))
            .finish()
    }
}
```
```bash
rustc +nightly --edition=2024 --emit=llvm-ir -Copt-level=0 -o before.ll repro.rs
rustc +stage1  --edition=2024 --emit=llvm-ir -Copt-level=0 -o after.ll  repro.rs
```
On the repro above, I saw the LLVM IR drop from 739 to 268 lines (an earlier version of this PR using `&mut dyn FnMut` measured 372). Since the stable `&dyn fmt::Debug` methods no longer go through any closure indirection, this should also avoid the potential runtime regression in the `derive(Debug)` microbenchmark.
This was the only remaining [blocker](rust-lang#117729 (comment)) for stabilizing `debug_closure_helpers`, so it should unblock rust-lang#146099.

Closed

rust-bors Bot pushed a commit that referenced this pull request

Jul 17, 2026
…uwer
Rollup of 16 pull requests
Successful merges:
 - #150732 (Convert `-Ctarget-cpu` into a target-modifier for AVR, AMDGCN and NVPTX )
 - #159301 (Update Enzyme to handle LLVM23)
 - #159365 (fix: point at method call chain when a return-position `impl Trait` assoc type diverges)
 - #159402 (Clarify safety requirements for SIMD shl/shr and masked load/store)
 - #159410 (rustdoc: remove old `--emit` types)
 - #158398 (Comment about empty run_passes, fixup of #158040)
 - #158843 (Fix ICE in `write_interface` when the interface file can't be written)
 - #159302 (Implement `Debug` helpers via `Cell`)
 - #159332 (Honor field-level lint attributes in non_snake_case)
 - #159386 (add a fallback for `fmuladdf*`)
 - #159391 (Update tests for LLVM 23)
 - #159400 (Update books)
 - #159401 (Gate `tests/debuginfo/function-call.rs` on min GDB 15.1)
 - #159404 ([aarch64][win] Pass oversized c-variadic args indirectly on Arm64EC)
 - #159405 (Manually implement Clone for GrowableBitSet)
 - #159415 (rustdoc: rename the doc parts metadata params)

Merged

rust-bors Bot pushed a commit that referenced this pull request

Jul 17, 2026
…uwer
Rollup of 17 pull requests
Successful merges:
 - #159301 (Update Enzyme to handle LLVM23)
 - #159365 (fix: point at method call chain when a return-position `impl Trait` assoc type diverges)
 - #159402 (Clarify safety requirements for SIMD shl/shr and masked load/store)
 - #159408 (rustc_data_structures: Expand documentation for rustc jobserver APIs)
 - #159410 (rustdoc: remove old `--emit` types)
 - #158398 (Comment about empty run_passes, fixup of #158040)
 - #158843 (Fix ICE in `write_interface` when the interface file can't be written)
 - #159302 (Implement `Debug` helpers via `Cell`)
 - #159332 (Honor field-level lint attributes in non_snake_case)
 - #159340 (Rename `errors.rs` file to `diagnostics.rs` (14/N))
 - #159386 (add a fallback for `fmuladdf*`)
 - #159391 (Update tests for LLVM 23)
 - #159400 (Update books)
 - #159401 (Gate `tests/debuginfo/function-call.rs` on min GDB 15.1)
 - #159404 ([aarch64][win] Pass oversized c-variadic args indirectly on Arm64EC)
 - #159405 (Manually implement Clone for GrowableBitSet)
 - #159415 (rustdoc: rename the doc parts metadata params)

@rust-bors

rust-timer added a commit that referenced this pull request

Jul 17, 2026
Rollup merge of #159302 - connortsui20:dyn-debug-helpers, r=hanna-kruppe
Implement `Debug` helpers via `Cell`
Related to #149745, but does not fix it (yet).
Following @jmillikin's [suggestion](#159302 (comment)), the builder logic now lives in the pre-existing non-generic methods taking `&dyn fmt::Debug` (where it used to exist), and each `*_with` method wraps its closure in a private `DebugOnce` struct that implements `Debug` by calling the closure, so the body is compiled once.
Just for context: A `dyn FnOnce` [can't be called behind a reference](#149745 (comment)), hence the `Cell<Option<..>>` stuff in `DebugOnce`.
###### repro.rs
```rust
#![feature(debug_closure_helpers)]
#![crate_type = "lib"]
use core::fmt;
pub struct Point {
    pub x: u32,
    pub y: u32,
}
impl fmt::Debug for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Point")
            .field_with("x", |f| self.x.fmt(f))
            .field_with("y", |f| self.y.fmt(f))
            .finish()
    }
}
```
```bash
rustc +nightly --edition=2024 --emit=llvm-ir -Copt-level=0 -o before.ll repro.rs
rustc +stage1  --edition=2024 --emit=llvm-ir -Copt-level=0 -o after.ll  repro.rs
```
On the repro above, I saw the LLVM IR drop from 739 to 268 lines (an earlier version of this PR using `&mut dyn FnMut` measured 372). Since the stable `&dyn fmt::Debug` methods no longer go through any closure indirection, this should also avoid the potential runtime regression in the `derive(Debug)` microbenchmark.
This was the only remaining [blocker](#117729 (comment)) for stabilizing `debug_closure_helpers`, so it should unblock #146099.

Kobzol pushed a commit to Kobzol/rustc_codegen_cranelift that referenced this pull request

Jul 23, 2026

Open

Read the original on github.com ↗