Change:
<!-- 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. -- <!-- 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. --: Same issue still exists in : and also in : <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details
T-compiler triage: P-high. Leaving nomination label in place, since I don't want to disrupt WG-async-await workflow.
This does already ICE on 1.39.0
I could further simplify the code as:
However, this code does not cause ICE:
If you can reproduce this without depending on tokio that would be great.
How abot this?
Minimized:
in T-compiler meeting. Keeping as P-high but removing nomination.
OK so I've been investigating this a bit. I am not quite able to write-up mentoring instructions yet because I don't really understand what's going on, but I can leave a few notes. First off, the ICE occurs in the code that is attempting to approximate what values may be live across an . It occurs specifically when you have a structure. The nested async blocks etc are not really needed. For example, this also fails in the same way; The ICE occurs in this match arm: It appears to be related to some logic that is attempting to figure out a "worst case" execution order for instructions: I confess I don't quite follow this logic anymore, but the problem has to do with entering a distinct async block. This code for example does not trigger the failure:
Ah, I think maybe I see the problem here actually -- I suspect the problem is that we need to clear (and then restore) the flag when we recurse into a closure body.

Discussion:
self.cx.parent ); <ins> // Save all state that is specific to the outer function // body. These will be restored once down below, once we've // visited the body. </ins> let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0); let outer_cx = self.cx; let outer_ts = mem::take(&mut self.terminating_scopes); <ins> // The 'pessimistic yield' flag is set to true when we are // processing a `+=` statement and have to make pessimistic // control flow assumptions. This doesn't apply to nested // bodies within the `+=` statements. See #69307. let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false); </ins> self.terminating_scopes.insert(body.value.hir_id.local_id); if let Some(root_id) = self.cx.root_id {

self.expr_and_pat_count = outer_ec; self.cx = outer_cx; self.terminating_scopes = outer_ts; <ins> self.pessimistic_yield = outer_pessimistic_yield; </ins> } fn visit_arm(&mut self, a: &'tcx Arm<'tcx>) {

<ins> // Regression test for #69307 // // Having a `async { .. foo.await .. }` block appear inside of a `+=` // expression was causing an ICE due to a failure to save/restore // state in the AST numbering pass when entering a nested body. // // check-pass // edition:2018 fn block_on<F>(_: F) -> usize { 0 } fn main() {} async fn bar() { let mut sum = 0; sum += { block_on(async { baz().await; let mut inner = 1; inner += block_on(async { baz().await; 0 }) }) }; } async fn baz() {} </ins>

<ins> // Regression test for #69307 // // Having a `async { .. foo.await .. }` block appear inside of a `+=` // expression was causing an ICE due to a failure to save/restore // state in the AST numbering pass when entering a nested body. // // check-pass // edition:2018 fn block_on<F>(_: F) -> usize { 0 } fn main() {} async fn bar() { let mut sum = 0; sum += block_on(async { baz().await; }); } async fn baz() {} </ins>