Skip to content

Commit b6c988b

Browse files
committed
Fix argument index remapping in format_args flattening.
1 parent b7678d4 commit b6c988b

File tree

1 file changed

+36
-28
lines changed

1 file changed

+36
-28
lines changed

compiler/rustc_ast_lowering/src/format.rs

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -68,33 +68,21 @@ fn flatten_format_args(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
6868
args.extend(remaining_args);
6969

7070
// Correct the indexes that refer to the arguments after the newly inserted arguments.
71-
for piece in &mut fmt.template {
72-
if let FormatArgsPiece::Placeholder(placeholder) = piece
73-
&& let Ok(index) = &mut placeholder.argument.index
74-
&& *index >= old_arg_offset
75-
{
71+
for_all_argument_indexes(&mut fmt.template, |index| {
72+
if *index >= old_arg_offset {
7673
*index -= old_arg_offset;
7774
*index += new_arg_offset;
7875
}
79-
}
76+
});
8077

8178
// Now merge the placeholders:
8279

8380
let rest = fmt.template.split_off(i + 1);
8481
fmt.template.pop(); // remove the placeholder for the nested fmt args.
85-
86-
for piece in fmt2.template.drain(..) {
87-
match piece {
88-
FormatArgsPiece::Literal(s) => fmt.template.push(FormatArgsPiece::Literal(s)),
89-
FormatArgsPiece::Placeholder(mut p) => {
90-
// Correct the index to refer to the right place into the outer argument list.
91-
if let Ok(n) = &mut p.argument.index {
92-
*n += arg_index;
93-
}
94-
fmt.template.push(FormatArgsPiece::Placeholder(p));
95-
}
96-
}
97-
}
82+
// Insert the pieces from the nested format args, but correct any
83+
// placeholders to point to the correct argument index.
84+
for_all_argument_indexes(&mut fmt2.template, |index| *index += arg_index);
85+
fmt.template.append(&mut fmt2.template);
9886
fmt.template.extend(rest);
9987

10088
// Don't increment `i` here, so we recurse into the newly added pieces.
@@ -150,16 +138,17 @@ fn inline_literals(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
150138
// Drop all the arguments that are marked for removal.
151139
let mut remove_it = remove.iter();
152140
fmt.arguments.all_args_mut().retain(|_| remove_it.next() != Some(&Some(true)));
141+
// Calculate the mapping of old to new indexes for the remaining arguments.
142+
let index_map: Vec<usize> = remove
143+
.into_iter()
144+
.scan(0, |i, remove| {
145+
let mapped = *i;
146+
*i += (remove != Some(true)) as usize;
147+
Some(mapped)
148+
})
149+
.collect();
153150
// Correct the indexes that refer to arguments that have shifted position.
154-
for piece in &mut fmt.template {
155-
let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
156-
let Ok(arg_index) = &mut placeholder.argument.index else { continue };
157-
for i in 0..*arg_index {
158-
if remove[i] == Some(true) {
159-
*arg_index -= 1;
160-
}
161-
}
162-
}
151+
for_all_argument_indexes(&mut fmt.template, |index| *index = index_map[*index]);
163152
}
164153

165154
fmt
@@ -572,3 +561,22 @@ fn may_contain_yield_point(e: &ast::Expr) -> bool {
572561
visitor.visit_expr(e);
573562
visitor.0
574563
}
564+
565+
fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) {
566+
for piece in template {
567+
let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
568+
if let Ok(index) = &mut placeholder.argument.index {
569+
f(index);
570+
}
571+
if let Some(FormatCount::Argument(FormatArgPosition { index: Ok(index), .. })) =
572+
&mut placeholder.format_options.width
573+
{
574+
f(index);
575+
}
576+
if let Some(FormatCount::Argument(FormatArgPosition { index: Ok(index), .. })) =
577+
&mut placeholder.format_options.precision
578+
{
579+
f(index);
580+
}
581+
}
582+
}

0 commit comments

Comments
 (0)