Skip to content

Commit 94c0faf

Browse files
committed
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 94c0faf

File tree

3 files changed

+29
-6
lines changed

3 files changed

+29
-6
lines changed

src/macros.rs

Lines changed: 17 additions & 6 deletions
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
);
@@ -1402,23 +1403,33 @@ fn rewrite_macro_with_items(
14021403
macro_name: &str,
14031404
shape: Shape,
14041405
style: Delimiter,
1406+
original_style: Delimiter,
14051407
position: MacroPosition,
14061408
span: Span,
14071409
) -> Option<String> {
1408-
let (opener, closer) = match style {
1409-
Delimiter::Parenthesis => ("(", ")"),
1410-
Delimiter::Bracket => ("[", "]"),
1411-
Delimiter::Brace => (" {", "}"),
1412-
_ => return None,
1410+
let style_to_delims = |style| match style {
1411+
Delimiter::Parenthesis => Some(("(", ")")),
1412+
Delimiter::Bracket => Some(("[", "]")),
1413+
Delimiter::Brace => Some((" {", "}")),
1414+
_ => None,
14131415
};
1416+
1417+
let (opener, closer) = style_to_delims(style)?;
1418+
let (original_opener, _) = style_to_delims(original_style)?;
14141419
let trailing_semicolon = match style {
14151420
Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
14161421
_ => "",
14171422
};
14181423

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

tests/source/issue_5735.rs

Lines changed: 6 additions & 0 deletions
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

Lines changed: 6 additions & 0 deletions
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)