Skip to content

Commit d93f90b

Browse files
committed
Prevent ICE when formatting braced vec!... (rust-lang#5735)
... when it contains only items. Fixes 5735 Attemtping 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 trigger an ICE in rustfmt. This is because the function that handles formatting macro invocations containing only items, `rewrite_macro_with_items`, assumes that the 'new' delimiter style of the macro being formatted is the same as the delimiter style in the 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 a72613b commit d93f90b

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
);
@@ -1378,23 +1379,33 @@ fn rewrite_macro_with_items(
13781379
macro_name: &str,
13791380
shape: Shape,
13801381
style: Delimiter,
1382+
original_style: Delimiter,
13811383
position: MacroPosition,
13821384
span: Span,
13831385
) -> Option<String> {
1384-
let (opener, closer) = match style {
1385-
Delimiter::Parenthesis => ("(", ")"),
1386-
Delimiter::Bracket => ("[", "]"),
1387-
Delimiter::Brace => (" {", "}"),
1388-
_ => return None,
1386+
let style_to_delims = |style| match style {
1387+
Delimiter::Parenthesis => Some(("(", ")")),
1388+
Delimiter::Bracket => Some(("[", "]")),
1389+
Delimiter::Brace => Some((" {", "}")),
1390+
_ => None,
13891391
};
1392+
1393+
let (opener, closer) = style_to_delims(style)?;
1394+
let (original_opener, _) = style_to_delims(original_style)?;
13901395
let trailing_semicolon = match style {
13911396
Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
13921397
_ => "",
13931398
};
13941399

13951400
let mut visitor = FmtVisitor::from_context(context);
13961401
visitor.block_indent = shape.indent.block_indent(context.config);
1397-
visitor.last_pos = context.snippet_provider.span_after(span, opener.trim());
1402+
1403+
// The current opener may be different from the original opener. This can happen
1404+
// if our macro is a forced bracket macro originally written with non-bracket
1405+
// delimiters. We need to use the original opener to locate the span after it.
1406+
visitor.last_pos = context
1407+
.snippet_provider
1408+
.span_after(span, original_opener.trim());
13981409
for item in items {
13991410
let item = match item {
14001411
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)