diff options
| author | bors <bors@rust-lang.org> | 2023-03-16 13:46:52 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-03-16 13:46:52 +0000 |
| commit | 1203e0866e6c3659775efcb8aecad21dc13ef38b (patch) | |
| tree | 649280a25f8efd4058120de4a4e104959b83e3f4 /library/core | |
| parent | 7ac4b82ddd596a218cac8cd6b88a91b54fcdcf13 (diff) | |
| parent | a08016514847d39ae3096ff41f98759abf59bee8 (diff) | |
| download | rust-1203e0866e6c3659775efcb8aecad21dc13ef38b.tar.gz rust-1203e0866e6c3659775efcb8aecad21dc13ef38b.zip | |
Auto merge of #106824 - m-ou-se:format-args-flatten, r=oli-obk
Flatten/inline format_args!() and (string and int) literal arguments into format_args!()
Implements https://github.com/rust-lang/rust/issues/78356
Gated behind `-Zflatten-format-args=yes`.
Part of #99012
This change inlines string literals, integer literals and nested format_args!() into format_args!() during ast lowering, making all of the following pairs result in equivalent hir:
```rust
println!("Hello, {}!", "World");
println!("Hello, World!");
```
```rust
println!("[info] {}", format_args!("error"));
println!("[info] error");
```
```rust
println!("[{}] {}", status, format_args!("error: {}", msg));
println!("[{}] error: {}", status, msg);
```
```rust
println!("{} + {} = {}", 1, 2, 1 + 2);
println!("1 + 2 = {}", 1 + 2);
```
And so on.
This is useful for macros. E.g. a `log::info!()` macro could just pass the tokens from the user directly into a `format_args!()` that gets efficiently flattened/inlined into a `format_args!("info: {}")`.
It also means that `dbg!(x)` will have its file, line, and expression name inlined:
```rust
eprintln!("[{}:{}] {} = {:#?}", file!(), line!(), stringify!(x), x); // before
eprintln!("[example.rs:1] x = {:#?}", x); // after
```
Which can be nice in some cases, but also means a lot more unique static strings than before if dbg!() is used a lot.
Diffstat (limited to 'library/core')
| -rw-r--r-- | library/core/src/fmt/mod.rs | 26 | ||||
| -rw-r--r-- | library/core/src/panicking.rs | 4 | ||||
| -rw-r--r-- | library/core/tests/fmt/mod.rs | 8 |
3 files changed, 30 insertions, 8 deletions
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index c9821bf8109..6d764237dc8 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -392,8 +392,31 @@ enum FlagV1 { } impl<'a> Arguments<'a> { + #[doc(hidden)] + #[inline] + #[unstable(feature = "fmt_internals", issue = "none")] + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + pub const fn new_const(pieces: &'a [&'static str]) -> Self { + if pieces.len() > 1 { + panic!("invalid args"); + } + Arguments { pieces, fmt: None, args: &[] } + } + /// When using the format_args!() macro, this function is used to generate the /// Arguments structure. + #[cfg(not(bootstrap))] + #[doc(hidden)] + #[inline] + #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { + if pieces.len() < args.len() || pieces.len() > args.len() + 1 { + panic!("invalid args"); + } + Arguments { pieces, fmt: None, args } + } + + #[cfg(bootstrap)] #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] @@ -417,8 +440,7 @@ impl<'a> Arguments<'a> { #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] - pub const fn new_v1_formatted( + pub fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>], fmt: &'a [rt::v1::Argument], diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 805a1e51ae9..dd0105c0eb4 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -111,7 +111,7 @@ pub const fn panic(expr: &'static str) -> ! { // truncation and padding (even though none is used here). Using // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the // output binary, saving up to a few kilobytes. - panic_fmt(fmt::Arguments::new_v1(&[expr], &[])); + panic_fmt(fmt::Arguments::new_const(&[expr])); } /// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize. @@ -120,7 +120,7 @@ pub const fn panic(expr: &'static str) -> ! { #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] pub fn panic_nounwind(expr: &'static str) -> ! { - panic_nounwind_fmt(fmt::Arguments::new_v1(&[expr], &[])); + panic_nounwind_fmt(fmt::Arguments::new_const(&[expr])); } #[inline] diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs index 61807635813..c1c80c46c78 100644 --- a/library/core/tests/fmt/mod.rs +++ b/library/core/tests/fmt/mod.rs @@ -22,11 +22,11 @@ fn test_pointer_formats_data_pointer() { #[test] fn test_estimated_capacity() { assert_eq!(format_args!("").estimated_capacity(), 0); - assert_eq!(format_args!("{}", "").estimated_capacity(), 0); + assert_eq!(format_args!("{}", {""}).estimated_capacity(), 0); assert_eq!(format_args!("Hello").estimated_capacity(), 5); - assert_eq!(format_args!("Hello, {}!", "").estimated_capacity(), 16); - assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 0); - assert_eq!(format_args!("{}. 16-bytes piece", "World").estimated_capacity(), 32); + assert_eq!(format_args!("Hello, {}!", {""}).estimated_capacity(), 16); + assert_eq!(format_args!("{}, hello!", {"World"}).estimated_capacity(), 0); + assert_eq!(format_args!("{}. 16-bytes piece", {"World"}).estimated_capacity(), 32); } #[test] |
