From 94c0faf330b354940e52baa9c54e92011f5fd77e Mon Sep 17 00:00:00 2001 From: Travis Danniels Date: Fri, 4 Aug 2023 17:55:48 -0700 Subject: [PATCH 1/2] 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. --- src/macros.rs | 23 +++++++++++++++++------ tests/source/issue_5735.rs | 6 ++++++ tests/target/issue_5735.rs | 6 ++++++ 3 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 tests/source/issue_5735.rs create mode 100644 tests/target/issue_5735.rs diff --git a/src/macros.rs b/src/macros.rs index b6a49536d17..e15b2e03970 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -255,6 +255,7 @@ fn rewrite_macro_inner( ¯o_name, shape, style, + original_style, position, mac.span(), ); @@ -1402,15 +1403,19 @@ fn rewrite_macro_with_items( macro_name: &str, shape: Shape, style: Delimiter, + original_style: Delimiter, position: MacroPosition, span: Span, ) -> Option { - 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 => ";", _ => "", @@ -1418,7 +1423,13 @@ fn rewrite_macro_with_items( 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, diff --git a/tests/source/issue_5735.rs b/tests/source/issue_5735.rs new file mode 100644 index 00000000000..7708d028bf5 --- /dev/null +++ b/tests/source/issue_5735.rs @@ -0,0 +1,6 @@ +fn find_errors(mut self) { + let errors: Vec<> = vec!{ + #[debug_format = "A({})"] + struct A {} + }; +} diff --git a/tests/target/issue_5735.rs b/tests/target/issue_5735.rs new file mode 100644 index 00000000000..2d1376303f5 --- /dev/null +++ b/tests/target/issue_5735.rs @@ -0,0 +1,6 @@ +fn find_errors(mut self) { + let errors: Vec = vec![ + #[debug_format = "A({})"] + struct A {} + ]; +} From a42faa5ddb46681c0b50642886f7a6a58593de3a Mon Sep 17 00:00:00 2001 From: Travis Danniels Date: Fri, 4 Aug 2023 18:04:24 -0700 Subject: [PATCH 2/2] Clean up a little redundancy --- src/macros.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index e15b2e03970..8047ab03687 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -296,20 +296,19 @@ fn rewrite_macro_inner( // If we are rewriting `vec!` macro or other special macros, // then we can rewrite this as a usual array literal. // Otherwise, we must preserve the original existence of trailing comma. - let macro_name = ¯o_name.as_str(); let mut force_trailing_comma = if trailing_comma { Some(SeparatorTactic::Always) } else { Some(SeparatorTactic::Never) }; - if FORCED_BRACKET_MACROS.contains(macro_name) && !is_nested_macro { + if is_forced_bracket && !is_nested_macro { context.leave_macro(); if context.use_block_indent() { force_trailing_comma = Some(SeparatorTactic::Vertical); }; } let rewrite = rewrite_array( - macro_name, + ¯o_name, arg_vec.iter(), mac.span(), context,