From c1c27a6cfc662220226d07572992c4a45471ad32 Mon Sep 17 00:00:00 2001 From: Matthew Hughes Date: Fri, 13 Feb 2026 20:26:47 +0000 Subject: [PATCH 1/2] Simplify test case for issue 5023 By replacing the code quoted from the issue with a single comment that more directly exposes the issue. This is to 1. Make the underlying issue easier to reason about 2. Make this test not behave upon the behaviour of indentation length when rewriting lines (my main motivation for this change, since it makes the followup patch simpler) This was tested by partially reverting 368a9b7cef25c22c3e836453e73d8584b251b578 with the patch: diff --git i/src/string.rs w/src/string.rs index 3b971188..561e70ac 100644 --- i/src/string.rs +++ w/src/string.rs @@ -278,9 +278,6 @@ fn break_string(max_width: usize, trim_end: bool, line_end: &str, input: &[&str] } cur_index }; - if max_width_index_in_input == 0 { - return SnippetState::EndOfInput(input.concat()); - } // Find the position in input for breaking the string if line_end.is_empty() The re-running tests, or executing `rustmft` directly on this test, triggered the panic from the original bug. --- tests/source/issue-5023.rs | 29 +++++++++++------------------ tests/target/issue-5023.rs | 30 ++++++++++++------------------ 2 files changed, 23 insertions(+), 36 deletions(-) diff --git a/tests/source/issue-5023.rs b/tests/source/issue-5023.rs index ae1c723eff7..c7c38f1fd0e 100644 --- a/tests/source/issue-5023.rs +++ b/tests/source/issue-5023.rs @@ -1,22 +1,15 @@ // rustfmt-wrap_comments: true +// below we try and force a split at a byte in the middle of a multi-byte +// character. The two parts of the first line are constructed such that: +// 1) the entire line is longer than `$comment_width` +// 2) the length of the second part is such that: +// `$comment_width - 3 + $length` is positive _and_ less than the number of +// bytes in the multi-byte char + +// xxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// 是 + /// A comment to test special unicode characters on boundaries /// 是,是,是,是,是,是,是,是,是,是,是,是 it should break right here this goes to the next line -fn main() { - if xxx { - let xxx = xxx - .into_iter() - .filter(|(xxx, xxx)| { - if let Some(x) = Some(1) { - // xxxxxxxxxxxxxxxxxx, xxxxxxxxxxxx, xxxxxxxxxxxxxxxxxxxx xxx xxxxxxx, xxxxx xxx - // xxxxxxxxxx. xxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxxx xxx xxxxxxx - // 是sdfadsdfxxxxxxxxx,sdfaxxxxxx_xxxxx_masdfaonxxx, - if false { - return true; - } - } - false - }) - .collect(); - } -} +fn main() {} diff --git a/tests/target/issue-5023.rs b/tests/target/issue-5023.rs index 4e84c7d9842..01e52ea3fa1 100644 --- a/tests/target/issue-5023.rs +++ b/tests/target/issue-5023.rs @@ -1,23 +1,17 @@ // rustfmt-wrap_comments: true +// below we try and force a split at a byte in the middle of a multi-byte +// character. The two parts of the first line are constructed such that: +// 1) the entire line is longer than `$comment_width` +// 2) the length of the second part is such that: +// `$comment_width - 3 + $length` is positive _and_ less than the number of +// bytes in the multi-byte char + +// xxxxxxxxxx +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// 是 + /// A comment to test special unicode characters on boundaries /// 是,是,是,是,是,是,是,是,是,是,是,是 it should break right here /// this goes to the next line -fn main() { - if xxx { - let xxx = xxx - .into_iter() - .filter(|(xxx, xxx)| { - if let Some(x) = Some(1) { - // xxxxxxxxxxxxxxxxxx, xxxxxxxxxxxx, xxxxxxxxxxxxxxxxxxxx xxx xxxxxxx, xxxxx xxx - // xxxxxxxxxx. xxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxxx xxx xxxxxxx - // 是sdfadsdfxxxxxxxxx,sdfaxxxxxx_xxxxx_masdfaonxxx, - if false { - return true; - } - } - false - }) - .collect(); - } -} +fn main() {} From fc0c6105f965fd0753ad80189baa9dd2928952d1 Mon Sep 17 00:00:00 2001 From: Matthew Hughes Date: Thu, 12 Feb 2026 21:37:13 +0000 Subject: [PATCH 2/2] Fix wrapping of comments sometimes making too long lines In the case where `comment_width` is less than `max_width` and we want to wrap right on `comment_width`: `rustfmt` would consider it's wrapping length to be exactly `comment_width`, ignoring the length of a trailing indent. The fix is essentially how similar formatting code behaves, see e.g. `shape::Shape::comment`. This involved rewriting some existing tests, without impacting what they're meant to be asserting on. This emphasises that this patch _is not_ backwards compatible: while I believe the change to be correct (some tests had comments longer than `comment_width` that weren't being formatted). So there's a trade-off to be made between correctness and stability, since `comment_width` is still not stabilised this may be acceptable. Issue: #6801 --- src/missed_spans.rs | 2 +- tests/source/issue_6801.rs | 7 +++++++ tests/target/issue_6801.rs | 8 ++++++++ tests/target/trailing_comments/hard_tabs.rs | 8 ++++---- tests/target/trailing_comments/soft_tabs.rs | 8 ++++---- tests/target/unicode.rs | 3 ++- 6 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 tests/source/issue_6801.rs create mode 100644 tests/target/issue_6801.rs diff --git a/src/missed_spans.rs b/src/missed_spans.rs index d394bb40b6d..f93643149d8 100644 --- a/src/missed_spans.rs +++ b/src/missed_spans.rs @@ -263,7 +263,7 @@ impl<'a> FmtVisitor<'a> { }; let comment_width = ::std::cmp::min( - self.config.comment_width(), + self.config.comment_width() - self.block_indent.width(), self.config.max_width() - self.block_indent.width(), ); let comment_shape = Shape::legacy(comment_width, comment_indent); diff --git a/tests/source/issue_6801.rs b/tests/source/issue_6801.rs new file mode 100644 index 00000000000..3c26a4e579e --- /dev/null +++ b/tests/source/issue_6801.rs @@ -0,0 +1,7 @@ +// rustfmt-wrap_comments: true + +fn foo() { + // this is a comment that could be broken right on max_comment and should break before that + + () +} diff --git a/tests/target/issue_6801.rs b/tests/target/issue_6801.rs new file mode 100644 index 00000000000..d3a3bb27f45 --- /dev/null +++ b/tests/target/issue_6801.rs @@ -0,0 +1,8 @@ +// rustfmt-wrap_comments: true + +fn foo() { + // this is a comment that could be broken right on max_comment and should + // break before that + + () +} diff --git a/tests/target/trailing_comments/hard_tabs.rs b/tests/target/trailing_comments/hard_tabs.rs index e7009ac00c0..8135b1a8caf 100644 --- a/tests/target/trailing_comments/hard_tabs.rs +++ b/tests/target/trailing_comments/hard_tabs.rs @@ -18,10 +18,10 @@ fn lorem_ipsum() { // nunc. Mauris consequat, enim vitae venenatis sollicitudin, dolor orci // bibendum enim, a sagittis nulla nunc quis elit. Phasellus augue. Nunc // suscipit, magna tincidunt lacinia faucibus, lacus tellus ornare purus, a - // pulvinar lacus orci eget nibh. Maecenas sed nibh non lacus tempor faucibus. - // In hac habitasse platea dictumst. Vivamus a orci at nulla tristique - // condimentum. Donec arcu quam, dictum accumsan, convallis accumsan, cursus sit - // amet, ipsum. In pharetra sagittis nunc. + // pulvinar lacus orci eget nibh. Maecenas sed nibh non lacus tempor + // faucibus. In hac habitasse platea dictumst. Vivamus a orci at nulla + // tristique condimentum. Donec arcu quam, dictum accumsan, convallis + // accumsan, cursus sit amet, ipsum. In pharetra sagittis nunc. let b = baz(); let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0] diff --git a/tests/target/trailing_comments/soft_tabs.rs b/tests/target/trailing_comments/soft_tabs.rs index 34cfed1a229..3e2dbc1bb7d 100644 --- a/tests/target/trailing_comments/soft_tabs.rs +++ b/tests/target/trailing_comments/soft_tabs.rs @@ -18,10 +18,10 @@ fn foo() { // nunc. Mauris consequat, enim vitae venenatis sollicitudin, dolor orci // bibendum enim, a sagittis nulla nunc quis elit. Phasellus augue. Nunc // suscipit, magna tincidunt lacinia faucibus, lacus tellus ornare purus, a - // pulvinar lacus orci eget nibh. Maecenas sed nibh non lacus tempor faucibus. - // In hac habitasse platea dictumst. Vivamus a orci at nulla tristique - // condimentum. Donec arcu quam, dictum accumsan, convallis accumsan, cursus sit - // amet, ipsum. In pharetra sagittis nunc. + // pulvinar lacus orci eget nibh. Maecenas sed nibh non lacus tempor + // faucibus. In hac habitasse platea dictumst. Vivamus a orci at nulla + // tristique condimentum. Donec arcu quam, dictum accumsan, convallis + // accumsan, cursus sit amet, ipsum. In pharetra sagittis nunc. let b = baz(); let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0] diff --git a/tests/target/unicode.rs b/tests/target/unicode.rs index 34a4f463479..610e482d6b4 100644 --- a/tests/target/unicode.rs +++ b/tests/target/unicode.rs @@ -4,7 +4,8 @@ fn foo() { let s = "this line goes to 100: ͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶ"; let s = 42; - // a comment of length 80, with the starting sigil: ҘҘҘҘҘҘҘҘҘҘ ҘҘҘҘҘҘҘҘҘҘҘҘҘҘ + // a comment of length 80, with the starting sigil: ҘҘҘҘҘҘҘҘҘҘ + // ҘҘҘҘҘҘҘҘҘҘҘҘҘҘ let s = 42; }