Change:
LazyLock::new(|| { let hook = panic::take_hook(); panic::set_hook(Box::new(|info| { <ins> // If the error was caused by a broken pipe then this is not a bug. // Write the error and return immediately. See #98700. #[cfg(windows)] if let Some(msg) = info.payload().downcast_ref::<String>() { if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") { early_error_no_abort(ErrorOutputType::default(), &msg); return; } }; </ins> // Invoke the default handler, which prints the actual panic message and optionally a backtrace (*DEFAULT_HOOK)(info);

Discussion:
<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --After more testing, this only reproduces consistently under cmd, as other Windows shells have diverging behavior about what it means to close a pipe via program termination does not panic, but this appears to be not because of rustc doing anything different, but because finishes writing to stdout before it is closed. Note: never occurs under , as rustc sets to . <details<summary<coderustcdriver::setsigpipehandler</code </details<!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details
label +O-Windows
This is a consequence of using the print series of macros. They ignore errors but otherwise they're designed to panic on I/O errors. The panic could be handled in a global . Or by using and handling the error in place.
rustc explicitly chooses to override the startup code (which installs a SIGPIPE handler of SIGIGN) and reinstall a handler of SIGDFL: This means that rustc halts via SIGPIPE on POSIXy platforms and a broken pipe. To match this behavior on non-POSIX platforms, rustc should probably avoid the family of macros, and use a custom version which s on . What makes this interesting to me is that does terminate quietly on Windows in the face of a broken pipe; it's only style help printing which ICEs. The Zulip thread about is highly relevant here. The provides a platform-specific (a la ) to choose the SIGPIPE behavior between inherit/SIGDFL/SIG_IGN.
Oh, that is interesting and a bit of an odd difference. Should be easily fixed though? I mean if rustc already has code to print without ICEs.
<details<summary<code--help</code </details<details<summary<code-C help</code </detailsThere's nothing different going on here; is used in both paths. Instead, what I think is happening is buffering.

I wrote a little test program: And running it I get (All runs here are done in the Windows Terminal terminal emulator with a shell of nushell, which as of 0.64.0 is using cmd to run non-builtin commands. I did a smaller number of tests directly in cmd when I realized that this may be impacting the results, and observed equivalent behavior.) The number of s I get is variable, though: I've seen as low as and as high as . (I even saw with in nushell...) <details<summarySome other runs with <eminteresting</emqualities</summaryThese commands were run directly into a cmd shell, still with Windows Terminal as the terminal emulator: In the limited trials I did, I didn't see any skipped iterations directly in cmd. </detailsSomething interesting is going on here: if you'll note, the highlighted example is missing and , despite stderr locking saying that this shouldn't be possible. This isn't a one-off error or just copy/paste error, either; this kind of data loss happened multiple times (see above dropdown for some cherry-picked trial runs). In any case, changing the loop to results in a quiet exit every time. The reason exits quietly thus seems to be not because that code path is handling , but because Windows isn't returning a broken pipe error quickly. Now, I realized after collecting most of the above data that the shell may be impacting the result... Observed differences: nushell turns into roughly . This is why results in a broken pipe. cmd and pwsh parse and do command lookup before executing the first part of a pipeline. This means e.g. <subpwsh</subfails before calling at all. pwsh is really an odd one out here... (this continues infinitely.) Eerily, it seems that pwsh treats a pipe-to-finished-program as an infinite sink, not a broken pipe! This means that in pwsh, and inputting will hang until you CTRL-C the pipeline. In cmd, nushell-on-cmd, and Git Bash For completeness sake, under Git Bash (a MINGW64), consistently gives . Additionally, under all tested shells (Git Bash, pwsh, cmd, nushell-on-cmd), doing the equivalent of and CTRL-Cing the pipeline exited without a panic, as did the equivalent of [^8].

(As opposed to on a properly POSIX shell with SIGPIPE, where AIUI non-final entries in the pipeline get SIGPIPE and continue running if they SIGIGN it, rather than receiving SIGINT? Leading to panics?) [^8]: New info! Most of the time in Git Bash hangs until CTRL-C exits without a panic. ( is not accepted by this pipeline.) But sometimes when I've just run with piping to (with or without ) will result in , and once I even just got with no more info. (I'm still running the same pc-windows-msvc build from MINGW.)