Skip to content

Commit ae238ef

Browse files
committed
Prefer new_v1_formatted instead of new_v1 with duplicates.
1 parent 0007492 commit ae238ef

File tree

1 file changed

+33
-36
lines changed
  • compiler/rustc_builtin_macros/src/format

1 file changed

+33
-36
lines changed

compiler/rustc_builtin_macros/src/format/expand.rs

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -164,18 +164,32 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
164164
.collect(),
165165
);
166166

167-
let has_any_format_options = fmt.template.iter().any(|piece| {
168-
let FormatArgsPiece::Placeholder(placeholder) = piece else { return false };
169-
placeholder.format_options != Default::default()
170-
});
167+
// Whether we'll use the `Arguments::new_v1_formatted` form (true),
168+
// or the `Arguments::new_v1` form (false).
169+
let mut use_format_options = false;
171170

172-
let (args, format_options) = if has_any_format_options {
173-
// Create a list of all _unique_ (argument, format trait) combinations.
174-
// E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
175-
let mut argmap = FxIndexSet::default();
171+
// Create a list of all _unique_ (argument, format trait) combinations.
172+
// E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
173+
let mut argmap = FxIndexSet::default();
174+
for piece in &fmt.template {
175+
let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
176+
if placeholder.format_options != Default::default() {
177+
// Can't use basic form if there's any formatting options.
178+
use_format_options = true;
179+
}
180+
if let Ok(index) = placeholder.argument.index {
181+
if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) {
182+
// Duplicate (argument, format trait) combination,
183+
// which we'll only put once in the args array.
184+
use_format_options = true;
185+
}
186+
}
187+
}
188+
189+
let format_options = use_format_options.then(|| {
176190
// Generate:
177191
// &[format_spec_0, format_spec_1, format_spec_2]
178-
let format_options = ecx.expr_array_ref(
192+
ecx.expr_array_ref(
179193
macsp,
180194
fmt.template
181195
.iter()
@@ -184,34 +198,18 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
184198
Some(make_format_spec(ecx, macsp, placeholder, &mut argmap))
185199
})
186200
.collect(),
187-
);
188-
(Vec::from_iter(argmap), Some(format_options))
189-
} else {
190-
// Create a list of all (argument, format trait) pairs, one for each placeholder.
191-
// E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (0, Display), (1, Display)]
192-
let args = fmt
193-
.template
194-
.iter()
195-
.filter_map(|piece| {
196-
let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
197-
Some((
198-
placeholder.argument.index.ok()?,
199-
ArgumentType::Format(placeholder.format_trait),
200-
))
201-
})
202-
.collect();
203-
(args, None)
204-
};
201+
)
202+
});
205203

206204
// If the args array contains exactly all the original arguments once,
207205
// in order, we can use a simple array instead of a `match` construction.
208206
// However, if there's a yield point in any argument except the first one,
209207
// we don't do this, because an ArgumentV1 cannot be kept across yield points.
210-
let use_simple_array = args.len() == fmt.arguments.len()
211-
&& args.iter().enumerate().all(|(i, &(j, _))| i == j)
208+
let use_simple_array = argmap.len() == fmt.arguments.len()
209+
&& argmap.iter().enumerate().all(|(i, &(j, _))| i == j)
212210
&& fmt.arguments.iter().skip(1).all(|(arg, _)| !may_contain_yield_point(arg));
213211

214-
let args_expr = if use_simple_array {
212+
let args = if use_simple_array {
215213
// Generate:
216214
// &[
217215
// ::core::fmt::ArgumentV1::new_display(&arg0),
@@ -222,7 +220,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
222220
macsp,
223221
fmt.arguments
224222
.into_iter()
225-
.zip(args)
223+
.zip(argmap)
226224
.map(|((arg, _), (_, ty))| {
227225
let sp = arg.span.with_ctxt(macsp.ctxt());
228226
make_argument(ecx, sp, ecx.expr_addr_of(sp, arg), ty)
@@ -239,7 +237,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
239237
// ]
240238
// }
241239
let args_ident = Ident::new(sym::args, macsp);
242-
let args = args
240+
let args = argmap
243241
.iter()
244242
.map(|&(arg_index, ty)| {
245243
if let Some((arg, _)) = fmt.arguments.get(arg_index) {
@@ -270,8 +268,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
270268
.map(|(arg, _)| ecx.expr_addr_of(arg.span.with_ctxt(macsp.ctxt()), arg))
271269
.collect(),
272270
),
273-
[ecx.arm(macsp, ecx.pat_ident(macsp, args_ident), ecx.expr_array(macsp, args))]
274-
.into(),
271+
vec![ecx.arm(macsp, ecx.pat_ident(macsp, args_ident), ecx.expr_array(macsp, args))],
275272
),
276273
)
277274
};
@@ -289,7 +286,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
289286
ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1_formatted]),
290287
vec![
291288
lit_pieces,
292-
args_expr,
289+
args,
293290
format_options,
294291
ecx.expr_block(P(ast::Block {
295292
stmts: vec![ecx.stmt_expr(ecx.expr_call_global(
@@ -314,7 +311,7 @@ pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<as
314311
ecx.expr_call_global(
315312
macsp,
316313
ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1]),
317-
vec![lit_pieces, args_expr],
314+
vec![lit_pieces, args],
318315
)
319316
}
320317
}

0 commit comments

Comments
 (0)