Skip to content

Commit

Permalink
Prevent ICE when formatting braced vec!... (rust-lang#5735)
Browse files Browse the repository at this point in the history
... 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.
  • Loading branch information
tdanniels committed Aug 5, 2023
1 parent a72613b commit d93f90b
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 6 deletions.
23 changes: 17 additions & 6 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ fn rewrite_macro_inner(
&macro_name,
shape,
style,
original_style,
position,
mac.span(),
);
Expand Down Expand Up @@ -1378,23 +1379,33 @@ fn rewrite_macro_with_items(
macro_name: &str,
shape: Shape,
style: Delimiter,
original_style: Delimiter,
position: MacroPosition,
span: Span,
) -> Option<String> {
let (opener, closer) = match style {
Delimiter::Parenthesis => ("(", ")"),
Delimiter::Bracket => ("[", "]"),
Delimiter::Brace => (" {", "}"),
_ => return None,
let style_to_delims = |style| match style {
Delimiter::Parenthesis => Some(("(", ")")),
Delimiter::Bracket => Some(("[", "]")),
Delimiter::Brace => Some((" {", "}")),
_ => None,
};

let (opener, closer) = style_to_delims(style)?;
let (original_opener, _) = style_to_delims(original_style)?;
let trailing_semicolon = match style {
Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
_ => "",
};

let mut visitor = FmtVisitor::from_context(context);
visitor.block_indent = shape.indent.block_indent(context.config);
visitor.last_pos = context.snippet_provider.span_after(span, opener.trim());

// The current opener may be different from the original opener. This can happen
// if our macro is a forced bracket macro originally written with non-bracket
// delimiters. We need to use the original opener to locate the span after it.
visitor.last_pos = context
.snippet_provider
.span_after(span, original_opener.trim());
for item in items {
let item = match item {
MacroArg::Item(item) => item,
Expand Down
6 changes: 6 additions & 0 deletions tests/source/issue_5735.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fn find_errors(mut self) {
let errors: Vec<> = vec!{
#[debug_format = "A({})"]
struct A {}
};
}
6 changes: 6 additions & 0 deletions tests/target/issue_5735.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fn find_errors(mut self) {
let errors: Vec = vec![
#[debug_format = "A({})"]
struct A {}
];
}

0 comments on commit d93f90b

Please sign in to comment.