Repository: rust-lang/rustfmt (rust)

Issue:
ICE panicked at 'begin <= end (12 <= 11) when slicing `fn main() {}`''
````rust
macro_rules! statement {
    () => {;};
}
````

```
thread 'main' panicked at 'begin <= end (12 <= 11) when slicing `fn main() {}
`', src/tools/rustfmt/src/lib.rs:393:47
stack backtrace:
   0:     0x7f4cbdd65e8a - std::backtrace_rs::backtrace::libunwind::trace::hc07ec51854030801
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
   1:     0x7f4cbdd65e8a - std::backtrace_rs::backtrace::trace_unsynchronized::hd5249f53d09c2c41
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:     0x7f4cbdd65e8a - std::sys_common::backtrace::_print_fmt::h7a58bb30aee44196
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/sys_common/backtrace.rs:65:5
   3:     0x7f4cbdd65e8a - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h4f2b7c295e3f8019
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/sys_common/backtrace.rs:44:22
   4:     0x7f4cbddc9e6f - core::fmt::write::h10777037b979b8b8
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/core/src/fmt/mod.rs:1254:17
   5:     0x7f4cbdd58ac5 - std::io::Write::write_fmt::he1dc4aa4bd2563db
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/io/mod.rs:1698:15
   6:     0x7f4cbdd65c55 - std::sys_common::backtrace::_print::h163c7799d3150ce8
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/sys_common/backtrace.rs:47:5
   7:     0x7f4cbdd65c55 - std::sys_common::backtrace::print::h3cf13564ddfd5c0e
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/sys_common/backtrace.rs:34:9
   8:     0x7f4cbdd688fe - std::panicking::default_hook::{{closure}}::h999811fec35f64bf
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panicking.rs:269:22
   9:     0x7f4cbdd686a5 - std::panicking::default_hook::he182d48ca482e8b2
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panicking.rs:288:9
  10:     0x7f4cbdd68f6e - std::panicking::rust_panic_with_hook::h2bc066147eaf9845
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panicking.rs:690:13
  11:     0x7f4cbdd68e69 - std::panicking::begin_panic_handler::{{closure}}::h1e4368c427832fe9
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panicking.rs:581:13
  12:     0x7f4cbdd662f6 - std::sys_common::backtrace::__rust_end_short_backtrace::h5466480ef33b438e
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/sys_common/backtrace.rs:150:18
  13:     0x7f4cbdd68bc2 - rust_begin_unwind
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panicking.rs:577:5
  14:     0x7f4cbddc6273 - core::panicking::panic_fmt::ha28b6d803d12671b
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/core/src/panicking.rs:67:14
  15:     0x7f4cbddcf28f - core::str::slice_error_fail_rt::h8157873ce0ac4c9d
  16:     0x7f4cbddcf0d7 - core::str::slice_error_fail::hc96d17d855cd472b
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/core/src/str/mod.rs:86:9
  17:     0x55ba79b8707a - rustfmt_nightly[e3445ded4feb3b46]::format_code_block
  18:     0x55ba79a92c28 - <rustfmt_nightly[e3445ded4feb3b46]::macros::MacroBranch>::rewrite
  19:     0x55ba79ab645d - <rustfmt_nightly[e3445ded4feb3b46]::lists::ListItems<core[a19e7c0c634483f1]::slice::iter::Iter<rustfmt_nightly[e3445ded4feb3b46]::macros::MacroBranch>, rustfmt_nightly[e3445ded4feb3b46]::macros::rewrite_macro_def::{closure#1}, rustfmt_nightly[e3445ded4feb3b46]::macros::rewrite_macro_def::{closure#2}, rustfmt_nightly[e3445ded4feb3b46]::macros::rewrite_macro_def::{closure#3}> as core[a19e7c0c634483f1]::iter::traits::iterator::Iterator>::next
  20:     0x55ba79b2db01 - <alloc[827ef145a957661e]::vec::Vec<rustfmt_nightly[e3445ded4feb3b46]::lists::ListItem> as alloc[827ef145a957661e]::vec::spec_from_iter::SpecFromIter<rustfmt_nightly[e3445ded4feb3b46]::lists::ListItem, rustfmt_nightly[e3445ded4feb3b46]::lists::ListItems<core[a19e7c0c634483f1]::slice::iter::Iter<rustfmt_nightly[e3445ded4feb3b46]::macros::MacroBranch>, rustfmt_nightly[e3445ded4feb3b46]::macros::rewrite_macro_def::{closure#1}, rustfmt_nightly[e3445ded4feb3b46]::macros::rewrite_macro_def::{closure#2}, rustfmt_nightly[e3445ded4feb3b46]::macros::rewrite_macro_def::{closure#3}>>>::from_iter
  21:     0x55ba79a8b843 - rustfmt_nightly[e3445ded4feb3b46]::macros::rewrite_macro_def
  22:     0x55ba79b4ff0a - <rustfmt_nightly[e3445ded4feb3b46]::visitor::FmtVisitor>::visit_item
  23:     0x55ba79b45049 - <rustfmt_nightly[e3445ded4feb3b46]::visitor::FmtVisitor>::visit_items_with_reordering
  24:     0x55ba79b5543f - <rustfmt_nightly[e3445ded4feb3b46]::visitor::FmtVisitor>::walk_mod_items
  25:     0x55ba79b56037 - <rustfmt_nightly[e3445ded4feb3b46]::visitor::FmtVisitor>::format_separate_mod
  26:     0x55ba799da9c5 - rustfmt_nightly[e3445ded4feb3b46]::formatting::format_project::<rustfmt_nightly[e3445ded4feb3b46]::Session<std[6ff7f37a454f70cc]::io::stdio::Stdout>>
  27:     0x55ba799d79d0 - <scoped_tls[abd3470abb840dd8]::ScopedKey<rustc_span[e810f079a636b72c]::SessionGlobals>>::with::<<rustfmt_nightly[e3445ded4feb3b46]::Session<std[6ff7f37a454f70cc]::io::stdio::Stdout>>::format_input_inner::{closure#0}, core[a19e7c0c634483f1]::result::Result<rustfmt_nightly[e3445ded4feb3b46]::FormatReport, rustfmt_nightly[e3445ded4feb3b46]::ErrorKind>>
  28:     0x55ba799d4a7f - <scoped_tls[abd3470abb840dd8]::ScopedKey<rustc_span[e810f079a636b72c]::SessionGlobals>>::set::<rustc_span[e810f079a636b72c]::create_session_if_not_set_then<core[a19e7c0c634483f1]::result::Result<rustfmt_nightly[e3445ded4feb3b46]::FormatReport, rustfmt_nightly[e3445ded4feb3b46]::ErrorKind>, <rustfmt_nightly[e3445ded4feb3b46]::Session<std[6ff7f37a454f70cc]::io::stdio::Stdout>>::format_input_inner::{closure#0}>::{closure#0}, core[a19e7c0c634483f1]::result::Result<rustfmt_nightly[e3445ded4feb3b46]::FormatReport, rustfmt_nightly[e3445ded4feb3b46]::ErrorKind>>
  29:     0x55ba799fd650 - <rustfmt_nightly[e3445ded4feb3b46]::Session<std[6ff7f37a454f70cc]::io::stdio::Stdout>>::format
  30:     0x55ba799ecb05 - rustfmt[fd29d8685e71f599]::format_and_emit_report::<std[6ff7f37a454f70cc]::io::stdio::Stdout>
  31:     0x55ba799fbb89 - <rustfmt_nightly[e3445ded4feb3b46]::Session<std[6ff7f37a454f70cc]::io::stdio::Stdout>>::override_config::<rustfmt[fd29d8685e71f599]::format::{closure#0}, ()>
  32:     0x55ba799eb865 - rustfmt[fd29d8685e71f599]::execute
  33:     0x55ba799e9221 - rustfmt[fd29d8685e71f599]::main
  34:     0x55ba799fc483 - std[6ff7f37a454f70cc]::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()>
  35:     0x55ba799facc9 - std[6ff7f37a454f70cc]::rt::lang_start::<()>::{closure#0}
  36:     0x7f4cbdd4969e - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::hd8ec26e1d0256733
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/core/src/ops/function.rs:287:13
  37:     0x7f4cbdd4969e - std::panicking::try::do_call::ha93a022fbffe13f1
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panicking.rs:485:40
  38:     0x7f4cbdd4969e - std::panicking::try::hb1493baa50505ff7
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panicking.rs:449:19
  39:     0x7f4cbdd4969e - std::panic::catch_unwind::h68d19a9efbc50ca2
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panic.rs:140:14
  40:     0x7f4cbdd4969e - std::rt::lang_start_internal::{{closure}}::hfefbc424423bf0ab
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/rt.rs:148:48
  41:     0x7f4cbdd4969e - std::panicking::try::do_call::h33a3e76f78055d3b
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panicking.rs:485:40
  42:     0x7f4cbdd4969e - std::panicking::try::hf16a19af84a23805
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panicking.rs:449:19
  43:     0x7f4cbdd4969e - std::panic::catch_unwind::hfd39d2618b0c9350
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/panic.rs:140:14
  44:     0x7f4cbdd4969e - std::rt::lang_start_internal::h8eb39434a671d889
                               at /rustc/17c11672167827b0dd92c88ef69f24346d1286dd/library/std/src/rt.rs:148:20
  45:     0x55ba799ed8a5 - main
  46:     0x7f4cbd9c3790 - <unknown>
  47:     0x7f4cbd9c384a - __libc_start_main
  48:     0x55ba799d0c59 - <unknown>
  49:                0x0 - <unknown>
```

Pull request description:
Prevent ICE when formatting an empty-ish macro arm
Fixes #5730

Previously rustfmt was attempting to slice a string with an invalid range (`start > end`), leading to the ICE.

When formatting a macro transcriber snippet consisting of a lone semicolon, the snippet was being formatted into the empty string, leading the enclosing `fn main() {\n}` added by `format_code_block` to be formatted into `fn main() {}`. However, rustfmt was assuming that the enclosing function string's length had been left unchanged. This was leading to an invalid range being constructed when attempting to trim off the enclosing function.

The fix is to just clamp the range's start to be less than or equal to the range's end, since if `end < start` there's nothing to iterate over anyway.

---

Hi rustfmt'ers! This is my first PR to the project. I'm still not too familiar with the codebase, so hopefully I'm doing this right. Any feedback is welcome.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 34fcd9a8..22f183c0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,7 +19,7 @@
 
 - When formatting doc comments with `wrap_comments = true` rustfmt will no longer wrap markdown tables [#4210](https://github.com/rust-lang/rustfmt/issues/4210)
 - Properly handle wrapping comments that include a numbered list in markdown [#5416](https://github.com/rust-lang/rustfmt/issues/5416)
-- Properly handle markdown sublists that utilize a `+` [#4041](https://github.com/rust-lang/rustfmt/issues/4210)
+- Properly handle markdown sublists that utilize a `+` [#4041](https://github.com/rust-lang/rustfmt/issues/4041)
 - rustfmt will no longer use shorthand initialization when rewriting a tuple struct even when `use_field_init_shorthand = true` as this leads to code that could no longer compile.
   Take the following struct as an example `struct MyStruct(u64);`. rustfmt will no longer format `MyStruct { 0: 0 }` as `MyStruct { 0 }` [#5488](https://github.com/rust-lang/rustfmt/issues/5488)
 - rustfmt no longer panics when formatting an empty code block in a doc comment with `format_code_in_doc_comments = true` [#5234](https://github.com/rust-lang/rustfmt/issues/5234). For example:
diff --git a/src/comment.rs b/src/comment.rs
index 85918ecc..c241e12c 100644
--- a/src/comment.rs
+++ b/src/comment.rs
@@ -58,25 +58,23 @@ fn custom_opener(s: &str) -> &str {
 }
 
 impl<'a> CommentStyle<'a> {
-    /// Returns `true` if the commenting style covers a line only.
+    /// Returns `true` if the commenting style cannot span multiple lines.
     pub(crate) fn is_line_comment(&self) -> bool {
-        match *self {
+        matches!(
+            self,
             CommentStyle::DoubleSlash
-            | CommentStyle::TripleSlash
-            | CommentStyle::Doc
-            | CommentStyle::Custom(_) => true,
-            _ => false,
-        }
+                | CommentStyle::TripleSlash
+                | CommentStyle::Doc
+                | CommentStyle::Custom(_)
+        )
     }
 
-    /// Returns `true` if the commenting style can span over multiple lines.
+    /// Returns `true` if the commenting style can span multiple lines.
     pub(crate) fn is_block_comment(&self) -> bool {
-        match *self {
-            CommentStyle::SingleBullet | CommentStyle::DoubleBullet | CommentStyle::Exclamation => {
-                true
-            }
-            _ => false,
-        }
+        matches!(
+            self,
+            CommentStyle::SingleBullet | CommentStyle::DoubleBullet | CommentStyle::Exclamation
+        )
     }
 
     /// Returns `true` if the commenting style is for documentation.
diff --git a/src/lib.rs b/src/lib.rs
index b9ab3ffd..8800e200 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -28,6 +28,7 @@ extern crate thin_vec;
 extern crate rustc_driver;
 
 use std::cell::RefCell;
+use std::cmp::min;
 use std::collections::HashMap;
 use std::fmt;
 use std::io::{self, Write};
@@ -385,9 +386,15 @@ fn format_code_block(
         .snippet
         .rfind('}')
         .unwrap_or_else(|| formatted.snippet.len());
+
+    // It's possible that `block_len < FN_MAIN_PREFIX.len()`. This can happen if the code block was
+    // formatted into the empty string, leading to the enclosing `fn main() {\n}` being formatted
+    // into `fn main() {}`. In this case no unindentation is done.
+    let block_start = min(FN_MAIN_PREFIX.len(), block_len);
+
     let mut is_indented = true;
     let indent_str = Indent::from_width(config, config.tab_spaces()).to_string(config);
-    for (kind, ref line) in LineClasses::new(&formatted.snippet[FN_MAIN_PREFIX.len()..block_len]) {
+    for (kind, ref line) in LineClasses::new(&formatted.snippet[block_start..block_len]) {
         if !is_first {
             result.push('\n');
         } else {
diff --git a/triagebot.toml b/triagebot.toml
index fa0824ac..b8691192 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1,1 +1,4 @@
+[autolabel."pr-not-reviewed"]
+new_pr = true
+
 [assign]


Test patch:
diff --git a/tests/source/issue_5730.rs b/tests/source/issue_5730.rs
new file mode 100644
index 00000000..9a3f4f0d
--- /dev/null
+++ b/tests/source/issue_5730.rs
@@ -0,0 +1,3 @@
+macro_rules! statement {
+    () => {;};
+}
diff --git a/tests/target/issue_5730.rs b/tests/target/issue_5730.rs
new file mode 100644
index 00000000..7922fdcc
--- /dev/null
+++ b/tests/target/issue_5730.rs
@@ -0,0 +1,3 @@
+macro_rules! statement {
+    () => {};
+}