about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-03-16 13:46:52 +0000
committerbors <bors@rust-lang.org>2023-03-16 13:46:52 +0000
commit1203e0866e6c3659775efcb8aecad21dc13ef38b (patch)
tree649280a25f8efd4058120de4a4e104959b83e3f4 /src
parent7ac4b82ddd596a218cac8cd6b88a91b54fcdcf13 (diff)
parenta08016514847d39ae3096ff41f98759abf59bee8 (diff)
downloadrust-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 'src')
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs21
1 files changed, 17 insertions, 4 deletions
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index e135bd9feee..c0e32068eca 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -533,6 +533,14 @@ struct FormatArgsValues<'tcx> {
 }
 
 impl<'tcx> FormatArgsValues<'tcx> {
+    fn new_empty(format_string_span: SpanData) -> Self {
+        Self {
+            value_args: Vec::new(),
+            pos_to_value_index: Vec::new(),
+            format_string_span,
+        }
+    }
+
     fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self {
         let mut pos_to_value_index = Vec::new();
         let mut value_args = Vec::new();
@@ -997,12 +1005,13 @@ impl<'tcx> FormatArgsExpn<'tcx> {
             .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?;
         let newline = macro_name == sym::format_args_nl;
 
+        // ::core::fmt::Arguments::new_const(pieces)
         // ::core::fmt::Arguments::new_v1(pieces, args)
         // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
-        if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
+        if let ExprKind::Call(callee, [pieces, rest @ ..]) = expr.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
             && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind
-            && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
+            && matches!(seg.ident.as_str(), "new_const" | "new_v1" | "new_v1_formatted")
         {
             let format_string = FormatString::new(cx, pieces)?;
 
@@ -1026,7 +1035,7 @@ impl<'tcx> FormatArgsExpn<'tcx> {
                 return None;
             }
 
-            let positions = if let Some(fmt_arg) = rest.first() {
+            let positions = if let Some(fmt_arg) = rest.get(1) {
                 // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse
                 // them.
 
@@ -1042,7 +1051,11 @@ impl<'tcx> FormatArgsExpn<'tcx> {
                 }))
             };
 
-            let values = FormatArgsValues::new(args, format_string.span.data());
+            let values = if let Some(args) = rest.first() {
+                FormatArgsValues::new(args, format_string.span.data())
+            } else {
+                FormatArgsValues::new_empty(format_string.span.data())
+            };
 
             let args = izip!(positions, parsed_args, parser.arg_places)
                 .map(|(position, parsed_arg, arg_span)| {