Skip to content

Inlining/flattening of format_args!() accidentally exposed as stable through const #139136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
m-ou-se opened this issue Mar 30, 2025 · 3 comments · May be fixed by #139624
Open

Inlining/flattening of format_args!() accidentally exposed as stable through const #139136

m-ou-se opened this issue Mar 30, 2025 · 3 comments · May be fixed by #139624
Labels
A-fmt Area: `core::fmt` C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged.

Comments

@m-ou-se
Copy link
Member

m-ou-se commented Mar 30, 2025

format_args!() can currently only be stored (and used later) if it has no arguments:

let a = format_args!("1 + 1 = 2"); // ok
let b = format_args!("1 + 1 = {}", 2); // error

println!("{a} {b}");

However, format_args!("1 + 1 = {}", 2) is optimized to (effectively) format_args!("1 + 1 = 2") as part of ast lowering.
To avoid allowing more code because of this optimization, the lowering results in a slightly different expansion that would still result in the same error. (By using &none() rather than &[].)

However, I had failed to consider the effect in a const:

However, because of #135139, we now have:

const X: std::fmt::Arguments = format_args!("1 + 1 = 2"); // ok
const Y: std::fmt::Arguments = format_args!("1 + 1 = {}", 2); // ok
const Z: std::fmt::Arguments = format_args!("1 + 1 = {}", 1 + 1); // error

println!("{X} {Y} {Z}");

(The expression for Y is subject to format_args inlining/flattening. The one for Z is not.)

It means there can be code out there that relies on format_args inlining/flattening working the way it does today.

Two solutions:

  1. Make the Y example fail to compile as well. This would be a (small?) breaking change. Don't allow flattened format_args in const. #139624
  2. Make all these examples work. (We probably want that in the future.)
@m-ou-se m-ou-se added the C-bug Category: This is a bug. label Mar 30, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Mar 30, 2025
@fmease fmease added the A-fmt Area: `core::fmt` label Mar 30, 2025
bors added a commit to rust-lang-ci/rust that referenced this issue Mar 31, 2025
Remove 'simple array' lowering of format_args!().

format_args!() uses a simpler (faster to compile) lowering in simple cases. However, selecting that case is somewhat complicated, as it does not work if any argument beyond the first one contains a yield point, so we have to check for that.

As part of the solution for rust-lang#92698 and rust-lang#139136, it might need to get even more complicated, checking for any lifetime-extended temporaries or any const-promotable expressions.

This is an experiment to see the impact of just removing this optimazation.

This has been tried before with [slightly negative results](rust-lang#106770 (comment)), but maybe things have changed by now. :)
@RalfJung
Copy link
Member

Make the Y example fail to compile as well. This would be a (small?) breaking change.

It seems worth at least cratering this to see whether we can go back to a "clean state" before extending the const-eval capabilities around format_args!.

@m-ou-se m-ou-se linked a pull request Apr 10, 2025 that will close this issue
@m-ou-se
Copy link
Member Author

m-ou-se commented Apr 10, 2025

PR for the crater run: #139624

bors added a commit to rust-lang-ci/rust that referenced this issue Apr 10, 2025
Don't allow flattened format_args in const.

Fixes rust-lang#139136 and rust-lang#139621 by breaking the 'flattened format_args' cases.

This is a breaking change.

Let's try a crater run.
@m-ou-se
Copy link
Member Author

m-ou-se commented Apr 22, 2025

However, I had failed to consider the effect in a const

Turns out that wasn't the error. I did do it right (by properly marking the new_v1/new_v1_formatted/none functions as non-const). The problem was introduced in Rust 1.86.0 by this PR: #135139

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-fmt Area: `core::fmt` C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants