Skip to content

Commit e480739

Browse files
authored
Prevent ICE when formatting item-only vec!{} (#5879)
* Prevent ICE when formatting item-only `vec!{}` Fixes 5735 Attempting to format invocations of macros which are considered "forced bracket macros" (currently only `vec!`), but are invoked with braces instead of brackets, and contain only items in their token trees, currently triggers an ICE in rustfmt. This is because the function that handles formatting macro invocations containing only items, `rewrite_macro_with_items`, assumes that the forced delimiter style of the macro being formatted is the same as the delimiter style in the macro's source text when attempting to locate the span after the macro's opening delimiter. This leads to the construction of an invalid span, triggering the ICE. The fix here is to pass the old delimiter style to `rewrite_macro_with_items` as well, so that it can successfully locate the span.
1 parent a57d57b commit e480739

File tree

3 files changed

+31
-9
lines changed

3 files changed

+31
-9
lines changed

src/macros.rs

+19-9
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ fn rewrite_macro_inner(
255255
&macro_name,
256256
shape,
257257
style,
258+
original_style,
258259
position,
259260
mac.span(),
260261
);
@@ -295,20 +296,19 @@ fn rewrite_macro_inner(
295296
// If we are rewriting `vec!` macro or other special macros,
296297
// then we can rewrite this as a usual array literal.
297298
// Otherwise, we must preserve the original existence of trailing comma.
298-
let macro_name = &macro_name.as_str();
299299
let mut force_trailing_comma = if trailing_comma {
300300
Some(SeparatorTactic::Always)
301301
} else {
302302
Some(SeparatorTactic::Never)
303303
};
304-
if FORCED_BRACKET_MACROS.contains(macro_name) && !is_nested_macro {
304+
if is_forced_bracket && !is_nested_macro {
305305
context.leave_macro();
306306
if context.use_block_indent() {
307307
force_trailing_comma = Some(SeparatorTactic::Vertical);
308308
};
309309
}
310310
let rewrite = rewrite_array(
311-
macro_name,
311+
&macro_name,
312312
arg_vec.iter(),
313313
mac.span(),
314314
context,
@@ -1402,23 +1402,33 @@ fn rewrite_macro_with_items(
14021402
macro_name: &str,
14031403
shape: Shape,
14041404
style: Delimiter,
1405+
original_style: Delimiter,
14051406
position: MacroPosition,
14061407
span: Span,
14071408
) -> Option<String> {
1408-
let (opener, closer) = match style {
1409-
Delimiter::Parenthesis => ("(", ")"),
1410-
Delimiter::Bracket => ("[", "]"),
1411-
Delimiter::Brace => (" {", "}"),
1412-
_ => return None,
1409+
let style_to_delims = |style| match style {
1410+
Delimiter::Parenthesis => Some(("(", ")")),
1411+
Delimiter::Bracket => Some(("[", "]")),
1412+
Delimiter::Brace => Some((" {", "}")),
1413+
_ => None,
14131414
};
1415+
1416+
let (opener, closer) = style_to_delims(style)?;
1417+
let (original_opener, _) = style_to_delims(original_style)?;
14141418
let trailing_semicolon = match style {
14151419
Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
14161420
_ => "",
14171421
};
14181422

14191423
let mut visitor = FmtVisitor::from_context(context);
14201424
visitor.block_indent = shape.indent.block_indent(context.config);
1421-
visitor.last_pos = context.snippet_provider.span_after(span, opener.trim());
1425+
1426+
// The current opener may be different from the original opener. This can happen
1427+
// if our macro is a forced bracket macro originally written with non-bracket
1428+
// delimiters. We need to use the original opener to locate the span after it.
1429+
visitor.last_pos = context
1430+
.snippet_provider
1431+
.span_after(span, original_opener.trim());
14221432
for item in items {
14231433
let item = match item {
14241434
MacroArg::Item(item) => item,

tests/source/issue_5735.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fn find_errors(mut self) {
2+
let errors: Vec<> = vec!{
3+
#[debug_format = "A({})"]
4+
struct A {}
5+
};
6+
}

tests/target/issue_5735.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fn find_errors(mut self) {
2+
let errors: Vec = vec![
3+
#[debug_format = "A({})"]
4+
struct A {}
5+
];
6+
}

0 commit comments

Comments
 (0)