about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-10-27 15:20:44 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-10-27 15:20:44 +0000
commiteb66d10cc3a6947cad6b4b169ed86b8c07f464d3 (patch)
tree952788030c03803438bf32ddda62233ce6c28c33 /compiler/rustc_mir_transform/src
parentb8bfd08999babd4b70822c445eb7b016e1f52fab (diff)
downloadrust-eb66d10cc3a6947cad6b4b169ed86b8c07f464d3.tar.gz
rust-eb66d10cc3a6947cad6b4b169ed86b8c07f464d3.zip
Fuse `gen` blocks
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs63
1 files changed, 49 insertions, 14 deletions
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 8fecff16a91..50d244d2831 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -249,18 +249,34 @@ struct TransformVisitor<'tcx> {
 }
 
 impl<'tcx> TransformVisitor<'tcx> {
-    // Make a `CoroutineState` or `Poll` variant assignment.
-    //
-    // `core::ops::CoroutineState` only has single element tuple variants,
-    // so we can just write to the downcasted first field and then set the
-    // discriminant to the appropriate variant.
-    fn make_state(
+    fn insert_none_ret_block(&self, body: &mut Body<'tcx>) -> BasicBlock {
+        let block = BasicBlock::new(body.basic_blocks.len());
+
+        let source_info = SourceInfo::outermost(body.span);
+
+        let (kind, idx) = self.coroutine_state_adt_and_variant_idx(true);
+        assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 0);
+        let statements = vec![Statement {
+            kind: StatementKind::Assign(Box::new((
+                Place::return_place(),
+                Rvalue::Aggregate(Box::new(kind), IndexVec::new()),
+            ))),
+            source_info,
+        }];
+
+        body.basic_blocks_mut().push(BasicBlockData {
+            statements,
+            terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
+            is_cleanup: false,
+        });
+
+        block
+    }
+
+    fn coroutine_state_adt_and_variant_idx(
         &self,
-        val: Operand<'tcx>,
-        source_info: SourceInfo,
         is_return: bool,
-        statements: &mut Vec<Statement<'tcx>>,
-    ) {
+    ) -> (AggregateKind<'tcx>, VariantIdx) {
         let idx = VariantIdx::new(match (is_return, self.coroutine_kind) {
             (true, hir::CoroutineKind::Coroutine) => 1, // CoroutineState::Complete
             (false, hir::CoroutineKind::Coroutine) => 0, // CoroutineState::Yielded
@@ -271,6 +287,22 @@ impl<'tcx> TransformVisitor<'tcx> {
         });
 
         let kind = AggregateKind::Adt(self.state_adt_ref.did(), idx, self.state_args, None, None);
+        (kind, idx)
+    }
+
+    // Make a `CoroutineState` or `Poll` variant assignment.
+    //
+    // `core::ops::CoroutineState` only has single element tuple variants,
+    // so we can just write to the downcasted first field and then set the
+    // discriminant to the appropriate variant.
+    fn make_state(
+        &self,
+        val: Operand<'tcx>,
+        source_info: SourceInfo,
+        is_return: bool,
+        statements: &mut Vec<Statement<'tcx>>,
+    ) {
+        let (kind, idx) = self.coroutine_state_adt_and_variant_idx(is_return);
 
         match self.coroutine_kind {
             // `Poll::Pending`
@@ -1285,10 +1317,13 @@ fn create_coroutine_resume_function<'tcx>(
     }
 
     if can_return {
-        cases.insert(
-            1,
-            (RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))),
-        );
+        let block = match coroutine_kind {
+            CoroutineKind::Async(_) | CoroutineKind::Coroutine => {
+                insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))
+            }
+            CoroutineKind::Gen(_) => transform.insert_none_ret_block(body),
+        };
+        cases.insert(1, (RETURNED, block));
     }
 
     insert_switch(body, cases, &transform, TerminatorKind::Unreachable);